Expressions
Expressions are used in the problem definition (PD) within the following constraint
fields:
exprFrom
: The starting point for iteration in a constraint sum of typeiterateVar
.exprTo
: The ending point for iteration in a constraint sum of typeiterateVar
.exprMain
: The calculation that is added to the solution score or aresultVar
if defined.
Expressions are used to calculate a value and return it. They have no features for looping or control or functional decomposition - they are purely and simply expressions.
Expression Variables
By default, the following variables (constants actually) are available to all expressions:
R
: The R (resource count) dimension of the atom array.T
: The T (time count) dimension of the atom array.S
: The S (state count) dimension of the atom array.
Variables declared in the following places can also appear in expressions:
iterVars
: Variables declared in theiterVars
of a constraint sum.resultVar
: Result variable declared in a child constraint sum.constants
: Any constant define in theconstants
section of the PD.array
: Anyname
of anyarray
object in the PD.
Expression Operators
The following standard operators are supported in expressions. They are grouped in order of precedence:
!, NOT
: Not operators. (From 0 to 1 and vice versa.) These are the only unary operators.*, /, %
: Multiple, divide, modulo divide.+, -
: Add, subtract.<, <=, >, >=, =, !=
: Inequality operators. The result of these operators is either 1 or 0.AND, OR
: Boolean operators. The result of these operators is either 1 or 0.
Example:
53 / 100 * (2 + 1) > 1.55
Answer:
1.0
Expression Functions
There are several built-in functions and dynamically named array accessors that are supported in expressions. These fall into three categories:
- Functions that access the atom array:
A
andX
. - Inequality functions:
IQ
andEQ
. - Array accessor functions named by the array itself.
Expression Functions: Atom Array
As described in the Concepts section of this guide, the atom array can be accessed, or "viewed", as either atoms or bits. In addition, in cases where the atom array is composed of a single column or row, there are short hand functions for not having to specify the 1 dimension.
The following functions are used to access the atom array as atoms:
A(r, t)
: returns the atom state at resource r, time t.Ar(r)
: assuming there is only a single time column (T = 1
), then this will return the atom state atA(r, 0)
At(t)
: assuming there is only a single resource row (R = 1
), then this will return the atom state atA(0, t)
ANY(r, t)
: returns 1 or 0 (true or false) if there is a non-zero state at atomr, t
. This is used for atom matrices with zero states.
The following functions are used to access the atom array as bits:
X(r, t, s)
: returns 0 or 1 depending on whether bits
of the atom atr, t
is set (i.e., the atom state is equal tos
).Xr(r, s)
: assuming there is only a single time column (T = 1
), then this will return the bit state atX(r, 0, s)
Xt(t, s)
: assuming there is only a single resource row (R = 1
), then this will return the bit state atX(0, t, s)
Expression Functions: Inequality
The two inequality functions are extremely important to the solver. These are fundamentally different than the inequality operators in that they are used by the solver for more than just expression functions - they are used to identify inequalities for multivariable models. Also, while an inequality operator simply returns a 1
or 0
given a condition, the inequality functions return how unequal the variables being compared are, and thus implement the "unconstrained constraint" described in the concepts section.
The two fundamental inequality functions are EQ
and IQ
(for equality and inequality, respectively) however technically EQ
could be represented with an IQ
as will be shown shortly. These functions more closely match the declaration in a constraint description. For example, a constraint description that states "variable v must be between 2 and 10" would be captured with a IQ(2, v, 10)
expression.
EQ
and IQ
return a value that is typically multiplied by the penaltyVar
defined on the constraint. However, there are cases where the penalty value might be different if the function result is less than vs. greater than the comparison value. In these cases, two additional inequality functions, EQP
and IQP
are provided that take two additional parameters - the penalty if less than, and the penalty if greater than. In this case, the constraint would not have a penaltyVar
as the penalty is defined in the inequality.
-
EQ(v, n)
: Compares whether n and v are equal. Equality would return 0 while not equal would return the absolute value of the difference. Formally, this would be represented as:\( v = n\)
Therefore, if a constraint description states that some variable must be equal to a value, then this should be defined using the
EQ
function. -
IQ(n, v, m)
: Checks whetherv
is within (inclusively) the rangen
tom
, in which case 0 is returned, while outside the range would return the distance outside the range. Formally, this would be represented as:\( n \le v \le m\)
Note that either
n
orm
(but not both) can be the infinity symbol~
. For example, the expressionIQ(~, v, m)
would formally be:\( v \le m \)
Or, the expression
IQ(n, v, ~)
would be;\( v \ge n \)
In addition,
IQ
could implementEQ
with an expressionIQ(n, v, n)
, but this is for illustrative purposes only. -
EQP(v, n, pu, po)
: Same asEQ
but has two additional parameters to define the penalty under vs. over, respectively. -
IQP(n, v, m, pu, po)
: Same asIQ
but has two additional parameters to define the penalty under vs. over, respectively.
Expression Functions: Array Accessors
Arrays are accessed by their name and appear just like functions. In addition, their optional ldimFields
can be used as the last parameter. For example, given the array definition below:
{
"array": {
"name": "shift_on_req",
"file": "array_shift_on_req.json",
"ldimFields": [
"shift_on",
"shift_on_weight"
]
}
}
And given the follow sample array that this definition refers to:
[
[
[
0.0,
0.0
],
[
0.0,
0.0
]
]
]
An expression that accesses the array values could be:
(A(r, t) != shift_on_req(r, t, shift_on)) * shift_on_req(r, t, shift_on_weight)
Note that the last parameter of the array accessor refers to one of the ldimFields
. In this case, this array is in essence a 2D index into a set of records that each contain two fields.