Source code for gamspy.math.misc

from __future__ import annotations

from typing import TYPE_CHECKING

import gamspy as gp
import gamspy._algebra.expression as expression
import gamspy._symbols.implicits as implicits
import gamspy.utils as utils
from gamspy.exceptions import ValidationError

if TYPE_CHECKING:
    from gamspy import Alias, Set
    from gamspy._algebra.expression import Expression
    from gamspy._symbols.implicits.implicit_symbol import ImplicitSymbol
    from gamspy._symbols.symbol import Symbol


class MathOp:
    def __init__(
        self,
        op_name: str,
        elements: tuple,
    ):
        self.op_name = op_name
        self.elements = elements

    def gamsRepr(self):
        operands_str = ",".join([_stringify(elem) for elem in self.elements])
        return f"{self.op_name}({operands_str})"

    def _find_variables(self):
        variables = []
        for elem in self.elements:
            if isinstance(elem, gp.Variable):
                variables.append(elem.name)
            elif isinstance(elem, implicits.ImplicitVariable):
                variables.append(elem.parent.name)
            elif isinstance(elem, expression.Expression):
                variables += elem._find_variables()

        return variables

    def __str__(self):
        return self.gamsRepr()

    def __len__(self):
        return len(self.gamsRepr())


def _stringify(x: str | int | float | Symbol | ImplicitSymbol):
    if isinstance(x, (int, float)):
        x = utils._map_special_values(x)

        return str(x)
    elif isinstance(x, str):
        return f'"{x}"'

    return x.gamsRepr()


[docs] def abs(x: int | float | Symbol) -> Expression: """ Absolute value of x (i.e. ``|x|``) Returns ------- Expression """ return expression.Expression(None, MathOp("abs", (x,)), None)
[docs] def ceil(x: int | float | Symbol) -> Expression: """ The smallest integer greater than or equal to x Returns ------- Expression """ return expression.Expression(None, MathOp("ceil", (x,)), None)
[docs] def div( dividend: int | float | Symbol, divisor: int | float | Symbol ) -> Expression: """ Dividing operation Parameters ---------- dividend : int | float | Symbol divisor : int | float | Symbol Returns ------- Expression """ return expression.Expression( None, MathOp("div", (dividend, divisor)), None )
[docs] def div0( dividend: int | float | Symbol, divisor: int | float | Symbol ) -> Expression: """ Dividing operation Parameters ---------- dividend : int | float | Symbol divisor : int | float | Symbol Returns ------- Expression """ return expression.Expression( None, MathOp("div0", (dividend, divisor)), None )
[docs] def dist( x1: tuple[int, float] | Symbol, x2: tuple[int, float] | Symbol, ) -> Expression: """ L2 norm Returns ------- Expression Raises ------ Exception In case both x1 and x2 are not a tuple or none. """ if isinstance(x1, tuple) or isinstance(x2, tuple): raise ValidationError("Both should be a tuple or none") return expression.Expression(None, MathOp("eDist", (x1, x2)), None)
[docs] def factorial(x: int | Symbol) -> Expression: """ Factorial of x Returns ------- Expression """ return expression.Expression(None, MathOp("fact", (x,)), None)
[docs] def floor(x: int | float | Symbol) -> Expression: """ The greatest integer less than or equal to x Returns ------- Expression """ return expression.Expression(None, MathOp("floor", (x,)), None)
[docs] def fractional(x: int | float | Symbol) -> Expression: """ Returns the fractional part of x Returns ------- Expression """ return expression.Expression(None, MathOp("frac", (x,)), None)
[docs] def Min(*values) -> Expression: """ Minimum value of the values, where the number of values may vary. Returns ------- Expression """ return expression.Expression(None, MathOp("min", values), None)
[docs] def Max(*values) -> Expression: """ Maximum value of the values, where the number of values may vary. Returns ------- Expression """ return expression.Expression(None, MathOp("max", values), None)
[docs] def mod(x: float | Symbol, y: float | Symbol) -> Expression: """ Remainder of x divided by y. Returns ------- Expression """ return expression.Expression(None, MathOp("mod", (x, y)), None)
[docs] def Round(x: float | Symbol, num_decimals: int = 0) -> Expression: """ Round x to num_decimals decimal places. Parameters ---------- x : float | Symbol decimal : int, optional Returns ------- Expression """ return expression.Expression( None, MathOp("round", (x, num_decimals)), None )
[docs] def sign(x: Symbol) -> Expression: """ Sign of x returns 1 if x > 0, -1 if x < 0, and 0 if x = 0 Parameters ---------- x : Symbol Returns ------- Expression """ return expression.Expression(None, MathOp("sign", (x,)), None)
[docs] def slexp(x: int | float | Symbol, S: int | float = 150) -> Expression: """ Smooth (linear) exponential Parameters ---------- x : int | float | Symbol S : int | float, by default 150 Returns ------- Expression """ return expression.Expression(None, MathOp("slexp", (x, S)), None)
[docs] def sqexp(x: int | float | Symbol, S: int | float = 150) -> Expression: """ Smooth (quadratic) exponential Parameters ---------- x : int | float | Symbol S : int | float, by default 150 Returns ------- Expression """ return expression.Expression(None, MathOp("sqexp", (x, S)), None)
[docs] def sqrt(x: int | float | Symbol) -> Expression: """ Square root of x Returns ------- Expression """ return expression.Expression(None, MathOp("sqrt", (x,)), None)
[docs] def truncate(x: int | float | Symbol) -> Expression: """ Returns the integer part of x Returns ------- Expression """ return expression.Expression(None, MathOp("trunc", (x,)), None)
[docs] def beta(x: int | float | Symbol, y: int | float | Symbol) -> Expression: """ Beta function Parameters ---------- x : int | float | Symbol y : int | float | Symbol Returns ------- Expression """ return expression.Expression(None, MathOp("beta", (x, y)), None)
[docs] def regularized_beta( x: int | float, y: int | float, z: int | float ) -> Expression: """ Beta function Parameters ---------- x : int | float y : int | float z : int | float Returns ------- Expression """ return expression.Expression(None, MathOp("betaReg", (x, y, z)), None)
[docs] def gamma(x: int | float | Symbol) -> Expression: """ Gamma function Parameters ---------- x : int | float Returns ------- Expression """ return expression.Expression(None, MathOp("gamma", (x,)), None)
[docs] def regularized_gamma(x: int | float, a: int | float) -> Expression: """ Gamma function Parameters ---------- x : int | float a : int | float Returns ------- Expression """ return expression.Expression(None, MathOp("gammaReg", (x, a)), None)
[docs] def lse_max(*xs) -> Expression: """ Smoothed Max via the Logarithm of the Sum of Exponentials Returns ------- Expression """ if len(xs) < 1: raise ValidationError("lse_max requires at least 1 x") return expression.Expression(None, MathOp("lseMax", xs), None)
[docs] def lse_max_sc(t, *xs) -> Expression: """ Scaled smoothed Max via the Logarithm of the Sum of Exponentials Returns ------- Expression """ if len(xs) < 1: raise ValidationError("lse_max requires at least 1 x") return expression.Expression(None, MathOp("lseMaxSc", xs + (t,)), None)
[docs] def lse_min(*xs) -> Expression: """ Smoothed Min via the Logarithm of the Sum of Exponentials Returns ------- Expression """ if len(xs) < 1: raise ValidationError("lse_max requires at least 1 x") return expression.Expression(None, MathOp("lseMin", xs), None)
[docs] def lse_min_sc(t, *xs) -> Expression: """ Scaled smoothed Min via the Logarithm of the Sum of Exponentials Returns ------- Expression """ if len(xs) < 1: raise ValidationError("lse_max requires at least 1 x") return expression.Expression(None, MathOp("lseMinSc", (t,) + xs), None)
[docs] def ncp_cm(x: Symbol, y: Symbol, z: float | int) -> Expression: """ Chen-Mangasarian smoothing Parameters ---------- x : Symbol y : Symbol z : int | float Returns ------- Expression """ return expression.Expression(None, MathOp("ncpCM", (x, y, z)), None)
[docs] def ncp_f(x: Symbol, y: Symbol, z: int | float = 0) -> Expression: """ Fisher-Burmeister smoothing Parameters ---------- x : Symbol y : Symbol z : int | float, optional Returns ------- Expression """ return expression.Expression(None, MathOp("ncpF", (x, y, z)), None)
[docs] def ncpVUpow( r: Symbol, s: Symbol, mu: int | float = 0, ) -> Expression: """ NCP Veelken-Ulbrich: smoothed min(r,s) Parameters ---------- r : Symbol s : Symbol mu : int | float, optional Returns ------- Expression """ return expression.Expression(None, MathOp("ncpVUpow", (r, s, mu)), None)
[docs] def ncpVUsin(r: Symbol, s: Symbol, mu: int | float = 0) -> Expression: """ NCP Veelken-Ulbrich: smoothed min(r,s) Parameters ---------- r : Symbol s : Symbol mu : int | float, optional Returns ------- Expression """ return expression.Expression(None, MathOp("ncpVUsin", (r, s, mu)), None)
[docs] def poly(x, *args) -> Expression: """ Polynomial function Returns ------- Expression """ return expression.Expression(None, MathOp("poly", (x,) + args), None)
[docs] def sigmoid(x: int | float | Symbol) -> Expression: """ Sigmoid of x Parameters ---------- x : int | float | Symbol Returns ------- Expression """ return expression.Expression(None, MathOp("sigmoid", (x,)), None)
[docs] def rand_binomial(n: int | float, p: int | float) -> Expression: """ Generate a random number from the binomial distribution, where n is the number of trials and p the probability of success for each trial Parameters ---------- n : int | float p : int | float Returns ------- Expression """ return expression.Expression(None, MathOp("randBinomial", (n, p)), None)
[docs] def rand_linear( low: int | float, slope: int | float, high: int | float ) -> Expression: """ Generate a random number between low and high with linear distribution. slope must be greater than 2 / (high - low) Parameters ---------- low : int | float slope : int | float high : int | float Returns ------- Expression """ return expression.Expression( None, MathOp("randLinear", (low, slope, high)), None )
[docs] def rand_triangle( low: int | float, mid: int | float, high: int | float ) -> Expression: """ Generate a random number between low and high with triangular distribution. mid is the most probable number. Parameters ---------- low : int | float mid : int | float high : int | float Returns ------- Expression """ return expression.Expression( None, MathOp("randTriangle", (low, mid, high)), None )
[docs] def same_as(self: Set | Alias, other: Set | Alias | str) -> Expression: """ Evaluates to true if this set is identical to the given set or alias, false otherwise. Parameters ---------- other : Set | Alias Returns ------- Expression """ return expression.Expression(None, MathOp("sameAs", (self, other)), None)
[docs] def slrec(x: int | float | Symbol, S: int | float = 1e-10) -> Expression: """ Smooth (linear) reciprocal Parameters ---------- x : int | float | Symbol S : int | float, by default 1e-10 Returns ------- Expression """ return expression.Expression(None, MathOp("slrec", (x, S)), None)
[docs] def sqrec(x: int | float | Symbol, S: int | float = 1e-10) -> Expression: """ Smooth (quadratic) reciprocal Parameters ---------- x : int | float | Symbol S : int | float, by default 1e-10 Returns ------- Expression """ return expression.Expression(None, MathOp("sqrec", (x, S)), None)
[docs] def entropy(x: int | float | Symbol) -> Expression: """ L2 Norm of x Parameters ---------- x : int | float | Symbol Returns ------- Expression """ return expression.Expression(None, MathOp("entropy", (x,)), None)
[docs] def errorf(x: int | float | Symbol) -> Expression: """ Integral of the standard normal distribution Parameters ---------- x : int, float, Symbol Returns ------- Expression """ return expression.Expression(None, MathOp("errorf", (x,)), None)
[docs] def ifthen( condition: Expression, yes_return: float | Expression, no_return: float | Expression, ) -> Expression: """ If the logical condition is true, the function returns iftrue, else it returns else Parameters ---------- condition : Expression yes_return : float | Expression no_return : float | Expression Returns ------- Expression Examples -------- >>> from gamspy.math import ifthen >>> import gamspy as gp >>> m = gp.Container() >>> tt = gp.Parameter(m, "tt", records=2) >>> y = gp.Parameter(m, "y", records=2) >>> x = ifthen(tt == 2, 3, 4 + y) """ condition.representation = utils._replace_equality_signs( condition.gamsRepr() ) return expression.Expression( None, MathOp("ifthen", (condition, yes_return, no_return)), None )
[docs] def bool_and(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_and", (x, y)), None)
[docs] def bool_eqv(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_eqv", (x, y)), None)
[docs] def bool_imp(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_imp", (x, y)), None)
[docs] def bool_not(x: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_not", (x,)), None)
[docs] def bool_or(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_or", (x, y)), None)
[docs] def bool_xor(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("bool_xor", (x, y)), None)
[docs] def rel_eq(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_eq", (x, y)), None)
[docs] def rel_ge(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_ge", (x, y)), None)
[docs] def rel_gt(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_gt", (x, y)), None)
[docs] def rel_le(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_le", (x, y)), None)
[docs] def rel_lt(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_lt", (x, y)), None)
[docs] def rel_ne(x: int | Symbol, y: int | Symbol) -> Expression: return expression.Expression(None, MathOp("rel_ne", (x, y)), None)