Skip to content

Expressions

Expressions are human-readable arithmetic expressions. They can contain a sign (in this case, they are equations) or not (simply representing a value or a function). They allow a large flexibility in defining objects of optimization.

Expressions can only be found in models (defined in libraries yaml files).

More specifically, they can be found in the following contexts inside a model :

  • constraints
  • binding-constraints
  • objective-contributions
  • port-field-definitions
  • in fields lower-bound and upper-bound of variables.
  • extra-output

Many elements can be found in an expression. In the following sections, we give a list of these elements, but have in mind that all these elements cannot be used in any kind of expression. It depends on the context of the expression inside the model. For instance, if the expression is used to define the lower-bound of a variable, it cannot contain a reference to any variable. For more precision see Cases where elements can be used in expressions

Here is the list of elements possibly composing an expression :

Arithmetic operators in expressions

The following operators are allowed between two elements :

  • +: addition
  • -: subtraction
  • *: multiplication
  • /: division
  • =: equality, only allowed for constraint definitions
  • <=: less or equal to, only allowed for constraint definitions
  • >=: greater or equal to, only allowed for constraint definitions

Literals in expressions

You can use simple floating-point literals anywhere. The character . represents the floating point.

Example:

expression: 3 * 67.43 - 5 / 3.14

References to elements defined elsewhere

Expressions can contain references to elements defined elsewhere, either in the same model (as the expression), or outside the model (via ports). These elements can be one of the following (we assume they are already defined elsewhere) :

Parameters in expressions

You can use a parameter by using its id. Note that if the parameter is time-dependent (resp. scenario-dependent), then it can be used only for variables or constraints that are time-dependent (resp. scenario-dependent), and that its values will be implicitly unfolded during the interpretation of the expression.

Example:

expression: 3 * parameter_1 + 6.345 / parameter_2

Variables in expressions

You can use a variable by using its id. Note that if the variable is time-dependent (resp. scenario-dependent), then it can be used only for constraints that are time-dependent (resp. scenario-dependent), and that its values will be implicitly unfolded during the interpretation of the expression.

Example:

expression: 3 * parameter_1 * variable_a + variable_b + 56.4 <= variable_4 * 439

Caution : A non linear mutiplication is multiplying 2 variables. A non linear division is : the division right operand is a variable, whatever the lft operand. There is an important restriction about non linear multiplications or divisions. They're only allowed in the context of extra-output.

In general, expressions must be linear with respect to variables. There is an exception : extra-output expressions allow non linear multiplications or divisions.

Examples of prohibited expressions (case extra-output excepted):

(X) expression: variable_a * variable_b
(X) expression: 3 / variable_a

Ports in expressions

You can use a port field in the expression, using its id composed by: port_ID.field_ID. Note that if the port is time-dependent (resp. scenario-dependent), which is deduced from the variables defining it, then it can be used only for constraints that are time-dependent (resp. scenario-dependent), and that its values will be implicitly unfolded during the interpretation of the expression. Unless, of course, you use time (resp. scenario) aggregators to aggregate it into a time-constant (resp. scenario-constant) value.

Example:

expression: 45.4 * port_3.field_6 + 5.4 * variable_6 - 9

Note that, like with variables, all expressions must be linear with respect to ports.

Other operators in expressions

In expressions, apart from arithmetic operators, other operator can be found.

Time operators

For time-dependent parameters, variables, and port fields, you can use these time operators:

  • [t] (as a suffix) : this operator is implied (doesn't have to be specified), but can be used if you like to explicit your intent
  • [N] (as a suffix) : where N is any expression resolving to an integer (using only literals and parameters), this selects the value of the element at the N-th timestamp.
  • [t+N] suffix: where N is any expression resolving to an integer (using only literals and parameters), this is a forward shift operator of N timestamps.
  • [t-N] suffix: where N is any expression resolving to an integer (using only literals and parameters), this is a backward shift operator of N timestamps.
  • sum(X) aggregator: where X is the time-dependent operand, this operator sums the operand on the whole optimization horizon.
  • sum(S .. E, X) aggregator: where X is the time-dependent operand, this operator sums the operand between S and E ( included), where:
    • S represents the first timestamp, either as an expression resolving to an integer, or a time-shift expression like the ones defined above
    • E represents the last timestamp, either as an expression resolving to an integer, or a time-shift expression like the ones defined above
    • in both forms, S and E must not depend on time

Examples:

expression: a[t] + b[t + 5] * c[t - 3 - 65 * parameter_1] - sum(a)

expression: sum(4 .. 87, c) - sum(t - 3 * parameter_15 + 5 .. t, d)

expression: sum(1 .. 2, expr) = expr[1] + expr[2]

Scenario operators

For scenario-dependent parameters, variables, and port fields, you can use this operator:

  • expec(X) aggregator: where X is the scenario-dependent operand, this operator computes its expected value (i.e. its scenario-wise average).

Ports' sum_connections operator

You can aggregate incoming ports using the following operator :

sum_connections(port.field)

where "port" is the port id and "field" is the field id, this operator computes the sum of values of this port field, on all incoming connections from other models.
Note that the resulting sum can be time-dependent and/or scenario-dependent, depending on the port definition.

Note that sum_connections operator is the only context where port field are used in receiver mode.

When this operator is used in another context than extra output, expressions coming from connected sender port field must be linear : they cannot contain operators such as dual, reduced_cost, power, max, min, floor, ceil (see further).

In the context of extra output, there is no such restriction.

Examples:

expression: sum_connections(dc_port.flow) = 0

Dual operators

By dual operators, we mean unary operators dual and reduced_cost. Any optimization problem supplies these 2 optimization results. So these 2 operators can only be used in expressions held in extra output context, either directly, or indirectly through a connection between components, that is through a port field.

Si, in some cases, we need to access the dual of a variable / constraint of the linear problem :

  • dual of a variable my_var is accessed by -reduced_cost(myVar)
  • dual of a constraint my_constraint is accessed by dual(myConstraint)

Note that these 2 operators are non linear operators.

Exemple :

models:
- id: myModel
  variables:
  - id: myVar
    upper_bound: 1
  constraints:
  - id: myConstraint
    expression: x <= 1
  extra-outputs:
  - id: marginal_price_variable
    expression: -reduced_cost(myVar)
  - id: marginal_price_constraint
    expression: dual(myConstraint)

Power operator

This binary operator ^ is used within any expression, but with following restrictions. In the context of a linear problem construction (any context but extra-output), its operands can only be literals or parameters.

Within an extra-output expression, references to variables are allowed.

Example :

models:
- id: myModel
  variables:
  - id: myVar
  parameters:
  - id: myParam
  extra-outputs:
  - id: myOutput
    expression: myVar^(2 + myParam)

Floor and ceil operators

The unary operators floor(X) and ceil(X) return, respectively, the greatest integer less than or equal to X and the smallest integer greater than or equal to X. When X is time-dependent (a parameter, variable, or port field with time dimension), the operators apply pointwise on the underlying time-series.

In the context of a linear problem construction (any context but extra-output), the argument of floor or ceil must not depend on decision variables: it must be a literal, a parameter, or any combination of them. In those contexts the optimizer works with the already-rounded, constant expression produced by floor/ceil.

Within an extra-output expression, floor and ceil can be applied to expressions involving variables as well. In that case, the operators are evaluated after optimization using the numerical solution.

Examples :

models:
- id: myModel
  parameters:
  - id: myParam
  variables:
  - id: x
    lower_bound: 0
    upper_bound: 10
  constraints:
  - id: c1
    # Allowed: argument only depends on parameters and literals
    expression: x <= floor(myParam)
  - id: c2
    expression: x >= ceil(myParam / 2)
  extra-outputs:
  - id: rounded_output_floor
    expression: floor(x)
  - id: rounded_output_ceil
    expression: ceil(x)

max (or min) operator

This n-ary operator max(u, v, ...) can be used within any expression, with following restrictions.

In the context of a linear problem construction (any context but extra-output), its operands can only be literals or parameters.

Within an extra-output expression, references to variables are allowed.

Furthermore, operands of min/max can only be literals or parameters.

Example :

models:
- id: myModel
  variables:
  - id: x
  parameters:
  - id: a
  - id: b
  constraints:
  - id: myConstraint
    expression: x < max(a,b)
  extra-outputs:
  - id: myOutput
    expression: max(x, a*b)

Nothing forbids to also have :

max(2, 3) * x + min(3,4) * y # in objective
max(2, 3) * x + min(3, 4) * y <= 42 # in a constraint

Cases where elements can be used in expressions

Operators

Caution : as already said, non-linear multiplications or divisions are forbidden in expressions in general, except within an extra-output expressions. Apart from that case, variables can only be multiplied/divided by literals/parameters.

In following tables :

  • L means : only linear multiplication or division is allowed
  • NL means non linear multiplication or division is allowed
  • NV : the operator applies to non-variable elements only (that is literals and parameters).

Context of expression [+-] [*/] [<>=] Time sum_connections
constraints yes L yes yes no
binding-constraints yes L yes yes yes
objective-contributions yes L no no no
port-field-definitions yes L no no no
variable bounds yes L no no no
extra-output yes NL no no no

Context of expression Scenario Dual Power Max/Min sum sum(S..E)
constraints ? no NV NV yes yes
binding-constraints ? no NV NV yes yes
objective-contributions no no NV NV yes no
port-field-definitions ? yes yes yes yes yes
variable bounds ? no NV NV yes yes
extra-output ? yes yes yes yes yes

References to elements defined elsewhere

Context of expression variable parameter Port
constraints yes yes no
binding-constraints yes yes yes
objective-contributions yes yes no
port-field-definitions yes yes no
variable bounds no yes no
extra-output yes yes yes

Particular context : port-field-definition

In previous tables, non-linear operators (dual, reduced_cost, power, max, min, floor, ceil) are forbidden in expressions held in many contexts, but not in the port-field-definitions context.

But it does mean there are no restriction on non linear operator in the context of port-field-definition, indeed :

Defining a port field expression necessarily takes place in a component where the port field is use in sender mode : the defined expression will be fetched from another connected component using the port field in receiver mode.

If the receiver of the expression defined by a port-field-definition uses it in an extra output context, there is no restriction on this expression. Otherwise, it has to be linear, that is contain no non-linear operator.