# Manipulating expressions

This guide highlights a syntactically appealing way to build expressions at the MOI level, but also to look at their contents. It may be especially useful when writing models or bridge code.

## Creating functions

This section details the ways to create functions with MathOptInterface.

### Creating scalar affine functions

The simplest scalar function is simply a variable:

```
julia> x = MOI.add_variable(model) # Create the variable x
MOI.VariableIndex(1)
```

This type of function is extremely simple; to express more complex functions, other types must be used. For instance, a `ScalarAffineFunction`

is a sum of linear terms (a factor times a variable) and a constant. Such an object can be built using the standard constructor:

```
julia> f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 2) # x + 2
(2) + (1) MOI.VariableIndex(1)
```

However, you can also use operators to build the same scalar function:

```
julia> f = x + 2
(2) + (1) MOI.VariableIndex(1)
```

### Creating scalar quadratic functions

Scalar quadratic functions are stored in `ScalarQuadraticFunction`

objects, in a way that is highly similar to scalar affine functions. You can obtain a quadratic function as a product of affine functions:

```
julia> 1 * x * x
(0) + 1.0 MOI.VariableIndex(1)²
julia> f * f # (x + 2)²
(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²
julia> f^2 # (x + 2)² too
(4) + (2) MOI.VariableIndex(1) + (2) MOI.VariableIndex(1) + 1.0 MOI.VariableIndex(1)²
```

### Creating vector functions

A vector function is a function with several values, irrespective of the number of input variables. Similarly to scalar functions, there are three main types of vector functions: `VectorOfVariables`

, `VectorAffineFunction`

, and `VectorQuadraticFunction`

.

The easiest way to create a vector function is to stack several scalar functions using `Utilities.vectorize`

. It takes a vector as input, and the generated vector function (of the most appropriate type) has each dimension corresponding to a dimension of the vector.

```
julia> g = MOI.Utilities.vectorize([f, 2 * f])
┌ ┐
│(2) + (1) MOI.VariableIndex(1)│
│(4) + (2) MOI.VariableIndex(1)│
└ ┘
```

`Utilities.vectorize`

only takes a vector of similar scalar functions: you cannot mix `VariableIndex`

and `ScalarAffineFunction`

, for instance. In practice, it means that `Utilities.vectorize([x, f])`

does not work; you should rather use `Utilities.vectorize([1 * x, f])`

instead to only have `ScalarAffineFunction`

objects.

## Canonicalizing functions

In more advanced use cases, you might need to ensure that a function is "canonical." Functions are stored as an array of terms, but there is no check that these terms are redundant: a `ScalarAffineFunction`

object might have two terms with the same variable, like `x + x + 1`

. These terms could be merged without changing the semantics of the function: `2x + 1`

.

Working with these objects might be cumbersome. Canonicalization helps maintain redundancy to zero.

`Utilities.is_canonical`

checks whether a function is already in its canonical form:

```
julia> MOI.Utilities.is_canonical(f + f) # (x + 2) + (x + 2) is stored as x + x + 4
false
```

`Utilities.canonical`

returns the equivalent canonical version of the function:

```
julia> MOI.Utilities.canonical(f + f) # Returns 2x + 4
(4) + (2) MOI.VariableIndex(1)
```

## Exploring functions

At some point, you might need to dig into a function, for instance to map it into solver constructs.

### Vector functions

`Utilities.scalarize`

returns a vector of scalar functions from a vector function:

```
julia> MOI.Utilities.scalarize(g) # Returns a vector [f, 2 * f].
2-element Vector{MathOptInterface.ScalarAffineFunction{Int64}}:
(2) + (1) MOI.VariableIndex(1)
(4) + (2) MOI.VariableIndex(1)
```

`Utilities.eachscalar`

returns an iterator on the dimensions, which serves the same purpose as `Utilities.scalarize`

.

`output_dimension`

returns the number of dimensions of the output of a function:

```
julia> MOI.output_dimension(g)
2
```