Skip to main content

oximo_core/
var.rs

1use oximo_expr::{Expr, VarId};
2use smol_str::SmolStr;
3
4use crate::domain::Domain;
5use crate::model::Model;
6
7/// Variable metadata held by the [`Model`]. Users do not construct this
8/// directly, they get an [`Expr`] back from [`VarBuilder::build`] and look up
9/// solution values via [`crate::Model`] / `oximo_solver::SolverResult`.
10#[derive(Clone, Debug)]
11pub struct Variable {
12    pub id: VarId,
13    pub name: SmolStr,
14    pub domain: Domain,
15    pub lb: f64,
16    pub ub: f64,
17    pub initial: Option<f64>,
18}
19
20/// Display name of `v` within `vars`, degrading to `variable #<index>` when the
21/// id is out of range (a foreign or not-yet-registered [`VarId`]). Used to build
22/// human-readable error messages that name the offending variable.
23#[must_use]
24pub fn var_name(vars: &[Variable], v: VarId) -> String {
25    vars.get(v.index()).map_or_else(|| format!("variable #{}", v.index()), |x| x.name.to_string())
26}
27
28/// Builder backing the `variable!` macro. Configure bounds / domain, then call
29/// [`Self::build`] to register the variable and obtain an `Expr` handle.
30#[must_use = "VarBuilder does nothing until you call .build()"]
31pub struct VarBuilder<'a> {
32    pub(crate) model: &'a Model,
33    pub(crate) name: SmolStr,
34    pub(crate) lb: f64,
35    pub(crate) ub: f64,
36    pub(crate) domain: Domain,
37    pub(crate) initial: Option<f64>,
38}
39
40impl<'a> std::fmt::Debug for VarBuilder<'a> {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        f.debug_struct("VarBuilder")
43            .field("name", &self.name)
44            .field("lb", &self.lb)
45            .field("ub", &self.ub)
46            .field("domain", &self.domain)
47            .finish()
48    }
49}
50
51impl<'a> VarBuilder<'a> {
52    pub fn lb(mut self, v: f64) -> Self {
53        self.lb = v;
54        self
55    }
56
57    pub fn ub(mut self, v: f64) -> Self {
58        self.ub = v;
59        self
60    }
61
62    pub fn bounds(mut self, lb: f64, ub: f64) -> Self {
63        self.lb = lb;
64        self.ub = ub;
65        self
66    }
67
68    pub fn fix(self, value: f64) -> Self {
69        self.bounds(value, value)
70    }
71
72    pub fn domain(mut self, d: Domain) -> Self {
73        self.domain = d;
74        self
75    }
76
77    pub fn integer(mut self) -> Self {
78        self.domain = Domain::Integer;
79        self
80    }
81
82    pub fn binary(mut self) -> Self {
83        self.domain = Domain::Binary;
84        self.lb = 0.0;
85        self.ub = 1.0;
86        self
87    }
88
89    pub fn initial(mut self, v: f64) -> Self {
90        self.initial = Some(v);
91        self
92    }
93
94    pub fn build(self) -> Expr<'a> {
95        self.model.register_var(self)
96    }
97}