1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! This module contains the structs passed to the [`Model::add_constr(s)`](crate::Model::add_constr) and [`Model::add_range(s)`](crate::Model::add_constr) methods.
//!
//! The structs themselves are usually constructed using the [`c!(...)`](crate::c) macro.
use crate::expr::{AttachModel, Attached, LinExpr, QuadExpr};
use crate::prelude::*;
use crate::Result;
use std::fmt;
/// A inequality constraint (linear or quadratic).  Creating this object does not automatically add the constraint to a model.
/// Instead, it should be passed to [`Model::add_constr`](crate::Model::add_constr) or [`Model::add_constrs`](crate::Model::add_constrs).
///
/// Usually created with an invocation of [`c!`]`(...)`.
#[derive(Debug, Clone)]
pub struct IneqExpr {
    /// Left-hand side
    pub lhs: Expr,
    /// Direction of the inequality, or if it the constraint is an equality
    pub sense: ConstrSense,
    /// Right-hand side
    pub rhs: Expr,
}

impl IneqExpr {
    pub(crate) fn into_normalised_linear(self) -> Result<(LinExpr, ConstrSense, f64)> {
        let IneqExpr { lhs, rhs, sense } = self;
        let mut lhs: LinExpr = (lhs - rhs).into_linexpr()?;
        let rhs = -lhs.set_offset(0.0);
        Ok((lhs, sense, rhs))
    }

    pub(crate) fn into_normalised_quad(self) -> (QuadExpr, ConstrSense, f64) {
        let IneqExpr { lhs, rhs, sense } = self;
        let mut lhs = (lhs - rhs).into_quadexpr();
        let rhs = -lhs.set_offset(0.0);
        (lhs, sense, rhs)
    }
}

impl AttachModel for IneqExpr {}

impl fmt::Debug for Attached<'_, IneqExpr> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let cmp = match self.inner.sense {
            ConstrSense::Less => "≤",
            ConstrSense::Greater => "≥",
            ConstrSense::Equal => "=",
        };
        f.write_fmt(format_args!(
            "{:?} {} {:?}",
            self.inner.lhs.attach(self.model),
            cmp,
            self.inner.rhs.attach(self.model)
        ))
    }
}

/// A linear range constraint expression.  Creating this object does not automatically add the constraint to a model.
/// Instead, it should be passed to [`Model::add_range`](crate::Model::add_range) or [`Model::add_ranges`](crate::Model::add_ranges).
///
/// Usually created with an invocation of `c!(...)`.
/// Note that `expr` must be linear.
#[derive(Debug, Clone)]
pub struct RangeExpr {
    /// The linear expression of variables to constrain
    pub expr: Expr,
    /// The maximum value of the expression
    pub ub: f64,
    /// The minimum value of the expression
    pub lb: f64,
}

impl RangeExpr {
    pub(crate) fn into_normalised(self) -> Result<(LinExpr, f64, f64)> {
        let RangeExpr {
            expr,
            mut ub,
            mut lb,
        } = self;
        let mut expr = expr.into_linexpr()?;
        let offset = expr.set_offset(0.0);
        ub -= offset;
        lb -= offset;
        Ok((expr, lb, ub))
    }
}

impl AttachModel for RangeExpr {}

impl fmt::Debug for Attached<'_, RangeExpr> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!(
            "{:?} ∈ [{}, {}]",
            self.inner.expr.attach(self.model),
            self.inner.lb,
            self.inner.ub
        ))
    }
}

// TODO: support for general PWL constraints