use crate::expression::Expression;
use crate::variable::{FormatWithVars, Variable};
use core::fmt::{Debug, Formatter};
use std::ops::{Shl, Shr, Sub};
#[derive(Clone)]
pub struct Constraint {
pub(crate) expression: Expression,
pub(crate) is_equality: bool,
pub(crate) name: Option<String>,
}
impl Constraint {
fn new(expression: Expression, is_equality: bool) -> Constraint {
Constraint {
expression,
is_equality,
name: None,
}
}
pub fn set_name(mut self, name: String) -> Self {
self.name = Some(name);
self
}
pub fn expression(&self) -> &Expression {
&self.expression
}
pub fn is_equality(&self) -> bool {
self.is_equality
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
}
impl FormatWithVars for Constraint {
fn format_with<FUN>(&self, f: &mut Formatter<'_>, variable_format: FUN) -> std::fmt::Result
where
FUN: FnMut(&mut Formatter<'_>, Variable) -> std::fmt::Result,
{
self.expression.linear.format_with(f, variable_format)?;
write!(f, " {} ", if self.is_equality { "=" } else { "<=" })?;
write!(f, "{}", -self.expression.constant)
}
}
impl Debug for Constraint {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.format_debug(f)
}
}
pub fn eq<B, A: Sub<B, Output = Expression>>(a: A, b: B) -> Constraint {
Constraint::new(a - b, true)
}
pub fn leq<B, A: Sub<B, Output = Expression>>(a: A, b: B) -> Constraint {
Constraint::new(a - b, false)
}
pub fn geq<A, B: Sub<A, Output = Expression>>(a: A, b: B) -> Constraint {
leq(b, a)
}
macro_rules! impl_shifts {
($($t:ty)*) => {$(
impl< RHS> Shl<RHS> for $t where Self: Sub<RHS, Output=Expression> {
type Output = Constraint;
fn shl(self, rhs: RHS) -> Self::Output {
leq(self, rhs)
}
}
impl< RHS: Sub<Self, Output=Expression>> Shr<RHS> for $t {
type Output = Constraint;
fn shr(self, rhs: RHS) -> Self::Output {
geq(self, rhs)
}
}
)*}
}
impl_shifts!(Expression Variable);
#[macro_export]
macro_rules! constraint {
([$($left:tt)*] <= $($right:tt)*) => {
$crate::constraint::leq($($left)*, $($right)*)
};
([$($left:tt)*] >= $($right:tt)*) => {
$crate::constraint::geq($($left)*, $($right)*)
};
([$($left:tt)*] == $($right:tt)*) => {
$crate::constraint::eq($($left)*, $($right)*)
};
([$($left:tt)*]) => {
$($left:tt)*
};
([$($left:tt)*] $next:tt $($right:tt)*) => {
constraint!([$($left)* $next] $($right)*)
};
($($all:tt)*) => {
constraint!([] $($all)*)
};
}
#[derive(Clone, PartialEq, Debug)]
pub struct ConstraintReference {
pub(crate) index: usize,
}
#[cfg(test)]
mod tests {
use crate::variables;
#[test]
fn test_leq() {
let mut vars = variables!();
let v0 = vars.add_variable();
let v1 = vars.add_variable();
let f = format!("{:?}", (3. - v0) >> v1);
assert!(["v0 + v1 <= 3", "v1 + v0 <= 3"].contains(&&*f), "{}", f)
}
}