1use oximo_expr::{Expr, VarId};
2use smol_str::SmolStr;
3
4use crate::domain::Domain;
5use crate::model::Model;
6
7#[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#[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
28pub(crate) fn assert_fixable(name: &str, domain: Domain, lb: f64, ub: f64, value: f64) {
32 assert!(value.is_finite(), "cannot fix variable {name:?} to the non-finite value {value}");
33 assert!(
34 !domain.is_integer() || value.fract() == 0.0,
35 "cannot fix {domain} variable {name:?} to the fractional value {value}"
36 );
37 let semi_zero = domain.semi_threshold().is_some() && value == 0.0;
38 assert!(
39 semi_zero || (lb <= value && value <= ub),
40 "cannot fix variable {name:?} to {value}, outside its bounds [{lb}, {ub}]"
41 );
42 if let Some(threshold) = domain.semi_threshold() {
43 assert!(
44 value == 0.0 || value >= threshold,
45 "cannot fix {domain} variable {name:?} to {value}: it must be 0 or at least {threshold}"
46 );
47 }
48}
49
50#[must_use = "VarBuilder does nothing until you call .build()"]
53pub struct VarBuilder<'a> {
54 pub(crate) model: &'a Model,
55 pub(crate) name: SmolStr,
56 pub(crate) lb: f64,
57 pub(crate) ub: f64,
58 pub(crate) domain: Domain,
59 pub(crate) initial: Option<f64>,
60}
61
62impl<'a> std::fmt::Debug for VarBuilder<'a> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("VarBuilder")
65 .field("name", &self.name)
66 .field("lb", &self.lb)
67 .field("ub", &self.ub)
68 .field("domain", &self.domain)
69 .finish()
70 }
71}
72
73impl<'a> VarBuilder<'a> {
74 pub fn lb(mut self, v: f64) -> Self {
75 self.lb = v;
76 self
77 }
78
79 pub fn ub(mut self, v: f64) -> Self {
80 self.ub = v;
81 self
82 }
83
84 pub fn bounds(mut self, lb: f64, ub: f64) -> Self {
85 self.lb = lb;
86 self.ub = ub;
87 self
88 }
89
90 pub fn fix(self, value: f64) -> Self {
99 assert_fixable(&self.name, self.domain, self.lb, self.ub, value);
100 self.bounds(value, value)
101 }
102
103 pub fn domain(mut self, d: Domain) -> Self {
104 self.domain = d;
105 self
106 }
107
108 pub fn integer(mut self) -> Self {
109 self.domain = Domain::Integer;
110 self
111 }
112
113 pub fn binary(mut self) -> Self {
114 self.domain = Domain::Binary;
115 self.lb = 0.0;
116 self.ub = 1.0;
117 self
118 }
119
120 pub fn initial(mut self, v: f64) -> Self {
121 self.initial = Some(v);
122 self
123 }
124
125 pub fn build(self) -> Expr<'a> {
126 self.model.register_var(self)
127 }
128}