--- /dev/null
+#include "mterm.hh"
+#include "signals.hh"
+#include "ppsig.hh"
+#include "xtended.hh"
+#include <assert.h>
+//static void collectMulTerms (Tree& coef, map<Tree,int>& M, Tree t, bool invflag=false);
+
+#undef TRACE
+
+using namespace std;
+
+typedef map<Tree,int> MP;
+
+mterm::mterm () : fCoef(sigInt(0)) {}
+mterm::mterm (int k) : fCoef(sigInt(k)) {}
+mterm::mterm (double k) : fCoef(sigReal(k)) {} // cerr << "DOUBLE " << endl; }
+mterm::mterm (const mterm& m) : fCoef(m.fCoef), fFactors(m.fFactors) {}
+
+/**
+ * create a mterm from a tree sexpression
+ */
+mterm::mterm (Tree t) : fCoef(sigInt(1))
+{
+ //cerr << "mterm::mterm (Tree t) : " << ppsig(t) << endl;
+ *this *= t;
+ //cerr << "MTERM(" << ppsig(t) << ") -> " << *this << endl;
+}
+
+/**
+ * true if mterm doesn't represent number 0
+ */
+bool mterm::isNotZero() const
+{
+ return !isZero(fCoef);
+}
+
+/**
+ * true if mterm doesn't represent number 0
+ */
+bool mterm::isNegative() const
+{
+ return !isGEZero(fCoef);
+}
+
+/**
+ * print a mterm in a human readable format
+ */
+ostream& mterm::print(ostream& dst) const
+{
+ const char* sep = "";
+ if (!isOne(fCoef) || fFactors.empty()) { dst << ppsig(fCoef); sep = " * "; }
+ //if (true) { dst << ppsig(fCoef); sep = " * "; }
+ for (MP::const_iterator p = fFactors.begin(); p != fFactors.end(); p++) {
+ dst << sep << ppsig(p->first);
+ if (p->second != 1) dst << "**" << p->second;
+ sep = " * ";
+ }
+ return dst;
+}
+
+/**
+ * Compute the "complexity" of a mterm, that is the number of
+ * factors it contains (weighted by the importance of these factors)
+ */
+int mterm::complexity() const
+{
+ int c = isOne(fCoef) ? 0 : 1;
+ for (MP::const_iterator p = fFactors.begin(); p != fFactors.end(); ++p) {
+ c += (1+getSigOrder(p->first))*abs(p->second);
+ }
+ return c;
+}
+
+/**
+ * match x^p with p:int
+ */
+static bool isSigPow(Tree sig, Tree& x, int& n)
+{
+ //cerr << "isSigPow("<< *sig << ')' << endl;
+ xtended* p = (xtended*) getUserData(sig);
+ if (p == gPowPrim) {
+ if (isSigInt(sig->branch(1), &n)) {
+ x = sig->branch(0);
+ //cerr << "factor of isSigPow " << *x << endl;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * produce x^p with p:int
+ */
+static Tree sigPow(Tree x, int p)
+{
+ return tree(gPowPrim->symbol(), x, sigInt(p));
+}
+
+/**
+ * Multiple a mterm by an expression tree t. Go down recursively looking
+ * for multiplications and divisions
+ */
+const mterm& mterm::operator *= (Tree t)
+{
+ int op, n;
+ Tree x,y;
+
+ assert(t!=0);
+
+ if (isNum(t)) {
+ fCoef = mulNums(fCoef,t);
+
+ } else if (isSigBinOp(t, &op, x, y) && (op == kMul)) {
+ *this *= x;
+ *this *= y;
+
+ } else if (isSigBinOp(t, &op, x, y) && (op == kDiv)) {
+ *this *= x;
+ *this /= y;
+
+ } else {
+ if (isSigPow(t,x,n)) {
+ fFactors[x] += n;
+ } else {
+ fFactors[t] += 1;
+ }
+ }
+ return *this;
+}
+
+/**
+ * Divide a mterm by an expression tree t. Go down recursively looking
+ * for multiplications and divisions
+ */
+const mterm& mterm::operator /= (Tree t)
+{
+ //cerr << "division en place : " << *this << " / " << ppsig(t) << endl;
+ int op,n;
+ Tree x,y;
+
+ assert(t!=0);
+
+ if (isNum(t)) {
+ fCoef = divExtendedNums(fCoef,t);
+
+ } else if (isSigBinOp(t, &op, x, y) && (op == kMul)) {
+ *this /= x;
+ *this /= y;
+
+ } else if (isSigBinOp(t, &op, x, y) && (op == kDiv)) {
+ *this /= x;
+ *this *= y;
+
+ } else {
+ if (isSigPow(t,x,n)) {
+ fFactors[x] -= n;
+ } else {
+ fFactors[t] -= 1;
+ }
+ }
+ return *this;
+}
+
+/**
+ * replace the content with a copy of m
+ */
+const mterm& mterm::operator = (const mterm& m)
+{
+ fCoef = m.fCoef;
+ fFactors = m.fFactors;
+ return *this;
+}
+
+/**
+ * Clean a mterm by removing x**0 factors
+ */
+void mterm::cleanup()
+{
+ if (isZero(fCoef)) {
+ fFactors.clear();
+ } else {
+ for (MP::iterator p = fFactors.begin(); p != fFactors.end(); ) {
+ if (p->second == 0) {
+ fFactors.erase(p++);
+ } else {
+ p++;
+ }
+ }
+ }
+}
+
+/**
+ * Add in place an mterm. As we want the result to be
+ * a mterm therefore essentially mterms of same signature can be added
+ */
+const mterm& mterm::operator += (const mterm& m)
+{
+ if (isZero(m.fCoef)) {
+ // nothing to do
+ } else if (isZero(fCoef)) {
+ // copy of m
+ fCoef = m.fCoef;
+ fFactors = m.fFactors;
+ } else {
+ // only add mterms of same signature
+ assert(signatureTree() == m.signatureTree());
+ fCoef = addNums(fCoef, m.fCoef);
+ }
+ cleanup();
+ return *this;
+}
+
+/**
+ * Substract in place an mterm. As we want the result to be
+ * a mterm therefore essentially mterms of same signature can be substracted
+ */
+const mterm& mterm::operator -= (const mterm& m)
+{
+ if (isZero(m.fCoef)) {
+ // nothing to do
+ } else if (isZero(fCoef)) {
+ // minus of m
+ fCoef = minusNum(m.fCoef);
+ fFactors = m.fFactors;
+ } else {
+ // only add mterms of same signature
+ assert(signatureTree() == m.signatureTree());
+ fCoef = subNums(fCoef, m.fCoef);
+ }
+ cleanup();
+ return *this;
+}
+
+/**
+ * Multiply a mterm by the content of another mterm
+ */
+const mterm& mterm::operator *= (const mterm& m)
+{
+ fCoef = mulNums(fCoef,m.fCoef);
+ for (MP::const_iterator p = m.fFactors.begin(); p != m.fFactors.end(); p++) {
+ fFactors[p->first] += p->second;
+ }
+ cleanup();
+ return *this;
+}
+
+/**
+ * Divide a mterm by the content of another mterm
+ */
+const mterm& mterm::operator /= (const mterm& m)
+{
+ //cerr << "division en place : " << *this << " / " << m << endl;
+ fCoef = divExtendedNums(fCoef,m.fCoef);
+ for (MP::const_iterator p = m.fFactors.begin(); p != m.fFactors.end(); p++) {
+ fFactors[p->first] -= p->second;
+ }
+ cleanup();
+ return *this;
+}
+
+/**
+ * Multiply two mterms
+ */
+mterm mterm::operator * (const mterm& m) const
+{
+ mterm r(*this);
+ r *= m;
+ return r;
+}
+
+/**
+ * Divide two mterms
+ */
+mterm mterm::operator / (const mterm& m) const
+{
+ mterm r(*this);
+ r /= m;
+ return r;
+}
+
+/**
+ * return the "common quantity" of two numbers
+ */
+static int common(int a, int b)
+{
+ if (a > 0 & b > 0) {
+ return min(a,b);
+ } else if (a < 0 & b < 0) {
+ return max(a,b);
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * return a mterm that is the greatest common divisor of two mterms
+ */
+mterm gcd (const mterm& m1, const mterm& m2)
+{
+ //cerr << "GCD of " << m1 << " and " << m2 << endl;
+
+ Tree c = (m1.fCoef == m2.fCoef) ? m1.fCoef : tree(1); // common coefficient (real gcd not needed)
+ mterm R(c);
+ for (MP::const_iterator p1 = m1.fFactors.begin(); p1 != m1.fFactors.end(); p1++) {
+ Tree t = p1->first;
+ MP::const_iterator p2 = m2.fFactors.find(t);
+ if (p2 != m2.fFactors.end()) {
+ int v1 = p1->second;
+ int v2 = p2->second;
+ int c = common(v1,v2);
+ if (c != 0) {
+ R.fFactors[t] = c;
+ }
+ }
+ }
+ //cerr << "GCD of " << m1 << " and " << m2 << " is : " << R << endl;
+ return R;
+}
+
+/**
+ * We say that a "contains" b if a/b > 0. For example 3 contains 2 and
+ * -4 contains -2, but 3 doesn't contains -2 and -3 doesn't contains 1
+ */
+static bool contains(int a, int b)
+{
+ return (b == 0) || (a/b > 0);
+}
+
+/**
+ * Check if M accept N has a divisor. We can say that N is
+ * a divisor of M if M = N*Q and the complexity is preserved :
+ * complexity(M) = complexity(N)+complexity(Q)
+ * x**u has divisor x**v if u >= v
+ * x**-u has divisor x**-v if -u <= -v
+ */
+bool mterm::hasDivisor (const mterm& n) const
+{
+ for (MP::const_iterator p1 = n.fFactors.begin(); p1 != n.fFactors.end(); p1++) {
+ // for each factor f**q of m
+ Tree f = p1->first;
+ int v = p1->second;
+
+ // check that f is also a factor of *this
+ MP::const_iterator p2 = fFactors.find(f);
+ if (p2 == fFactors.end()) return false;
+
+ // analyze quantities
+ int u = p2->second;
+ if (! contains(u,v) ) return false;
+ }
+ return true;
+}
+
+/**
+ * produce the canonical tree correspoding to a mterm
+ */
+
+/**
+ * Build a power term of type f**q -> (((f.f).f)..f) with q>0
+ */
+static Tree buildPowTerm(Tree f, int q)
+{
+ assert(f);
+ assert(q>0);
+ if (q>1) {
+ return sigPow(f, q);
+ } else {
+ return f;
+ }
+}
+
+/**
+ * Combine R and A doing R = R*A or R = A
+ */
+static void combineMulLeft(Tree& R, Tree A)
+{
+ if (R && A) R = sigMul(R,A);
+ else if (A) R = A;
+ else exit(1);
+}
+
+/**
+ * Combine R and A doing R = R*A or R = A
+ */
+static void combineDivLeft(Tree& R, Tree A)
+{
+ if (R && A) R = sigDiv(R,A);
+ else if (A) R = sigDiv(tree(1.0f),A);
+ else exit(1);
+}
+
+/**
+ * Do M = M * f**q or D = D * f**-q
+ */
+static void combineMulDiv(Tree& M, Tree& D, Tree f, int q)
+{
+ #ifdef TRACE
+ cerr << "combineMulDiv (" << M << "/" << D << "*" << ppsig(f)<< "**" << q << endl;
+ #endif
+ if (f) {
+ assert(q != 0);
+ if (q > 0) {
+ combineMulLeft(M, buildPowTerm(f,q));
+ } else if (q < 0) {
+ combineMulLeft(D, buildPowTerm(f,-q));
+ }
+ }
+}
+
+
+/**
+ * returns a normalized (canonical) tree expression of structure :
+ * ((v1/v2)*(c1/c2))*(s1/s2)
+ */
+Tree mterm::signatureTree() const
+{
+ return normalizedTree(true);
+}
+
+/**
+ * returns a normalized (canonical) tree expression of structure :
+ * ((k*(v1/v2))*(c1/c2))*(s1/s2)
+ * In signature mode the fCoef factor is ommited
+ * In negativeMode the sign of the fCoef factor is inverted
+ */
+Tree mterm::normalizedTree(bool signatureMode, bool negativeMode) const
+{
+ if (fFactors.empty() || isZero(fCoef)) {
+ // it's a pure number
+ if (signatureMode) return tree(1);
+ if (negativeMode) return minusNum(fCoef);
+ else return fCoef;
+ } else {
+ // it's not a pure number, it has factors
+ Tree A[4], B[4];
+
+ // group by order
+ for (int order = 0; order < 4; order++) {
+ A[order] = 0; B[order] = 0;
+ for (MP::const_iterator p = fFactors.begin(); p != fFactors.end(); p++) {
+ Tree f = p->first; // f = factor
+ int q = p->second; // q = power of f
+ if (f && q && getSigOrder(f)==order) {
+
+ combineMulDiv (A[order], B[order], f, q);
+ }
+ }
+ }
+ if (A[0] != 0) cerr << "A[0] == " << *A[0] << endl;
+ if (B[0] != 0) cerr << "B[0] == " << *B[0] << endl;
+ // en principe ici l'order zero est vide car il correspond au coef numerique
+ assert(A[0] == 0);
+ assert(B[0] == 0);
+
+ // we only use a coeficient if it differes from 1 and if we are not in signature mode
+ if (! (signatureMode | isOne(fCoef))) {
+ A[0] = (negativeMode) ? minusNum(fCoef) : fCoef;
+ }
+
+ if (signatureMode) {
+ A[0] = 0;
+ } else if (negativeMode) {
+ if (isMinusOne(fCoef)) { A[0] = 0; } else { A[0] = minusNum(fCoef); }
+ } else if (isOne(fCoef)) {
+ A[0] = 0;
+ } else {
+ A[0] = fCoef;
+ }
+
+ // combine each order separately : R[i] = A[i]/B[i]
+ Tree RR = 0;
+ for (int order = 0; order < 4; order++) {
+ if (A[order] && B[order]) combineMulLeft(RR,sigDiv(A[order],B[order]));
+ else if (A[order]) combineMulLeft(RR,A[order]);
+ else if (B[order]) combineDivLeft(RR,B[order]);
+ }
+ if (RR == 0) RR = tree(1); // a verifier *******************
+
+ assert(RR);
+ //cerr << "Normalized Tree of " << *this << " is " << ppsig(RR) << endl;
+ return RR;
+ }
+}
+