use crate::{common::expression::LinearExpr, modeling::variable::VariableKey};
use slotmap::{new_key_type, DenseSlotMap};
use std::fmt;
new_key_type! {
pub struct ConstraintKey;
}
impl fmt::Display for ConstraintKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ConstraintKey({:?})", self.0)
}
}
#[derive(Debug, Clone, Copy)]
pub enum ConstraintSense {
LessEqual,
GreaterEqual,
Equal,
}
#[derive(Debug, Clone)]
pub struct Constraint {
name: Option<String>,
lhs: LinearExpr<VariableKey>,
sense: ConstraintSense,
rhs: LinearExpr<VariableKey>,
}
impl Constraint {
pub fn name(&self) -> &str {
self.name.as_deref().unwrap_or("<unnamed>")
}
pub fn lhs(&self) -> &LinearExpr<VariableKey> {
&self.lhs
}
pub fn rhs(&self) -> &LinearExpr<VariableKey> {
&self.rhs
}
pub fn sense(&self) -> ConstraintSense {
self.sense
}
}
impl fmt::Display for Constraint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sense_str = match self.sense {
ConstraintSense::LessEqual => "<=",
ConstraintSense::GreaterEqual => ">=",
ConstraintSense::Equal => "=",
};
write!(
f,
"Constraint({}: {} {} {})",
self.name(),
self.lhs,
sense_str,
self.rhs
)
}
}
pub struct ConstraintBuilder<'a> {
arena: &'a mut DenseSlotMap<ConstraintKey, Constraint>,
lhs: LinearExpr<VariableKey>,
name: Option<String>,
}
impl<'a> ConstraintBuilder<'a> {
pub(crate) fn new(
arena: &'a mut DenseSlotMap<ConstraintKey, Constraint>,
lhs: LinearExpr<VariableKey>,
) -> Self {
Self {
arena,
lhs,
name: None,
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn less_than_or_equal(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.finish(ConstraintSense::LessEqual, rhs.into())
}
pub fn le(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.less_than_or_equal(rhs)
}
pub fn greater_than_or_equal(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.finish(ConstraintSense::GreaterEqual, rhs.into())
}
pub fn ge(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.greater_than_or_equal(rhs)
}
pub fn equal_to(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.finish(ConstraintSense::Equal, rhs.into())
}
pub fn eq(self, rhs: impl Into<LinearExpr<VariableKey>>) -> ConstraintKey {
self.equal_to(rhs)
}
fn finish(self, sense: ConstraintSense, rhs: LinearExpr<VariableKey>) -> ConstraintKey {
let data = Constraint {
name: self.name,
lhs: self.lhs,
sense,
rhs,
};
self.arena.insert(data)
}
}