Source code for comando

"""Configuration of the backends for COMANDO."""

# This file is part of the COMANDO project which is released under the MIT
# license. See file LICENSE for full license details.
#
# AUTHORS: Marco Langiu
import operator
import os
from enum import Enum
from functools import partial, reduce

os.environ["SYMPY_CACHE_SIZE"] = "None"
import sympy  # noqa: E402

sympy.Boolean = sympy.logic.boolalg.Boolean

try:
    # symengine brings significant speedup when using arrays of variables or constraints.
    # this code tries to use it, if available

    import symengine
    from symengine.lib import symengine_wrapper

    symengine.Boolean = symengine_wrapper.Boolean

    def _0(self):
        return self.args[0]

    def _1(self):
        return self.args[1]

    symengine_wrapper.Relational.lhs = property(_0)
    symengine_wrapper.Relational.rhs = property(_1)
    symengine_wrapper.Le.lts = property(_0)
    symengine_wrapper.Le.gts = property(_1)

    # this variable is used by core.py to correctly use the symengine.Symbol or the sympy.Symbol as a backup
    USING_SYMENGINE = True
except ImportError:
    USING_SYMENGINE = False


[docs] class Domain(Enum): """Simple Enum for variable domains, specify other types via bounds.""" REAL = 1 INTEGER = 2 BINARY = 3
REAL, INTEGER, BINARY = Domain.REAL, Domain.INTEGER, Domain.BINARY NAN = float("nan") INF = float("inf") UNBOUNDED = {-INF, INF} EPS = 1e-9 def identity(expr): """Return expr.""" return expr def _sum(*args): """Return the sum of the elements in args.""" return sum(args)
[docs] def prod(*args): """Return the product of the elements in args.""" return reduce(operator.mul, args)
base_op_map = { "()": identity, "Add": _sum, "Neg": lambda arg: -arg, "Mul": prod, "Div": operator.truediv, "Pow": operator.pow, "Inv": partial(operator.truediv, 1), "LessThan": operator.le, "GreaterThan": operator.ge, "Equality": operator.eq, } exponential_function_names = {"exp", "log"} nonsmooth_function_names = {"sign", "Abs", "Min", "Max", "ceiling", "floor"} trigonometric_function_names = {"sin", "cos", "tan", "cot", "sec", "csc"} trigonometric_inverse_function_names = {"asin", "acos", "atan", "acot", "asec", "acsc"} hyperbolic_function_names = {"sinh", "cosh", "tanh", "coth", "sech", "csch"} hyperbolic_inverse_function_names = { "asinh", "acosh", "atanh", "acoth", "asech", "acsch", } # NOTE: All of these functions depend on the backend and therefore need to be # looked up dynamically to allow for backend switches! comando_functions = set().union( exponential_function_names, nonsmooth_function_names, trigonometric_function_names, trigonometric_inverse_function_names, hyperbolic_function_names, hyperbolic_inverse_function_names, ) def _get_sympy_attr(name): if USING_SYMENGINE: return getattr(symengine, name) else: return getattr(sympy, name) def __getattr__(name): """Get attributes that can't be found from the backend.""" from comando import core try: return getattr(core, name) # if comando.core does not have an attribute, we check symengine/sympy for it except AttributeError: return _get_sympy_attr(name) op_map = base_op_map.copy() for f_name in comando_functions: op_map[f_name] = _get_sympy_attr(f_name) Zero = _get_sympy_attr("S")(0) from .core import * # noqa: F401, E402, F403 # DEPRECATED - use evaluate from comando/utility.py instead! ## Teaching all sympy expressions about their value (Won't work with symengine!) ## sympy.Expr.value = property(comando.utility.evaluate) # NOTE: must be last line of file! __version__ = "1.2.0"