Source code for bertini.symbolics

# This file is part of Bertini 2.
#
# python/bertini/symbolics/__init__.py is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# python/bertini/symbolics/__init__.py is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with python/bertini/symbolics/__init__.py.  If not, see <http://www.gnu.org/licenses/>.
#
#  Copyright(C) Bertini2 Development Team
#
#  See <http://www.gnu.org/licenses/> for a copy of the license,
#  as well as COPYING.  Bertini2 is provided with permitted
#  additional terms in the b2/licenses/ directory.

"""The symbolic expression system for building polynomial systems -- a FLAT namespace.

Renamed from ``function_tree`` (the underlying C++ module keeps that name).  Everything lives
directly here, with no ``.symbol`` / ``.operator`` / ``.root`` sub-levels:

* symbols -- :class:`Variable`, :class:`Complex`, :class:`Integer`, :class:`Rational`, ``E``, ``Pi``
* operator node types -- :class:`Sum`, :class:`Mult`, :class:`Power`, :class:`Sqrt`, ... (for
  inspecting/walking expression trees)
* roots -- :class:`NamedExpression`

plus :func:`variables`, :func:`sqrt`, and :class:`VariableGroup`.
"""

from bertini._pybertini import function_tree as _pybft
from bertini._pybertini.container import VariableGroup

# Flatten: pull the top-level utilities and every node type from symbol/operator/root up to here.
from bertini._pybertini.function_tree import *          # noqa: F401,F403  (sin, cos, canonicalize, ...)
from bertini._pybertini.function_tree.symbol import *   # noqa: F401,F403  (Variable, Complex, E, Pi, ...)
from bertini._pybertini.function_tree.operator import * # noqa: F401,F403  (Sum, Mult, Power, ...)
from bertini._pybertini.function_tree.root import *     # noqa: F401,F403  (NamedExpression, ...)

# The top-level `import *` dragged the C++ sub-submodule objects in as names (symbol/operator/root);
# drop them so this namespace stays flat.  `AbstractNode` stays public -- it is the base every node
# inherits, so isinstance-based tree walking can spell it from the flat namespace.  The finer-grained
# abstract bases exist in C++ only and are not part of the public surface, so they are dropped.
_HIDDEN = {'symbol', 'operator', 'root',
           'AbstractSymbol', 'AbstractNamedSymbol', 'AbstractNumber', 'AbstractOp',
           # constants factories superseded by the bertini.E / bertini.Pi / bertini.I constants
           'make_e', 'make_i', 'make_pi',
           # Differential is an internal differentiation artifact, not a user-facing symbol
           'Differential'}
for _n in _HIDDEN:
    globals().pop(_n, None)
del _n

from bertini._pybertini.function_tree.operator import Sqrt as _Sqrt


[docs] def sqrt(x): """Symbolic square-root operator.""" return _Sqrt(x)
[docs] def random_real(): """A random real number as a constant node (a real :class:`Complex` leaf, imaginary part 0). The always-symbolic shortcut for ``bertini.random_real(symbolic=True)`` -- a random real *coefficient* to drop straight into an expression, at the current default precision (set ``bertini.default_precision`` first for more digits). For a precision-independent *exact* random constant use :meth:`Rational.rand_real` instead. """ from bertini.random import random_real as _rr return _rr(symbolic=True)
[docs] def random_complex(): """A random complex number as a constant node (a :class:`Complex` leaf). The always-symbolic shortcut for ``bertini.random_complex(symbolic=True)`` -- a random complex *coefficient* to drop straight into an expression, at the current default precision (set ``bertini.default_precision`` first for more digits). For a precision-independent *exact* random constant use :meth:`Rational.rand` instead. """ from bertini.random import random_complex as _rc return _rc(symbolic=True)
VariableGroup.__str__ = lambda vg: '[{}]'.format(','.join([str(v) for v in vg])) def _variablegroup_matmul(self, coefficients): """``vg @ coeffs`` -- the single linear-combination node sum_i vg[i]*coeffs[i]. ``coeffs`` is a length-``len(vg)`` 1-D iterable/array of exact values (see :func:`bertini.coefficient`; Python floats are refused) or function-tree nodes. Handy for a projection / linear functional: ``pi = vg @ bertini.random_vector(len(vg), real=True)``. """ import numpy as _np from bertini._coefficients import coefficient as _coefficient from bertini._pybertini.function_tree import AbstractNode as _AbstractNode c = _np.asarray(coefficients, dtype=object).ravel() if c.size != len(self): raise ValueError( "vg @ coeffs: expected {} coefficients (one per variable) but got {}" .format(len(self), c.size)) terms = [var * (coef if isinstance(coef, _AbstractNode) else _coefficient(coef)) for var, coef in zip(self, c)] result = terms[0] for t in terms[1:]: result = result + t return result VariableGroup.__matmul__ = _variablegroup_matmul
[docs] def variables(base, indices=None, fmt='{base}{index}'): """Make a list of Variables. Two forms: :: # explicit names -- pass a list/tuple of names as the sole argument: x, y, z = bertini.variables(['x', 'y', 'z']) # integer-indexed -- a name prefix + a count (or an iterable of indices): v = bertini.variables('v', 3) # -> [v0, v1, v2] Parameters ---------- base : str or iterable of str A name prefix (with ``indices``), OR -- when ``indices`` is omitted -- an iterable of the explicit variable names. indices : int or iterable of int, optional An int ``n`` (shorthand for ``range(n)``) or any iterable of ints. Omit to use the explicit-names form. fmt : str ``str.format`` template using ``{base}`` and ``{index}``; default ``'{base}{index}'`` gives ``x0, x1, x2, ...``. Returns a ``list[Variable]``. Wrap in a VariableGroup if desired:: pb.VariableGroup(pb.variables('x', 5)) """ from bertini._pybertini.function_tree.symbol import Variable # explicit-names form: variables(['x', 'y', 'z']) if indices is None: if isinstance(base, str): raise TypeError( "variables('x') needs a count or indices, e.g. variables('x', 3); to name variables " "explicitly pass a list of names, e.g. variables(['x', 'y', 'z'])") return [Variable(name) for name in base] if isinstance(indices, int): indices = range(indices) return [Variable(fmt.format(base=base, index=i)) for i in indices]
__all__ = list(dict.fromkeys( [n for n in dir(_pybft) if n not in _HIDDEN] + [n for n in dir(_pybft.symbol) if n not in _HIDDEN] + [n for n in dir(_pybft.operator) if n not in _HIDDEN] + [n for n in dir(_pybft.root) if n not in _HIDDEN] + ['VariableGroup', 'variables', 'sqrt', 'random_real', 'random_complex']))