#![doc = include_str!("../js/mathjax.tag")]
use std::marker::PhantomData;
use crate::domain::{DomainTrait, IntoShapedDomain};
use crate::expr::workstack::WorkStack;
use crate::expr::{ExprTrait, IntoExpr};
use crate::model::{DJCDomainTrait, DJCModelTrait};
pub trait ConjunctionTrait<M> where M : DJCModelTrait
{
fn eval(&mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<usize,String>;
fn dynamic(self) -> Box<dyn ConjunctionTrait<M>> where Self:Sized+'static { Box::new(self) }
}
pub trait DisjunctionTrait<M> where M : DJCModelTrait
{
fn eval(& mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String>;
fn dynamic(self) -> Box<dyn DisjunctionTrait<M>> where Self: Sized+'static { Box::new(self) }
}
pub struct AffineConstraint<const N : usize,E,D,M>
where M : DJCModelTrait,
E : ExprTrait<N>,
D : IntoShapedDomain<N>,
D::Result : DomainTrait<N>+DJCDomainTrait<M>,
{
m : PhantomData<M>,
expr : E,
domain : Option<D>,
}
impl<const N : usize,E,D,M> AffineConstraint<N,E,D,M>
where M : DJCModelTrait,
E : ExprTrait<N>,
D : IntoShapedDomain<N>,
D::Result : DomainTrait<N>+DJCDomainTrait<M>,
{
pub fn new(expr : E, domain : D) -> Self {
AffineConstraint{
m : PhantomData::default(),
expr : expr.into_expr(),
domain : Some(domain),
}
}
}
impl<M> ConjunctionTrait<M> for Box<dyn ConjunctionTrait<M>> where M : DJCModelTrait {
fn dynamic(self) -> Box<dyn ConjunctionTrait<M>> {
self
}
fn eval(&mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<usize,String> {
self.as_mut().eval(domains, rs, ws, xs)
}
}
impl<M> DisjunctionTrait<M> for Box<dyn DisjunctionTrait<M>+'static> where M : DJCModelTrait {
fn eval(&mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String> {
self.as_mut().eval(domains,term_size, rs, ws, xs)
}
fn dynamic(self) -> Box<dyn DisjunctionTrait<M>> {
self
}
}
impl<const N : usize,E,D,M> AffineConstraint<N,E,D,M>
where M : DJCModelTrait,
E : ExprTrait<N>,
D : IntoShapedDomain<N>,
D::Result : DJCDomainTrait<M>
{
pub fn and<C2>(self, other : C2) -> AffineConstraintsAnd<Self,C2,M> where C2 : ConjunctionTrait<M>, Self: Sized {
AffineConstraintsAnd { m : Default::default(), c0: self, c1: other }
}
pub fn or<D2>(self, other : D2) -> DisjunctionOr<Self,D2,M> where D2 : DisjunctionTrait<M> {
DisjunctionOr { m : Default::default(), c0: self, c1: other }
}
}
impl<const N : usize,E,D,M> ConjunctionTrait<M> for AffineConstraint<N,E,D,M>
where M : DJCModelTrait,
E : ExprTrait<N>,
D : IntoShapedDomain<N>,
D::Result : DomainTrait<N>+DJCDomainTrait<M>
{
fn eval(& mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<usize,String>
{
self.expr.eval_finalize(rs,ws,xs).map_err(|e| format!("{:?}",e))?;
let (eshape,_,_,_,_) = rs.peek_expr();
if eshape.len() != N { return Err(format!("Evaluated expression dimension {} does not match domain {}",eshape.len(),N)); }
let mut shape = [0usize;N]; shape.copy_from_slice(eshape);
let dom = self.domain.take().unwrap().try_into_domain(shape)?;
domains.push(Box::new(dom));
Ok(1)
}
}
impl<const N : usize,E,D,M> DisjunctionTrait<M> for AffineConstraint<N,E,D,M>
where M : DJCModelTrait,
E : ExprTrait<N>,
D : IntoShapedDomain<N>,
D::Result : DomainTrait<N>+DJCDomainTrait<M>
{
fn dynamic(self) -> Box<dyn DisjunctionTrait<M>> where Self: Sized+'static {
Box::new(self)
}
fn eval(& mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String>
{
term_size.push(<AffineConstraint<N,E,D,M> as ConjunctionTrait<M>>::eval(self,domains,rs,ws,xs)?);
Ok(())
}
}
impl<C,M> DisjunctionTrait<M> for Vec<C> where C : ConjunctionTrait<M>, M : DJCModelTrait {
fn eval(&mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String> {
for c in self.iter_mut() {
term_size.push(c.eval(domains, rs, ws, xs)?);
}
Ok(())
}
}
pub struct AffineConstraintsAnd<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : ConjunctionTrait<M>
{
m : PhantomData<M>,
c0 : C0,
c1 : C1
}
impl<C0,C1,M> AffineConstraintsAnd<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : ConjunctionTrait<M>
{
pub fn and<C2>(self, other : C2) -> AffineConstraintsAnd<Self,C2,M> where C2 : ConjunctionTrait<M> {
AffineConstraintsAnd { m : Default::default(), c0: self, c1: other }
}
pub fn or<D2>(self, other : D2) -> DisjunctionOr<Self,D2,M> where D2 : DisjunctionTrait<M> {
DisjunctionOr { m : Default::default(), c0: self, c1: other }
}
}
impl<C0,C1,M> ConjunctionTrait<M> for AffineConstraintsAnd<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : ConjunctionTrait<M>
{
fn eval(&mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<usize,String>
{
Ok(self.c0.eval(domains,rs,ws,xs)? + self.c1.eval(domains,rs,ws,xs)?)
}
}
impl<C0,C1,M> DisjunctionTrait<M> for AffineConstraintsAnd<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : ConjunctionTrait<M>
{
fn dynamic(self) -> Box<dyn DisjunctionTrait<M>> where Self: Sized+'static {
Box::new(self)
}
fn eval(& mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String>
{
term_size.push(<Self as ConjunctionTrait<M>>::eval(self,domains, rs, ws, xs)?);
Ok(())
}
}
pub struct DisjunctionOr<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : DisjunctionTrait<M>
{
m : PhantomData<M>,
c0 : C0,
c1 : C1
}
impl<C0,C1,M> DisjunctionOr<C0,C1,M>
where
M : DJCModelTrait,
C0 : ConjunctionTrait<M>,
C1 : DisjunctionTrait<M>
{
pub fn or<C2>(self, other : C2) -> DisjunctionOr<C2,Self,M> where C2 : ConjunctionTrait<M> {
DisjunctionOr { m : Default::default(), c0: other, c1: self }
}
}
impl<C0,C1,M> DisjunctionTrait<M> for DisjunctionOr<C0,C1,M>
where
C0 : ConjunctionTrait<M>,
C1 : DisjunctionTrait<M>,
M : DJCModelTrait
{
fn eval(& mut self,
domains : & mut Vec<Box<dyn DJCDomainTrait<M>+'static>>,
term_size : & mut Vec<usize>,
rs : &mut WorkStack,
ws : &mut WorkStack,
xs : &mut WorkStack) -> Result<(),String> {
term_size.push(self.c0.eval(domains, rs, ws, xs)?);
self.c1.eval(domains,term_size, rs, ws, xs)
}
}