use crate::{Constraint, VarId};
use std::{
fmt::Display,
ops::{Add, AddAssign},
};
#[derive(Clone, Debug)]
pub struct LinTerm {
pub var: VarId,
pub coeff: f64,
}
#[derive(Clone, Debug, Default)]
pub struct LinExpr {
pub terms: Vec<LinTerm>,
pub constant: f64,
}
impl LinExpr {
pub fn new(var: VarId, coeff: f64) -> Self {
Self { terms: vec![LinTerm { var, coeff }], constant: 0.0 }
}
pub fn constant(c: f64) -> Self {
Self { terms: vec![], constant: c }
}
pub fn leq(self, rhs: f64) -> Constraint {
Constraint::leq(self, rhs)
}
pub fn geq(self, rhs: f64) -> Constraint {
Constraint::geq(self, rhs)
}
pub fn eq(self, rhs: f64) -> Constraint {
Constraint::eq(self, rhs)
}
}
impl Display for LinExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut parts = Vec::new();
for term in &self.terms {
parts.push(format!("{}*VarId({})", term.coeff, term.var.0));
}
if self.constant != 0.0 || parts.is_empty() {
parts.push(self.constant.to_string());
}
write!(f, "{}", parts.join(" + "))
}
}
impl Add for LinExpr {
type Output = LinExpr;
fn add(self, rhs: LinExpr) -> LinExpr {
let mut terms = self.terms;
terms.extend(rhs.terms);
LinExpr { terms, constant: self.constant + rhs.constant }
}
}
impl Add<VarId> for LinExpr {
type Output = LinExpr;
fn add(mut self, rhs: VarId) -> LinExpr {
self.terms.push(LinTerm { var: rhs, coeff: 1.0 });
self
}
}
impl Add<LinExpr> for VarId {
type Output = LinExpr;
fn add(self, rhs: LinExpr) -> LinExpr {
let mut terms = vec![LinTerm { var: self, coeff: 1.0 }];
terms.extend(rhs.terms);
LinExpr { terms, constant: rhs.constant }
}
}
impl Add for VarId {
type Output = LinExpr;
fn add(self, rhs: VarId) -> LinExpr {
LinExpr {
terms: vec![
LinTerm { var: self, coeff: 1.0 },
LinTerm { var: rhs, coeff: 1.0 },
],
constant: 0.0,
}
}
}
impl AddAssign for LinExpr {
fn add_assign(&mut self, rhs: LinExpr) {
self.terms.extend(rhs.terms);
self.constant += rhs.constant;
}
}
impl AddAssign<VarId> for LinExpr {
fn add_assign(&mut self, rhs: VarId) {
self.terms.push(LinTerm { var: rhs, coeff: 1.0 });
}
}
impl Add<LinExpr> for f64 {
type Output = LinExpr;
fn add(self, rhs: LinExpr) -> LinExpr {
let mut expr = rhs.clone();
expr.constant += self;
expr
}
}
impl Add<f64> for LinExpr {
type Output = LinExpr;
fn add(mut self, rhs: f64) -> LinExpr {
self.constant += rhs;
self
}
}
impl From<VarId> for LinExpr {
fn from(var: VarId) -> Self {
LinExpr::new(var, 1.0)
}
}