use std::collections::HashMap;
use std::ops::{Add, Mul, Neg, Sub};
use super::constraint::{Constraint, ConstraintSense};
use super::variable::Variable;
#[derive(Debug, Clone, Default)]
pub struct Expression {
pub(crate) coefficients: HashMap<Variable, f64>,
pub(crate) constant: f64,
}
impl Expression {
pub fn from_constant(c: f64) -> Self {
Expression {
coefficients: HashMap::new(),
constant: c,
}
}
pub(crate) fn coefficient(&self, var: Variable) -> f64 {
self.coefficients.get(&var).copied().unwrap_or(0.0)
}
fn merge_add(&mut self, rhs: Expression) {
for (var, coeff) in rhs.coefficients {
*self.coefficients.entry(var).or_insert(0.0) += coeff;
}
self.constant += rhs.constant;
}
fn constraint(self, rhs: impl Into<Expression>, sense: ConstraintSense) -> Constraint {
let mut lhs = self;
let mut rhs_expr = rhs.into();
for (var, coeff) in rhs_expr.coefficients.drain() {
*lhs.coefficients.entry(var).or_insert(0.0) -= coeff;
}
let rhs_val = rhs_expr.constant - lhs.constant;
lhs.constant = 0.0;
Constraint { lhs, rhs: rhs_val, sense }
}
pub fn leq(self, rhs: impl Into<Expression>) -> Constraint {
self.constraint(rhs, ConstraintSense::Le)
}
pub fn geq(self, rhs: impl Into<Expression>) -> Constraint {
self.constraint(rhs, ConstraintSense::Ge)
}
pub fn eq_constraint(self, rhs: impl Into<Expression>) -> Constraint {
self.constraint(rhs, ConstraintSense::Eq)
}
}
impl From<Variable> for Expression {
fn from(var: Variable) -> Self {
let mut coefficients = HashMap::new();
coefficients.insert(var, 1.0);
Expression {
coefficients,
constant: 0.0,
}
}
}
impl From<f64> for Expression {
fn from(c: f64) -> Self {
Expression::from_constant(c)
}
}
impl From<i32> for Expression {
fn from(c: i32) -> Self {
Expression::from_constant(c as f64)
}
}
impl Neg for Expression {
type Output = Expression;
fn neg(mut self) -> Expression {
for coeff in self.coefficients.values_mut() {
*coeff = -*coeff;
}
self.constant = -self.constant;
self
}
}
impl Neg for Variable {
type Output = Expression;
fn neg(self) -> Expression {
-Expression::from(self)
}
}
impl Add for Expression {
type Output = Expression;
fn add(mut self, rhs: Expression) -> Expression {
self.merge_add(rhs);
self
}
}
impl Sub for Expression {
type Output = Expression;
fn sub(self, rhs: Expression) -> Expression {
self + (-rhs)
}
}
impl Mul<Expression> for f64 {
type Output = Expression;
fn mul(self, mut rhs: Expression) -> Expression {
for coeff in rhs.coefficients.values_mut() {
*coeff *= self;
}
rhs.constant *= self;
rhs
}
}
impl Mul<f64> for Expression {
type Output = Expression;
fn mul(self, rhs: f64) -> Expression {
rhs * self
}
}
impl Mul<Variable> for f64 {
type Output = Expression;
fn mul(self, rhs: Variable) -> Expression {
let mut coefficients = HashMap::new();
coefficients.insert(rhs, self);
Expression {
coefficients,
constant: 0.0,
}
}
}
impl Mul<f64> for Variable {
type Output = Expression;
fn mul(self, rhs: f64) -> Expression {
rhs * self
}
}
impl Add<Variable> for Variable {
type Output = Expression;
fn add(self, rhs: Variable) -> Expression {
Expression::from(self) + Expression::from(rhs)
}
}
impl Sub<Variable> for Variable {
type Output = Expression;
fn sub(self, rhs: Variable) -> Expression {
Expression::from(self) - Expression::from(rhs)
}
}
impl Add<Expression> for Variable {
type Output = Expression;
fn add(self, rhs: Expression) -> Expression {
Expression::from(self) + rhs
}
}
impl Add<Variable> for Expression {
type Output = Expression;
fn add(mut self, rhs: Variable) -> Expression {
*self.coefficients.entry(rhs).or_insert(0.0) += 1.0;
self
}
}
impl Sub<Expression> for Variable {
type Output = Expression;
fn sub(self, rhs: Expression) -> Expression {
Expression::from(self) - rhs
}
}
impl Sub<Variable> for Expression {
type Output = Expression;
fn sub(mut self, rhs: Variable) -> Expression {
*self.coefficients.entry(rhs).or_insert(0.0) -= 1.0;
self
}
}
impl Add<f64> for Expression {
type Output = Expression;
fn add(mut self, rhs: f64) -> Expression {
self.constant += rhs;
self
}
}
impl Add<Expression> for f64 {
type Output = Expression;
fn add(self, mut rhs: Expression) -> Expression {
rhs.constant += self;
rhs
}
}
impl Sub<f64> for Expression {
type Output = Expression;
fn sub(mut self, rhs: f64) -> Expression {
self.constant -= rhs;
self
}
}
impl Sub<Expression> for f64 {
type Output = Expression;
fn sub(self, rhs: Expression) -> Expression {
self + (-rhs)
}
}
impl Add<f64> for Variable {
type Output = Expression;
fn add(self, rhs: f64) -> Expression {
Expression::from(self) + rhs
}
}
impl Add<Variable> for f64 {
type Output = Expression;
fn add(self, rhs: Variable) -> Expression {
self + Expression::from(rhs)
}
}
impl Sub<f64> for Variable {
type Output = Expression;
fn sub(self, rhs: f64) -> Expression {
Expression::from(self) - rhs
}
}
impl Sub<Variable> for f64 {
type Output = Expression;
fn sub(self, rhs: Variable) -> Expression {
self - Expression::from(rhs)
}
}