macro_rules! variables {
() => { ... };
(
$vars:ident:
$(
$($min:literal <= )?
$var_name:ident
$([$length:expr])?
$(($qualifier:tt))?
$(<= $max:expr;)?
$(>= $postfix_min:expr;)?
$(;)?
)*
) => { ... };
(@add_variable, $vars:expr, $var:expr, $length:expr) => { ... };
(@add_variable, $vars:expr, $var:expr,) => { ... };
}Expand description
Instantiates ProblemVariables, to create a set of related variables.
Using a macro allows you to create variables with a readable syntax close to the LP file format. If you don’t need that, you can instantiate your linear program with only ProblemVariables::new
§Working examples
§Defining variables in the macro
The most concise way to define variables is to do it directly in the macro.
use good_lp::{variables, default_solver, SolverModel};
variables!{problem:
0 <= x; // Create a variable x that varies between 0 and +∞
0 <= y <= 10; // y varies between 0 and 10
z; // z varies between -∞ and +∞
} // x, y, and z are now three rust variables that are in scope
problem.minimise(x + y + z).using(default_solver).solve();§Creating a vector of variables
use good_lp::{variable, variables, Expression};
variables!{vars: 0 <= x[3] <= 1; } // x will be a vector of variables
let objective = x[0] + x[1] - x[2];§Creating integer variables
variables!{vars: 0 <= x[3] (integer) <= 8; } // x will be a vector of integer variables§Creating binary variables
use good_lp::{variable, variables};
variables!{vars: x (binary); }
// equivalent to:
variables!{vars: 0 <= x (integer) <= 1; }§Simply instantiating ProblemVariables
use good_lp::{variable, variables, Expression};
let mut vars = variables!();
let x = vars.add(variable().min(0));
let y = vars.add(variable().max(9));
let objective = x + y;§Defining variables programmatically
Sometimes you don’t know before run time how many variables you are going to have. In these cases, you can use the methods in ProblemVariables to dynamically add variables to your problem.
use good_lp::{variable, variables, Expression};
variables!{vars: 0 <= x; } // The variable x will always be present
let y = if should_add_y { // The variable y will be present only if the condition is true
Some(vars.add(variable().min(0)))
} else {None};
let objective = x + y.map(Expression::from).unwrap_or_default();
// objective is now x + y if should_add_y, and just x otherwise§Setting bounds from outside expressions
Because of restrictions on rust macros, this works :
let max_x = 10;
variables!{vars: x <= max_x; } // max_x is the upper bound for xBut this doesn’t:
let min_x = 10;
variables!{vars: min_x <= x; } // trying to set min_x as the lower bound for x, but this failsIf you want to use a value computed outside of the macro invocation as a lower bound, use this syntax:
let min_x = 10;
variables!{vars: x >= min_x; } // min_x is the lower bound for x§Trying to add incompatible variables
You should never create expressions with variables that come from different ProblemVariables instances.
use good_lp::{variables, default_solver, SolverModel};
variables!{pb1: a;}
variables!{pb2: x; y;} // Creating my variables on pb2 ...
pb1.minimise(x + y) // ... but running the optimization on pb1
.using(default_solver)
.solve();Since pb1 and pb2 are different problems, their variables are not compatible with one another.
Trying to solve problems with incompatible variables will panic.