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/theory.h"
29 #include "theory/arith/arith_constants.h"
30 #include "theory/arith/arith_utilities.h"
34 #include <ext/algorithm>
40 /***********************************************/
41 /***************** Normal Form *****************/
42 /***********************************************/
43 /***********************************************/
46 * Section 1: Languages
47 * The normal form for arithmetic nodes is defined by the language
48 * accepted by the following BNFs with some guard conditions.
49 * (The guard conditions are in Section 3 for completeness.)
53 * n.getMetaKind() == metakind::VARIABLE
57 * n.getKind() == kind::CONST_RATIONAL
59 * var_list := variable | (* [variable])
62 * isSorted varOrder [variable]
64 * monomial := constant | var_list | (* constant' var_list')
66 * constant' \not\in {0,1}
68 * polynomial := monomial' | (+ [monomial])
71 * isStrictlySorted monoOrder [monomial]
72 * forall (\x -> x != 0) [monomial]
74 * restricted_cmp := (|><| polynomial constant)
76 * |><| is GEQ, EQ, or EQ
77 * not (exists constantMonomial (monomialList polynomial))
78 * monomialCoefficient (head (monomialList polynomial)) == 1
80 * comparison := TRUE | FALSE | restricted_cmp | (not restricted_cmp)
82 * Normal Form for terms := polynomial
83 * Normal Form for atoms := comparison
87 * Section 2: Helper Classes
88 * The langauges accepted by each of these defintions
89 * roughly corresponds to one of the following helper classes:
97 * Each of the classes obeys the following contracts/design decisions:
98 * -Calling isMember(Node node) on a node returns true iff that node is a
99 * a member of the language. Note: isMember is O(n).
100 * -Calling isNormalForm() on a helper class object returns true iff that
101 * helper class currently represents a normal form object.
102 * -If isNormalForm() is false, then this object must have been made
103 * using a mk*() factory function.
104 * -If isNormalForm() is true, calling getNode() on all of these classes
105 * returns a node that would be accepted by the corresponding language.
106 * And if isNormalForm() is false, returns Node::null().
107 * -Each of the classes is immutable.
108 * -Public facing constuctors have a 1-to-1 correspondence with one of
109 * production rules in the above grammar.
110 * -Public facing constuctors are required to fail in debug mode when the
111 * guards of the production rule are not strictly met.
112 * For example: Monomial(Constant(1),VarList(Variable(x))) must fail.
113 * -When a class has a Class parseClass(Node node) function,
114 * if isMember(node) is true, the function is required to return an instance
115 * of the helper class, instance, s.t. instance.getNode() == node.
116 * And if isMember(node) is false, this throws an assertion failure in debug
117 * mode and has undefined behaviour if not in debug mode.
118 * -Only public facing constructors, parseClass(node), and mk*() functions are
119 * considered privileged functions for the helper class.
120 * -Only privileged functions may use private constructors, and access
121 * private data members.
122 * -All non-privileged functions are considered utility functions and
123 * must use a privileged function in order to create an instance of the class.
127 * Section 3: Guard Conditions Misc.
133 * | (* [variable]) -> len [variable]
137 * Empty -> (0,Node::null())
138 * | NonEmpty(vl) -> (var_list_len vl, vl)
140 * var_listOrder a b = tuple_cmp (order a) (order b)
142 * monomialVarList monomial =
143 * match monomial with
145 * | var_list -> NonEmpty(var_list)
146 * | (* constant' var_list') -> NonEmpty(var_list')
148 * monoOrder m0 m1 = var_listOrder (monomialVarList m0) (monomialVarList m1)
150 * constantMonomial monomial =
151 * match monomial with
153 * | var_list -> false
154 * | (* constant' var_list') -> false
156 * monomialCoefficient monomial =
157 * match monomial with
158 * constant -> constant
159 * | var_list -> Constant(1)
160 * | (* constant' var_list') -> constant'
162 * monomialList polynomial =
163 * match polynomial with
164 * monomial -> monomial::[]
165 * | (+ [monomial]) -> [monomial]
170 * A NodeWrapper is a class that is a thinly veiled container of a Node object.
176 NodeWrapper(Node n
) : node(n
) {}
177 const Node
& getNode() const { return node
; }
178 };/* class NodeWrapper */
181 class Variable
: public NodeWrapper
{
183 Variable(Node n
) : NodeWrapper(n
) {
184 Assert(isMember(getNode()));
187 // TODO: check if it's a theory leaf also
188 static bool isMember(Node n
) {
189 if (n
.getKind() == kind::CONST_INTEGER
) return false;
190 if (n
.getKind() == kind::CONST_RATIONAL
) return false;
191 return Theory::isLeafOf(n
, theory::THEORY_ARITH
);
194 bool isNormalForm() { return isMember(getNode()); }
196 bool operator<(const Variable
& v
) const { return getNode() < v
.getNode();}
197 bool operator==(const Variable
& v
) const { return getNode() == v
.getNode();}
199 };/* class Variable */
202 class Constant
: public NodeWrapper
{
204 Constant(Node n
) : NodeWrapper(n
) {
205 Assert(isMember(getNode()));
208 static bool isMember(Node n
) {
209 return n
.getKind() == kind::CONST_RATIONAL
;
212 bool isNormalForm() { return isMember(getNode()); }
214 static Constant
mkConstant(Node n
) {
215 return Constant(coerceToRationalNode(n
));
218 static Constant
mkConstant(const Rational
& rat
) {
219 return Constant(mkRationalNode(rat
));
222 const Rational
& getValue() const {
223 return getNode().getConst
<Rational
>();
226 bool isZero() const { return getValue() == 0; }
227 bool isOne() const { return getValue() == 1; }
229 Constant
operator*(const Constant
& other
) const {
230 return mkConstant(getValue() * other
.getValue());
232 Constant
operator+(const Constant
& other
) const {
233 return mkConstant(getValue() + other
.getValue());
235 Constant
operator-() const {
236 return mkConstant(-getValue());
239 };/* class Constant */
242 template <class GetNodeIterator
>
243 inline Node
makeNode(Kind k
, GetNodeIterator start
, GetNodeIterator end
) {
246 while(start
!= end
) {
247 nb
<< (*start
).getNode();
252 }/* makeNode<GetNodeIterator>(Kind, iterator, iterator) */
255 template <class GetNodeIterator
, class T
>
256 static void copy_range(GetNodeIterator begin
, GetNodeIterator end
, std::vector
<T
>& result
){
258 result
.push_back(*begin
);
263 template <class GetNodeIterator
, class T
>
264 static void merge_ranges(GetNodeIterator first1
,
265 GetNodeIterator last1
,
266 GetNodeIterator first2
,
267 GetNodeIterator last2
,
268 std::vector
<T
>& result
) {
270 while(first1
!= last1
&& first2
!= last2
){
271 if( (*first1
) < (*first2
) ){
272 result
.push_back(*first1
);
275 result
.push_back(*first2
);
279 copy_range(first1
, last1
, result
);
280 copy_range(first2
, last2
, result
);
284 * A VarList is a sorted list of variables representing a product.
285 * If the VarList is empty, it represents an empty product or 1.
286 * If the VarList has size 1, it represents a single variable.
288 * A non-sorted VarList can never be successfully made in debug mode.
290 class VarList
: public NodeWrapper
{
293 static Node
multList(const std::vector
<Variable
>& list
) {
294 Assert(list
.size() >= 2);
296 return makeNode(kind::MULT
, list
.begin(), list
.end());
299 VarList() : NodeWrapper(Node::null()) {}
301 VarList(Node n
) : NodeWrapper(n
) {
302 Assert(isSorted(begin(), end()));
305 typedef expr::NodeSelfIterator internal_iterator
;
307 internal_iterator
internalBegin() const {
309 return expr::NodeSelfIterator::self(getNode());
311 return getNode().begin();
315 internal_iterator
internalEnd() const {
317 return expr::NodeSelfIterator::selfEnd(getNode());
319 return getNode().end();
327 internal_iterator d_iter
;
330 explicit iterator(internal_iterator i
) : d_iter(i
) {}
332 inline Variable
operator*() {
333 return Variable(*d_iter
);
336 bool operator==(const iterator
& i
) {
337 return d_iter
== i
.d_iter
;
340 bool operator!=(const iterator
& i
) {
341 return d_iter
!= i
.d_iter
;
344 iterator
operator++() {
349 iterator
operator++(int) {
350 return iterator(d_iter
++);
354 iterator
begin() const {
355 return iterator(internalBegin());
358 iterator
end() const {
359 return iterator(internalEnd());
362 VarList(Variable v
) : NodeWrapper(v
.getNode()) {
363 Assert(isSorted(begin(), end()));
366 VarList(const std::vector
<Variable
>& l
) : NodeWrapper(multList(l
)) {
367 Assert(l
.size() >= 2);
368 Assert(isSorted(begin(), end()));
371 static bool isMember(Node n
);
373 bool isNormalForm() const {
377 static VarList
mkEmptyVarList() {
382 /** There are no restrictions on the size of l */
383 static VarList
mkVarList(const std::vector
<Variable
>& l
) {
385 return mkEmptyVarList();
386 } else if(l
.size() == 1) {
387 return VarList((*l
.begin()).getNode());
393 bool empty() const { return getNode().isNull(); }
394 bool singleton() const {
395 return !empty() && getNode().getKind() != kind::MULT
;
402 return getNode().getNumChildren();
405 static VarList
parseVarList(Node n
);
407 VarList
operator*(const VarList
& vl
) const;
409 int cmp(const VarList
& vl
) const;
411 bool operator<(const VarList
& vl
) const { return cmp(vl
) < 0; }
413 bool operator==(const VarList
& vl
) const { return cmp(vl
) == 0; }
416 bool isSorted(iterator start
, iterator end
);
418 };/* class VarList */
421 class Monomial
: public NodeWrapper
{
425 Monomial(Node n
, const Constant
& c
, const VarList
& vl
):
426 NodeWrapper(n
), constant(c
), varList(vl
)
428 Assert(!c
.isZero() || vl
.empty() );
429 Assert( c
.isZero() || !vl
.empty() );
431 Assert(!c
.isOne() || !multStructured(n
));
434 static Node
makeMultNode(const Constant
& c
, const VarList
& vl
) {
438 return NodeManager::currentNM()->mkNode(kind::MULT
, c
.getNode(), vl
.getNode());
441 static bool multStructured(Node n
) {
442 return n
.getKind() == kind::MULT
&&
443 n
[0].getKind() == kind::CONST_RATIONAL
&&
444 n
.getNumChildren() == 2;
449 Monomial(const Constant
& c
):
450 NodeWrapper(c
.getNode()), constant(c
), varList(VarList::mkEmptyVarList())
453 Monomial(const VarList
& vl
):
454 NodeWrapper(vl
.getNode()), constant(Constant::mkConstant(1)), varList(vl
)
456 Assert( !varList
.empty() );
459 Monomial(const Constant
& c
, const VarList
& vl
):
460 NodeWrapper(makeMultNode(c
,vl
)), constant(c
), varList(vl
)
462 Assert( !c
.isZero() );
463 Assert( !c
.isOne() );
464 Assert( !varList
.empty() );
466 Assert(multStructured(getNode()));
469 static bool isMember(TNode n
);
471 /** Makes a monomial with no restrictions on c and vl. */
472 static Monomial
mkMonomial(const Constant
& c
, const VarList
& vl
);
475 static Monomial
parseMonomial(Node n
);
477 static Monomial
mkZero() {
478 return Monomial(Constant::mkConstant(0));
480 static Monomial
mkOne() {
481 return Monomial(Constant::mkConstant(1));
483 const Constant
& getConstant() const { return constant
; }
484 const VarList
& getVarList() const { return varList
; }
486 bool isConstant() const {
487 return varList
.empty();
490 bool isZero() const {
491 return constant
.isZero();
494 bool coefficientIsOne() const {
495 return constant
.isOne();
498 Monomial
operator*(const Monomial
& mono
) const;
501 int cmp(const Monomial
& mono
) const {
502 return getVarList().cmp(mono
.getVarList());
505 bool operator<(const Monomial
& vl
) const {
509 bool operator==(const Monomial
& vl
) const {
513 static bool isSorted(const std::vector
<Monomial
>& m
) {
514 return __gnu_cxx::is_sorted(m
.begin(), m
.end());
517 static bool isStrictlySorted(const std::vector
<Monomial
>& m
) {
518 return isSorted(m
) && std::adjacent_find(m
.begin(),m
.end()) == m
.end();
522 * Given a sorted list of monomials, this function transforms this
523 * into a strictly sorted list of monomials that does not contain zero.
525 static std::vector
<Monomial
> sumLikeTerms(const std::vector
<Monomial
>& monos
);
528 static void printList(const std::vector
<Monomial
>& list
);
530 };/* class Monomial */
533 class Polynomial
: public NodeWrapper
{
537 Polynomial(TNode n
) : NodeWrapper(n
), d_singleton(Monomial::isMember(n
)) {
538 Assert(isMember(getNode()));
541 static Node
makePlusNode(const std::vector
<Monomial
>& m
) {
542 Assert(m
.size() >= 2);
544 return makeNode(kind::PLUS
, m
.begin(), m
.end());
547 typedef expr::NodeSelfIterator internal_iterator
;
549 internal_iterator
internalBegin() const {
551 return expr::NodeSelfIterator::self(getNode());
553 return getNode().begin();
557 internal_iterator
internalEnd() const {
559 return expr::NodeSelfIterator::selfEnd(getNode());
561 return getNode().end();
565 bool singleton() const { return d_singleton
; }
568 static bool isMember(TNode n
) {
569 if(Monomial::isMember(n
)){
571 }else if(n
.getKind() == kind::PLUS
){
572 Assert(n
.getNumChildren() >= 2);
573 for(Node::iterator curr
= n
.begin(), end
= n
.end(); curr
!= end
;++curr
){
574 if(!Monomial::isMember(*curr
)){
586 internal_iterator d_iter
;
589 explicit iterator(internal_iterator i
) : d_iter(i
) {}
591 inline Monomial
operator*() {
592 return Monomial::parseMonomial(*d_iter
);
595 bool operator==(const iterator
& i
) {
596 return d_iter
== i
.d_iter
;
599 bool operator!=(const iterator
& i
) {
600 return d_iter
!= i
.d_iter
;
603 iterator
operator++() {
608 iterator
operator++(int) {
609 return iterator(d_iter
++);
613 iterator
begin() const { return iterator(internalBegin()); }
614 iterator
end() const { return iterator(internalEnd()); }
616 Polynomial(const Monomial
& m
):
617 NodeWrapper(m
.getNode()), d_singleton(true)
620 Polynomial(const std::vector
<Monomial
>& m
):
621 NodeWrapper(makePlusNode(m
)), d_singleton(false)
623 Assert( m
.size() >= 2);
624 Assert( Monomial::isStrictlySorted(m
) );
628 static Polynomial
mkPolynomial(const std::vector
<Monomial
>& m
) {
630 return Polynomial(Monomial::mkZero());
631 } else if(m
.size() == 1) {
632 return Polynomial((*m
.begin()));
634 return Polynomial(m
);
638 static Polynomial
parsePolynomial(Node n
) {
639 return Polynomial(n
);
642 static Polynomial
mkZero() {
643 return Polynomial(Monomial::mkZero());
645 static Polynomial
mkOne() {
646 return Polynomial(Monomial::mkOne());
648 bool isZero() const {
649 return singleton() && (getHead().isZero());
652 bool isConstant() const {
653 return singleton() && (getHead().isConstant());
656 bool containsConstant() const {
657 return getHead().isConstant();
660 Monomial
getHead() const {
664 Polynomial
getTail() const {
665 Assert(! singleton());
667 iterator tailStart
= begin();
669 std::vector
<Monomial
> subrange
;
670 copy_range(tailStart
, end(), subrange
);
671 return mkPolynomial(subrange
);
674 void printList() const {
675 if(Debug
.isOn("normal-form")){
676 Debug("normal-form") << "start list" << std::endl
;
677 for(iterator i
= begin(), oend
= end(); i
!= oend
; ++i
) {
678 const Monomial
& m
=*i
;
681 Debug("normal-form") << "end list" << std::endl
;
685 Polynomial
operator+(const Polynomial
& vl
) const;
687 Polynomial
operator*(const Monomial
& mono
) const;
689 Polynomial
operator*(const Polynomial
& poly
) const;
691 };/* class Polynomial */
694 class Comparison
: public NodeWrapper
{
700 static Node
toNode(Kind k
, const Polynomial
& l
, const Constant
& r
);
702 Comparison(TNode n
, Kind k
, const Polynomial
& l
, const Constant
& r
):
703 NodeWrapper(n
), oper(k
), left(l
), right(r
)
706 Comparison(bool val
) :
707 NodeWrapper(NodeManager::currentNM()->mkConst(val
)),
708 oper(kind::CONST_BOOLEAN
),
709 left(Polynomial::mkZero()),
710 right(Constant::mkConstant(0))
713 Comparison(Kind k
, const Polynomial
& l
, const Constant
& r
):
714 NodeWrapper(toNode(k
, l
, r
)), oper(k
), left(l
), right(r
)
716 Assert(isRelationOperator(oper
));
717 Assert(!left
.containsConstant());
718 Assert(left
.getHead().getConstant().isOne());
721 static Comparison
mkComparison(Kind k
, const Polynomial
& left
, const Constant
& right
);
723 bool isBoolean() const {
724 return (oper
== kind::CONST_BOOLEAN
);
727 bool isNormalForm() const {
730 } else if(left
.containsConstant()) {
732 } else if(left
.getHead().getConstant().isOne()) {
739 const Polynomial
& getLeft() const { return left
; }
740 const Constant
& getRight() const { return right
; }
742 Comparison
addConstant(const Constant
& constant
) const;
743 Comparison
multiplyConstant(const Constant
& constant
) const;
745 static Comparison
parseNormalForm(TNode n
);
747 inline static bool isNormalAtom(TNode n
){
748 Comparison parse
= Comparison::parseNormalForm(n
);
749 return parse
.isNormalForm();
752 };/* class Comparison */
754 }/* CVC4::theory::arith namespace */
755 }/* CVC4::theory namespace */
756 }/* CVC4 namespace */
758 #endif /* __CVC4__THEORY__ARITH__NORMAL_FORM_H */