1 /********************* */
2 /*! \file normal_form.h
4 ** Original author: taking
5 ** Major contributors: mdeters
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
9 ** Courant Institute of Mathematical Sciences
10 ** New York University
11 ** See the file COPYING in the top-level source directory for licensing
12 ** information.\endverbatim
14 ** \brief [[ Add one-line brief description here ]]
16 ** [[ Add lengthier description here ]]
17 ** \todo document this file
20 #include "cvc4_private.h"
22 #ifndef __CVC4__THEORY__ARITH__NORMAL_FORM_H
23 #define __CVC4__THEORY__ARITH__NORMAL_FORM_H
25 #include "expr/node.h"
26 #include "expr/node_self_iterator.h"
27 #include "util/rational.h"
28 #include "theory/arith/arith_constants.h"
29 #include "theory/arith/arith_utilities.h"
33 #include <ext/algorithm>
39 /***********************************************/
40 /***************** Normal Form *****************/
41 /***********************************************/
42 /***********************************************/
45 * Section 1: Languages
46 * The normal form for arithmetic nodes is defined by the language
47 * accepted by the following BNFs with some guard conditions.
48 * (The guard conditions are in Section 3 for completeness.)
52 * n.getMetaKind() == metakind::VARIABLE
56 * n.getKind() == kind::CONST_RATIONAL
58 * var_list := variable | (* [variable])
61 * isSorted varOrder [variable]
63 * monomial := constant | var_list | (* constant' var_list')
65 * constant' \not\in {0,1}
67 * polynomial := monomial' | (+ [monomial])
70 * isStrictlySorted monoOrder [monomial]
71 * forall (\x -> x != 0) [monomial]
73 * restricted_cmp := (|><| polynomial constant)
75 * |><| is GEQ, EQ, or EQ
76 * not (exists constantMonomial (monomialList polynomial))
77 * monomialCoefficient (head (monomialList polynomial)) == 1
79 * comparison := TRUE | FALSE | restricted_cmp | (not restricted_cmp)
81 * Normal Form for terms := polynomial
82 * Normal Form for atoms := comparison
86 * Section 2: Helper Classes
87 * The langauges accepted by each of these defintions
88 * roughly corresponds to one of the following helper classes:
96 * Each of the classes obeys the following contracts/design decisions:
97 * -Calling isMember(Node node) on a node returns true iff that node is a
98 * a member of the language. Note: isMember is O(n).
99 * -Calling isNormalForm() on a helper class object returns true iff that
100 * helper class currently represents a normal form object.
101 * -If isNormalForm() is false, then this object must have been made
102 * using a mk*() factory function.
103 * -If isNormalForm() is true, calling getNode() on all of these classes
104 * returns a node that would be accepted by the corresponding language.
105 * And if isNormalForm() is false, returns Node::null().
106 * -Each of the classes is immutable.
107 * -Public facing constuctors have a 1-to-1 correspondence with one of
108 * production rules in the above grammar.
109 * -Public facing constuctors are required to fail in debug mode when the
110 * guards of the production rule are not strictly met.
111 * For example: Monomial(Constant(1),VarList(Variable(x))) must fail.
112 * -When a class has a Class parseClass(Node node) function,
113 * if isMember(node) is true, the function is required to return an instance
114 * of the helper class, instance, s.t. instance.getNode() == node.
115 * And if isMember(node) is false, this throws an assertion failure in debug
116 * mode and has undefined behaviour if not in debug mode.
117 * -Only public facing constructors, parseClass(node), and mk*() functions are
118 * considered privileged functions for the helper class.
119 * -Only privileged functions may use private constructors, and access
120 * private data members.
121 * -All non-privileged functions are considered utility functions and
122 * must use a privileged function in order to create an instance of the class.
126 * Section 3: Guard Conditions Misc.
132 * | (* [variable]) -> len [variable]
136 * Empty -> (0,Node::null())
137 * | NonEmpty(vl) -> (var_list_len vl, vl)
139 * var_listOrder a b = tuple_cmp (order a) (order b)
141 * monomialVarList monomial =
142 * match monomial with
144 * | var_list -> NonEmpty(var_list)
145 * | (* constant' var_list') -> NonEmpty(var_list')
147 * monoOrder m0 m1 = var_listOrder (monomialVarList m0) (monomialVarList m1)
149 * constantMonomial monomial =
150 * match monomial with
152 * | var_list -> false
153 * | (* constant' var_list') -> false
155 * monomialCoefficient monomial =
156 * match monomial with
157 * constant -> constant
158 * | var_list -> Constant(1)
159 * | (* constant' var_list') -> constant'
161 * monomialList polynomial =
162 * match polynomial with
163 * monomial -> monomial::[]
164 * | (+ [monomial]) -> [monomial]
169 * A NodeWrapper is a class that is a thinly veiled container of a Node object.
175 NodeWrapper(Node n
) : node(n
) {}
176 const Node
& getNode() const { return node
; }
177 };/* class NodeWrapper */
180 class Variable
: public NodeWrapper
{
182 Variable(Node n
) : NodeWrapper(n
) {
183 Assert(isMember(getNode()));
186 static bool isMember(Node n
) {
187 return n
.getMetaKind() == kind::metakind::VARIABLE
;
190 bool isNormalForm() { return isMember(getNode()); }
192 bool operator<(const Variable
& v
) const { return getNode() < v
.getNode();}
193 bool operator==(const Variable
& v
) const { return getNode() == v
.getNode();}
195 };/* class Variable */
198 class Constant
: public NodeWrapper
{
200 Constant(Node n
) : NodeWrapper(n
) {
201 Assert(isMember(getNode()));
204 static bool isMember(Node n
) {
205 return n
.getKind() == kind::CONST_RATIONAL
;
208 bool isNormalForm() { return isMember(getNode()); }
210 static Constant
mkConstant(Node n
) {
211 return Constant(coerceToRationalNode(n
));
214 static Constant
mkConstant(const Rational
& rat
) {
215 return Constant(mkRationalNode(rat
));
218 const Rational
& getValue() const {
219 return getNode().getConst
<Rational
>();
222 bool isZero() const { return getValue() == 0; }
223 bool isOne() const { return getValue() == 1; }
225 Constant
operator*(const Constant
& other
) const {
226 return mkConstant(getValue() * other
.getValue());
228 Constant
operator+(const Constant
& other
) const {
229 return mkConstant(getValue() + other
.getValue());
231 Constant
operator-() const {
232 return mkConstant(-getValue());
235 };/* class Constant */
238 template <class GetNodeIterator
>
239 inline Node
makeNode(Kind k
, GetNodeIterator start
, GetNodeIterator end
) {
242 while(start
!= end
) {
243 nb
<< (*start
).getNode();
248 }/* makeNode<GetNodeIterator>(Kind, iterator, iterator) */
251 template <class GetNodeIterator
, class T
>
252 static void copy_range(GetNodeIterator begin
, GetNodeIterator end
, std::vector
<T
>& result
){
254 result
.push_back(*begin
);
259 template <class GetNodeIterator
, class T
>
260 static void merge_ranges(GetNodeIterator first1
,
261 GetNodeIterator last1
,
262 GetNodeIterator first2
,
263 GetNodeIterator last2
,
264 std::vector
<T
>& result
) {
266 while(first1
!= last1
&& first2
!= last2
){
267 if( (*first1
) < (*first2
) ){
268 result
.push_back(*first1
);
271 result
.push_back(*first2
);
275 copy_range(first1
, last1
, result
);
276 copy_range(first2
, last2
, result
);
280 * A VarList is a sorted list of variables representing a product.
281 * If the VarList is empty, it represents an empty product or 1.
282 * If the VarList has size 1, it represents a single variable.
284 * A non-sorted VarList can never be successfully made in debug mode.
286 class VarList
: public NodeWrapper
{
289 static Node
multList(const std::vector
<Variable
>& list
) {
290 Assert(list
.size() >= 2);
292 return makeNode(kind::MULT
, list
.begin(), list
.end());
295 VarList() : NodeWrapper(Node::null()) {}
297 VarList(Node n
) : NodeWrapper(n
) {
298 Assert(isSorted(begin(), end()));
301 typedef expr::NodeSelfIterator internal_iterator
;
303 internal_iterator
internalBegin() const {
305 return expr::NodeSelfIterator::self(getNode());
307 return getNode().begin();
311 internal_iterator
internalEnd() const {
313 return expr::NodeSelfIterator::selfEnd(getNode());
315 return getNode().end();
323 internal_iterator d_iter
;
326 explicit iterator(internal_iterator i
) : d_iter(i
) {}
328 inline Variable
operator*() {
329 return Variable(*d_iter
);
332 bool operator==(const iterator
& i
) {
333 return d_iter
== i
.d_iter
;
336 bool operator!=(const iterator
& i
) {
337 return d_iter
!= i
.d_iter
;
340 iterator
operator++() {
345 iterator
operator++(int) {
346 return iterator(d_iter
++);
350 iterator
begin() const {
351 return iterator(internalBegin());
354 iterator
end() const {
355 return iterator(internalEnd());
358 VarList(Variable v
) : NodeWrapper(v
.getNode()) {
359 Assert(isSorted(begin(), end()));
362 VarList(const std::vector
<Variable
>& l
) : NodeWrapper(multList(l
)) {
363 Assert(l
.size() >= 2);
364 Assert(isSorted(begin(), end()));
367 static bool isMember(Node n
);
369 bool isNormalForm() const {
373 static VarList
mkEmptyVarList() {
378 /** There are no restrictions on the size of l */
379 static VarList
mkVarList(const std::vector
<Variable
>& l
) {
381 return mkEmptyVarList();
382 } else if(l
.size() == 1) {
383 return VarList((*l
.begin()).getNode());
389 bool empty() const { return getNode().isNull(); }
390 bool singleton() const {
391 return !empty() && getNode().getKind() != kind::MULT
;
398 return getNode().getNumChildren();
401 static VarList
parseVarList(Node n
);
403 VarList
operator*(const VarList
& vl
) const;
405 int cmp(const VarList
& vl
) const;
407 bool operator<(const VarList
& vl
) const { return cmp(vl
) < 0; }
409 bool operator==(const VarList
& vl
) const { return cmp(vl
) == 0; }
412 bool isSorted(iterator start
, iterator end
);
414 };/* class VarList */
417 class Monomial
: public NodeWrapper
{
421 Monomial(Node n
, const Constant
& c
, const VarList
& vl
):
422 NodeWrapper(n
), constant(c
), varList(vl
)
424 Assert(!c
.isZero() || vl
.empty() );
425 Assert( c
.isZero() || !vl
.empty() );
427 Assert(!c
.isOne() || !multStructured(n
));
430 static Node
makeMultNode(const Constant
& c
, const VarList
& vl
) {
434 return NodeManager::currentNM()->mkNode(kind::MULT
, c
.getNode(), vl
.getNode());
437 static bool multStructured(Node n
) {
438 return n
.getKind() == kind::MULT
&&
439 n
[0].getKind() == kind::CONST_RATIONAL
&&
440 n
.getNumChildren() == 2;
445 Monomial(const Constant
& c
):
446 NodeWrapper(c
.getNode()), constant(c
), varList(VarList::mkEmptyVarList())
449 Monomial(const VarList
& vl
):
450 NodeWrapper(vl
.getNode()), constant(Constant::mkConstant(1)), varList(vl
)
452 Assert( !varList
.empty() );
455 Monomial(const Constant
& c
, const VarList
& vl
):
456 NodeWrapper(makeMultNode(c
,vl
)), constant(c
), varList(vl
)
458 Assert( !c
.isZero() );
459 Assert( !c
.isOne() );
460 Assert( !varList
.empty() );
462 Assert(multStructured(getNode()));
465 static bool isMember(TNode n
);
467 /** Makes a monomial with no restrictions on c and vl. */
468 static Monomial
mkMonomial(const Constant
& c
, const VarList
& vl
);
471 static Monomial
parseMonomial(Node n
);
473 static Monomial
mkZero() {
474 return Monomial(Constant::mkConstant(0));
476 static Monomial
mkOne() {
477 return Monomial(Constant::mkConstant(1));
479 const Constant
& getConstant() const { return constant
; }
480 const VarList
& getVarList() const { return varList
; }
482 bool isConstant() const {
483 return varList
.empty();
486 bool isZero() const {
487 return constant
.isZero();
490 bool coefficientIsOne() const {
491 return constant
.isOne();
494 Monomial
operator*(const Monomial
& mono
) const;
497 int cmp(const Monomial
& mono
) const {
498 return getVarList().cmp(mono
.getVarList());
501 bool operator<(const Monomial
& vl
) const {
505 bool operator==(const Monomial
& vl
) const {
509 static bool isSorted(const std::vector
<Monomial
>& m
) {
510 return __gnu_cxx::is_sorted(m
.begin(), m
.end());
513 static bool isStrictlySorted(const std::vector
<Monomial
>& m
) {
514 return isSorted(m
) && std::adjacent_find(m
.begin(),m
.end()) == m
.end();
518 * Given a sorted list of monomials, this function transforms this
519 * into a strictly sorted list of monomials that does not contain zero.
521 static std::vector
<Monomial
> sumLikeTerms(const std::vector
<Monomial
>& monos
);
524 static void printList(const std::vector
<Monomial
>& list
);
526 };/* class Monomial */
529 class Polynomial
: public NodeWrapper
{
533 Polynomial(TNode n
) : NodeWrapper(n
), d_singleton(Monomial::isMember(n
)) {
534 Assert(isMember(getNode()));
537 static Node
makePlusNode(const std::vector
<Monomial
>& m
) {
538 Assert(m
.size() >= 2);
540 return makeNode(kind::PLUS
, m
.begin(), m
.end());
543 typedef expr::NodeSelfIterator internal_iterator
;
545 internal_iterator
internalBegin() const {
547 return expr::NodeSelfIterator::self(getNode());
549 return getNode().begin();
553 internal_iterator
internalEnd() const {
555 return expr::NodeSelfIterator::selfEnd(getNode());
557 return getNode().end();
561 bool singleton() const { return d_singleton
; }
564 static bool isMember(TNode n
) {
565 if(Monomial::isMember(n
)){
567 }else if(n
.getKind() == kind::PLUS
){
568 Assert(n
.getNumChildren() >= 2);
569 for(Node::iterator curr
= n
.begin(), end
= n
.end(); curr
!= end
;++curr
){
570 if(!Monomial::isMember(*curr
)){
582 internal_iterator d_iter
;
585 explicit iterator(internal_iterator i
) : d_iter(i
) {}
587 inline Monomial
operator*() {
588 return Monomial::parseMonomial(*d_iter
);
591 bool operator==(const iterator
& i
) {
592 return d_iter
== i
.d_iter
;
595 bool operator!=(const iterator
& i
) {
596 return d_iter
!= i
.d_iter
;
599 iterator
operator++() {
604 iterator
operator++(int) {
605 return iterator(d_iter
++);
609 iterator
begin() const { return iterator(internalBegin()); }
610 iterator
end() const { return iterator(internalEnd()); }
612 Polynomial(const Monomial
& m
):
613 NodeWrapper(m
.getNode()), d_singleton(true)
616 Polynomial(const std::vector
<Monomial
>& m
):
617 NodeWrapper(makePlusNode(m
)), d_singleton(false)
619 Assert( m
.size() >= 2);
620 Assert( Monomial::isStrictlySorted(m
) );
624 static Polynomial
mkPolynomial(const std::vector
<Monomial
>& m
) {
626 return Polynomial(Monomial::mkZero());
627 } else if(m
.size() == 1) {
628 return Polynomial((*m
.begin()));
630 return Polynomial(m
);
634 static Polynomial
parsePolynomial(Node n
) {
635 return Polynomial(n
);
638 static Polynomial
mkZero() {
639 return Polynomial(Monomial::mkZero());
641 static Polynomial
mkOne() {
642 return Polynomial(Monomial::mkOne());
644 bool isZero() const {
645 return singleton() && (getHead().isZero());
648 bool isConstant() const {
649 return singleton() && (getHead().isConstant());
652 bool containsConstant() const {
653 return getHead().isConstant();
656 Monomial
getHead() const {
660 Polynomial
getTail() const {
661 Assert(! singleton());
663 iterator tailStart
= begin();
665 std::vector
<Monomial
> subrange
;
666 copy_range(tailStart
, end(), subrange
);
667 return mkPolynomial(subrange
);
670 void printList() const {
671 if(Debug
.isOn("normal-form")){
672 Debug("normal-form") << "start list" << std::endl
;
673 for(iterator i
= begin(), oend
= end(); i
!= oend
; ++i
) {
674 const Monomial
& m
=*i
;
677 Debug("normal-form") << "end list" << std::endl
;
681 Polynomial
operator+(const Polynomial
& vl
) const;
683 Polynomial
operator*(const Monomial
& mono
) const;
685 Polynomial
operator*(const Polynomial
& poly
) const;
687 };/* class Polynomial */
690 class Comparison
: public NodeWrapper
{
696 static Node
toNode(Kind k
, const Polynomial
& l
, const Constant
& r
);
698 Comparison(TNode n
, Kind k
, const Polynomial
& l
, const Constant
& r
):
699 NodeWrapper(n
), oper(k
), left(l
), right(r
)
702 Comparison(bool val
) :
703 NodeWrapper(NodeManager::currentNM()->mkConst(val
)),
704 oper(kind::CONST_BOOLEAN
),
705 left(Polynomial::mkZero()),
706 right(Constant::mkConstant(0))
709 Comparison(Kind k
, const Polynomial
& l
, const Constant
& r
):
710 NodeWrapper(toNode(k
, l
, r
)), oper(k
), left(l
), right(r
)
712 Assert(isRelationOperator(oper
));
713 Assert(!left
.containsConstant());
714 Assert(left
.getHead().getConstant().isOne());
717 static Comparison
mkComparison(Kind k
, const Polynomial
& left
, const Constant
& right
);
719 bool isBoolean() const {
720 return (oper
== kind::CONST_BOOLEAN
);
723 bool isNormalForm() const {
726 } else if(left
.containsConstant()) {
728 } else if(left
.getHead().getConstant().isOne()) {
735 const Polynomial
& getLeft() const { return left
; }
736 const Constant
& getRight() const { return right
; }
738 Comparison
addConstant(const Constant
& constant
) const;
739 Comparison
multiplyConstant(const Constant
& constant
) const;
741 static Comparison
parseNormalForm(TNode n
);
743 };/* class Comparison */
745 }/* CVC4::theory::arith namespace */
746 }/* CVC4::theory namespace */
747 }/* CVC4 namespace */
749 #endif /* __CVC4__THEORY__ARITH__NORMAL_FORM_H */