Refactor arithmetic pre-rewriter for multiplication (#7930)
[cvc5.git] / src / theory / arith / normal_form.h
index 29db6cdb971940d06410bbc922d76b517bc5248d..577bd052d0372d93f9e6eb75fac0a98a685f261c 100644 (file)
@@ -1,39 +1,35 @@
-/*********************                                                        */
-/*! \file normal_form.h
- ** \verbatim
- ** Original author: taking
- ** Major contributors: mdeters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__ARITH__NORMAL_FORM_H
-#define __CVC4__THEORY__ARITH__NORMAL_FORM_H
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Tim King, Morgan Deters, Gereon Kremer
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * [[ Add one-line brief description here ]]
+ *
+ * [[ Add lengthier description here ]]
+ * \todo document this file
+ */
+
+#include "cvc5_private.h"
 
+#ifndef CVC5__THEORY__ARITH__NORMAL_FORM_H
+#define CVC5__THEORY__ARITH__NORMAL_FORM_H
+
+#include <algorithm>
+
+#include "base/output.h"
 #include "expr/node.h"
 #include "expr/node_self_iterator.h"
+#include "theory/arith/delta_rational.h"
 #include "util/rational.h"
-#include "theory/theory.h"
-#include "theory/arith/arith_constants.h"
-#include "theory/arith/arith_utilities.h"
-
-#include <list>
-#include <algorithm>
-#include <ext/algorithm>
 
-namespace CVC4 {
+namespace cvc5 {
 namespace theory {
 namespace arith {
 
@@ -50,7 +46,8 @@ namespace arith {
  *
  * variable := n
  *   where
- *     n.getMetaKind() == metakind::VARIABLE
+ *     n.isVar() or is foreign
+ *     n.getType() \in {Integer, Real}
  *
  * constant := n
  *   where
@@ -63,7 +60,7 @@ namespace arith {
  *
  * monomial := constant | var_list | (* constant' var_list')
  *   where
- *     constant' \not\in {0,1}
+ *     \f$ constant' \not\in {0,1} \f$
  *
  * polynomial := monomial' | (+ [monomial])
  *   where
@@ -71,13 +68,46 @@ namespace arith {
  *     isStrictlySorted monoOrder [monomial]
  *     forall (\x -> x != 0) [monomial]
  *
- * restricted_cmp := (|><| polynomial constant)
+ * rational_cmp := (|><| qpolynomial constant)
  *   where
- *     |><| is GEQ, EQ, or EQ
- *     not (exists constantMonomial (monomialList polynomial))
- *     monomialCoefficient (head (monomialList polynomial)) == 1
+ *     |><| is GEQ, or GT
+ *     not (exists constantMonomial (monomialList qpolynomial))
+ *     (exists realMonomial (monomialList qpolynomial))
+ *     abs(monomialCoefficient (head (monomialList qpolynomial))) == 1
  *
- * comparison := TRUE | FALSE | restricted_cmp | (not restricted_cmp)
+ * integer_cmp := (>= zpolynomial constant)
+ *   where
+ *     not (exists constantMonomial (monomialList zpolynomial))
+ *     (forall integerMonomial (monomialList zpolynomial))
+ *     the gcd of all numerators of coefficients is 1
+ *     the denominator of all coefficients and the constant is 1
+ *     the leading coefficient is positive
+ *
+ * rational_eq := (= qvarlist qpolynomial)
+ *   where
+ *     let allMonomials = (cons qvarlist (monomialList zpolynomial))
+ *     let variableMonomials = (drop constantMonomial allMonomials)
+ *     isStrictlySorted variableMonomials
+ *     exists realMonomial variableMonomials
+ *     is not empty qvarlist
+ *
+ * integer_eq := (= zmonomial zpolynomial)
+ *   where
+ *     let allMonomials = (cons zmonomial (monomialList zpolynomial))
+ *     let variableMonomials = (drop constantMonomial allMonomials)
+ *     not (constantMonomial zmonomial)
+ *     (forall integerMonomial allMonomials)
+ *     isStrictlySorted variableMonomials
+ *     the gcd of all numerators of coefficients is 1
+ *     the denominator of all coefficients and the constant is 1
+ *     the coefficient of monomial is positive
+ *     the value of the coefficient of monomial is minimal in variableMonomials
+ *
+ * comparison := TRUE | FALSE
+ *   | rational_cmp | (not rational_cmp)
+ *   | rational_eq | (not rational_eq)
+ *   | integer_cmp | (not integer_cmp)
+ *   | integer_eq | (not integer_eq)
  *
  * Normal Form for terms := polynomial
  * Normal Form for atoms := comparison
@@ -127,6 +157,15 @@ namespace arith {
  * Section 3: Guard Conditions Misc.
  *
  *
+ *  variable_order x y =
+ *    if (meta_kind_variable x) and (meta_kind_variable y)
+ *    then node_order x y
+ *    else if (meta_kind_variable x)
+ *    then false
+ *    else if (meta_kind_variable y)
+ *    then true
+ *    else node_order x y
+ *
  *  var_list_len vl =
  *    match vl with
  *       variable -> 1
@@ -147,6 +186,11 @@ namespace arith {
  *
  *  monoOrder m0 m1 = var_listOrder (monomialVarList m0) (monomialVarList m1)
  *
+ *  integerMonomial mono =
+ *    forall varHasTypeInteger (monomialVarList mono)
+ *
+ *  realMonomial mono = not (integerMonomial mono)
+ *
  *  constantMonomial monomial =
  *    match monomial with
  *        constant -> true
@@ -165,7 +209,6 @@ namespace arith {
  *      | (+ [monomial]) -> [monomial]
  */
 
-
 /**
  * A NodeWrapper is a class that is a thinly veiled container of a Node object.
  */
@@ -180,52 +223,161 @@ public:
 
 class Variable : public NodeWrapper {
 public:
-  Variable(Node n) : NodeWrapper(n) {
-    Assert(isMember(getNode()));
+ Variable(Node n) : NodeWrapper(n) { Assert(isMember(getNode())); }
+
+ // TODO: check if it's a theory leaf also
+ static bool isMember(Node n)
+ {
+   Kind k = n.getKind();
+   switch (k)
+   {
+     case kind::CONST_RATIONAL: return false;
+     case kind::INTS_DIVISION:
+     case kind::INTS_MODULUS:
+     case kind::DIVISION:
+     case kind::INTS_DIVISION_TOTAL:
+     case kind::INTS_MODULUS_TOTAL:
+     case kind::DIVISION_TOTAL: return isDivMember(n);
+     case kind::IAND: return isIAndMember(n);
+     case kind::POW2: return isPow2Member(n);
+     case kind::EXPONENTIAL:
+     case kind::SINE:
+     case kind::COSINE:
+     case kind::TANGENT:
+     case kind::COSECANT:
+     case kind::SECANT:
+     case kind::COTANGENT:
+     case kind::ARCSINE:
+     case kind::ARCCOSINE:
+     case kind::ARCTANGENT:
+     case kind::ARCCOSECANT:
+     case kind::ARCSECANT:
+     case kind::ARCCOTANGENT:
+     case kind::SQRT:
+     case kind::PI: return isTranscendentalMember(n);
+     case kind::ABS:
+     case kind::TO_INTEGER:
+       // Treat to_int as a variable; it is replaced in early preprocessing
+       // by a variable.
+       return true;
+     default: return isLeafMember(n);
+   }
+ }
+
+  static bool isLeafMember(Node n);
+  static bool isIAndMember(Node n);
+  static bool isPow2Member(Node n);
+  static bool isDivMember(Node n);
+  bool isDivLike() const{
+    return isDivMember(getNode());
   }
+  static bool isTranscendentalMember(Node n);
 
-  // TODO: check if it's a theory leaf also
-  static bool isMember(Node n) {
-    if (n.getKind() == kind::CONST_INTEGER) return false;
-    if (n.getKind() == kind::CONST_RATIONAL) return false;
-    return Theory::isLeafOf(n, theory::THEORY_ARITH);
+  bool isNormalForm() { return isMember(getNode()); }
+
+  bool isIntegral() const {
+    return getNode().getType().isInteger();
   }
 
-  bool isNormalForm() { return isMember(getNode()); }
+  bool isMetaKindVariable() const {
+    return getNode().isVar();
+  }
+
+  bool operator<(const Variable& v) const {
+    VariableNodeCmp cmp;
+    return cmp(this->getNode(), v.getNode());
+  }
+
+  struct VariableNodeCmp {
+    static inline int cmp(const Node& n, const Node& m) {
+      if ( n == m ) { return 0; }
+
+      // this is now slightly off of the old variable order.
+
+      bool nIsInteger = n.getType().isInteger();
+      bool mIsInteger = m.getType().isInteger();
+
+      if(nIsInteger == mIsInteger){
+        bool nIsVariable = n.isVar();
+        bool mIsVariable = m.isVar();
+
+        if(nIsVariable == mIsVariable){
+          if(n < m){
+            return -1;
+          }else{
+            Assert(n != m);
+            return 1;
+          }
+        }else{
+          if(nIsVariable){
+            return -1; // nIsVariable => !mIsVariable
+          }else{
+            return 1; // !nIsVariable => mIsVariable
+          }
+        }
+      }else{
+        Assert(nIsInteger != mIsInteger);
+        if(nIsInteger){
+          return 1; // nIsInteger => !mIsInteger
+        }else{
+          return -1; // !nIsInteger => mIsInteger
+        }
+      }
+    }
+
+    bool operator()(const Node& n, const Node& m) const {
+      return VariableNodeCmp::cmp(n,m) < 0;
+    }
+  };
 
-  bool operator<(const Variable& v) const { return getNode() < v.getNode();}
   bool operator==(const Variable& v) const { return getNode() == v.getNode();}
 
+  size_t getComplexity() const;
 };/* class Variable */
 
-
 class Constant : public NodeWrapper {
 public:
-  Constant(Node n) : NodeWrapper(n) {
-    Assert(isMember(getNode()));
-  }
+ Constant(Node n) : NodeWrapper(n) { Assert(isMember(getNode())); }
 
-  static bool isMember(Node n) {
-    return n.getKind() == kind::CONST_RATIONAL;
-  }
+ static bool isMember(Node n) { return n.getKind() == kind::CONST_RATIONAL; }
 
-  bool isNormalForm() { return isMember(getNode()); }
+ bool isNormalForm() { return isMember(getNode()); }
+
+ static Constant mkConstant(Node n)
+ {
+   Assert(n.getKind() == kind::CONST_RATIONAL);
+   return Constant(n);
+ }
+
+  static Constant mkConstant(const Rational& rat);
 
-  static Constant mkConstant(Node n) {
-    return Constant(coerceToRationalNode(n));
+  static Constant mkZero() {
+    return mkConstant(Rational(0));
   }
 
-  static Constant mkConstant(const Rational& rat) {
-    return Constant(mkRationalNode(rat));
+  static Constant mkOne() {
+    return mkConstant(Rational(1));
   }
 
   const Rational& getValue() const {
     return getNode().getConst<Rational>();
   }
 
-  bool isZero() const { return getValue() == 0; }
+  static int absCmp(const Constant& a, const Constant& b);
+  bool isIntegral() const { return getValue().isIntegral(); }
+
+  int sgn() const { return getValue().sgn(); }
+
+  bool isZero() const { return sgn() == 0; }
+  bool isNegative() const { return sgn() < 0; }
+  bool isPositive() const { return sgn() > 0; }
+
   bool isOne() const { return getValue() == 1; }
 
+  Constant operator*(const Rational& other) const {
+    return mkConstant(getValue() * other);
+  }
+
   Constant operator*(const Constant& other) const {
     return mkConstant(getValue() * other.getValue());
   }
@@ -236,12 +388,41 @@ public:
     return mkConstant(-getValue());
   }
 
+  Constant inverse() const{
+    Assert(!isZero());
+    return mkConstant(getValue().inverse());
+  }
+
+  bool operator<(const Constant& other) const {
+    return getValue() < other.getValue();
+  }
+
+  bool operator==(const Constant& other) const {
+    //Rely on node uniqueness.
+    return getNode() == other.getNode();
+  }
+
+  Constant abs() const {
+    if(isNegative()){
+      return -(*this);
+    }else{
+      return (*this);
+    }
+  }
+
+  uint32_t length() const{
+    Assert(isIntegral());
+    return getValue().getNumerator().length();
+  }
+
+  size_t getComplexity() const;
+
 };/* class Constant */
 
 
 template <class GetNodeIterator>
 inline Node makeNode(Kind k, GetNodeIterator start, GetNodeIterator end) {
-  NodeBuilder<> nb(k);
+  NodeBuilder nb(k);
 
   while(start != end) {
     nb << (*start).getNode();
@@ -251,35 +432,6 @@ inline Node makeNode(Kind k, GetNodeIterator start, GetNodeIterator end) {
   return Node(nb);
 }/* makeNode<GetNodeIterator>(Kind, iterator, iterator) */
 
-
-template <class GetNodeIterator, class T>
-static void copy_range(GetNodeIterator begin, GetNodeIterator end, std::vector<T>& result){
-  while(begin != end){
-    result.push_back(*begin);
-    ++begin;
-  }
-}
-
-template <class GetNodeIterator, class T>
-static void merge_ranges(GetNodeIterator first1,
-                  GetNodeIterator last1,
-                  GetNodeIterator first2,
-                  GetNodeIterator last2,
-                  std::vector<T>& result) {
-
-  while(first1 != last1 && first2 != last2){
-    if( (*first1) < (*first2) ){
-      result.push_back(*first1);
-      ++ first1;
-    }else{
-      result.push_back(*first2);
-      ++ first2;
-    }
-  }
-  copy_range(first1, last1, result);
-  copy_range(first2, last2, result);
-}
-
 /**
  * A VarList is a sorted list of variables representing a product.
  * If the VarList is empty, it represents an empty product or 1.
@@ -293,14 +445,12 @@ private:
   static Node multList(const std::vector<Variable>& list) {
     Assert(list.size() >= 2);
 
-    return makeNode(kind::MULT, list.begin(), list.end());
+    return makeNode(kind::NONLINEAR_MULT, list.begin(), list.end());
   }
 
   VarList() : NodeWrapper(Node::null()) {}
 
-  VarList(Node n) : NodeWrapper(n) {
-    Assert(isSorted(begin(), end()));
-  }
+  VarList(Node n);
 
   typedef expr::NodeSelfIterator internal_iterator;
 
@@ -327,6 +477,25 @@ public:
     internal_iterator d_iter;
 
   public:
+    /* The following types are required by trait std::iterator_traits */
+
+    /** Iterator tag */
+    using iterator_category = std::forward_iterator_tag;
+
+    /** The type of the item */
+    using value_type = Variable;
+
+    /** The pointer type of the item */
+    using pointer = Variable*;
+
+    /** The reference type of the item */
+    using reference = Variable&;
+
+    /** The type returned when two iterators are subtracted */
+    using difference_type = std::ptrdiff_t;
+
+    /* End of std::iterator_traits required types */
+
     explicit iterator(internal_iterator i) : d_iter(i) {}
 
     inline Variable operator*() {
@@ -359,6 +528,11 @@ public:
     return iterator(internalEnd());
   }
 
+  Variable getHead() const {
+    Assert(!empty());
+    return *(begin());
+  }
+
   VarList(Variable v) : NodeWrapper(v.getNode()) {
     Assert(isSorted(begin(), end()));
   }
@@ -392,7 +566,7 @@ public:
 
   bool empty() const { return getNode().isNull(); }
   bool singleton() const {
-    return !empty() && getNode().getKind() != kind::MULT;
+    return !empty() && getNode().getKind() != kind::NONLINEAR_MULT;
   }
 
   int size() const {
@@ -412,12 +586,24 @@ public:
 
   bool operator==(const VarList& vl) const { return cmp(vl) == 0; }
 
+  bool isIntegral() const {
+    for(iterator i = begin(), e=end(); i != e; ++i ){
+      Variable var = *i;
+      if(!var.isIntegral()){
+        return false;
+      }
+    }
+    return true;
+  }
+  size_t getComplexity() const;
+
 private:
   bool isSorted(iterator start, iterator end);
 
 };/* class VarList */
 
 
+/** Constructors have side conditions. Use the static mkMonomial functions instead. */ 
 class Monomial : public NodeWrapper {
 private:
   Constant constant;
@@ -425,8 +611,8 @@ private:
   Monomial(Node n, const Constant& c, const VarList& vl):
     NodeWrapper(n), constant(c), varList(vl)
   {
-    Assert(!c.isZero() ||  vl.empty() );
-    Assert( c.isZero() || !vl.empty() );
+    Assert(!c.isZero() || vl.empty());
+    Assert(c.isZero() || !vl.empty());
 
     Assert(!c.isOne() || !multStructured(n));
   }
@@ -444,33 +630,41 @@ private:
       n.getNumChildren() == 2;
   }
 
-public:
-
   Monomial(const Constant& c):
     NodeWrapper(c.getNode()), constant(c), varList(VarList::mkEmptyVarList())
   { }
-
+  
   Monomial(const VarList& vl):
     NodeWrapper(vl.getNode()), constant(Constant::mkConstant(1)), varList(vl)
   {
-    Assert( !varList.empty() );
+    Assert(!varList.empty());
   }
 
   Monomial(const Constant& c, const VarList& vl):
     NodeWrapper(makeMultNode(c,vl)), constant(c), varList(vl)
   {
-    Assert( !c.isZero() );
-    Assert( !c.isOne() );
-    Assert( !varList.empty() );
+    Assert(!c.isZero());
+    Assert(!c.isOne());
+    Assert(!varList.empty());
 
     Assert(multStructured(getNode()));
   }
-
+public:
   static bool isMember(TNode n);
 
   /** Makes a monomial with no restrictions on c and vl. */
   static Monomial mkMonomial(const Constant& c, const VarList& vl);
 
+  /** If vl is empty, this make one. */
+  static Monomial mkMonomial(const VarList& vl);
+
+  static Monomial mkMonomial(const Constant& c){
+    return Monomial(c);
+  }
+  
+  static Monomial mkMonomial(const Variable& v){
+    return Monomial(VarList(v));
+  }
 
   static Monomial parseMonomial(Node n);
 
@@ -482,7 +676,7 @@ public:
   }
   const Constant& getConstant() const { return constant; }
   const VarList& getVarList() const { return varList; }
-
+  
   bool isConstant() const {
     return varList.empty();
   }
@@ -495,8 +689,22 @@ public:
     return constant.isOne();
   }
 
+  bool absCoefficientIsOne() const {
+    return coefficientIsOne() || constant.getValue() == -1;
+  }
+
+  bool constantIsPositive() const {
+    return getConstant().isPositive();
+  }
+
+  Monomial operator*(const Rational& q) const;
+  Monomial operator*(const Constant& c) const;
   Monomial operator*(const Monomial& mono) const;
 
+  Monomial operator-() const{
+    return (*this) * Rational(-1);
+  }
+
 
   int cmp(const Monomial& mono) const {
     return getVarList().cmp(mono.getVarList());
@@ -511,24 +719,67 @@ public:
   }
 
   static bool isSorted(const std::vector<Monomial>& m) {
-    return __gnu_cxx::is_sorted(m.begin(), m.end());
+    return std::is_sorted(m.begin(), m.end());
   }
 
   static bool isStrictlySorted(const std::vector<Monomial>& m) {
     return isSorted(m) && std::adjacent_find(m.begin(),m.end()) == m.end();
   }
 
+  static void sort(std::vector<Monomial>& m);
+  static void combineAdjacentMonomials(std::vector<Monomial>& m);
+
+  /**
+   * The variable product
+   */
+  bool integralVariables() const {
+    return getVarList().isIntegral();
+  }
+
+  /**
+   * The coefficient of the monomial is integral.
+   */
+  bool integralCoefficient() const {
+    return getConstant().isIntegral();
+  }
+
+  /**
+   * A Monomial is an "integral" monomial if the constant is integral.
+   */
+  bool isIntegral() const {
+    return integralCoefficient() && integralVariables();
+  }
+
+  /** Returns true if the VarList is a product of at least 2 Variables.*/
+  bool isNonlinear() const {
+    return getVarList().size() >= 2;
+  }
+
   /**
    * Given a sorted list of monomials, this function transforms this
    * into a strictly sorted list of monomials that does not contain zero.
    */
-  static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
+  //static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
+
+  int absCmp(const Monomial& other) const{
+    return getConstant().getValue().absCmp(other.getConstant().getValue());
+  }
+  // bool absLessThan(const Monomial& other) const{
+  //   return getConstant().abs() < other.getConstant().abs();
+  // }
+
+  uint32_t coefficientLength() const{
+    return getConstant().length();
+  }
 
   void print() const;
   static void printList(const std::vector<Monomial>& list);
 
+  size_t getComplexity() const;
 };/* class Monomial */
 
+class SumPair;
+class Comparison;;
 
 class Polynomial : public NodeWrapper {
 private:
@@ -565,27 +816,32 @@ private:
   bool singleton() const { return d_singleton; }
 
 public:
-  static bool isMember(TNode n) {
-    if(Monomial::isMember(n)){
-      return true;
-    }else if(n.getKind() == kind::PLUS){
-      Assert(n.getNumChildren() >= 2);
-      for(Node::iterator curr = n.begin(), end = n.end(); curr != end;++curr){
-        if(!Monomial::isMember(*curr)){
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
+  static bool isMember(TNode n);
 
   class iterator {
   private:
     internal_iterator d_iter;
 
   public:
+    /* The following types are required by trait std::iterator_traits */
+
+    /** Iterator tag */
+    using iterator_category = std::forward_iterator_tag;
+
+    /** The type of the item */
+    using value_type = Monomial;
+
+    /** The pointer type of the item */
+    using pointer = Monomial*;
+
+    /** The reference type of the item */
+    using reference = Monomial&;
+
+    /** The type returned when two iterators are subtracted */
+    using difference_type = std::ptrdiff_t;
+
+    /* End of std::iterator_traits required types */
+
     explicit iterator(internal_iterator i) : d_iter(i) {}
 
     inline Monomial operator*() {
@@ -620,10 +876,17 @@ public:
   Polynomial(const std::vector<Monomial>& m):
     NodeWrapper(makePlusNode(m)), d_singleton(false)
   {
-    Assert( m.size() >= 2);
-    Assert( Monomial::isStrictlySorted(m) );
+    Assert(m.size() >= 2);
+    Assert(Monomial::isStrictlySorted(m));
   }
 
+  static Polynomial mkPolynomial(const Constant& c){
+    return Polynomial(Monomial::mkMonomial(c));
+  }
+
+  static Polynomial mkPolynomial(const Variable& v){
+    return Polynomial(Monomial::mkMonomial(v));
+  }
 
   static Polynomial mkPolynomial(const std::vector<Monomial>& m) {
     if(m.size() == 0) {
@@ -657,20 +920,32 @@ public:
     return getHead().isConstant();
   }
 
+  uint32_t size() const{
+    if(singleton()){
+      return 1;
+    }else{
+      Assert(getNode().getKind() == kind::PLUS);
+      return getNode().getNumChildren();
+    }
+  }
+
   Monomial getHead() const {
     return *(begin());
   }
 
   Polynomial getTail() const {
-    Assert(! singleton());
+    Assert(!singleton());
 
     iterator tailStart = begin();
     ++tailStart;
     std::vector<Monomial> subrange;
-    copy_range(tailStart, end(), subrange);
+    std::copy(tailStart, end(), std::back_inserter(subrange));
     return mkPolynomial(subrange);
   }
 
+  Monomial minimumVariableMonomial() const;
+  bool variableMonomialAreStrictlyGreater(const Monomial& m) const;
+
   void printList() const {
     if(Debug.isOn("normal-form")){
       Debug("normal-form") << "start list" << std::endl;
@@ -682,65 +957,461 @@ public:
     }
   }
 
+  /** A Polynomial is an "integral" polynomial if all of the monomials are integral. */
+  bool allIntegralVariables() const {
+    for(iterator i = begin(), e=end(); i!=e; ++i){
+      if(!(*i).integralVariables()){
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * A Polynomial is an "integral" polynomial if all of the monomials are integral
+   * and all of the coefficients are Integral. */
+  bool isIntegral() const {
+    for(iterator i = begin(), e=end(); i!=e; ++i){
+      if(!(*i).isIntegral()){
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static Polynomial sumPolynomials(const std::vector<Polynomial>& polynomials);
+
+  /** Returns true if the polynomial contains a non-linear monomial.*/
+  bool isNonlinear() const;
+
+  /** Check whether this polynomial is only a single variable. */
+  bool isVariable() const
+  {
+    return singleton() && getHead().getVarList().singleton()
+           && getHead().coefficientIsOne();
+  }
+  /** Return the variable, given that isVariable() holds. */
+  Variable getVariable() const
+  {
+    Assert(isVariable());
+    return getHead().getVarList().getHead();
+  }
+
+  /**
+   * Selects a minimal monomial in the polynomial by the absolute value of
+   * the coefficient.
+   */
+  Monomial selectAbsMinimum() const;
+
+  /** Returns true if the absolute value of the head coefficient is one. */
+  bool leadingCoefficientIsAbsOne() const;
+  bool leadingCoefficientIsPositive() const;
+  bool denominatorLCMIsOne() const;
+  bool numeratorGCDIsOne() const;
+
+  bool signNormalizedReducedSum() const {
+    return leadingCoefficientIsPositive() && denominatorLCMIsOne() && numeratorGCDIsOne();
+  }
+
+  /**
+   * Returns the Least Common Multiple of the denominators of the coefficients
+   * of the monomials.
+   */
+  Integer denominatorLCM() const;
+
+  /**
+   * Returns the GCD of the numerators of the monomials.
+   * Requires this to be an isIntegral() polynomial.
+   */
+  Integer numeratorGCD() const;
+
+  /**
+   * Returns the GCD of the coefficients of the monomials.
+   * Requires this to be an isIntegral() polynomial.
+   */
+  Integer gcd() const;
+
+  /** z must divide all of the coefficients of the polynomial. */
+  Polynomial exactDivide(const Integer& z) const;
+
   Polynomial operator+(const Polynomial& vl) const;
+  Polynomial operator-(const Polynomial& vl) const;
+  Polynomial operator-() const{
+    return (*this) * Rational(-1);
+  }
 
+  Polynomial operator*(const Rational& q) const;
+  Polynomial operator*(const Constant& c) const;
   Polynomial operator*(const Monomial& mono) const;
 
   Polynomial operator*(const Polynomial& poly) const;
 
+  /**
+   * Viewing the integer polynomial as a list [(* coeff_i mono_i)]
+   * The quotient and remainder of p divided by the non-zero integer z is:
+   *   q := [(* floor(coeff_i/z) mono_i )]
+   *   r := [(* rem(coeff_i/z) mono_i)]
+   * computeQR(p,z) returns the node (+ q r).
+   *
+   * q and r are members of the Polynomial class.
+   * For example:
+   * computeQR( p = (+ 5 (* 3 x) (* 8 y)) , z = 2) returns
+   *   (+ (+ 2 x (* 4 y)) (+ 1 x))
+   */
+  static Node computeQR(const Polynomial& p, const Integer& z);
+
+  /** Returns the coefficient associated with the VarList in the polynomial. */
+  Constant getCoefficient(const VarList& vl) const;
+
+  uint32_t maxLength() const{
+    iterator i = begin(), e=end();
+    if( i == e){
+      return 1;
+    }else{
+      uint32_t max = (*i).coefficientLength();
+      ++i;
+      for(; i!=e; ++i){
+        uint32_t curr = (*i).coefficientLength();
+        if(curr > max){
+          max = curr;
+        }
+      }
+      return max;
+    }
+  }
+
+  uint32_t numMonomials() const {
+    if( getNode().getKind() == kind::PLUS ){
+      return getNode().getNumChildren();
+    }else if(isZero()){
+      return 0;
+    }else{
+      return 1;
+    }
+  }
+
+  const Rational& asConstant() const{
+    Assert(isConstant());
+    return getNode().getConst<Rational>();
+    //return getHead().getConstant().getValue();
+  }
+
+  bool isVarList() const {
+    if(singleton()){
+      return VarList::isMember(getNode());
+    }else{
+      return false;
+    }
+  }
+
+  VarList asVarList() const {
+    Assert(isVarList());
+    return getHead().getVarList();
+  }
+
+  size_t getComplexity() const;
+
+  friend class SumPair;
+  friend class Comparison;
+
+  /** Returns a node that if asserted ensures v is the abs of this polynomial.*/
+  Node makeAbsCondition(Variable v){
+    return makeAbsCondition(v, *this);
+  }
+
+  /** Returns a node that if asserted ensures v is the abs of p.*/
+  static Node makeAbsCondition(Variable v, Polynomial p);
+
 };/* class Polynomial */
 
 
+/**
+ * SumPair is a utility class that extends polynomials for use in computations.
+ * A SumPair is always a combination of (+ p c) where
+ *  c is a constant and p is a polynomial such that p = 0 or !p.containsConstant().
+ *
+ * These are a useful utility for representing the equation p = c as (+ p -c) where the pair
+ * is known to implicitly be equal to 0.
+ *
+ * SumPairs do not have unique representations due to the potential for p = 0.
+ * This makes them inappropriate for normal forms.
+ */
+class SumPair : public NodeWrapper {
+private:
+  static Node toNode(const Polynomial& p, const Constant& c){
+    return NodeManager::currentNM()->mkNode(kind::PLUS, p.getNode(), c.getNode());
+  }
+
+  SumPair(TNode n) : NodeWrapper(n) { Assert(isNormalForm()); }
+
+ public:
+  SumPair(const Polynomial& p):
+    NodeWrapper(toNode(p, Constant::mkConstant(0)))
+  {
+    Assert(isNormalForm());
+  }
+
+  SumPair(const Polynomial& p, const Constant& c):
+    NodeWrapper(toNode(p, c))
+  {
+    Assert(isNormalForm());
+  }
+
+  static bool isMember(TNode n) {
+    if(n.getKind() == kind::PLUS && n.getNumChildren() == 2){
+      if(Constant::isMember(n[1])){
+        if(Polynomial::isMember(n[0])){
+          Polynomial p = Polynomial::parsePolynomial(n[0]);
+          return p.isZero() || (!p.containsConstant());
+        }else{
+          return false;
+        }
+      }else{
+        return false;
+      }
+    }else{
+      return false;
+    }
+  }
+
+  bool isNormalForm() const {
+    return isMember(getNode());
+  }
+
+  Polynomial getPolynomial() const {
+    return Polynomial::parsePolynomial(getNode()[0]);
+  }
+
+  Constant getConstant() const {
+    return Constant::mkConstant((getNode())[1]);
+  }
+
+  SumPair operator+(const SumPair& other) const {
+    return SumPair(getPolynomial() + other.getPolynomial(),
+                   getConstant() + other.getConstant());
+  }
+
+  SumPair operator*(const Constant& c) const {
+    return SumPair(getPolynomial() * c, getConstant() * c);
+  }
+
+  SumPair operator-(const SumPair& other) const {
+    return (*this) + (other * Constant::mkConstant(-1));
+  }
+
+  static SumPair mkSumPair(const Polynomial& p);
+
+  static SumPair mkSumPair(const Variable& var){
+    return SumPair(Polynomial::mkPolynomial(var));
+  }
+
+  static SumPair parseSumPair(TNode n){
+    return SumPair(n);
+  }
+
+  bool isIntegral() const{
+    return getConstant().isIntegral() && getPolynomial().isIntegral();
+  }
+
+  bool isConstant() const {
+    return getPolynomial().isZero();
+  }
+
+  bool isZero() const {
+    return getConstant().isZero() && isConstant();
+  }
+
+  uint32_t size() const{
+    return getPolynomial().size();
+  }
+
+  bool isNonlinear() const{
+    return getPolynomial().isNonlinear();
+  }
+
+  /**
+   * Returns the greatest common divisor of gcd(getPolynomial()) and getConstant().
+   * The SumPair must be integral.
+   */
+  Integer gcd() const {
+    Assert(isIntegral());
+    return (getPolynomial().gcd()).gcd(getConstant().getValue().getNumerator());
+  }
+
+  uint32_t maxLength() const {
+    Assert(isIntegral());
+    return std::max(getPolynomial().maxLength(), getConstant().length());
+  }
+
+  static SumPair mkZero() {
+    return SumPair(Polynomial::mkZero(), Constant::mkConstant(0));
+  }
+
+  static Node computeQR(const SumPair& sp, const Integer& div);
+
+};/* class SumPair */
+
+/* class OrderedPolynomialPair { */
+/* private: */
+/*   Polynomial d_first; */
+/*   Polynomial d_second; */
+/* public: */
+/*   OrderedPolynomialPair(const Polynomial& f, const Polynomial& s) */
+/*     : d_first(f), */
+/*       d_second(s) */
+/*   {} */
+
+/*   /\** Returns the first part of the pair. *\/ */
+/*   const Polynomial& getFirst() const { */
+/*     return d_first; */
+/*   } */
+
+/*   /\** Returns the second part of the pair. *\/ */
+/*   const Polynomial& getSecond() const { */
+/*     return d_second; */
+/*   } */
+
+/*   OrderedPolynomialPair operator*(const Constant& c) const; */
+/*   OrderedPolynomialPair operator+(const Polynomial& p) const; */
+
+/*   /\** Returns true if both of the polynomials are constant. *\/ */
+/*   bool isConstant() const; */
+
+/*   /\** */
+/*    * Evaluates an isConstant() ordered pair as if */
+/*    *   (k getFirst() getRight()) */
+/*    *\/ */
+/*   bool evaluateConstant(Kind k) const; */
+
+/*   /\** */
+/*    * Returns the Least Common Multiple of the monomials */
+/*    * on the lefthand side and the constant on the right. */
+/*    *\/ */
+/*   Integer denominatorLCM() const; */
+
+/*   /\** Constructs a SumPair. *\/ */
+/*   SumPair toSumPair() const; */
+
+
+/*   OrderedPolynomialPair divideByGCD() const; */
+/*   OrderedPolynomialPair multiplyConstant(const Constant& c) const; */
+
+/*   /\** */
+/*    * Returns true if all of the variables are integers, */
+/*    * and the coefficients are integers. */
+/*    *\/ */
+/*   bool isIntegral() const; */
+
+/*   /\** Returns true if all of the variables are integers. *\/ */
+/*   bool allIntegralVariables() const { */
+/*     return getFirst().allIntegralVariables() && getSecond().allIntegralVariables(); */
+/*   } */
+/* }; */
+
 class Comparison : public NodeWrapper {
 private:
-  Kind oper;
-  Polynomial left;
-  Constant right;
 
-  static Node toNode(Kind k, const Polynomial& l, const Constant& r);
+  static Node toNode(Kind k, const Polynomial& l, const Constant& c);
+  static Node toNode(Kind k, const Polynomial& l, const Polynomial& r);
+
+  Comparison(TNode n);
+
+  /**
+   * Creates a node in normal form equivalent to (= l 0).
+   * All variables in l are integral.
+   */
+  static Node mkIntEquality(const Polynomial& l);
+
+  /**
+   * Creates a comparison equivalent to (k l 0).
+   * k is either GT or GEQ.
+   * All variables in l are integral.
+   */
+  static Node mkIntInequality(Kind k, const Polynomial& l);
+
+  /**
+   * Creates a node equivalent to (= l 0).
+   * It is not the case that all variables in l are integral.
+   */
+  static Node mkRatEquality(const Polynomial& l);
+
+  /**
+   * Creates a comparison equivalent to (k l 0).
+   * k is either GT or GEQ.
+   * It is not the case that all variables in l are integral.
+   */
+  static Node mkRatInequality(Kind k, const Polynomial& l);
 
-  Comparison(TNode n, Kind k, const Polynomial& l, const Constant& r):
-    NodeWrapper(n), oper(k), left(l), right(r)
-  { }
 public:
+
   Comparison(bool val) :
-    NodeWrapper(NodeManager::currentNM()->mkConst(val)),
-    oper(kind::CONST_BOOLEAN),
-    left(Polynomial::mkZero()),
-    right(Constant::mkConstant(0))
+    NodeWrapper(NodeManager::currentNM()->mkConst(val))
   { }
 
-  Comparison(Kind k, const Polynomial& l, const Constant& r):
-    NodeWrapper(toNode(k, l, r)), oper(k), left(l), right(r)
-  {
-    Assert(isRelationOperator(oper));
-    Assert(!left.containsConstant());
-    Assert(left.getHead().getConstant().isOne());
-  }
+  /**
+   * Given a literal to TheoryArith return a single kind to
+   * to indicate its underlying structure.
+   * The function returns the following in each case:
+   * - (K left right)           -> K where is either EQUAL, GT, or GEQ
+   * - (CONST_BOOLEAN b)        -> CONST_BOOLEAN
+   * - (NOT (EQUAL left right)) -> DISTINCT
+   * - (NOT (GT left right))    -> LEQ
+   * - (NOT (GEQ left right))   -> LT
+   * If none of these match, it returns UNDEFINED_KIND.
+   */
+  static Kind comparisonKind(TNode literal);
 
-  static Comparison mkComparison(Kind k, const Polynomial& left, const Constant& right);
+  Kind comparisonKind() const { return comparisonKind(getNode()); }
 
-  bool isBoolean() const {
-    return (oper == kind::CONST_BOOLEAN);
-  }
+  static Comparison mkComparison(Kind k, const Polynomial& l, const Polynomial& r);
 
-  bool isNormalForm() const {
-    if(isBoolean()) {
-      return true;
-    } else if(left.containsConstant()) {
-      return false;
-    } else if(left.getHead().getConstant().isOne()) {
-      return true;
-    } else {
-      return false;
-    }
+  /** Returns true if the comparison is a boolean constant. */
+  bool isBoolean() const;
+
+  /**
+   * Returns true if the comparison is either a boolean term,
+   * in integer normal form or mixed normal form.
+   */
+  bool isNormalForm() const;
+
+private:
+  bool isNormalGT() const;
+  bool isNormalGEQ() const;
+
+  bool isNormalLT() const;
+  bool isNormalLEQ() const;
+
+  bool isNormalEquality() const;
+  bool isNormalDistinct() const;
+  bool isNormalEqualityOrDisequality() const;
+
+  bool allIntegralVariables() const {
+    return getLeft().allIntegralVariables() && getRight().allIntegralVariables();
   }
+  bool rightIsConstant() const;
+
+public:
+  Polynomial getLeft() const;
+  Polynomial getRight() const;
+
+  /* /\** Normal form check if at least one variable is real. *\/ */
+  /* bool isMixedCompareNormalForm() const; */
+
+  /* /\** Normal form check if at least one variable is real. *\/ */
+  /* bool isMixedEqualsNormalForm() const; */
 
-  const Polynomial& getLeft() const { return left; }
-  const Constant& getRight() const { return right; }
+  /* /\** Normal form check is all variables are integer.*\/ */
+  /* bool isIntegerCompareNormalForm() const; */
 
-  Comparison addConstant(const Constant& constant) const;
-  Comparison multiplyConstant(const Constant& constant) const;
+  /* /\** Normal form check is all variables are integer.*\/ */
+  /* bool isIntegerEqualsNormalForm() const; */
+
+
+  /**
+   * Returns true if all of the variables are integers, the coefficients are integers,
+   * and the right hand coefficient is an integer.
+   */
+  bool debugIsIntegral() const;
 
   static Comparison parseNormalForm(TNode n);
 
@@ -749,10 +1420,30 @@ public:
     return parse.isNormalForm();
   }
 
+  size_t getComplexity() const;
+
+  SumPair toSumPair() const;
+
+  Polynomial normalizedVariablePart() const;
+  DeltaRational normalizedDeltaRational() const;
+
+  /**
+   * Transforms a Comparison object into a stronger normal form:
+   *    Polynomial ~Kind~ Constant
+   * 
+   * From the comparison, this method resolved a negation (if present) and
+   * moves everything to the left side.
+   * If split_constant is false, the constant is always zero.
+   * If split_constant is true, the polynomial has no constant term and is
+   * normalized to have leading coefficient one.
+   */
+  std::tuple<Polynomial, Kind, Constant> decompose(
+      bool split_constant = false) const;
+
 };/* class Comparison */
 
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+}  // namespace arith
+}  // namespace theory
+}  // namespace cvc5
 
-#endif /* __CVC4__THEORY__ARITH__NORMAL_FORM_H */
+#endif /* CVC5__THEORY__ARITH__NORMAL_FORM_H */