Skip to main content

otspot_model/
constraint.rs

1//! Constraint types and the `constraint!` macro
2
3use super::expression::Expression;
4
5/// Sense (direction) of a linear constraint.
6#[non_exhaustive]
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub enum ConstraintSense {
9    /// Less-than-or-equal: `lhs <= rhs`
10    Le,
11    /// Greater-than-or-equal: `lhs >= rhs`
12    Ge,
13    /// Equality: `lhs == rhs`
14    Eq,
15}
16
17/// A linear constraint: `lhs sense rhs`.
18///
19/// Stored in normalized form: `lhs` contains only variable terms (no constant),
20/// and `rhs` is a scalar.
21#[derive(Debug, Clone)]
22pub struct Constraint {
23    /// Left-hand side (variable terms only, constant == 0)
24    pub(crate) lhs: Expression,
25    /// Right-hand side scalar
26    pub(crate) rhs: f64,
27    /// Constraint direction
28    pub(crate) sense: ConstraintSense,
29}
30
31/// Build a `Constraint` using natural inequality syntax.
32///
33/// # Examples
34/// ```
35/// use otspot_model::{Model, constraint};
36/// let mut model = Model::new("demo");
37/// let x = model.add_var("x", 0.0, f64::INFINITY);
38/// let y = model.add_var("y", 0.0, 10.0);
39/// model.add_constraint(constraint!((2.0 * x + 3.0 * y) <= 12.0));
40/// model.add_constraint(constraint!((x + y) >= 3.0));
41/// ```
42/// Build a `Constraint` using natural inequality syntax.
43///
44/// Supported forms:
45/// - `constraint!(x <= 5.0)` — single variable on the left
46/// - `constraint!((expr) <= rhs)` — parenthesised expression on the left
47///
48/// For complex LHS expressions, wrap them in parentheses:
49/// ```rust,no_run
50/// # use otspot_model::{Model, constraint};
51/// # let mut model = Model::new("demo");
52/// # let x = model.add_var("x", 0.0, f64::INFINITY);
53/// # let y = model.add_var("y", 0.0, f64::INFINITY);
54/// model.add_constraint(constraint!((2.0 * x + 3.0 * y) <= 12.0));
55/// ```
56/// or use the method API directly:
57/// ```rust,no_run
58/// # use otspot_model::Model;
59/// # let mut model = Model::new("demo");
60/// # let x = model.add_var("x", 0.0, f64::INFINITY);
61/// # let y = model.add_var("y", 0.0, f64::INFINITY);
62/// model.add_constraint((2.0 * x + 3.0 * y).leq(12.0));
63/// ```
64#[macro_export]
65macro_rules! constraint {
66    // Complex LHS in parentheses
67    (($lhs:expr) <= $rhs:expr) => {
68        $crate::expression::Expression::from($lhs).leq($rhs)
69    };
70    (($lhs:expr) >= $rhs:expr) => {
71        $crate::expression::Expression::from($lhs).geq($rhs)
72    };
73    (($lhs:expr) == $rhs:expr) => {
74        $crate::expression::Expression::from($lhs).eq_constraint($rhs)
75    };
76    // Single variable (ident can be followed by <= in macro rules)
77    ($lhs:ident <= $rhs:expr) => {
78        $crate::expression::Expression::from($lhs).leq($rhs)
79    };
80    ($lhs:ident >= $rhs:expr) => {
81        $crate::expression::Expression::from($lhs).geq($rhs)
82    };
83    ($lhs:ident == $rhs:expr) => {
84        $crate::expression::Expression::from($lhs).eq_constraint($rhs)
85    };
86}