1use oximo_expr::{Expr, ExprId};
2use smol_str::SmolStr;
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6pub enum Sense {
7 Le,
8 Ge,
9 Eq,
10}
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
13pub struct ConstraintId(pub u32);
14
15impl ConstraintId {
16 #[inline]
17 pub fn index(self) -> usize {
18 self.0 as usize
19 }
20}
21
22#[derive(Clone, Debug)]
32pub struct Constraint {
33 pub name: SmolStr,
34 pub lhs: ExprId,
35 pub lower: f64,
36 pub upper: f64,
37 pub active: bool,
38}
39
40impl Constraint {
41 fn is_equality(&self) -> bool {
45 self.lower.total_cmp(&self.upper).is_eq()
46 }
47
48 #[must_use]
53 pub fn is_range(&self) -> bool {
54 self.lower.is_finite() && self.upper.is_finite() && !self.is_equality()
55 }
56
57 #[must_use]
61 pub fn as_single(&self) -> Option<(Sense, f64)> {
62 match (self.lower.is_finite(), self.upper.is_finite()) {
63 (false, true) => Some((Sense::Le, self.upper)),
64 (true, false) => Some((Sense::Ge, self.lower)),
65 (true, true) if self.is_equality() => Some((Sense::Eq, self.lower)),
66 _ => None,
67 }
68 }
69}
70
71#[derive(Copy, Clone, Debug)]
74pub struct ConstraintExpr<'a> {
75 pub lhs: Expr<'a>,
76 pub sense: Sense,
77 pub rhs: f64,
78}
79
80pub trait Relate<'a> {
82 fn le<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a>;
83 fn ge<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a>;
84 fn eq<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a>;
85}
86
87pub trait IntoRhs<'a> {
90 fn fold_rhs(self, lhs: Expr<'a>) -> (Expr<'a>, f64);
91
92 fn const_bound(&self) -> Option<f64> {
98 None
99 }
100}
101
102impl<'a> IntoRhs<'a> for f64 {
103 fn fold_rhs(self, lhs: Expr<'a>) -> (Expr<'a>, f64) {
104 (lhs, self)
105 }
106 fn const_bound(&self) -> Option<f64> {
107 Some(*self)
108 }
109}
110
111impl<'a> IntoRhs<'a> for i32 {
112 fn fold_rhs(self, lhs: Expr<'a>) -> (Expr<'a>, f64) {
113 (lhs, f64::from(self))
114 }
115 fn const_bound(&self) -> Option<f64> {
116 Some(f64::from(*self))
117 }
118}
119
120impl<'a> IntoRhs<'a> for Expr<'a> {
121 fn fold_rhs(self, lhs: Expr<'a>) -> (Expr<'a>, f64) {
122 (lhs - self, 0.0)
123 }
124}
125
126impl<'a> Relate<'a> for Expr<'a> {
127 fn le<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a> {
128 let (lhs, rhs) = rhs.fold_rhs(self);
129 ConstraintExpr { lhs, sense: Sense::Le, rhs }
130 }
131
132 fn ge<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a> {
133 let (lhs, rhs) = rhs.fold_rhs(self);
134 ConstraintExpr { lhs, sense: Sense::Ge, rhs }
135 }
136
137 fn eq<R: IntoRhs<'a>>(self, rhs: R) -> ConstraintExpr<'a> {
138 let (lhs, rhs) = rhs.fold_rhs(self);
139 ConstraintExpr { lhs, sense: Sense::Eq, rhs }
140 }
141}