Merge pull request #142 from timothy-king/nlAlgMerge
[cvc5.git] / src / theory / arith / normal_form.h
1 /********************* */
2 /*! \file normal_form.h
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Tim King, Morgan Deters, Dejan Jovanovic
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** \brief [[ Add one-line brief description here ]]
13 **
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
16 **/
17
18 #include "cvc4_private.h"
19
20 #ifndef __CVC4__THEORY__ARITH__NORMAL_FORM_H
21 #define __CVC4__THEORY__ARITH__NORMAL_FORM_H
22
23 #include <algorithm>
24 #include <list>
25
26 #if IS_SORTED_IN_GNUCXX_NAMESPACE
27 # include <ext/algorithm>
28 #endif /* IS_SORTED_IN_GNUCXX_NAMESPACE */
29
30 #include "base/output.h"
31 #include "expr/node.h"
32 #include "expr/node_self_iterator.h"
33 #include "theory/arith/delta_rational.h"
34 #include "util/rational.h"
35
36
37 namespace CVC4 {
38 namespace theory {
39 namespace arith {
40
41 /***********************************************/
42 /***************** Normal Form *****************/
43 /***********************************************/
44 /***********************************************/
45
46 /**
47 * Section 1: Languages
48 * The normal form for arithmetic nodes is defined by the language
49 * accepted by the following BNFs with some guard conditions.
50 * (The guard conditions are in Section 3 for completeness.)
51 *
52 * variable := n
53 * where
54 * n.isVar() or is foreign
55 * n.getType() \in {Integer, Real}
56 *
57 * constant := n
58 * where
59 * n.getKind() == kind::CONST_RATIONAL
60 *
61 * var_list := variable | (* [variable])
62 * where
63 * len [variable] >= 2
64 * isSorted varOrder [variable]
65 *
66 * monomial := constant | var_list | (* constant' var_list')
67 * where
68 * \f$ constant' \not\in {0,1} \f$
69 *
70 * polynomial := monomial' | (+ [monomial])
71 * where
72 * len [monomial] >= 2
73 * isStrictlySorted monoOrder [monomial]
74 * forall (\x -> x != 0) [monomial]
75 *
76 * rational_cmp := (|><| qpolynomial constant)
77 * where
78 * |><| is GEQ, or GT
79 * not (exists constantMonomial (monomialList qpolynomial))
80 * (exists realMonomial (monomialList qpolynomial))
81 * abs(monomialCoefficient (head (monomialList qpolynomial))) == 1
82 *
83 * integer_cmp := (>= zpolynomial constant)
84 * where
85 * not (exists constantMonomial (monomialList zpolynomial))
86 * (forall integerMonomial (monomialList zpolynomial))
87 * the gcd of all numerators of coefficients is 1
88 * the denominator of all coefficients and the constant is 1
89 * the leading coefficient is positive
90 *
91 * rational_eq := (= qvarlist qpolynomial)
92 * where
93 * let allMonomials = (cons qvarlist (monomialList zpolynomial))
94 * let variableMonomials = (drop constantMonomial allMonomials)
95 * isStrictlySorted variableMonomials
96 * exists realMonomial variableMonomials
97 * is not empty qvarlist
98 *
99 * integer_eq := (= zmonomial zpolynomial)
100 * where
101 * let allMonomials = (cons zmonomial (monomialList zpolynomial))
102 * let variableMonomials = (drop constantMonomial allMonomials)
103 * not (constantMonomial zmonomial)
104 * (forall integerMonomial allMonomials)
105 * isStrictlySorted variableMonomials
106 * the gcd of all numerators of coefficients is 1
107 * the denominator of all coefficients and the constant is 1
108 * the coefficient of monomial is positive
109 * the value of the coefficient of monomial is minimal in variableMonomials
110 *
111 * comparison := TRUE | FALSE
112 * | rational_cmp | (not rational_cmp)
113 * | rational_eq | (not rational_eq)
114 * | integer_cmp | (not integer_cmp)
115 * | integer_eq | (not integer_eq)
116 *
117 * Normal Form for terms := polynomial
118 * Normal Form for atoms := comparison
119 */
120
121 /**
122 * Section 2: Helper Classes
123 * The langauges accepted by each of these defintions
124 * roughly corresponds to one of the following helper classes:
125 * Variable
126 * Constant
127 * VarList
128 * Monomial
129 * Polynomial
130 * Comparison
131 *
132 * Each of the classes obeys the following contracts/design decisions:
133 * -Calling isMember(Node node) on a node returns true iff that node is a
134 * a member of the language. Note: isMember is O(n).
135 * -Calling isNormalForm() on a helper class object returns true iff that
136 * helper class currently represents a normal form object.
137 * -If isNormalForm() is false, then this object must have been made
138 * using a mk*() factory function.
139 * -If isNormalForm() is true, calling getNode() on all of these classes
140 * returns a node that would be accepted by the corresponding language.
141 * And if isNormalForm() is false, returns Node::null().
142 * -Each of the classes is immutable.
143 * -Public facing constuctors have a 1-to-1 correspondence with one of
144 * production rules in the above grammar.
145 * -Public facing constuctors are required to fail in debug mode when the
146 * guards of the production rule are not strictly met.
147 * For example: Monomial(Constant(1),VarList(Variable(x))) must fail.
148 * -When a class has a Class parseClass(Node node) function,
149 * if isMember(node) is true, the function is required to return an instance
150 * of the helper class, instance, s.t. instance.getNode() == node.
151 * And if isMember(node) is false, this throws an assertion failure in debug
152 * mode and has undefined behaviour if not in debug mode.
153 * -Only public facing constructors, parseClass(node), and mk*() functions are
154 * considered privileged functions for the helper class.
155 * -Only privileged functions may use private constructors, and access
156 * private data members.
157 * -All non-privileged functions are considered utility functions and
158 * must use a privileged function in order to create an instance of the class.
159 */
160
161 /**
162 * Section 3: Guard Conditions Misc.
163 *
164 *
165 * variable_order x y =
166 * if (meta_kind_variable x) and (meta_kind_variable y)
167 * then node_order x y
168 * else if (meta_kind_variable x)
169 * then false
170 * else if (meta_kind_variable y)
171 * then true
172 * else node_order x y
173 *
174 * var_list_len vl =
175 * match vl with
176 * variable -> 1
177 * | (* [variable]) -> len [variable]
178 *
179 * order res =
180 * match res with
181 * Empty -> (0,Node::null())
182 * | NonEmpty(vl) -> (var_list_len vl, vl)
183 *
184 * var_listOrder a b = tuple_cmp (order a) (order b)
185 *
186 * monomialVarList monomial =
187 * match monomial with
188 * constant -> Empty
189 * | var_list -> NonEmpty(var_list)
190 * | (* constant' var_list') -> NonEmpty(var_list')
191 *
192 * monoOrder m0 m1 = var_listOrder (monomialVarList m0) (monomialVarList m1)
193 *
194 * integerMonomial mono =
195 * forall varHasTypeInteger (monomialVarList mono)
196 *
197 * realMonomial mono = not (integerMonomial mono)
198 *
199 * constantMonomial monomial =
200 * match monomial with
201 * constant -> true
202 * | var_list -> false
203 * | (* constant' var_list') -> false
204 *
205 * monomialCoefficient monomial =
206 * match monomial with
207 * constant -> constant
208 * | var_list -> Constant(1)
209 * | (* constant' var_list') -> constant'
210 *
211 * monomialList polynomial =
212 * match polynomial with
213 * monomial -> monomial::[]
214 * | (+ [monomial]) -> [monomial]
215 */
216
217 /**
218 * A NodeWrapper is a class that is a thinly veiled container of a Node object.
219 */
220 class NodeWrapper {
221 private:
222 Node node;
223 public:
224 NodeWrapper(Node n) : node(n) {}
225 const Node& getNode() const { return node; }
226 };/* class NodeWrapper */
227
228
229 class Variable : public NodeWrapper {
230 public:
231 Variable(Node n) : NodeWrapper(n) {
232 Assert(isMember(getNode()));
233 }
234
235 // TODO: check if it's a theory leaf also
236 static bool isMember(Node n) {
237 Kind k = n.getKind();
238 switch(k){
239 case kind::CONST_RATIONAL:
240 return false;
241 case kind::INTS_DIVISION:
242 case kind::INTS_MODULUS:
243 case kind::DIVISION:
244 case kind::INTS_DIVISION_TOTAL:
245 case kind::INTS_MODULUS_TOTAL:
246 case kind::DIVISION_TOTAL:
247 return isDivMember(n);
248 case kind::ABS:
249 case kind::TO_INTEGER:
250 // Treat to_int as a variable; it is replaced in early preprocessing
251 // by a variable.
252 return true;
253 default:
254 return isLeafMember(n);
255 }
256 }
257
258 static bool isLeafMember(Node n);
259 static bool isDivMember(Node n);
260 bool isDivLike() const{
261 return isDivMember(getNode());
262 }
263
264 bool isNormalForm() { return isMember(getNode()); }
265
266 bool isIntegral() const {
267 return getNode().getType().isInteger();
268 }
269
270 bool isMetaKindVariable() const {
271 return getNode().isVar();
272 }
273
274 bool operator<(const Variable& v) const {
275 VariableNodeCmp cmp;
276 return cmp(this->getNode(), v.getNode());
277 }
278
279 struct VariableNodeCmp {
280 static inline int cmp(Node n, Node m) {
281 if ( n == m ) { return 0; }
282
283 // this is now slightly off of the old variable order.
284
285 bool nIsInteger = n.getType().isInteger();
286 bool mIsInteger = m.getType().isInteger();
287
288 if(nIsInteger == mIsInteger){
289 bool nIsVariable = n.isVar();
290 bool mIsVariable = m.isVar();
291
292 if(nIsVariable == mIsVariable){
293 if(n < m){
294 return -1;
295 }else{
296 Assert( n != m );
297 return 1;
298 }
299 }else{
300 if(nIsVariable){
301 return -1; // nIsVariable => !mIsVariable
302 }else{
303 return 1; // !nIsVariable => mIsVariable
304 }
305 }
306 }else{
307 Assert(nIsInteger != mIsInteger);
308 if(nIsInteger){
309 return 1; // nIsInteger => !mIsInteger
310 }else{
311 return -1; // !nIsInteger => mIsInteger
312 }
313 }
314 }
315
316 bool operator()(Node n, Node m) const {
317 return VariableNodeCmp::cmp(n,m) < 0;
318 }
319 };
320
321 bool operator==(const Variable& v) const { return getNode() == v.getNode();}
322
323 size_t getComplexity() const;
324 };/* class Variable */
325
326
327 class Constant : public NodeWrapper {
328 public:
329 Constant(Node n) : NodeWrapper(n) {
330 Assert(isMember(getNode()));
331 }
332
333 static bool isMember(Node n) {
334 return n.getKind() == kind::CONST_RATIONAL;
335 }
336
337 bool isNormalForm() { return isMember(getNode()); }
338
339 static Constant mkConstant(Node n) {
340 Assert(n.getKind() == kind::CONST_RATIONAL);
341 return Constant(n);
342 }
343
344 static Constant mkConstant(const Rational& rat);
345
346 static Constant mkZero() {
347 return mkConstant(Rational(0));
348 }
349
350 static Constant mkOne() {
351 return mkConstant(Rational(1));
352 }
353
354 const Rational& getValue() const {
355 return getNode().getConst<Rational>();
356 }
357
358 static int absCmp(const Constant& a, const Constant& b);
359 bool isIntegral() const { return getValue().isIntegral(); }
360
361 int sgn() const { return getValue().sgn(); }
362
363 bool isZero() const { return sgn() == 0; }
364 bool isNegative() const { return sgn() < 0; }
365 bool isPositive() const { return sgn() > 0; }
366
367 bool isOne() const { return getValue() == 1; }
368
369 Constant operator*(const Rational& other) const {
370 return mkConstant(getValue() * other);
371 }
372
373 Constant operator*(const Constant& other) const {
374 return mkConstant(getValue() * other.getValue());
375 }
376 Constant operator+(const Constant& other) const {
377 return mkConstant(getValue() + other.getValue());
378 }
379 Constant operator-() const {
380 return mkConstant(-getValue());
381 }
382
383 Constant inverse() const{
384 Assert(!isZero());
385 return mkConstant(getValue().inverse());
386 }
387
388 bool operator<(const Constant& other) const {
389 return getValue() < other.getValue();
390 }
391
392 bool operator==(const Constant& other) const {
393 //Rely on node uniqueness.
394 return getNode() == other.getNode();
395 }
396
397 Constant abs() const {
398 if(isNegative()){
399 return -(*this);
400 }else{
401 return (*this);
402 }
403 }
404
405 uint32_t length() const{
406 Assert(isIntegral());
407 return getValue().getNumerator().length();
408 }
409
410 size_t getComplexity() const;
411
412 };/* class Constant */
413
414
415 template <class GetNodeIterator>
416 inline Node makeNode(Kind k, GetNodeIterator start, GetNodeIterator end) {
417 NodeBuilder<> nb(k);
418
419 while(start != end) {
420 nb << (*start).getNode();
421 ++start;
422 }
423
424 return Node(nb);
425 }/* makeNode<GetNodeIterator>(Kind, iterator, iterator) */
426
427
428 template <class GetNodeIterator, class T>
429 static void copy_range(GetNodeIterator begin, GetNodeIterator end, std::vector<T>& result){
430 while(begin != end){
431 result.push_back(*begin);
432 ++begin;
433 }
434 }
435
436 template <class GetNodeIterator, class T>
437 static void merge_ranges(GetNodeIterator first1,
438 GetNodeIterator last1,
439 GetNodeIterator first2,
440 GetNodeIterator last2,
441 std::vector<T>& result) {
442
443 while(first1 != last1 && first2 != last2){
444 if( (*first1) < (*first2) ){
445 result.push_back(*first1);
446 ++ first1;
447 }else{
448 result.push_back(*first2);
449 ++ first2;
450 }
451 }
452 copy_range(first1, last1, result);
453 copy_range(first2, last2, result);
454 }
455
456 template <class GetNodeIterator, class T, class Cmp>
457 static void merge_ranges(GetNodeIterator first1,
458 GetNodeIterator last1,
459 GetNodeIterator first2,
460 GetNodeIterator last2,
461 std::vector<T>& result,
462 const Cmp& cmp) {
463
464 while(first1 != last1 && first2 != last2){
465 if( cmp(*first1, *first2) ){
466 result.push_back(*first1);
467 ++ first1;
468 }else{
469 result.push_back(*first2);
470 ++ first2;
471 }
472 }
473 copy_range(first1, last1, result);
474 copy_range(first2, last2, result);
475 }
476
477 /**
478 * A VarList is a sorted list of variables representing a product.
479 * If the VarList is empty, it represents an empty product or 1.
480 * If the VarList has size 1, it represents a single variable.
481 *
482 * A non-sorted VarList can never be successfully made in debug mode.
483 */
484 class VarList : public NodeWrapper {
485 private:
486
487 static Node multList(const std::vector<Variable>& list) {
488 Assert(list.size() >= 2);
489
490 return makeNode(kind::NONLINEAR_MULT, list.begin(), list.end());
491 }
492
493 VarList() : NodeWrapper(Node::null()) {}
494
495 VarList(Node n);
496
497 typedef expr::NodeSelfIterator internal_iterator;
498
499 internal_iterator internalBegin() const {
500 if(singleton()){
501 return expr::NodeSelfIterator::self(getNode());
502 }else{
503 return getNode().begin();
504 }
505 }
506
507 internal_iterator internalEnd() const {
508 if(singleton()){
509 return expr::NodeSelfIterator::selfEnd(getNode());
510 }else{
511 return getNode().end();
512 }
513 }
514
515 public:
516
517 class iterator : public std::iterator<std::input_iterator_tag, Variable> {
518 private:
519 internal_iterator d_iter;
520
521 public:
522 explicit iterator(internal_iterator i) : d_iter(i) {}
523
524 inline Variable operator*() {
525 return Variable(*d_iter);
526 }
527
528 bool operator==(const iterator& i) {
529 return d_iter == i.d_iter;
530 }
531
532 bool operator!=(const iterator& i) {
533 return d_iter != i.d_iter;
534 }
535
536 iterator operator++() {
537 ++d_iter;
538 return *this;
539 }
540
541 iterator operator++(int) {
542 return iterator(d_iter++);
543 }
544 };
545
546 iterator begin() const {
547 return iterator(internalBegin());
548 }
549
550 iterator end() const {
551 return iterator(internalEnd());
552 }
553
554 Variable getHead() const {
555 Assert(!empty());
556 return *(begin());
557 }
558
559 VarList(Variable v) : NodeWrapper(v.getNode()) {
560 Assert(isSorted(begin(), end()));
561 }
562
563 VarList(const std::vector<Variable>& l) : NodeWrapper(multList(l)) {
564 Assert(l.size() >= 2);
565 Assert(isSorted(begin(), end()));
566 }
567
568 static bool isMember(Node n);
569
570 bool isNormalForm() const {
571 return !empty();
572 }
573
574 static VarList mkEmptyVarList() {
575 return VarList();
576 }
577
578
579 /** There are no restrictions on the size of l */
580 static VarList mkVarList(const std::vector<Variable>& l) {
581 if(l.size() == 0) {
582 return mkEmptyVarList();
583 } else if(l.size() == 1) {
584 return VarList((*l.begin()).getNode());
585 } else {
586 return VarList(l);
587 }
588 }
589
590 bool empty() const { return getNode().isNull(); }
591 bool singleton() const {
592 return !empty() && getNode().getKind() != kind::NONLINEAR_MULT;
593 }
594
595 int size() const {
596 if(singleton())
597 return 1;
598 else
599 return getNode().getNumChildren();
600 }
601
602 static VarList parseVarList(Node n);
603
604 VarList operator*(const VarList& vl) const;
605
606 int cmp(const VarList& vl) const;
607
608 bool operator<(const VarList& vl) const { return cmp(vl) < 0; }
609
610 bool operator==(const VarList& vl) const { return cmp(vl) == 0; }
611
612 bool isIntegral() const {
613 for(iterator i = begin(), e=end(); i != e; ++i ){
614 Variable var = *i;
615 if(!var.isIntegral()){
616 return false;
617 }
618 }
619 return true;
620 }
621 size_t getComplexity() const;
622
623 private:
624 bool isSorted(iterator start, iterator end);
625
626 };/* class VarList */
627
628
629 /** Constructors have side conditions. Use the static mkMonomial functions instead. */
630 class Monomial : public NodeWrapper {
631 private:
632 Constant constant;
633 VarList varList;
634 Monomial(Node n, const Constant& c, const VarList& vl):
635 NodeWrapper(n), constant(c), varList(vl)
636 {
637 Assert(!c.isZero() || vl.empty() );
638 Assert( c.isZero() || !vl.empty() );
639
640 Assert(!c.isOne() || !multStructured(n));
641 }
642
643 static Node makeMultNode(const Constant& c, const VarList& vl) {
644 Assert(!c.isZero());
645 Assert(!c.isOne());
646 Assert(!vl.empty());
647 return NodeManager::currentNM()->mkNode(kind::MULT, c.getNode(), vl.getNode());
648 }
649
650 static bool multStructured(Node n) {
651 return n.getKind() == kind::MULT &&
652 n[0].getKind() == kind::CONST_RATIONAL &&
653 n.getNumChildren() == 2;
654 }
655
656 Monomial(const Constant& c):
657 NodeWrapper(c.getNode()), constant(c), varList(VarList::mkEmptyVarList())
658 { }
659
660 Monomial(const VarList& vl):
661 NodeWrapper(vl.getNode()), constant(Constant::mkConstant(1)), varList(vl)
662 {
663 Assert( !varList.empty() );
664 }
665
666 Monomial(const Constant& c, const VarList& vl):
667 NodeWrapper(makeMultNode(c,vl)), constant(c), varList(vl)
668 {
669 Assert( !c.isZero() );
670 Assert( !c.isOne() );
671 Assert( !varList.empty() );
672
673 Assert(multStructured(getNode()));
674 }
675 public:
676 static bool isMember(TNode n);
677
678 /** Makes a monomial with no restrictions on c and vl. */
679 static Monomial mkMonomial(const Constant& c, const VarList& vl);
680
681 /** If vl is empty, this make one. */
682 static Monomial mkMonomial(const VarList& vl);
683
684 static Monomial mkMonomial(const Constant& c){
685 return Monomial(c);
686 }
687
688 static Monomial mkMonomial(const Variable& v){
689 return Monomial(VarList(v));
690 }
691
692 static Monomial parseMonomial(Node n);
693
694 static Monomial mkZero() {
695 return Monomial(Constant::mkConstant(0));
696 }
697 static Monomial mkOne() {
698 return Monomial(Constant::mkConstant(1));
699 }
700 const Constant& getConstant() const { return constant; }
701 const VarList& getVarList() const { return varList; }
702
703 bool isConstant() const {
704 return varList.empty();
705 }
706
707 bool isZero() const {
708 return constant.isZero();
709 }
710
711 bool coefficientIsOne() const {
712 return constant.isOne();
713 }
714
715 bool absCoefficientIsOne() const {
716 return coefficientIsOne() || constant.getValue() == -1;
717 }
718
719 bool constantIsPositive() const {
720 return getConstant().isPositive();
721 }
722
723 Monomial operator*(const Rational& q) const;
724 Monomial operator*(const Constant& c) const;
725 Monomial operator*(const Monomial& mono) const;
726
727 Monomial operator-() const{
728 return (*this) * Rational(-1);
729 }
730
731
732 int cmp(const Monomial& mono) const {
733 return getVarList().cmp(mono.getVarList());
734 }
735
736 bool operator<(const Monomial& vl) const {
737 return cmp(vl) < 0;
738 }
739
740 bool operator==(const Monomial& vl) const {
741 return cmp(vl) == 0;
742 }
743
744 static bool isSorted(const std::vector<Monomial>& m) {
745 #if IS_SORTED_IN_GNUCXX_NAMESPACE
746 return __gnu_cxx::is_sorted(m.begin(), m.end());
747 #else /* IS_SORTED_IN_GNUCXX_NAMESPACE */
748 return std::is_sorted(m.begin(), m.end());
749 #endif /* IS_SORTED_IN_GNUCXX_NAMESPACE */
750 }
751
752 static bool isStrictlySorted(const std::vector<Monomial>& m) {
753 return isSorted(m) && std::adjacent_find(m.begin(),m.end()) == m.end();
754 }
755
756 static void sort(std::vector<Monomial>& m);
757 static void combineAdjacentMonomials(std::vector<Monomial>& m);
758
759 /**
760 * The variable product
761 */
762 bool integralVariables() const {
763 return getVarList().isIntegral();
764 }
765
766 /**
767 * The coefficient of the monomial is integral.
768 */
769 bool integralCoefficient() const {
770 return getConstant().isIntegral();
771 }
772
773 /**
774 * A Monomial is an "integral" monomial if the constant is integral.
775 */
776 bool isIntegral() const {
777 return integralCoefficient() && integralVariables();
778 }
779
780 /** Returns true if the VarList is a product of at least 2 Variables.*/
781 bool isNonlinear() const {
782 return getVarList().size() >= 2;
783 }
784
785 /**
786 * Given a sorted list of monomials, this function transforms this
787 * into a strictly sorted list of monomials that does not contain zero.
788 */
789 //static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
790
791 int absCmp(const Monomial& other) const{
792 return getConstant().getValue().absCmp(other.getConstant().getValue());
793 }
794 // bool absLessThan(const Monomial& other) const{
795 // return getConstant().abs() < other.getConstant().abs();
796 // }
797
798 uint32_t coefficientLength() const{
799 return getConstant().length();
800 }
801
802 void print() const;
803 static void printList(const std::vector<Monomial>& list);
804
805 size_t getComplexity() const;
806 };/* class Monomial */
807
808 class SumPair;
809 class Comparison;;
810
811 class Polynomial : public NodeWrapper {
812 private:
813 bool d_singleton;
814
815 Polynomial(TNode n) : NodeWrapper(n), d_singleton(Monomial::isMember(n)) {
816 Assert(isMember(getNode()));
817 }
818
819 static Node makePlusNode(const std::vector<Monomial>& m) {
820 Assert(m.size() >= 2);
821
822 return makeNode(kind::PLUS, m.begin(), m.end());
823 }
824
825 typedef expr::NodeSelfIterator internal_iterator;
826
827 internal_iterator internalBegin() const {
828 if(singleton()){
829 return expr::NodeSelfIterator::self(getNode());
830 }else{
831 return getNode().begin();
832 }
833 }
834
835 internal_iterator internalEnd() const {
836 if(singleton()){
837 return expr::NodeSelfIterator::selfEnd(getNode());
838 }else{
839 return getNode().end();
840 }
841 }
842
843 bool singleton() const { return d_singleton; }
844
845 public:
846 static bool isMember(TNode n);
847
848 class iterator {
849 private:
850 internal_iterator d_iter;
851
852 public:
853 explicit iterator(internal_iterator i) : d_iter(i) {}
854
855 inline Monomial operator*() {
856 return Monomial::parseMonomial(*d_iter);
857 }
858
859 bool operator==(const iterator& i) {
860 return d_iter == i.d_iter;
861 }
862
863 bool operator!=(const iterator& i) {
864 return d_iter != i.d_iter;
865 }
866
867 iterator operator++() {
868 ++d_iter;
869 return *this;
870 }
871
872 iterator operator++(int) {
873 return iterator(d_iter++);
874 }
875 };
876
877 iterator begin() const { return iterator(internalBegin()); }
878 iterator end() const { return iterator(internalEnd()); }
879
880 Polynomial(const Monomial& m):
881 NodeWrapper(m.getNode()), d_singleton(true)
882 {}
883
884 Polynomial(const std::vector<Monomial>& m):
885 NodeWrapper(makePlusNode(m)), d_singleton(false)
886 {
887 Assert( m.size() >= 2);
888 Assert( Monomial::isStrictlySorted(m) );
889 }
890
891 static Polynomial mkPolynomial(const Constant& c){
892 return Polynomial(Monomial::mkMonomial(c));
893 }
894
895 static Polynomial mkPolynomial(const Variable& v){
896 return Polynomial(Monomial::mkMonomial(v));
897 }
898
899 static Polynomial mkPolynomial(const std::vector<Monomial>& m) {
900 if(m.size() == 0) {
901 return Polynomial(Monomial::mkZero());
902 } else if(m.size() == 1) {
903 return Polynomial((*m.begin()));
904 } else {
905 return Polynomial(m);
906 }
907 }
908
909 static Polynomial parsePolynomial(Node n) {
910 return Polynomial(n);
911 }
912
913 static Polynomial mkZero() {
914 return Polynomial(Monomial::mkZero());
915 }
916 static Polynomial mkOne() {
917 return Polynomial(Monomial::mkOne());
918 }
919 bool isZero() const {
920 return singleton() && (getHead().isZero());
921 }
922
923 bool isConstant() const {
924 return singleton() && (getHead().isConstant());
925 }
926
927 bool containsConstant() const {
928 return getHead().isConstant();
929 }
930
931 uint32_t size() const{
932 if(singleton()){
933 return 1;
934 }else{
935 Assert(getNode().getKind() == kind::PLUS);
936 return getNode().getNumChildren();
937 }
938 }
939
940 Monomial getHead() const {
941 return *(begin());
942 }
943
944 Polynomial getTail() const {
945 Assert(! singleton());
946
947 iterator tailStart = begin();
948 ++tailStart;
949 std::vector<Monomial> subrange;
950 copy_range(tailStart, end(), subrange);
951 return mkPolynomial(subrange);
952 }
953
954 Monomial minimumVariableMonomial() const;
955 bool variableMonomialAreStrictlyGreater(const Monomial& m) const;
956
957 void printList() const {
958 if(Debug.isOn("normal-form")){
959 Debug("normal-form") << "start list" << std::endl;
960 for(iterator i = begin(), oend = end(); i != oend; ++i) {
961 const Monomial& m =*i;
962 m.print();
963 }
964 Debug("normal-form") << "end list" << std::endl;
965 }
966 }
967
968 /** A Polynomial is an "integral" polynomial if all of the monomials are integral. */
969 bool allIntegralVariables() const {
970 for(iterator i = begin(), e=end(); i!=e; ++i){
971 if(!(*i).integralVariables()){
972 return false;
973 }
974 }
975 return true;
976 }
977
978 /**
979 * A Polynomial is an "integral" polynomial if all of the monomials are integral
980 * and all of the coefficients are Integral. */
981 bool isIntegral() const {
982 for(iterator i = begin(), e=end(); i!=e; ++i){
983 if(!(*i).isIntegral()){
984 return false;
985 }
986 }
987 return true;
988 }
989
990 static Polynomial sumPolynomials(const std::vector<Polynomial>& polynomials);
991
992 /** Returns true if the polynomial contains a non-linear monomial.*/
993 bool isNonlinear() const;
994
995
996 /**
997 * Selects a minimal monomial in the polynomial by the absolute value of
998 * the coefficient.
999 */
1000 Monomial selectAbsMinimum() const;
1001
1002 /** Returns true if the absolute value of the head coefficient is one. */
1003 bool leadingCoefficientIsAbsOne() const;
1004 bool leadingCoefficientIsPositive() const;
1005 bool denominatorLCMIsOne() const;
1006 bool numeratorGCDIsOne() const;
1007
1008 bool signNormalizedReducedSum() const {
1009 return leadingCoefficientIsPositive() && denominatorLCMIsOne() && numeratorGCDIsOne();
1010 }
1011
1012 /**
1013 * Returns the Least Common Multiple of the denominators of the coefficients
1014 * of the monomials.
1015 */
1016 Integer denominatorLCM() const;
1017
1018 /**
1019 * Returns the GCD of the numerators of the monomials.
1020 * Requires this to be an isIntegral() polynomial.
1021 */
1022 Integer numeratorGCD() const;
1023
1024 /**
1025 * Returns the GCD of the coefficients of the monomials.
1026 * Requires this to be an isIntegral() polynomial.
1027 */
1028 Integer gcd() const;
1029
1030 /** z must divide all of the coefficients of the polynomial. */
1031 Polynomial exactDivide(const Integer& z) const;
1032
1033 Polynomial operator+(const Polynomial& vl) const;
1034 Polynomial operator-(const Polynomial& vl) const;
1035 Polynomial operator-() const{
1036 return (*this) * Rational(-1);
1037 }
1038
1039 Polynomial operator*(const Rational& q) const;
1040 Polynomial operator*(const Constant& c) const;
1041 Polynomial operator*(const Monomial& mono) const;
1042
1043 Polynomial operator*(const Polynomial& poly) const;
1044
1045 /**
1046 * Viewing the integer polynomial as a list [(* coeff_i mono_i)]
1047 * The quotient and remainder of p divided by the non-zero integer z is:
1048 * q := [(* floor(coeff_i/z) mono_i )]
1049 * r := [(* rem(coeff_i/z) mono_i)]
1050 * computeQR(p,z) returns the node (+ q r).
1051 *
1052 * q and r are members of the Polynomial class.
1053 * For example:
1054 * computeQR( p = (+ 5 (* 3 x) (* 8 y)) , z = 2) returns
1055 * (+ (+ 2 x (* 4 y)) (+ 1 x))
1056 */
1057 static Node computeQR(const Polynomial& p, const Integer& z);
1058
1059 /** Returns the coefficient associated with the VarList in the polynomial. */
1060 Constant getCoefficient(const VarList& vl) const;
1061
1062 uint32_t maxLength() const{
1063 iterator i = begin(), e=end();
1064 if( i == e){
1065 return 1;
1066 }else{
1067 uint32_t max = (*i).coefficientLength();
1068 ++i;
1069 for(; i!=e; ++i){
1070 uint32_t curr = (*i).coefficientLength();
1071 if(curr > max){
1072 max = curr;
1073 }
1074 }
1075 return max;
1076 }
1077 }
1078
1079 uint32_t numMonomials() const {
1080 if( getNode().getKind() == kind::PLUS ){
1081 return getNode().getNumChildren();
1082 }else if(isZero()){
1083 return 0;
1084 }else{
1085 return 1;
1086 }
1087 }
1088
1089 const Rational& asConstant() const{
1090 Assert(isConstant());
1091 return getNode().getConst<Rational>();
1092 //return getHead().getConstant().getValue();
1093 }
1094
1095 bool isVarList() const {
1096 if(singleton()){
1097 return VarList::isMember(getNode());
1098 }else{
1099 return false;
1100 }
1101 }
1102
1103 VarList asVarList() const {
1104 Assert(isVarList());
1105 return getHead().getVarList();
1106 }
1107
1108 size_t getComplexity() const;
1109
1110 friend class SumPair;
1111 friend class Comparison;
1112
1113 /** Returns a node that if asserted ensures v is the abs of this polynomial.*/
1114 Node makeAbsCondition(Variable v){
1115 return makeAbsCondition(v, *this);
1116 }
1117
1118 /** Returns a node that if asserted ensures v is the abs of p.*/
1119 static Node makeAbsCondition(Variable v, Polynomial p);
1120
1121 };/* class Polynomial */
1122
1123
1124 /**
1125 * SumPair is a utility class that extends polynomials for use in computations.
1126 * A SumPair is always a combination of (+ p c) where
1127 * c is a constant and p is a polynomial such that p = 0 or !p.containsConstant().
1128 *
1129 * These are a useful utility for representing the equation p = c as (+ p -c) where the pair
1130 * is known to implicitly be equal to 0.
1131 *
1132 * SumPairs do not have unique representations due to the potential for p = 0.
1133 * This makes them inappropriate for normal forms.
1134 */
1135 class SumPair : public NodeWrapper {
1136 private:
1137 static Node toNode(const Polynomial& p, const Constant& c){
1138 return NodeManager::currentNM()->mkNode(kind::PLUS, p.getNode(), c.getNode());
1139 }
1140
1141 SumPair(TNode n) :
1142 NodeWrapper(n)
1143 {
1144 Assert(isNormalForm());
1145 }
1146
1147 public:
1148
1149 SumPair(const Polynomial& p):
1150 NodeWrapper(toNode(p, Constant::mkConstant(0)))
1151 {
1152 Assert(isNormalForm());
1153 }
1154
1155 SumPair(const Polynomial& p, const Constant& c):
1156 NodeWrapper(toNode(p, c))
1157 {
1158 Assert(isNormalForm());
1159 }
1160
1161 static bool isMember(TNode n) {
1162 if(n.getKind() == kind::PLUS && n.getNumChildren() == 2){
1163 if(Constant::isMember(n[1])){
1164 if(Polynomial::isMember(n[0])){
1165 Polynomial p = Polynomial::parsePolynomial(n[0]);
1166 return p.isZero() || (!p.containsConstant());
1167 }else{
1168 return false;
1169 }
1170 }else{
1171 return false;
1172 }
1173 }else{
1174 return false;
1175 }
1176 }
1177
1178 bool isNormalForm() const {
1179 return isMember(getNode());
1180 }
1181
1182 Polynomial getPolynomial() const {
1183 return Polynomial::parsePolynomial(getNode()[0]);
1184 }
1185
1186 Constant getConstant() const {
1187 return Constant::mkConstant((getNode())[1]);
1188 }
1189
1190 SumPair operator+(const SumPair& other) const {
1191 return SumPair(getPolynomial() + other.getPolynomial(),
1192 getConstant() + other.getConstant());
1193 }
1194
1195 SumPair operator*(const Constant& c) const {
1196 return SumPair(getPolynomial() * c, getConstant() * c);
1197 }
1198
1199 SumPair operator-(const SumPair& other) const {
1200 return (*this) + (other * Constant::mkConstant(-1));
1201 }
1202
1203 static SumPair mkSumPair(const Polynomial& p);
1204
1205 static SumPair mkSumPair(const Variable& var){
1206 return SumPair(Polynomial::mkPolynomial(var));
1207 }
1208
1209 static SumPair parseSumPair(TNode n){
1210 return SumPair(n);
1211 }
1212
1213 bool isIntegral() const{
1214 return getConstant().isIntegral() && getPolynomial().isIntegral();
1215 }
1216
1217 bool isConstant() const {
1218 return getPolynomial().isZero();
1219 }
1220
1221 bool isZero() const {
1222 return getConstant().isZero() && isConstant();
1223 }
1224
1225 uint32_t size() const{
1226 return getPolynomial().size();
1227 }
1228
1229 bool isNonlinear() const{
1230 return getPolynomial().isNonlinear();
1231 }
1232
1233 /**
1234 * Returns the greatest common divisor of gcd(getPolynomial()) and getConstant().
1235 * The SumPair must be integral.
1236 */
1237 Integer gcd() const {
1238 Assert(isIntegral());
1239 return (getPolynomial().gcd()).gcd(getConstant().getValue().getNumerator());
1240 }
1241
1242 uint32_t maxLength() const {
1243 Assert(isIntegral());
1244 return std::max(getPolynomial().maxLength(), getConstant().length());
1245 }
1246
1247 static SumPair mkZero() {
1248 return SumPair(Polynomial::mkZero(), Constant::mkConstant(0));
1249 }
1250
1251 static Node computeQR(const SumPair& sp, const Integer& div);
1252
1253 };/* class SumPair */
1254
1255 /* class OrderedPolynomialPair { */
1256 /* private: */
1257 /* Polynomial d_first; */
1258 /* Polynomial d_second; */
1259 /* public: */
1260 /* OrderedPolynomialPair(const Polynomial& f, const Polynomial& s) */
1261 /* : d_first(f), */
1262 /* d_second(s) */
1263 /* {} */
1264
1265 /* /\** Returns the first part of the pair. *\/ */
1266 /* const Polynomial& getFirst() const { */
1267 /* return d_first; */
1268 /* } */
1269
1270 /* /\** Returns the second part of the pair. *\/ */
1271 /* const Polynomial& getSecond() const { */
1272 /* return d_second; */
1273 /* } */
1274
1275 /* OrderedPolynomialPair operator*(const Constant& c) const; */
1276 /* OrderedPolynomialPair operator+(const Polynomial& p) const; */
1277
1278 /* /\** Returns true if both of the polynomials are constant. *\/ */
1279 /* bool isConstant() const; */
1280
1281 /* /\** */
1282 /* * Evaluates an isConstant() ordered pair as if */
1283 /* * (k getFirst() getRight()) */
1284 /* *\/ */
1285 /* bool evaluateConstant(Kind k) const; */
1286
1287 /* /\** */
1288 /* * Returns the Least Common Multiple of the monomials */
1289 /* * on the lefthand side and the constant on the right. */
1290 /* *\/ */
1291 /* Integer denominatorLCM() const; */
1292
1293 /* /\** Constructs a SumPair. *\/ */
1294 /* SumPair toSumPair() const; */
1295
1296
1297 /* OrderedPolynomialPair divideByGCD() const; */
1298 /* OrderedPolynomialPair multiplyConstant(const Constant& c) const; */
1299
1300 /* /\** */
1301 /* * Returns true if all of the variables are integers, */
1302 /* * and the coefficients are integers. */
1303 /* *\/ */
1304 /* bool isIntegral() const; */
1305
1306 /* /\** Returns true if all of the variables are integers. *\/ */
1307 /* bool allIntegralVariables() const { */
1308 /* return getFirst().allIntegralVariables() && getSecond().allIntegralVariables(); */
1309 /* } */
1310 /* }; */
1311
1312 class Comparison : public NodeWrapper {
1313 private:
1314
1315 static Node toNode(Kind k, const Polynomial& l, const Constant& c);
1316 static Node toNode(Kind k, const Polynomial& l, const Polynomial& r);
1317
1318 Comparison(TNode n);
1319
1320 /**
1321 * Creates a node in normal form equivalent to (= l 0).
1322 * All variables in l are integral.
1323 */
1324 static Node mkIntEquality(const Polynomial& l);
1325
1326 /**
1327 * Creates a comparison equivalent to (k l 0).
1328 * k is either GT or GEQ.
1329 * All variables in l are integral.
1330 */
1331 static Node mkIntInequality(Kind k, const Polynomial& l);
1332
1333 /**
1334 * Creates a node equivalent to (= l 0).
1335 * It is not the case that all variables in l are integral.
1336 */
1337 static Node mkRatEquality(const Polynomial& l);
1338
1339 /**
1340 * Creates a comparison equivalent to (k l 0).
1341 * k is either GT or GEQ.
1342 * It is not the case that all variables in l are integral.
1343 */
1344 static Node mkRatInequality(Kind k, const Polynomial& l);
1345
1346 public:
1347
1348 Comparison(bool val) :
1349 NodeWrapper(NodeManager::currentNM()->mkConst(val))
1350 { }
1351
1352 /**
1353 * Given a literal to TheoryArith return a single kind to
1354 * to indicate its underlying structure.
1355 * The function returns the following in each case:
1356 * - (K left right) -> K where is either EQUAL, GT, or GEQ
1357 * - (CONST_BOOLEAN b) -> CONST_BOOLEAN
1358 * - (NOT (EQUAL left right)) -> DISTINCT
1359 * - (NOT (GT left right)) -> LEQ
1360 * - (NOT (GEQ left right)) -> LT
1361 * If none of these match, it returns UNDEFINED_KIND.
1362 */
1363 static Kind comparisonKind(TNode literal);
1364
1365 Kind comparisonKind() const { return comparisonKind(getNode()); }
1366
1367 static Comparison mkComparison(Kind k, const Polynomial& l, const Polynomial& r);
1368
1369 /** Returns true if the comparison is a boolean constant. */
1370 bool isBoolean() const;
1371
1372 /**
1373 * Returns true if the comparison is either a boolean term,
1374 * in integer normal form or mixed normal form.
1375 */
1376 bool isNormalForm() const;
1377
1378 private:
1379 bool isNormalGT() const;
1380 bool isNormalGEQ() const;
1381
1382 bool isNormalLT() const;
1383 bool isNormalLEQ() const;
1384
1385 bool isNormalEquality() const;
1386 bool isNormalDistinct() const;
1387 bool isNormalEqualityOrDisequality() const;
1388
1389 bool allIntegralVariables() const {
1390 return getLeft().allIntegralVariables() && getRight().allIntegralVariables();
1391 }
1392 bool rightIsConstant() const;
1393
1394 public:
1395 Polynomial getLeft() const;
1396 Polynomial getRight() const;
1397
1398 /* /\** Normal form check if at least one variable is real. *\/ */
1399 /* bool isMixedCompareNormalForm() const; */
1400
1401 /* /\** Normal form check if at least one variable is real. *\/ */
1402 /* bool isMixedEqualsNormalForm() const; */
1403
1404 /* /\** Normal form check is all variables are integer.*\/ */
1405 /* bool isIntegerCompareNormalForm() const; */
1406
1407 /* /\** Normal form check is all variables are integer.*\/ */
1408 /* bool isIntegerEqualsNormalForm() const; */
1409
1410
1411 /**
1412 * Returns true if all of the variables are integers, the coefficients are integers,
1413 * and the right hand coefficient is an integer.
1414 */
1415 bool debugIsIntegral() const;
1416
1417 static Comparison parseNormalForm(TNode n);
1418
1419 inline static bool isNormalAtom(TNode n){
1420 Comparison parse = Comparison::parseNormalForm(n);
1421 return parse.isNormalForm();
1422 }
1423
1424 size_t getComplexity() const;
1425
1426 SumPair toSumPair() const;
1427
1428 Polynomial normalizedVariablePart() const;
1429 DeltaRational normalizedDeltaRational() const;
1430
1431 };/* class Comparison */
1432
1433 }/* CVC4::theory::arith namespace */
1434 }/* CVC4::theory namespace */
1435 }/* CVC4 namespace */
1436
1437 #endif /* __CVC4__THEORY__ARITH__NORMAL_FORM_H */