1use std::mem;
2use crate::{Polynomial};
3
4#[derive(Clone,Debug,PartialEq)]
5pub struct Constraint {
6 term: Term
7}
8
9impl Constraint {
10 pub const FALSE: Constraint = Constraint{term: Term::Lit(false)};
11 pub const TRUE: Constraint = Constraint{term: Term::Lit(true)};
12
13 pub fn eq_zero(poly: Polynomial) -> Self {
14 Self{term: Term::Eq(poly).simplify()}
15 }
16 pub fn neq_zero(poly: Polynomial) -> Self {
17 Self{term: Term::Neq(poly).simplify()}
18 }
19 pub fn gt_zero(poly: Polynomial) -> Self {
20 Self{term: Term::Gt(poly).simplify()}
21 }
22 pub fn gteq_zero(poly: Polynomial) -> Self {
23 Self{term: Term::GtEq(poly).simplify()}
24 }
25 pub fn and(mut self, cs: Constraint) -> Self {
26 let term = Term::Conjunct(vec![self.term,cs.term]);
27 Self{term: term.simplify()}
28 }
29 pub fn or(mut self, cs: Constraint) -> Self {
30 let term = Term::Disjunct(vec![self.term,cs.term]);
31 Self{term: term.simplify()}
32 }
33 pub fn not(mut self) -> Self {
34 Self{term:self.term.not().simplify()}
35 }
36 pub fn implies(mut self, rhs: Constraint) -> Self {
37 self.not().or(rhs)
38 }
39 pub fn substitute(&mut self, var: usize, val: &Polynomial) {
40 let mut tmp = Term::Lit(false);
41 self.term.substitute(var,val);
42 mem::swap(&mut tmp,&mut self.term);
43 self.term = tmp.simplify();
44 }
45}
46
47impl From<bool> for Constraint {
48 fn from(b: bool) -> Constraint {
49 Constraint{term: Term::Lit(b)}
50 }
51}
52
53#[derive(Clone,Debug,PartialEq)]
56enum Term {
57 Conjunct(Vec<Term>),
58 Disjunct(Vec<Term>),
59 Eq(Polynomial),
61 Neq(Polynomial),
62 Gt(Polynomial),
63 GtEq(Polynomial),
64 Lit(bool)
65}
66
67impl Term {
68 pub fn substitute(&mut self, var: usize, val: &Polynomial) {
69 match self {
70 Term::Disjunct(cs)|Term::Conjunct(cs) => {
71 for p in cs.iter_mut() {
72 p.substitute(var,val);
73 }
74 }
75 Term::Eq(p)|Term::Neq(p)|Term::Gt(p)|Term::GtEq(p) => {
76 *p = p.substitute(var,val);
77 }
78 Term::Lit(_) => { }
79 }
80 }
81
82 pub fn simplify(mut self) -> Self {
84 match self {
85 Term::Disjunct(cs) => { Term::simplify_or(cs) }
86 Term::Conjunct(cs) => { Term::simplify_and(cs) }
87 Term::Eq(p) => { Term::simplify_eq(p) }
88 Term::Neq(p) => { Term::simplify_neq(p) }
89 Term::Gt(p) => { Term::simplify_gt(p) }
90 Term::GtEq(p) => { Term::simplify_gteq(p) }
91 Term::Lit(b) => self
92 }
93 }
94
95 pub fn not(self) -> Self {
96 match self {
97 Term::Eq(p) => Term::Neq(p),
98 Term::Neq(p) => Term::Eq(p),
99 Term::Gt(p) => Term::GtEq(p.negate()),
100 Term::GtEq(p) => Term::Gt(p.negate()),
101 Term::Disjunct(cs) => Term::Conjunct(Self::negate(cs)),
102 Term::Conjunct(cs) => Term::Disjunct(Self::negate(cs)),
103 Term::Lit(b) => Term::Lit(!b)
104 }
105 }
106
107 fn negate(cs: Vec<Term>) -> Vec<Term> {
108 cs.iter().map(|t| t.clone().not()).collect()
109 }
110
111 fn simplify_and(mut cs: Vec<Term>) -> Term {
112 for i in 0..cs.len() {
113 let ith = cs[i].clone().simplify();
115 if &ith == &Term::Lit(false) {
117 return ith;
119 } else {
120 cs[i] = ith;
121 }
122 }
123 cs.retain(|item| item != &Term::Lit(true));
125 if cs.is_empty() {
128 Term::Lit(true)
129 } else if cs.len() == 1 {
130 cs[0].clone()
132 } else {
133 Term::Conjunct(cs)
134 }
135 }
136
137 fn simplify_or(mut cs: Vec<Term>) -> Term {
138 for i in 0..cs.len() {
139 let ith = cs[i].clone().simplify();
141 if &ith == &Term::Lit(true) {
143 return ith;
145 } else {
146 cs[i] = ith;
147 }
148 }
149 cs.retain(|item| item != &Term::Lit(false));
151 if cs.is_empty() {
154 Term::Lit(false)
155 } else if cs.len() == 1 {
156 cs[0].clone()
158 } else {
159 Term::Disjunct(cs)
160 }
161 }
162
163 fn simplify_eq(p: Polynomial) -> Term {
164 match p.is_zero() {
165 Some(b) => Term::Lit(b),
166 None => Term::Eq(p)
167 }
168 }
169
170 fn simplify_neq(p: Polynomial) -> Term {
171 match p.is_zero() {
172 Some(b) => Term::Lit(!b),
173 None => Term::Neq(p)
174 }
175 }
176
177 fn simplify_gt(p: Polynomial) -> Term {
178 match p.above_zero() {
179 Some(b) => Term::Lit(b),
180 None => Term::Gt(p)
181 }
182 }
183 fn simplify_gteq(p: Polynomial) -> Term {
184 match p.below_zero() {
185 Some(b) => Term::Lit(!b),
186 None => Term::GtEq(p)
187 }
188 }
189}