Skip to contents

The values of decision variables and random variables are not known when you write a model, so arithmetic on them cannot compute a number. Instead it builds an expression: a description of a quantity, which the service evaluates for every solution it considers. Expressions are written as ordinary R code, with these operators and functions:

Details

Expressions need not be linear. Printing an expression shows what was built.

Expressions are vectors

A variable declared with length = 10 is an expression of length 10, and expressions behave like numeric vectors in most ways: arithmetic works element by element, x[3] picks one element, c() combines expressions and numbers into a longer expression, and length() counts the elements.

There are two differences. First, the two sides of an arithmetic operation must have the same length, or one of them length 1. R would recycle the shorter vector, which in a model is almost always a mistake, so here it is an error. Second, sum(), prod(), max(), min() and mean() combine all the elements of all their arguments into one, as they do for numbers: max(x, 0) is the largest of all the elements of x and 0, not an element-by-element maximum, and there is no pmax(). The arguments can come in any order, so max(0, x) works too (see summaries). mean(x) is the mean over the elements of x; the mean over the scenarios is expectation().

Comparisons

Comparing two expressions, as in x <= y, builds a comparison rather than returning TRUE or FALSE. What the comparison means depends on the function it is given to: add() makes it a constraint, prob() measures how often it holds across the scenarios, and holds() turns it into an expression that is 1 where it holds and 0 where it does not. add() and prob() accept <= and >=, and add() also ==; holds() accepts all six comparisons.

What does not work

Functions not listed above, such as round(), %% and log() with a base, stop with an error. Base R functions that are not written for expressions do not work on them either: use variance() instead of var(), holds() instead of ifelse(), and identical() instead of %in% or match() to check whether two expressions are the same.

A model with max(), min() or holds() is solved by a search, so its status is "heuristic". When every variable of such a model is an integer or a binary variable, each needs finite bounds; a model with a continuous variable or with random variables has no such limit. A fixed fee for using a variable at all is the exception: written with active() on a variable declared with semi = TRUE, it keeps a linear model exact.

Examples

m <- model()
tables <- num_var(m, "tables", lower = 0)
chairs <- num_var(m, "chairs", lower = 0)
50 * tables + 20 * chairs                 # an expression, not a number
#> ((50 * tables) + (20 * chairs))
tables + chairs <= 18                     # a comparison, not TRUE or FALSE
#> (tables + chairs) <= 18 

x <- num_var(m, "x", lower = 0, upper = 1, length = 3)
2 * x                                     # element by element
#> [1] (2 * x[1])
#> [2] (2 * x[2])
#> [3] (2 * x[3])
sum(x)                                    # one expression
#> (x[1] + x[2] + x[3])
max(x, 0.5)                               # the largest of all four
#> max(max(max(x[1], x[2]), x[3]), 0.5)