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))
y0Here 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)
y0Again 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)
dThis 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 
InfOptVariableTypeto 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 
InfiniteModeland assign a name viaJuMP.add_variable - Create a 
GeneralVariableRefthat 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 aBoolit has a lower boundlower_bound::Real: Specifies lower bound valuehas_ub::Bool: Specifies aBoolit has a upper boundupper_bound::Real: Specifies upper bound valuehas_fix::Bool: Specifies aBoolit is fixedfixed_value::Real: Specifies the fixed valuehas_start::Bool: Specifies aBoolit has a start valuestart::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: SpecifiesBoolif it is binaryinteger: SpecifiesBoolif 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 GeneralVariableRefs and the corresponding concrete subtypes of DispatchVariableRefs 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
zFor 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
nonamePlease 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)) # okayFor 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_fixNote 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 fixedBounds 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 ysVariable 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 integerIntegrality 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_startMoreover, 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 Arrays, DenseAxisArrays, and  SparseAxisArrays to contain the variable references created. Here  DenseAxisArrays and SparseAxisArrays 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")
       endMoreover, 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
 nonameFor 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)
2Similarly, 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)
trueThus, 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.0Note 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)
trueOther 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)
falseType 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)
falseAnother 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)
falseOther 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.0Thus, 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.0Other 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.0For 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.