Source code for gamspy.math.misc

from __future__ import annotations

from typing import TYPE_CHECKING, Literal

import gamspy._algebra.condition as condition
import gamspy._algebra.expression as expression
import gamspy._algebra.operable as operable
import gamspy._symbols as syms
import gamspy._symbols.implicits as implicits
import gamspy._validation as validation
import gamspy.utils as utils
from gamspy._container import Container
from gamspy.exceptions import ValidationError

if TYPE_CHECKING:
    import pandas as pd

    from gamspy import Alias, Parameter, Set
    from gamspy._algebra.expression import Expression
    from gamspy._symbols.implicits.implicit_symbol import (
        ImplicitParameter,
        ImplicitSet,
        ImplicitSymbol,
    )
    from gamspy._symbols.symbol import Symbol
    from gamspy._types import OperableType


[docs] class MathOp(operable.Operable): """ Represents a symbolic and numerical mathematical operation. Parameters ---------- op_name : str Name of the operation. elements : tuple Arguments for the operation. safe_cancel : bool Whether to allow square and square root to cancel each other. Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import Round, div >>> m = Container() >>> a = Parameter(m, "a", records=200) >>> b = Parameter(m, "b") >>> Round(div(a, 3), 2).toValue() np.float64(66.67) """ def __init__( self, op_name: str, elements: tuple, safe_cancel: bool = False, ): self.op_name = op_name self.elements = list(elements) self.safe_cancel = safe_cancel self.container = None self.domain: list[Set | Alias] = [] self.dimension = 0 if hasattr(elements[0], "container"): self.container = elements[0].container # type: ignore if hasattr(elements[0], "domain"): self.domain: list[Set | Alias] = elements[0].domain # type: ignore self.dimension = validation.get_dimension(self.domain) self.where = condition.Condition(self) def __eq__(self, other): return expression.Expression(self, "=e=", other) def __ne__(self, other): return expression.Expression(self, "ne", other) def __len__(self): if self.records is not None: return len(self.records.index) return 0 @property def records(self) -> pd.DataFrame | None: """ Evaluates the expression and returns the resulting records. Returns ------- pd.DataFrame | None Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import Round, div >>> m = Container() >>> a = Parameter(m, "a", records=200) >>> b = Parameter(m, "b") >>> Round(div(a, 3), 2).records value 0 66.67 """ container = self.container if container is None: container = Container() temp_name = "a" + utils._get_unique_name() temp_param = syms.Parameter._constructor_bypass( container, temp_name, self.domain ) temp_param[...] = self del container.data[temp_name] return temp_param.records
[docs] def toValue(self) -> float | None: """ Convenience method to return expression records as a Python float. Only possible if there is a single record as a result of the expression evaluation. Returns ------- float | None Raises ------ TypeError In case the dimension of the expression is not zero. Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import Round, div >>> m = Container() >>> a = Parameter(m, "a", records=200) >>> b = Parameter(m, "b") >>> Round(div(a, 3), 2).toValue() np.float64(66.67) """ if self.dimension != 0: raise TypeError( f"Cannot extract value data for non-scalar expressions (expression dimension is {self.dimension})" ) records = self.records if records is not None: return records["value"][0] return records
[docs] def toList(self) -> list | None: """ Convenience method to return the records of the expression as a list. Returns ------- list | None Examples -------- >>> import numpy as np >>> from gamspy import Container, Parameter, Set >>> from gamspy.math import Round, div >>> m = Container() >>> i = Set(m, "i", records=["i1", "i2"]) >>> a = Parameter(m, "a", domain=i, records=np.array([200, 300])) >>> Round(div(a, 3), 2).toList() [['i1', 66.67], ['i2', 100.0]] """ records = self.records if records is not None: return records.values.tolist() return None
[docs] def gamsRepr(self) -> str: """ Representation of this MathOp in GAMS. Returns ------- str Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> a = gp.Parameter(m, "a", records=5) >>> print(gp.math.div(a,5).gamsRepr()) div(a,5) """ operands_str = ",".join([_stringify(elem) for elem in self.elements]) return f"{self.op_name}({operands_str})"
[docs] def latexRepr(self) -> str: """ Representation of this MathOp in Latex. Returns ------- str Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> a = gp.Parameter(m, "a", records=5) >>> print(gp.math.div(a,5).latexRepr()) div(a,5) """ op_map = { "sqrt": "\\sqrt", "floor": "\\floor", "ceil": "\\lceil", "abs": "\\lvert", } operands_str = ",".join( [_stringify(elem, latex=True) for elem in self.elements] ) if self.op_name in op_map: return f"{op_map[self.op_name]}{{{operands_str}}}" op_name = self.op_name.replace("_", r"\_") return f"{op_name}({operands_str})"
def __str__(self): return self.gamsRepr()
def _option_statement( source: Set | Alias | ImplicitSet | Parameter | ImplicitParameter, target: Set | Alias | Parameter | ImplicitSet | ImplicitParameter, direction: Literal["right", "left"], ) -> None: if ( isinstance(source, (implicits.ImplicitSet, implicits.ImplicitParameter)) and source.domain != source.parent.domain ): raise ValidationError( f"Given indices for {source.gamsRepr()} does not match its domain!" ) if ( isinstance(target, (implicits.ImplicitSet, implicits.ImplicitParameter)) and target.domain != target.parent.domain ): raise ValidationError( f"Given indices for {target.gamsRepr()} does not match its domain!" ) if direction == "right": operator = "<" elif direction == "left": operator = "<=" else: raise ValidationError("Direction must be either 'right' or 'left'.") source.container._add_statement(f"option {target.name} {operator} {source.name};") source.container._synch_with_gams(gams_to_gamspy=True)
[docs] def project( source: Set | Alias | ImplicitSet | Parameter | ImplicitParameter, target: Set | Alias | ImplicitSet, direction: Literal["right", "left"] = "right", ) -> None: """ Projects the dimensions of a source set onto a target set. Parameters ---------- source : Set | Alias | ImplicitSet | Parameter | ImplicitParameter The multi-dimensional source set. target : Set | Alias | ImplicitSet The target set to project into. direction : Literal["right", "left"], optional The direction of the permutation/projection if domains are ambiguous. Default is "right". Examples -------- >>> import gamspy as gp >>> import gamspy.math as gmath >>> m = gp.Container() >>> i = gp.Set(m, "i", records=["i1", "i2"]) >>> j = gp.Set(m, "j", records=["j1", "j2"]) >>> k = gp.Set(m, "k", records=["k1", "k2"]) >>> ijk = gp.Set(m, "ijk", domain=[i, j, k]) >>> ijk[i, j, k] = True >>> ij = gp.Set(m, "ij", domain=[i, j]) >>> gmath.project(source=ijk[i, j, k], target=ij[i, j]) >>> ij.toList() [('i1', 'j1'), ('i1', 'j2'), ('i2', 'j1'), ('i2', 'j2')] """ _option_statement(source, target, direction)
[docs] def aggregate( source: Set | Alias | ImplicitSet | Parameter | ImplicitParameter, target: Parameter | ImplicitParameter, direction: Literal["right", "left"] = "right", ) -> None: """ Aggregates the elements of a source set into a target parameter. Parameters ---------- source : Set | Alias | ImplicitSet The multi-dimensional source set. target : Parameter | ImplicitParameter The target set to project into. direction : Literal["right", "left"], optional The direction of the permutation/projection if domains are ambiguous. Default is "right". Examples -------- >>> import gamspy as gp >>> import gamspy.math as gmath >>> m = gp.Container() >>> i = gp.Set(m, "i", records=["i1", "i2"]) >>> j = gp.Set(m, "j", records=["j1", "j2"]) >>> k = gp.Set(m, "k", records=["k1", "k2", "k3"]) >>> ijk = gp.Set(m, "ijk", domain=[i, j, k]) >>> ijk[i, j, k] = True >>> count_ij = gp.Parameter(m, "count_ij", domain=[i, j]) >>> gmath.aggregate(source=ijk[i, j, k], target=count_ij[i, j]) >>> count_ij.toList() [('i1', 'j1', 3.0), ('i1', 'j2', 3.0), ('i2', 'j1', 3.0), ('i2', 'j2', 3.0)] """ if not isinstance(target, (syms.Parameter, implicits.ImplicitParameter)): raise TypeError( f"`target` must be of type Parameter or ImplicitParameter but given {type(target)}!" ) # Functionally identical to project, but separated for semantic clarity # to the Python user since the GAMS backend behavior changes depending on # the target symbol type. _option_statement(source, target, direction)
def _stringify(x: str | int | float | Symbol | ImplicitSymbol, *, latex: bool = False): if isinstance(x, (int, float)): x = utils._map_special_values(x) return str(x) elif isinstance(x, str): if latex: x = x.replace("_", r"\_") return f'"{x}"' if latex: return x.latexRepr() return x.gamsRepr() # type: ignore
[docs] def abs(x: OperableType) -> MathOp: """ Absolute value of ``x`` (i.e. ``|x|``) Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import abs >>> m = Container() >>> a = Parameter(m, "a", records=-3.8) >>> b = Parameter(m, "b") >>> b[...] = abs(a) >>> b.toValue() np.float64(3.8) """ return MathOp("abs", (x,))
[docs] def ceil(x: OperableType) -> MathOp: """ The smallest integer greater than or equal to ``x`` (i.e. ``ceil(4.1)`` returns ``5``) Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import ceil >>> m = Container() >>> a = Parameter(m, "a", records=3.2) >>> b = Parameter(m, "b") >>> b[...] = ceil(a) >>> b.toValue() np.float64(4.0) """ return MathOp("ceil", (x,))
[docs] def div(dividend: OperableType, divisor: OperableType) -> MathOp: """ Dividing operation, Error if the divisor is ``0``. To avoid the error, ``div0`` can be used instead. Parameters ---------- dividend : OperableType divisor : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import div >>> m = Container() >>> a = Parameter(m, "a", records=210) >>> b = Parameter(m, "b") >>> b[...] = div(a, 3) >>> b.toValue() np.float64(70.0) """ return MathOp("div", (dividend, divisor))
[docs] def div0(dividend: OperableType, divisor: OperableType) -> MathOp: """ Dividing operation, returns ``1e+299`` if the divisor is ``0`` Parameters ---------- dividend : OperableType divisor : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import div0 >>> m = Container() >>> a = Parameter(m, "a", records=210) >>> b = Parameter(m, "b") >>> b[...] = div0(a, 0) >>> b.toValue() np.float64(1e+299) """ return MathOp("div0", (dividend, divisor))
[docs] def dist( x1: OperableType, x2: OperableType, ) -> MathOp: """ Euclidean or L-2 Norm: ``sqrt(x1^2 + x2^2 + ... + xn^2)`` Returns ------- MathOp Raises ------ Exception In case both x1 and x2 are not a tuple or none. Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import dist >>> m = Container() >>> a = Parameter(m, "a", records=210) >>> b = Parameter(m, "b") >>> b[...] = dist(a, 100) """ return MathOp("eDist", (x1, x2))
[docs] def factorial(x: int) -> MathOp: """ Factorial of ``x``: ``x!`` Parameters ---------- x : int Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import factorial >>> m = Container() >>> b = Parameter(m, "b") >>> b[...] = factorial(2) """ return MathOp("fact", (x,))
[docs] def floor(x: OperableType) -> MathOp: """ The greatest integer less than or equal to ``x`` (i.e. ``floor(4.9)`` returns ``4``) Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import floor >>> m = Container() >>> a = Parameter(m, "a", records=3.9) >>> b = Parameter(m, "b") >>> b[...] = floor(a) >>> b.toValue() np.float64(3.0) """ return MathOp("floor", (x,))
[docs] def fractional(x: OperableType) -> MathOp: """ Returns the fractional part of ``x`` (i.e. ``fractional(3.9)`` returns ``0.9``) Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import fractional >>> m = Container() >>> a = Parameter(m, "a", records=3.9) >>> b = Parameter(m, "b") >>> b[...] = fractional(a) >>> math.isclose(b.toValue(), 0.8999999999999999) True """ return MathOp("frac", (x,))
[docs] def Min(*values) -> MathOp: """ Minimum value of the values, where the number of values may vary. Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import Min >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", -2), ("i2", 0.3), ("i3", 2)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = Min(a[i], 1) >>> b.toList() [('i1', -2.0), ('i2', 0.3), ('i3', 1.0)] """ return MathOp("min", values)
[docs] def Max(*values) -> MathOp: """ Maximum value of the values, where the number of values may vary. Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import Max >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 2), ("i2", 0.3), ("i3", 2.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = Max(a[i], 1) >>> b.toList() [('i1', 2.0), ('i2', 1.0), ('i3', 2.5)] """ return MathOp("max", values)
[docs] def mod(x: OperableType, y: OperableType) -> MathOp: """ Remainder of ``x`` divided by ``y`` (i.e. ``mod(10, 3)`` returns ``1``) Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import mod >>> m = Container() >>> a = Parameter(m, "a", records=200) >>> b = Parameter(m, "b") >>> b[...] = mod(a, 3) >>> b.toValue() np.float64(2.0) """ return MathOp("mod", (x, y))
[docs] def Round(x: OperableType, num_decimals: int = 0) -> MathOp: """ Round ``x`` to ``num_decimals`` decimal places (i.e. ``Round(3.14159, 2)`` returns ``3.14``) Parameters ---------- x : OperableType num_decimals : int, optional Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import Round, div >>> m = Container() >>> a = Parameter(m, "a", records=200) >>> b = Parameter(m, "b") >>> b[...] = Round(div(a, 3), 2) >>> b.toValue() np.float64(66.67) """ return MathOp("round", (x, num_decimals))
[docs] def sign(x: Symbol) -> MathOp: """ Sign of ``x`` returns ``1 if x > 0``, ``-1 if x < 0``, and ``0 if x = 0`` Parameters ---------- x : Symbol Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import sign >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 2), ("i2", -5.4), ("i3", 0)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = sign(a[i]) >>> b.toList() [('i1', 1.0), ('i2', -1.0)] """ return MathOp("sign", (x,))
[docs] def slexp(x: OperableType, S: int | float = 150) -> MathOp: """ Smooth (linear) exponential where ``S <= 150``. (Default ``S = 150``) Parameters ---------- x : OperableType S : int | float, by default 150 Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import slexp >>> m = Container() >>> a = Parameter(m, "a", records=3) >>> b = Parameter(m, "b") >>> b[...] = slexp(a) >>> math.isclose(b.toValue(), 20.085536923187668) True """ return MathOp("slexp", (x, S))
[docs] def sqexp(x: OperableType, S: int | float = 150) -> MathOp: """ Smooth (quadratic) exponential where ``S <= 150``. (Default ``S = 150``) Parameters ---------- x : OperableType S : int | float, by default 150 Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import sqexp >>> m = Container() >>> a = Parameter(m, "a", records=3) >>> b = Parameter(m, "b") >>> b[...] = sqexp(a) >>> math.isclose(b.toValue(), 20.085536923187668) True """ return MathOp("sqexp", (x, S))
[docs] def sqrt(x: OperableType, safe_cancel: bool = False) -> MathOp: """ Square root of ``x`` Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import sqrt >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 54), ("i3", 0)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = sqrt(a[i]) """ return MathOp("sqrt", (x,), safe_cancel=safe_cancel)
[docs] def truncate(x: OperableType) -> MathOp: """ Returns the integer part of ``x`` (i.e. ``truncate(3.9)`` returns ``3``) Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import truncate >>> m = Container() >>> a = Parameter(m, "a", records=3.9) >>> b = Parameter(m, "b") >>> b[...] = truncate(a) >>> b.toValue() np.float64(3.0) """ return MathOp("trunc", (x,))
[docs] def beta(x: OperableType, y: OperableType) -> MathOp: """ Beta function: ``B(x, y) = gamma(x) * gamma(y) / gamma(x + y) = (x-1)! * (y-1)! / (x + y - 1)!`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import beta >>> m = Container() >>> a = Parameter(m, "a", records=3) >>> b = Parameter(m, "b") >>> b[...] = beta(a, 1) >>> math.isclose(b.toValue(), 0.3333333333333333) True """ return MathOp("beta", (x, y))
[docs] def regularized_beta(x: int | float, y: int | float, z: int | float) -> MathOp: """ Regularized Beta Function, See `MathWorld <https://mathworld.wolfram.com/RegularizedBetaFunction.html>`_ Parameters ---------- x : int | float y : int | float z : int | float Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import regularized_beta >>> m = Container() >>> a = Parameter(m, "a", records=3) >>> b = Parameter(m, "b") >>> b[...] = regularized_beta(0.5, a, 1) >>> math.isclose(b.toValue(), 0.12500000000000003) True """ return MathOp("betaReg", (x, y, z))
[docs] def gamma(x: OperableType) -> MathOp: """ Gamma function: ``gamma(x) = (x-1)!`` Parameters ---------- x : int | float Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import gamma >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 7), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = gamma(a[i]) """ return MathOp("gamma", (x,))
[docs] def regularized_gamma(x: int | float, a: int | float) -> MathOp: """ Lower Incomplete Regularized Gamma function, See `MathWorld <https://mathworld.wolfram.com/RegularizedGammaFunction.html>`_ Parameters ---------- x : int | float a : int | float Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import regularized_gamma >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 1), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = regularized_gamma(0.5, a[i]) """ return MathOp("gammaReg", (x, a))
[docs] def lse_max(*xs) -> MathOp: """ Smoothed Max via the Logarithm of the Sum of Exponentials: ``ln(exp(x1) + exp(x2) + ... + exp(xn))`` Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import lse_max >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 10), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = lse_max(a[i], 5) """ if len(xs) < 1: raise ValidationError("lse_max requires at least 1 x") return MathOp("lseMax", xs)
[docs] def lse_max_sc(t, *xs) -> MathOp: """ Scaled smoothed Max via the Logarithm of the Sum of Exponentials: ``lse_max_sc(T,x) = lse_max(Tx)/T`` Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import lse_max_sc >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 100), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = lse_max_sc(7.5, a[i], 10.5) """ if len(xs) < 1: raise ValidationError("lse_max_sc requires at least 1 x") return MathOp("lseMaxSc", (t,) + xs)
[docs] def lse_min(*xs) -> MathOp: """ Smoothed Min via the Logarithm of the Sum of Exponentials: ``-ln(exp(-x1) + exp(-x2) + ... + exp(-xn))`` Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import lse_min >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 10), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = lse_min(a[i], 5) """ if len(xs) < 1: raise ValidationError("lse_min requires at least 1 x") return MathOp("lseMin", xs)
[docs] def lse_min_sc(t, *xs) -> MathOp: """ Scaled smoothed Min via the Logarithm of the Sum of Exponentials: ``lse_min_sc(T,x) = lse_min(Tx)/T`` Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import lse_min_sc >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 100), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = lse_min_sc(7.5, a[i], 10.5) >>> b.toList() [('i1', 4.0), ('i2', 10.5), ('i3', 0.5)] """ if len(xs) < 1: raise ValidationError("lse_min_sc requires at least 1 x") return MathOp("lseMinSc", (t,) + xs)
[docs] def ncp_cm(x: Symbol, y: Symbol, z: float | int) -> MathOp: """ Chen-Mangasarian smoothing: ``x - z*ln(1 + exp((x-y)/z))`` Parameters ---------- x : Symbol y : Symbol z : int | float Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import ncp_cm >>> m = Container() >>> y = Parameter(m, "y", records=2) >>> b = Parameter(m, "b") >>> b[...] = ncp_cm(1, y, 0.5) >>> math.isclose(b.toValue(), 0.9365359944785137) True """ return MathOp("ncpCM", (x, y, z))
[docs] def ncp_f(x: Symbol, y: Symbol, z: int | float = 0) -> MathOp: """ Fisher-Burmeister smoothing: ``sqrt(x^2 + y^2 + 2z) - x - y`` where ``z >= 0`` (default ``z = 0``) Parameters ---------- x : Symbol y : Symbol z : int | float, optional Returns ------- MathOp Examples -------- >>> import math >>> from gamspy import Container, Parameter >>> from gamspy.math import ncp_f >>> m = Container() >>> y = Parameter(m, "y", records=2) >>> b = Parameter(m, "b") >>> b[...] = ncp_f(1, y, 0.5) >>> math.isclose(b.toValue(), -0.5505102572168221) True """ return MathOp("ncpF", (x, y, z))
[docs] def ncpVUpow( r: Symbol, s: Symbol, mu: int | float = 0, ) -> MathOp: """ NCP Veelken-Ulbrich (smoothed min(r,s)) Parameters ---------- r : Symbol s : Symbol mu : int | float, optional Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import ncpVUpow >>> m = Container() >>> y = Parameter(m, "y", records=2) >>> b = Parameter(m, "b") >>> b[...] = ncpVUpow(1, y, 0.5) >>> b.toValue() np.float64(1.0) """ return MathOp("ncpVUpow", (r, s, mu))
[docs] def ncpVUsin(r: Symbol, s: Symbol, mu: int | float = 0) -> MathOp: """ NCP Veelken-Ulbrich (smoothed min(r,s)) Parameters ---------- r : Symbol s : Symbol mu : int | float, optional Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import ncpVUsin >>> m = Container() >>> y = Parameter(m, "y", records=2) >>> b = Parameter(m, "b") >>> b[...] = ncpVUsin(1, y, 0.5) >>> b.toValue() np.float64(1.0) """ return MathOp("ncpVUsin", (r, s, mu))
[docs] def poly(x, *args) -> MathOp: """ Polynomial function: ``p(x) = A[0] + A[1]*x + A[2]*x^2 + ... + A[n-1]*x^(n-1)`` Returns ------- MathOp Raises ------ ValidationError If the number of arguments (args) is less than 3 or if any of args is not an integer or a float. Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import poly >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", 10), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = poly(a[i], 15, 3, 4) >>> b.toList() [('i1', 91.0), ('i2', 445.0), ('i3', 17.5)] """ if len(args) < 3: raise ValidationError("poly requires at least 3 arguments after x") return MathOp("poly", (x,) + args)
[docs] def sigmoid(x: OperableType) -> MathOp: """ Sigmoid of ``x`` (i.e. ``1 / (1 + exp(-x))``) Parameters ---------- x : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import sigmoid >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 4), ("i2", -1), ("i3", 0.5)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = sigmoid(a[i]) """ return MathOp("sigmoid", (x,))
[docs] def rand_binomial(n: int | float, p: int | float) -> MathOp: """ 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 ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import rand_binomial >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> p = Parameter(m, "p", domain=i, records=[("i1", 0.3), ("i2", 0.8), ("i3", 0.45)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = rand_binomial(75, p[i]) >>> b.toList() [('i1', 21.0), ('i2', 63.0), ('i3', 25.0)] """ return MathOp("randBinomial", (n, p))
[docs] def rand_linear(low: int | float, slope: int | float, high: int | float) -> MathOp: """ Generate a random number between low and high with linear distribution. ``slope`` must be less than ``2 / (high - low)`` and greater than ``0`` Parameters ---------- low : int | float slope : int | float high : int | float Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import rand_linear >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> s = Parameter(m, "s", domain=i, records=[("i1", 0.03), ("i2", 0.008), ("i3", 0.04)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = rand_linear(75, s[i], 125) """ return MathOp("randLinear", (low, slope, high))
[docs] def rand_triangle(low: int | float, mid: int | float, high: int | float) -> MathOp: """ 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 ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import rand_triangle >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> s = Parameter(m, "s", domain=i, records=[("i1", 103), ("i2", 80), ("i3", 115)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = rand_triangle(75, s[i], 125) """ return MathOp("randTriangle", (low, mid, high))
[docs] def same_as(arg1: Set | Alias | str, arg2: Set | Alias | str) -> MathOp: """ Evaluates to true if this set is identical to the given set or alias, false otherwise. Parameters ---------- arg1 : Set | Alias | str other : Set | Alias | str Returns ------- MathOp Examples -------- >>> import gamspy as gp >>> from gamspy.math import same_as >>> m = gp.Container() >>> i = gp.Set(m, name="i", records=["seattle", "san-diego"]) >>> j = gp.Set(m, name="j", records=["new-york", "seattle"]) >>> attr = gp.Parameter(m, "attr", domain = [i, j]) >>> attr[i,j] = same_as(i, j) >>> attr.records.values.tolist() [['seattle', 'seattle', 1.0]] """ return MathOp("sameAs", (arg1, arg2))
[docs] def slrec(x: OperableType, S: int | float = 1e-10) -> MathOp: """ Smooth (linear) reciprocal, where ``S >= 1e-10``. (Default ``S = 1e-10``) Parameters ---------- x : OperableType S : int | float, by default 1e-10 Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import slrec >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 1), ("i2", 0.8), ("i3", 15)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = slrec(a[i]) """ return MathOp("slrec", (x, S))
[docs] def sqrec(x: OperableType, S: int | float = 1e-10) -> MathOp: """ Smooth (quadratic) reciprocal, where ``S >= 1e-10``. (Default ``S = 1e-10``) Parameters ---------- x : OperableType S : int | float, by default 1e-10 Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import sqrec >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 1), ("i2", 0.8), ("i3", 15)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = sqrec(a[i]) """ return MathOp("sqrec", (x, S))
[docs] def entropy(x: OperableType) -> MathOp: """ Entropy function: ``-x*ln(x)`` where ``x >= 0`` Parameters ---------- x : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import entropy >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", 1), ("i2", 0.8), ("i3", 15)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = entropy(a[i]) """ return MathOp("entropy", (x,))
[docs] def errorf(x: OperableType) -> MathOp: """ Integral of the standard normal distribution from negative infinity to ``x`` Parameters ---------- x : int, float, Symbol Returns ------- MathOp Examples -------- >>> from gamspy import Container, Set, Parameter >>> from gamspy.math import errorf >>> m = Container() >>> i = Set(m, name="i", records=["i1", "i2", "i3"]) >>> a = Parameter(m, "a", domain=i, records=[("i1", -2.5), ("i2", 0.8), ("i3", 1.7)]) >>> b = Parameter(m, "b", domain=i) >>> b[i] = errorf(a[i]) """ return MathOp("errorf", (x,))
[docs] def ifthen( condition: Expression, yes_return: float | Expression, no_return: float | Expression, ) -> MathOp: """ If the logical condition is ``true``, the function returns ``yes_return``, else it returns ``no_return`` Parameters ---------- condition : Expression yes_return : float | Expression no_return : float | Expression Returns ------- MathOp 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 MathOp("ifthen", (condition, yes_return, no_return))
[docs] def bool_and(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff both ``x and y`` are true Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_and >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_and(a > 10, b < 5) >>> c.toValue() np.float64(0.0) """ return MathOp("bool_and", (x, y))
[docs] def bool_eqv(x: OperableType, y: OperableType) -> MathOp: """ Returns ``false`` iff exactly one argument is false Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_eqv >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_eqv(a > 10, b < 5) >>> c.toValue() np.float64(0.0) """ return MathOp("bool_eqv", (x, y))
[docs] def bool_imp(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x is false`` or ``y is true`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_imp >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_imp(a < 10, b > 5) >>> c.toValue() np.float64(1.0) """ return MathOp("bool_imp", (x, y))
[docs] def bool_not(x: OperableType) -> MathOp: """ Returns ``true`` iff ``x is false`` Parameters ---------- x : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_not >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_not(a > 10) >>> c.toValue() np.float64(0.0) """ return MathOp("bool_not", (x,))
[docs] def bool_or(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x is true`` or ``y is true`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_or >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_or(a > 15, b < 5) >>> c.toValue() np.float64(0.0) """ return MathOp("bool_or", (x, y))
[docs] def bool_xor(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff exactly one argument is ``false`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import bool_xor >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = bool_xor(a < 15, b > 5) >>> c.toValue() np.float64(0.0) """ return MathOp("bool_xor", (x, y))
[docs] def rel_eq(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x == y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_eq >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = rel_eq(a, b) >>> c.toValue() np.float64(0.0) """ return MathOp("rel_eq", (x, y))
[docs] def rel_ge(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x >= y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_ge >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = rel_ge(a, b) >>> c.toValue() np.float64(1.0) """ return MathOp("rel_ge", (x, y))
[docs] def rel_gt(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x > y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_gt >>> m = Container() >>> a = Parameter(m, "a", records=7) >>> b = Parameter(m, "b", records=7) >>> c = Parameter(m, "c") >>> c[...] = rel_gt(a, b) >>> c.toValue() np.float64(0.0) """ return MathOp("rel_gt", (x, y))
[docs] def rel_le(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x <= y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_le >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=11) >>> c = Parameter(m, "c") >>> c[...] = rel_le(a, b) >>> c.toValue() np.float64(0.0) """ return MathOp("rel_le", (x, y))
[docs] def rel_lt(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x < y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_lt >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=17) >>> c = Parameter(m, "c") >>> c[...] = rel_lt(a, b) >>> c.toValue() np.float64(1.0) """ return MathOp("rel_lt", (x, y))
[docs] def rel_ne(x: OperableType, y: OperableType) -> MathOp: """ Returns ``true`` iff ``x != y`` Parameters ---------- x : OperableType y : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import rel_ne >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b", records=12) >>> c = Parameter(m, "c") >>> c[...] = rel_ne(a, b) >>> c.toValue() np.float64(0.0) """ return MathOp("rel_ne", (x, y))
[docs] def map_value(x: OperableType) -> MathOp: """ Returns an integer value that indicates what special value (if any) is stored in the input. Possible results: 0: is not a special value 4: is UNDF (undefined) 5: is NA (not available) 6: is INF 7: is -INF 8: is EPS Parameters ---------- x : OperableType Returns ------- MathOp Examples -------- >>> from gamspy import Container, Parameter >>> from gamspy.math import map_value >>> m = Container() >>> a = Parameter(m, "a", records=12) >>> b = Parameter(m, "b") >>> b[...] = map_value(a) >>> b.toValue() np.float64(0.0) >>> a[...] = float('inf') >>> b[...] = map_value(a) >>> b.toValue() np.float64(6.0) """ return MathOp("mapval", (x,))