# Variables

A guide for variables in `InfiniteOpt`

. See the respective technical manual for more details.

## Overview

Decision variables are at the very core of `InfiniteOpt`

as its name alludes to mathematical programs that entail infinite decision spaces (i.e., contain infinite decision variables). Principally, 4 variable types are employed: infinite, semi-infinite, point, and finite. Infinite variables encompass any decision variable that is parameterized by an infinite parameter(s) (e.g., space-time variables and stochastic recourse variables). Semi-infinite variables denote infinite variables where certain infinite parameters are restricted to point values. Point variables are infinite variables at a particular point. Finally, finite variables are decisions that are made irrespective of the infinite domain (e.g., first stage variables and design variables).

## Basic Usage

Infinite, semi-infinite, point, and finite variables are summarized in the following table:

Name | Variable Type Object | Description | Example |
---|---|---|---|

Infinite | `Infinite` | decision functions | $y(t, x, \xi)$ |

Semi-Infinite | `SemiInfinite` | partially evaluated decision functions | $y(t_0, x, \xi)$ |

Point | `Point` | fully evaluated decision functions | $y(t_0, x_0, \xi_k)$ |

Finite | NA | classical decision variables | $z$ |

Infinite, semi-infinite, point, and finite variables are defined via `@variable`

(inherited from `JuMP`

) with their respective variable type object arguments: `Infinite`

, `SemiInfinite`

, and `Point`

(finite variables don't use a variable type object).

Let's first set up a simple space-time model with infinite parameters time `t`

and spatial position `x`

:

```
julia> using InfiniteOpt
julia> model = InfiniteModel();
julia> @infinite_parameter(model, t in [0, 10])
t
julia> @infinite_parameter(model, x[1:2] in [-1, 1], independent = true)
2-element Vector{GeneralVariableRef}:
x[1]
x[2]
```

### Infinite Variables

Now let's define a time dependent infinite variable `y(t)`

with a lower bound of 0:

```
julia> @variable(model, y >= 0, Infinite(t))
y(t)
```

This creates a Julia variable `y`

that points to the decision variable `y(t)`

that is stored in `model`

which is added to include a lower bound of 0. Another useful case is that of defining an array of variables `w`

that depend on both position and time:

```
julia> @variable(model, w[i = 1:3], Infinite(t, x), start = [0, 2, 1][i])
3-element Vector{GeneralVariableRef}:
w[1](t, x)
w[2](t, x)
w[3](t, x)
```

Thus, we create a Julia array variable `w`

whose elements `w[i]`

point to their respective infinite variables `w[i](t, x)`

stored in `model`

. Note that the `i`

used in the array definition can be used to index attributes assigned to each variable in the array. In this case, we used `i`

to assign different initial guess values for each variable via the `start`

keyword argument.

Moreover, for infinite variables a function can be given to determine the start values over a range of support points (e.g., a guess trajectory). This is discussed further below in the Macro Definition section.

### Semi-Infinite Variables

Now let's restrict the above infinite variables `w[i](t, x)`

to a particular time via semi-infinite variables:

```
julia> @variable(model, w0[i = 1:3], SemiInfinite(w[i], 0, x))
3-element Vector{GeneralVariableRef}:
w0[1]
w0[2]
w0[3]
```

Thus we create a Julia array variable `w0`

whose elements `w0[i]`

point to their respective semi-infinite variables `w[i](0, x)`

stored in `model`

. Alternatively, we can make a semi-infinite variable via our restriction syntax:

```
julia> [w[i](0, x) for i in 1:3]
3-element Vector{GeneralVariableRef}:
w0[1]
w0[2]
w0[3]
```

These are often useful to define semi-infinite variables directly in constraint expressions. See Restricted Variables to learn about symbolic inline definition of semi-infinite variables.

### Point Variables

Now let's add some point variables. These allow us to consider an infinite variable evaluated at a certain infinite parameter point. For example, let's define a point variable for `y(0)`

with the alias `y0`

that is fixed at a value of 0:

```
julia> @variable(model, y0 == 0, Point(y, 0))
y0
```

Here we create a Julia variable `y0`

which points to the point variable `y(0)`

. Notice that in the second argument we specify the infinite variable indexed at the appropriate parameter value(s). Point variables automatically inherit attributes of the infinite variable (e.g., bounds, start values, etc.), but these are overwritten with properties specified for the point variable. In this case the lower bound inherited from `y(t)`

is overwritten by instead fixing `y(0)`

to a value of 0.

Alternatively, we can use the convenient restriction syntax:

```
julia> y(0)
y0
```

Again this is very useful when embedded directly in constraint expressions (e.g., when defining boundary conditions). See Restricted Variables to learn about symbolic inline definition of point variables.

### Finite Variables

Finally, we can add finite variables to our model. These denote variables that hold a single value over the infinite domain or some portion of it (e.g., design variables, first stage variables, etc.). Let's add a finite variable $0 \leq d \leq 42$ that is an integer variable and defined over all infinite domains (i.e., time and space):

```
julia> @variable(model, 0 <= d <= 42, Int)
d
```

This creates a Julia variable `d`

that points to the finite variable `d`

which has a lower bound of 0, an upper bound of 42, and is an integer variable. Thus, finite variables are equivalent to those employed in `JuMP`

.

Now we have defined variables that we can use in the objective, measures, and constraints. Please note that the above tutorial only shows a small portion of the capabilities and options available in defining variables. A full description is provided in the documentation below.

## Variable Definition Methodology

Defining/initializing a variable (what happens behind the scenes of the variable macros) principally involves the following steps:

- Define the variable information pertaining to
`JuMP.VariableInfo`

(e.g., bounds, indicate if it is integer, etc.) - Construct a concrete subtype of
`InfOptVariableType`

to specify the desired type and its required additional information if appropriate - Build the variable object via
`JuMP.build_variable`

- Add the variable object to an
`InfiniteModel`

and assign a name via`JuMP.add_variable`

- Create a
`GeneralVariableRef`

that points to the variable object stored in the model

This methodology is presented for those wanting to learn more about the ins and outs of variable definition. We recommend that all variables be created via `@variable`

. See Macro Variable Definition.

The `JuMP.VariableInfo`

data structure stores the following variable information:

`has_lb::Bool`

: Specifies a`Bool`

it has a lower bound`lower_bound::Real`

: Specifies lower bound value`has_ub::Bool`

: Specifies a`Bool`

it has a upper bound`upper_bound::Real`

: Specifies upper bound value`has_fix::Bool`

: Specifies a`Bool`

it is fixed`fixed_value::Real`

: Specifies the fixed value`has_start::Bool`

: Specifies a`Bool`

it has a start value`start::Union{Real, Function}`

: Specifies the start guess value, this can be a function for infinite variables that intakes a support and maps it to a guess value (allowing to specify guess trajectories)`binary`

: Specifies`Bool`

if it is binary`integer`

: Specifies`Bool`

if it is integer.

Thus, the user specifies this information to prepare such an object:

`julia> info = VariableInfo(true, 0., true, 42., false, 0., false, 0., false, true);`

Here we specified a lower bound of 0, an upper bound of 42, and that it is integer valued.

The variable type objects (`InfOptVariableType`

subtypes) are used with `build_variable`

to specify the desired variable type along with any additional information needed for that type. For example, let's build an infinite variable `y(t)`

that has an lower bound of 0, an upper bound of 42, and is integer valued:

```
julia> @infinite_parameter(model, t in [0, 10])
t
julia> info = VariableInfo(true, 0, true, 42, false, 0, false, 0, false, true);
julia> inf_var = build_variable(error, info, Infinite(t));
```

Thus, we create an `InfiniteVariable`

object with the desired properties.

Once a variable has been built, it needs to be added to our `model`

and a Julia variable should be defined to reference it. Variables are added via `add_variable`

which adds a variable object to the model, assigns a name to the variable, adds any constraints associated with the `JuMP.VariableInfo`

, and returns an appropriate variable reference variable (a `GeneralVariableRef`

). For example, let's add `inf_var`

to `model`

:

```
julia> var_ref = add_variable(model, inf_var, "y")
y(t)
```

Thus, we have added an infinite variable `y`

that is parameterized by `t`

with the variable information mentioned above and now have a `GeneralVariableRef`

called `var_ref`

that can be used in defining our infinite model.

Note that the use of `GeneralVariableRef`

s and the corresponding concrete subtypes of `DispatchVariableRef`

s is discussed on the Expressions page.

## Macro Variable Definition

The `@variable`

macro automates the variable definition process discussed above in the Variable Definition Methodology section via a straightforward symbolic syntax. The only key difference is that non-anonymous macro calls will register variable names to ensure they are not repeated. Anonymous macro calls forgo this step and exactly follow the process described above. This section will highlight the details of using this macro which is the recommended way to define variables.

`JuMP`

's documentation on variables is a good place to start since `InfiniteOpt`

simply extends `JuMP`

to accommodate our additional variable types.

We directly build upon `JuMP.@variable`

to create all of our decision variable types. To illustrate this via example, let's setup a model with a variety of infinite parameters $t \in [0,10]$, $x \in [-1, 1]^3$, and $\xi \in \mathcal{N}(0, 1)$:

```
julia> using InfiniteOpt, Distributions
julia> model = InfiniteModel();
julia> @infinite_parameter(model, t in [0, 10]);
julia> @infinite_parameter(model, x[1:3] in [-1, 1], independent = true);
julia> @infinite_parameter(model, ξ ~ Normal());
```

### Variable Types

We specify the variable type by providing a subtype of `InfOptVariableType`

as an extra positional argument:

```
julia> @variable(model, y, Infinite(t, x, ξ)) # explicit infinite variable
y(t, x, ξ)
julia> @variable(model, ys, SemiInfinite(y, 0, x, ξ)) # explicit semi-infinite variable
ys
julia> @variable(model, yp, Point(y, 0, [1, 1, 1], 0)) # explicit point variable
yp
julia> @variable(model, z) # explicit finite variable
z
```

For anonymous definition, we use the `variable_type`

keyword argument instead:

```
julia> y = @variable(model, variable_type = Infinite(t, x, ξ)) # anon infinite variable
noname(t, x, ξ)
julia> ys = @variable(model, variable_type = SemiInfinite(y, 0, x, ξ)) # anon semi-infinite variable
noname(0, [x[1], x[2], x[3]], ξ)
julia> yp = @variable(model, variable_type = Point(y, 0, [1, 1, 1], 0)) # anon point variable
noname(0, [1, 1, 1], 0)
julia> z = @variable(model) # anon finite variable
noname
```

Please refer to `Infinite`

, `SemiInfinite`

, and `Point`

for more information.

### Variable Names

Variable inherit their names from the symbolic literal given with explicit definitions:

```
julia> @variable(model, myname, Infinite(t))
myname(t)
```

This creates an infinite variable with name `"myname"`

that is added to `model`

and creates a Julia variable `myname`

that stores a `GeneralVariableRef`

which points to the infinite variable in `model`

.

We can overwrite the inherited name using the `base_name`

keyword argument:

```
julia> @variable(model, myjlvar, Infinite(t), base_name = "myname")
myname(t)
```

This creates an infinite variable with name `"myname"`

that is added to `model`

and creates a Julia variable `myjlvar`

that stores a `GeneralVariableRef`

which points to the infinite variable in `model`

.

This syntax is particularly useful for anonymous variables to have meaningful names:

```
julia> myjlvar = @variable(model, variable_type = Infinite(t), base_name = "myname")
myname(t)
```

See the Queries and Modification sections further below for more information on how to query/modify variable names.

### Variable Bounds

We can specify variable bounds in like manner to `JuMP`

variables. Let's demonstrate this with infinite variables:

```
julia> @variable(model, y_lb >= 0, Infinite(t, x)) # add w/ lower bound
y_lb(t, x)
julia> @variable(model, y_ub <= 10, Infinite(t, x)) # add w/ upper bound
y_ub(t, x)
julia> @variable(model, 0 <= y_bd <= 10, Infinite(t, x)) # add w/ bounds
y_bd(t, x)
julia> @variable(model, y_fix == 42, Infinite(t, x)) # add w/ fixed value
y_fix(t, x)
```

When creating a variable with only a single bound and the value of the bound is not an explicit numeric literal, the name of the variable must appear on the left-hand side. Otherwise, the macro will error.

```
@variable(model, 0 <= y, Infinite(t)) # okay
a = 0
@variable(model, a <= y, Infinite(t)) # bad
@variable(model, y >= a, Infinite(t)) # okay
```

For anonymous definition, we use the `lower_bound`

and `upper_bound`

. Let's use finite variables for example:

```
julia> z_lb = @variable(model, lower_bound = 0, base_name = "z_lb") # add w/ lower bound
z_lb
julia> z_ub = @variable(model, upper_bound = 10, base_name = "z_ub") # add w/ upper bound
z_ub
julia> z_bd = @variable(model, lower_bound = 0, upper_bound = 10,
base_name = "z_bd") # add w/ bounds
z_bd
julia> z_fix = @variable(model, lower_bound = 10, upper_bound = 10,
base_name = "z_fix") # ~add w/ fixed value
z_fix
```

Note that there isn't a keyword for fixing variables. Instead, `fix`

should be used.

See the Queries and Modification sections further below for more information on how to query/modify variable bounds.

Point variables inherit all the bounds of their respective infinite variables by default. This can be overwritten by specifying different ones at creation.

```
@variable(model, y >= 0, Infinite(t, x)) # has lower bound
@variable(model, yp == 0, Point(w, 0, [0, 0, 0])) # forces the point to be fixed
```

Bounds cannot be specified on creation for semi-infinite variables. Note that they will inherit these from the infinite variable they depend on. Additional bound be created by directly adding constraints. For example:

```
@variable(model, y >= 0, Infinite(t, x)) # has lower bound
@variable(model, ys, SemiInfinite(w, 0, x)) # inherits the lower bound
@constraint(model, ys <= 10) # add upper bound to ys
```

### Variable Integrality

We can constrain the integrality of decision variables in like manner to `JuMP`

using the `Bin`

and `Int`

positional arguments for explicit macro definition:

```
julia> @variable(model, y_bin, Infinite(t, x), Bin) # add as binary variable
y_bin(t, x)
julia> @variable(model, y_int, Infinite(t, x), Int) # add as integer variable
y_int(t, x)
```

For anonymous definition, we use the `binary`

and `integer`

keyword arguments:

```
julia> y_bin = @variable(model, variable_type = Infinite(t, x), binary = true)
noname(t, x)
julia> y_int = @variable(model, variable_type = Infinite(t, x), integer = true)
noname(t, x)
```

Moreover, we can add bounds as needed to constrain the domain of integer variables:

```
julia> @variable(model, 0 <= y_int2 <= 10, Infinite(t, x), Int)
y_int2(t, x)
```

See the Queries and Modification sections further below for more information on how to query/modify variable integralities.

Point variables inherit the integrality of their respective infinite variables by default. This can be overwritten by specifying different ones at creation.

```
@variable(model, y, Infinite(t, x), Bin) # is binary
@variable(model, yp, Point(w, 0, [0, 0, 0]), Int) # is integer
```

Integrality cannot be specified for semi-infinite variables. Note that they will inherit these from the infinite variable they depend on. ```

### Variable Start Values

Optimization solvers often benefit from giving initial guesses for the optimal decision variable values. Following `JuMP`

vernacular, these are called start values. We use the keyword `start`

to specify these at variable creation:

```
julia> @variable(model, z_start, start = 42)
z_start
```

Moreover, infinite variables can accept a function that specifies the start value of over the range of its infinite parameters (e.g., a function that provides an initial guess trajectory). For example, consider the difference between these two infinite variables:

```
julia> @variable(model, y_uniform, Infinite(t), start = 0) # start with y(t) = 0
y_uniform(t)
julia> @variable(model, y_sin, Infinite(t), start = sin) # start with y(t) = sin(t)
y_sin(t)
```

Note that such start functions must be able to accept parameter values as arguments that exactly match the format of the infinite parameters given in `Infinite(params...)`

.

Start values be specified for semi-infinite variables. Note that they will inherit these from the infinite variable they depend on.

See the Queries and Modification sections further below for more information on how to query/modify variable names.

### Variable Containers

Optimization problems often involve multi-dimensional decision variables. Luckily, `JuMP`

provides a versatile syntax for specifying collections (i.e., containers) of variables. See JuMP's container documentation for a thorough tutorial on the syntax. It uses `Array`

s, `DenseAxisArray`

s, and `SparseAxisArray`

s to contain the variable references created. Here `DenseAxisArray`

s and `SparseAxisArray`

s allow the use of nontraditional indices (i.e., can use indices that are not sequential integers).

To illustrate what this means, consider the two equivalent ways to define a 3-dimensional vector of variables with indices `[1, 2, 3]`

:

```
julia> s = [0, 2, 1];
julia> var_refs = @variable(model, [i = 1:3], start = s[i], base_name = "z")
3-element Vector{GeneralVariableRef}:
z[1]
z[2]
z[3]
julia> var_refs = Vector{GeneralVariableRef}(undef, 3);
julia> for i in eachindex(var_refs)
var_refs[i] = @variable(model, start = s[i], base_name = "z")
end
```

Moreover, here are a few illustrative examples:

```
julia> @variable(model, z_dense[2:4])
1-dimensional DenseAxisArray{GeneralVariableRef,1,...} with index sets:
Dimension 1, 2:4
And data, a 3-element Vector{GeneralVariableRef}:
z_dense[2]
z_dense[3]
z_dense[4]
julia> @variable(model, z_named[[:A, :C, :Z]])
1-dimensional DenseAxisArray{GeneralVariableRef,1,...} with index sets:
Dimension 1, [:A, :C, :Z]
And data, a 3-element Vector{GeneralVariableRef}:
z_named[A]
z_named[C]
z_named[Z]
julia> @variable(model, z_sparse[i = 1:2, j = 1:2; i + j <= 3])
JuMP.Containers.SparseAxisArray{GeneralVariableRef, 2, Tuple{Int64, Int64}} with 3 entries:
[1, 1] = z_sparse[1,1]
[1, 2] = z_sparse[1,2]
[2, 1] = z_sparse[2,1]
```

The variable macro will by default automatically detect which container type should be used. However, the user can specify a particular container type using the `container`

keyword. For example, if we want to use indices `a:b`

where `a = 1`

and `b = 3`

, a `DenseAxisArray`

will be used by default, but we can force it to be a regular `Array`

:

```
julia> a = 1; b = 3;
julia> var_refs1 = @variable(model, [a:b], base_name = "z")
1-dimensional DenseAxisArray{GeneralVariableRef,1,...} with index sets:
Dimension 1, 1:3
And data, a 3-element Vector{GeneralVariableRef}:
z[1]
z[2]
z[3]
julia> var_refs2 = @variable(model, [a:b], base_name = "z", container = Array)
3-element Vector{GeneralVariableRef}:
z[1]
z[2]
z[3]
```

### Variable Sets

Like `JuMP`

variables, we can constrain variables on creation to lie in particular sets. This allows us to make semi-definite variables, cone constrained variables, and more.

For example:

```
julia> @variable(model, z_psd[1:2, 1:2], PSD) # positive semi-definite variable matrix
2×2 LinearAlgebra.Symmetric{GeneralVariableRef, Matrix{GeneralVariableRef}}:
z_psd[1,1] z_psd[1,2]
z_psd[1,2] z_psd[2,2]
julia> @variable(model, z_cone[1:3] in SecondOrderCone()) # 2nd order cone variables
3-element Vector{GeneralVariableRef}:
z_cone[1]
z_cone[2]
z_cone[3]
```

Typically, variable sets can be defined symbolically using the syntax `var in set`

. For anonymous variables, the `set`

keyword argument must be used:

```
julia> z_cone = @variable(model, [1:3], set = SecondOrderCone())
3-element Vector{GeneralVariableRef}:
noname
noname
noname
```

For a more thorough tutorial please see JuMP's semi-definite documentation and/or JuMP's variables constrained on creation documentation.

### Anonymous Variables

Above we talked showed the syntax for both explicit and anonymous variable creation. Anonymous creation is typically helpful in the following situations:

- defining multiple variables with the same name
- creating variables in user defined extensions
- using nontraditional naming

For anonymous variables, the only accepted positional arguments are the `model`

and the container expression `[indices...]`

. Everything else must be specified via keyword arguments `kwargs...`

as shown in the subsections above.

`@variable(model, [indices...], kwargs...)`

For more information, see JuMP's anonymous variable documentation.

### The `@variables`

Macro

When using many `@variable`

calls, we can instead use `@variables`

to enhance the readability:

```
julia> @variables(model, begin
y1, Infinite(t, x)
y2[i=1:2] >= i, Infinite(t), (start = i, base_name = "Y_$i")
z2, Bin
end)
(y1(t, x), GeneralVariableRef[Y_1[1](t), Y_2[2](t)], z2)
```

## Restricted Variables

To define point and semi-infinite variables, we can also use `restrict`

for convenient inline definitions.

For example, let's consider restricting the infinite variable `y(t, x)`

:

```
julia> model = InfiniteModel();
julia> @infinite_parameter(model, t in [0, 1]);
julia> @infinite_parameter(model, x[1:2] in [-1, 1]);
julia> @variable(model, y, Infinite(t, x))
y(t, x)
julia> pt = restrict(y, 0, [-1, 1]) # make point variable y(0, [-1, 1])
y(0, [-1, 1])
julia> semi = restrict(y, 0, x) # make semi-infinite variable y(0, x)
y(0, [x[1], x[2]])
```

We can also, even more conveniently, treat the infinite variable as a function to accomplish this in a more intuitive syntax:

```
julia> pt = y(0, [-1, 1]) # make point variable y(0, [-1, 1])
y(0, [-1, 1])
julia> semi = y(0, x) # make semi-infinite variable y(0, x)
y(0, [x[1], x[2]])
```

## Queries

`InfiniteOpt`

contains a large suite of methods to query information about variables. This suite comprises extensions to all current `JuMP`

query methods and many more that are specific to `InfiniteOpt`

. A number of the more commonly used ones are explained in this section, but all the available methods are explained in the technical manual.

### General Information

Here we describe some methods used to query general variable information such as the name. Variable names can be extracted via `name`

which returns the name of a variable. The index of a variable (where it is stored in the infinite model) is accessed via `index`

and the infinite model it belongs to is given by `owner_model`

. These methods are demonstrated below:

```
julia> name(y)
"y"
julia> index(y)
InfiniteVariableIndex(2)
julia> model_where_stored = owner_model(y);
```

Also, `num_variables`

is useful in returning the total number of decision variables currently stored in an infinite model:

```
julia> num_variables(model)
61
julia> num_variables(model, PointVariable)
2
```

Similarly, `all_variables`

returns a list of all the variables currently added to the model.

Finally, `variable_by_name`

can be employed to return the appropriate `GeneralVariableRef`

based off of the variable name if it is unique. Returns `nothing`

if such a name cannot be found and errors if it is not unique. For example, we can request the reference associated with `"y_ub"`

:

```
julia> variable_by_name(model, "y_ub")
y_ub(t, x)
```

### Variable Constraint Info

As described above, variables in `InfiniteOpt`

can have constraints associated with them like `JuMP`

variables. These constraints include:

- lower bounds
- upper bounds
- fixed values
- binary valued
- integer valued.

Thus, a number of methods exist to query information about these constraints.

First, the `[has/is]_[variable constraint type]`

methods indicate whether a variable has that particular constraint type. For example, to query if a variable `y_lb`

has a lower bound we can use `has_lower_bound`

:

```
julia> has_lower_bound(y_bd)
true
```

Thus, `y_bd`

does have a lower bound. The other methods are `has_upper_bound`

, `is_fixed`

, `is_binary`

, and `is_integer`

.

Next, the `[ConstraintType]Ref`

methods return an appropriate explicit type `InfOptConstraintRef`

that points to the constraint (errors if no such constraint exists). For example, the upper bound constraint of `y_bd`

can be obtained via `UpperBoundRef`

:

```
julia> UpperBoundRef(y_bd)
y_bd(t, x) ≤ 10, ∀ t ∈ [0, 10], x[1] ∈ [-1, 1], x[2] ∈ [-1, 1], x[3] ∈ [-1, 1]
```

The other methods are `LowerBoundRef`

, `FixRef`

, `BinaryRef`

, and `IntegerRef`

.

Finally, variable constraints that entail values (i.e., lower bounds, upper bounds, and fixed values) have their values queried via the appropriate method. For example, the lower bound value of `y_bd`

is obtained via `lower_bound`

:

```
julia> lower_bound(y_bd)
0.0
```

Note these methods error when no such constraint is associated with the variable. The other methods are `upper_bound`

and `fix_value`

.

The start value can also be queried via `start_value`

where nothing is returned if not start value is specified:

```
julia> start_value(var_refs[1])
0.0
julia> start_value(yp)
```

For infinite and semi-infinite variables, the `start_value_function`

should be used instead:

```
julia> start_value_function(y_sin)
sin (generic function with 18 methods)
```

### Variable Use

`InfiniteOpt`

defines a number of methods to track if and how variables are used in an infinite model. For example, `used_by_constraint`

is used to determine if a variable is used by a constraint. For example, let's see if `y_bd`

is used by a constraint:

```
julia> used_by_constraint(y_bd)
true
```

Other methods include `used_by_measure`

and `used_by_objective`

. For infinite variables, `used_by_point_variable`

can also be used similarly.

Finally, in general `is_used`

can be used to determine if a variable is used at all in the infinite model or not. For example, if we check `yp`

using `is_used`

we find that it isn't:

```
julia> is_used(yp)
false
```

### Type Specific

`InfiniteOpt`

also employs a few methods for specific variable types that return information pertaining to that particular variable type. For infinite variables and semi-infinite variables, `parameter_refs`

returns the tuple of infinite parameters that the variable depends on. For example, consider `y(t, x)`

:

```
julia> parameter_refs(y)
(t, GeneralVariableRef[x[1], x[2], x[3]], ξ)
```

For point variables, `infinite_variable_ref`

and `parameter_values`

return the infinite variable it depends on and the infinite parameter point values, respectively. For example, consider the point variable `yp`

:

```
julia> infinite_variable_ref(yp)
y(t, x, ξ)
julia> parameter_values(yp)
(0.0, [1.0, 1.0, 1.0], 0.0)
```

## Modification

`InfiniteOpt`

employs a wide variety of methods to modify/delete variables. These are comprised of `JuMP`

extensions and methods native only to `InfiniteOpt`

. This section will highlight some of the more commonly used ones. All the methods/macros are detailed in the technical manual.

### Deletion

Like `JuMP v0.19+`

, `InfiniteOpt`

fully supports deletion throughout its data types. Any variable and its dependencies can be deleted via `delete`

. Thus, when `delete`

is invoked any bound/type constraints associated with the variable will be removed and it will be removed from any other constraints, measures, and/or objectives. For example, if we delete `y(t, x, ξ)`

it will be removed along with its bounds and the point variable `yp`

will also be removed since it is a dependent:

```
julia> delete(model, y)
julia> is_valid(model, yp)
false
```

Another class of deletion methods correspond to variable constraints. For example, `delete_lower_bound`

is used to delete a lower bound associated with a variable if it has one. Let's illustrate this by deleting the lower bound of `y_bd`

:

```
julia> delete_lower_bound(y_bd)
julia> has_lower_bound(y_bd)
false
```

Other similar methods are `delete_upper_bound`

, `unfix`

, `unset_binary`

, and `unset_integer`

.

### Variable Constraints

Another class of methods seek to add/modify variable constraints such as bounds. For example, `set_lower_bound`

specifies the lower bound of a variable. We can add a lower bound of 0 to `z`

by:

```
julia> set_lower_bound(z, 0)
julia> lower_bound(z)
0.0
```

Thus, adding a lower bound to `z`

. Furthermore, we can later modify the lower bound using the same method:

```
julia> set_lower_bound(z, -2)
julia> lower_bound(z)
-2.0
```

Other similar methods are `set_upper_bound`

, `fix`

, `set_binary`

, and `set_integer`

.

### Start Values

We can update the start value of a variable using `set_start_value`

. For example:

```
julia> set_start_value(z, 0)
julia> start_value(z)
0.0
```

For infinite variables, this should be done using `set_start_value_function`

. FOr example:

```
julia> set_start_value_function(myname, sin)
julia> start_value_function(myname)
sin (generic function with 18 methods)
```

Again note that such start functions must be able to accept parameter values as arguments that exactly match the format of the infinite parameters given in `Infinite(params...)`

.

A number of other techniques exist for the various variable types can be found in the manual below.