Linear programming covers an enormous fraction of business optimization. Variables are continuous (money, hours, units of inventory). Constraints and objective are linear (budget caps, capacity limits, sum-to-one). Modern solvers — HiGHS (open source), Gurobi, CPLEX — handle millions of variables in seconds. Diet planning, blending problems, transportation problems, scheduling relaxations, network flow at scale, portfolio allocation, blending ad targeting — all linear programs. Rust's lp" data-term="good_lp">good_lp library lets your team model the problem in code (define variables, add constraints, set objective) and dispatch to a backend solver. HiGHS is the recommended open-source backend. When some variables must be integer (page 32), the problem moves to the expensive category. When the variables are continuous, the work is industrial and your team should not be writing their own solver.
19
Optimization with continuous numbers
Real-valued optimization with linear constraints is in the cheap category — even at millions of variables. Buy or open-source the solver.
-
good_lplets your team model the LP in code — variables with bounds, linear constraints with operator overloading, an objective — and dispatch to a backend solver. HiGHS is the recommended open-source backend; the model below is a diet problem in three lines of math.use good_lp::{constraint, default_solver, variables, SolverModel, Solution}; fn cheapest_diet() -> (f64, f64, f64) { variables! { vars: 0 <= bread; 0 <= rice; 0 <= eggs; } let model = vars .minimise(2.0 * bread + 1.5 * rice + 3.0 * eggs) // dollars .using(default_solver) .with(constraint!(80.0 * bread + 130.0 * rice + 70.0 * eggs >= 2000.0)) .with(constraint!( 3.0 * bread + 2.0 * rice + 13.0 * eggs >= 50.0)); let sol = model.solve().expect("feasible"); (sol.value(bread), sol.value(rice), sol.value(eggs)) } - The trailing exclamation point in
variables!(andconstraint!two lines below) marks them as macros, not regular function calls. Rust macros are metaprogramming — they take code at compile time and transform it into other code before normal compilation runs. The!is how Rust distinguishes a macro invocation from a function call; the rest of the call site looks similar. Macros exist because some patterns cannot be expressed as ordinary functions: taking a variable number of arguments, accepting non-expression syntax like0 <= bread; 0 <= rice;, or declaring new variables in the caller's scope.variables!does that last thing — it expands at compile time into a sequence ofletbindings, one per variable name listed, plus aProblemVariablesbuilder. A regular function call cannot introduce new local bindings into its caller, so this work has to happen via macro.constraint!is a macro for a related reason: it parses an inequality expression with<=or>=in the middle, which is not how function arguments normally look.// Macros are marked with a trailing ! — the only syntactic difference // from a function call. println!("hello"); // macro format!("hi {}", name); // macro vec![1, 2, 3]; // macro (and uses [] instead of ()) assert_eq!(x, y); // macro some_function(x); // not a macro — no ! // What variables! roughly expands to at compile time: variables! { vars: 0 <= bread; 0 <= rice; 0 <= eggs; } // ≈ let mut vars = ProblemVariables::new(); let bread = vars.add(variable().min(0.0)); let rice = vars.add(variable().min(0.0)); let eggs = vars.add(variable().min(0.0)); // A regular function CAN'T do this — function calls cannot introduce // new bindings (`bread`, `rice`, `eggs`) into their caller's scope. // Macros expand inline AT the call site, so the bindings appear // where they're written. // Two flavors of macro you'll meet in real Rust code: // // macro_rules! NAME { ... } declarative macros — pattern-match on // token trees. vec!, println!, todo!. // // #[derive(Debug)] procedural macros — actual Rust code // #[serde(rename = "x")] that takes a TokenStream and returns // sql!("SELECT ...") one. Includes #[derive], attribute // macros, and function-like procedural // macros (the !-call variety). // Common macros you'll see everywhere in Rust: // println! print! eprintln! formatted output // vec! build a Vec inline // format! build a String inline // assert! assert_eq! assert_ne! tests and runtime checks // panic! crash with a message // dbg! print + return — for debugging // todo! unimplemented! placeholders that compile but panic // write! writeln! format into a Write target