Source code for gamspy._algebra.operation

from __future__ import annotations

from typing import TYPE_CHECKING

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.utils as utils
from gamspy.exceptions import ValidationError

if TYPE_CHECKING:
    from gams.transfer import Alias, Parameter, Set

    from gamspy._algebra import Domain
    from gamspy._algebra.expression import Expression
    from gamspy._symbols.implicits import ImplicitParameter, ImplicitVariable


class Operation(operable.Operable):
    def __init__(
        self,
        domain: Set | Alias | tuple[Set | Alias] | Domain | Expression,
        expression: (
            Expression | ImplicitVariable | ImplicitParameter | int | bool
        ),
        op_name: str,
    ):
        self.domain = utils._to_list(domain)
        assert len(self.domain) > 0, "Operation requires at least one index"
        self.expression = expression
        self._op_name = op_name

        # allow conditions
        self.where = condition.Condition(self)

    def _get_index_str(self) -> str:
        if len(self.domain) == 1:
            domain = self.domain[0]
            representaiton = domain.gamsRepr()
            if isinstance(domain, expression.Expression):
                # sum((l(root,s,s1,s2) $ od(root,s)),1); -> not valid
                # sum(l(root,s,s1,s2) $ od(root,s),1); -> valid
                return representaiton[1:-1]

            return representaiton

        return (
            "(" + ",".join([index.gamsRepr() for index in self.domain]) + ")"
        )

    def __eq__(self, other):  # type: ignore
        return expression.Expression(self, "=e=", other)

    def __ne__(self, other):  # type: ignore
        return expression.Expression(self, "ne", other)

    def __neg__(self):
        return expression.Expression(None, "-", self)

    def _replace_operations(self, output: str) -> str:
        output = output.replace("=l=", "<=")
        output = output.replace("=g=", ">=")
        output = output.replace("=e=", "eq")

        return output

    def gamsRepr(self) -> str:
        # Ex: sum((i,j), c(i,j) * x(i,j))
        output = f"{self._op_name}("

        index_str = self._get_index_str()

        output += index_str
        output += ","

        if isinstance(self.expression, float):
            self.expression = utils._map_special_values(self.expression)

        if isinstance(self.expression, bool):
            self.expression = (
                "yes" if self.expression is True else "no"  # type: ignore
            )

        expression_str = (
            str(self.expression)
            if isinstance(self.expression, (int, str))
            else self.expression.gamsRepr()
        )

        output += expression_str
        output += ")"

        output = self._replace_operations(output)

        return output


[docs] class Sum(Operation): """ Represents a sum operation over a domain. Parameters ---------- domain : Set | Alias | Tuple[Set | Alias], Domain, Expression expression : Expression | int | bool Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> i = gp.Set(m, "i", records=['i1','i2', 'i3']) >>> v = gp.Variable(m, "v") >>> e = gp.Equation(m, "e", type="eq") >>> e[...] = gp.Sum(i, 3) <= v """ def __init__( self, domain: Set | Alias | tuple[Set | Alias] | Domain | Expression, expression: Expression | int | bool, ): super().__init__(domain, expression, "sum")
[docs] def gamsRepr(self): """ Representation of the Sum operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Parameter, Variable, Sum >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> c = Parameter(m, "c", domain=i) >>> v = Variable(m, "v", domain=i) >>> Sum(i, c[i]*v[i]).gamsRepr() 'sum(i,(c(i) * v(i)))' """ repr = super().gamsRepr() return repr
[docs] class Product(Operation): """ Represents a product operation over a domain. Parameters ---------- domain : Set | Alias | Tuple[Set | Alias], Domain, Expression expression : Expression | int | bool Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> i = gp.Set(m, "i", records=['i1','i2', 'i3']) >>> v = gp.Variable(m, "v") >>> e = gp.Equation(m, "e", type="eq") >>> e[...] = gp.Product(i, 3) <= v """ def __init__( self, domain: Set | Alias | tuple[Set | Alias] | Domain | Expression, expression: Expression | int | bool, ): super().__init__(domain, expression, "prod")
[docs] def gamsRepr(self): """ Representation of the Product operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Parameter, Variable, Product >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> c = Parameter(m, "c", domain=i) >>> v = Variable(m, "v", domain=i) >>> Product(i, c[i]*v[i]).gamsRepr() 'prod(i,(c(i) * v(i)))' """ repr = super().gamsRepr() return repr
[docs] class Smin(Operation): """ Represents a smin operation over a domain. Parameters ---------- domain : Set | Alias | Tuple[Set | Alias], Domain, Expression expression : Expression | int | bool Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> i = gp.Set(m, "i", records=['i1','i2', 'i3']) >>> v = gp.Variable(m, "v") >>> e = gp.Equation(m, "e", type="eq") >>> e[...] = gp.Smin(i, 3) <= v """ def __init__( self, domain: Set | Alias | tuple[Set | Alias] | Domain | Expression, expression: Expression | int | bool, ): super().__init__(domain, expression, "smin")
[docs] def gamsRepr(self): """ Representation of the Smin operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Parameter, Variable, Smin >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> c = Parameter(m, "c", domain=i) >>> v = Variable(m, "v", domain=i) >>> Smin(i, c[i]*v[i]).gamsRepr() 'smin(i,(c(i) * v(i)))' """ repr = super().gamsRepr() return repr
[docs] class Smax(Operation): """ Represents a smax operation over a domain. Parameters ---------- domain : Set | Alias | Tuple[Set | Alias], Domain, Expression expression : Expression | int | bool Examples -------- >>> import gamspy as gp >>> m = gp.Container() >>> i = gp.Set(m, "i", records=['i1','i2', 'i3']) >>> v = gp.Variable(m, "v") >>> e = gp.Equation(m, "e", type="eq") >>> e[...] = gp.Smax(i, 3) <= v """ def __init__( self, domain: Set | Alias | tuple[Set | Alias] | Domain | Expression, expression: Expression | int | bool, ): super().__init__(domain, expression, "smax")
[docs] def gamsRepr(self): """ Representation of the Smax operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Parameter, Variable, Smax >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> c = Parameter(m, "c", domain=i) >>> v = Variable(m, "v", domain=i) >>> Smax(i, c[i]*v[i]).gamsRepr() 'smax(i,(c(i) * v(i)))' """ repr = super().gamsRepr() return repr
[docs] class Ord(operable.Operable): """ The operator ord may be used only with one-dimensional sets. Parameters ---------- set : Set | Alias Examples -------- >>> import gamspy as gp >>> >>> m = gp.Container() >>> t = gp.Set( >>> m, >>> name="t", >>> description="time periods", >>> records=[str(x) for x in range(1985, 1996)], >>> ) >>> val = gp.Parameter(m, name="val", domain=[t]) >>> val[t] = gp.Ord(t) """ def __init__(self, set: Set | Alias): if not isinstance(set, (syms.Set, syms.Alias)): raise ValidationError( "Ord operation is only for Set and Alias objects!" ) self._set = set def __eq__(self, other) -> Expression: # type: ignore return expression.Expression(self, "eq", other) def __ge__(self, other): return expression.Expression(self, ">=", other) def __le__(self, other): return expression.Expression(self, "<=", other) def __ne__(self, other): # type: ignore return expression.Expression(self, "ne", other)
[docs] def gamsRepr(self) -> str: """ Representation of the Ord operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Ord >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> Ord(i).gamsRepr() 'ord(i)' """ return f"ord({self._set.name})"
[docs] class Card(operable.Operable): """ The operator card may be used with any symbol and returns its number of records. Parameters ---------- symbol : Set | Alias | Parameter | Variable | Equation | Model Examples -------- >>> import gamspy as gp >>> >>> m = gp.Container() >>> >>> t = gp.Set( >>> m, >>> name="t", >>> description="time periods", >>> records=[str(x) for x in range(1985, 1996)], >>> ) >>> s = gp.Parameter(m, name="s") >>> s[...] = gp.Card(t) """ def __init__( self, symbol: Set | Alias | Parameter, ) -> None: self._symbol = symbol def __eq__(self, other) -> Expression: # type: ignore return expression.Expression(self, "eq", other) def __ge__(self, other): return expression.Expression(self, ">=", other) def __le__(self, other): return expression.Expression(self, "<=", other) def __ne__(self, other): # type: ignore return expression.Expression(self, "ne", other) def __bool__(self): raise ValidationError( "Card operation cannot be used as a truth value. Use len(<symbol>.records) instead." )
[docs] def gamsRepr(self) -> str: """ Representation of the Card operation in GAMS language. Returns ------- str Examples -------- >>> from gamspy import Container, Set, Card >>> m = Container() >>> i = Set(m, "i", records=['i1','i2', 'i3']) >>> Card(i).gamsRepr() 'card(i)' """ return f"card({self._symbol.name})"