1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5     ---------------------------------------------------------------------
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ************************************************************************
20  ************************************************************************/
21 
22 #include "mterm.hh"
23 #include "exception.hh"
24 #include "global.hh"
25 #include "ppsig.hh"
26 #include "signals.hh"
27 #include "xtended.hh"
28 
29 #undef TRACE
30 
31 using namespace std;
32 
33 typedef map<Tree, int> MP;
34 
mterm()35 mterm::mterm() : fCoef(sigInt(0))
36 {
37 }
mterm(int k)38 mterm::mterm(int k) : fCoef(sigInt(k))
39 {
40 }
mterm(double k)41 mterm::mterm(double k) : fCoef(sigReal(k))
42 {
43 }  // cerr << "DOUBLE " << endl; }
mterm(const mterm & m)44 mterm::mterm(const mterm& m) : fCoef(m.fCoef), fFactors(m.fFactors)
45 {
46 }
47 
48 /**
49  * Create a mterm from a tree expression
50  */
mterm(Tree t)51 mterm::mterm(Tree t) : fCoef(sigInt(1))
52 {
53 #ifdef TRACE
54     cerr << "mterm::mterm (Tree t) : " << ppsig(t) << endl;
55 #endif
56     *this *= t;
57 #ifdef TRACE
58     cerr << "MTERM(" << ppsig(t) << ") -> " << *this << endl;
59 #endif
60 }
61 
62 /**
63  * true if mterm doesn't represent number 0
64  */
isNotZero() const65 bool mterm::isNotZero() const
66 {
67     return !isZero(fCoef);
68 }
69 
70 /**
71  * true if mterm doesn't represent number 0
72  */
isNegative() const73 bool mterm::isNegative() const
74 {
75     return !isGEZero(fCoef);
76 }
77 
78 /**
79  * Print a mterm in a human readable format
80  */
print(ostream & dst) const81 ostream& mterm::print(ostream& dst) const
82 {
83     const char* sep = "";
84     if (!isOne(fCoef) || fFactors.empty()) {
85         dst << ppsig(fCoef);
86         sep = " * ";
87     }
88     // if (true) { dst << ppsig(fCoef); sep = " * "; }
89     for (MP::const_iterator p = fFactors.begin(); p != fFactors.end(); p++) {
90         dst << sep << ppsig(p->first);
91         if (p->second != 1) dst << "**" << p->second;
92         sep = " * ";
93     }
94     return dst;
95 }
96 
97 /**
98  * Compute the "complexity" of a mterm, that is the number of
99  * factors it contains (weighted by the importance of these factors)
100  */
complexity() const101 int mterm::complexity() const
102 {
103     int c = isOne(fCoef) ? 0 : (isMinusOne(fCoef) ? 0 : 1);
104     for (MP::const_iterator p = fFactors.begin(); p != fFactors.end(); ++p) {
105         c += (1 + getSigOrder(p->first)) * abs(p->second);
106     }
107     // cerr << __LINE__ << ":" << __FUNCTION__ << "(" << *this << ") --> " << c << endl;
108     return c;
109 }
110 
111 /**
112  * Match x^p with p:int
113  */
isSigPow(Tree sig,Tree & x,int & n)114 static bool isSigPow(Tree sig, Tree& x, int& n)
115 {
116     // cerr << "isSigPow("<< *sig << ')' << endl;
117     xtended* p = (xtended*)getUserData(sig);
118     if (p == gGlobal->gPowPrim) {
119         if (isSigInt(sig->branch(1), &n)) {
120             x = sig->branch(0);
121             // cerr << "factor of isSigPow " << *x << endl;
122             return true;
123         }
124     }
125     return false;
126 }
127 
128 /**
129  * Produce x^p with p:int
130  */
sigPow(Tree x,int p)131 static Tree sigPow(Tree x, int p)
132 {
133     return tree(gGlobal->gPowPrim->symbol(), x, sigInt(p));
134 }
135 
136 /**
137  * Multiply a mterm by an expression tree. Go down recursively looking
138  * for multiplications and divisions
139  */
operator *=(Tree t)140 const mterm& mterm::operator*=(Tree t)
141 {
142     int  op, n;
143     Tree x, y;
144 
145     faustassert(t);
146 
147     if (isNum(t)) {
148         fCoef = mulNums(fCoef, t);
149 
150     } else if (isSigBinOp(t, &op, x, y) && (op == kMul)) {
151         *this *= x;
152         *this *= y;
153 
154     } else if (isSigBinOp(t, &op, x, y) && (op == kDiv)) {
155         *this *= x;
156         *this /= y;
157 
158     } else {
159         if (isSigPow(t, x, n)) {
160             fFactors[x] += n;
161         } else {
162             fFactors[t] += 1;
163         }
164     }
165     return *this;
166 }
167 
168 /**
169  * Divide a mterm by an expression tree t. Go down recursively looking
170  * for multiplications and divisions
171  */
operator /=(Tree t)172 const mterm& mterm::operator/=(Tree t)
173 {
174     // cerr << "division en place : " << *this << " / " << ppsig(t) << endl;
175     int  op, n;
176     Tree x, y;
177 
178     faustassert(t);
179 
180     if (isNum(t)) {
181         if (isZero(t)) {
182             stringstream error;
183             error << "ERROR : division by 0 in " << *this << " / " << ppsig(t) << endl;
184             throw faustexception(error.str());
185         }
186         fCoef = divExtendedNums(fCoef, t);
187 
188     } else if (isSigBinOp(t, &op, x, y) && (op == kMul)) {
189         *this /= x;
190         *this /= y;
191 
192     } else if (isSigBinOp(t, &op, x, y) && (op == kDiv)) {
193         *this /= x;
194         *this *= y;
195 
196     } else {
197         if (isSigPow(t, x, n)) {
198             fFactors[x] -= n;
199         } else {
200             fFactors[t] -= 1;
201         }
202     }
203     return *this;
204 }
205 
206 /**
207  * replace the content with a copy of m
208  */
operator =(const mterm & m)209 const mterm& mterm::operator=(const mterm& m)
210 {
211     fCoef    = m.fCoef;
212     fFactors = m.fFactors;
213     return *this;
214 }
215 
216 /**
217  * Clean a mterm by removing x**0 factors
218  */
cleanup()219 void mterm::cleanup()
220 {
221     if (isZero(fCoef)) {
222         fFactors.clear();
223     } else {
224         for (MP::iterator p = fFactors.begin(); p != fFactors.end();) {
225             if (p->second == 0) {
226                 fFactors.erase(p++);
227             } else {
228                 p++;
229             }
230         }
231     }
232 }
233 
234 /**
235  * Add in place an mterm. As we want the result to be
236  * a mterm therefore essentially mterms of same signature can be added
237  */
operator +=(const mterm & m)238 const mterm& mterm::operator+=(const mterm& m)
239 {
240     if (isZero(m.fCoef)) {
241         // nothing to do
242     } else if (isZero(fCoef)) {
243         // copy of m
244         fCoef    = m.fCoef;
245         fFactors = m.fFactors;
246     } else {
247         // only add mterms of same signature
248         faustassert(signatureTree() == m.signatureTree());
249         fCoef = addNums(fCoef, m.fCoef);
250     }
251     cleanup();
252     return *this;
253 }
254 
255 /**
256  * Substract in place an mterm. As we want the result to be
257  * a mterm therefore essentially mterms of same signature can be substracted
258  */
operator -=(const mterm & m)259 const mterm& mterm::operator-=(const mterm& m)
260 {
261     if (isZero(m.fCoef)) {
262         // nothing to do
263     } else if (isZero(fCoef)) {
264         // minus of m
265         fCoef    = minusNum(m.fCoef);
266         fFactors = m.fFactors;
267     } else {
268         // only add mterms of same signature
269         faustassert(signatureTree() == m.signatureTree());
270         fCoef = subNums(fCoef, m.fCoef);
271     }
272     cleanup();
273     return *this;
274 }
275 
276 /**
277  * Multiply a mterm by the content of another mterm
278  */
operator *=(const mterm & m)279 const mterm& mterm::operator*=(const mterm& m)
280 {
281     fCoef = mulNums(fCoef, m.fCoef);
282     for (MP::const_iterator p = m.fFactors.begin(); p != m.fFactors.end(); p++) {
283         fFactors[p->first] += p->second;
284     }
285     cleanup();
286     return *this;
287 }
288 
289 /**
290  * Divide a mterm by the content of another mterm
291  */
operator /=(const mterm & m)292 const mterm& mterm::operator/=(const mterm& m)
293 {
294     // cerr << "division en place : " << *this << " / " << m << endl;
295     if (m.fCoef == 0) {
296         stringstream error;
297         error << "ERROR : division by 0 in " << *this << " / " << m << endl;
298         throw faustexception(error.str());
299     }
300     fCoef = divExtendedNums(fCoef, m.fCoef);
301     for (MP::const_iterator p = m.fFactors.begin(); p != m.fFactors.end(); p++) {
302         fFactors[p->first] -= p->second;
303     }
304     cleanup();
305     return *this;
306 }
307 
308 /**
309  * Multiply two mterms
310  */
operator *(const mterm & m) const311 mterm mterm::operator*(const mterm& m) const
312 {
313     mterm r(*this);
314     r *= m;
315     return r;
316 }
317 
318 /**
319  * Divide two mterms
320  */
operator /(const mterm & m) const321 mterm mterm::operator/(const mterm& m) const
322 {
323     mterm r(*this);
324     r /= m;
325     return r;
326 }
327 
328 /**
329  * return the "common quantity" of two numbers
330  */
common(int a,int b)331 static int common(int a, int b)
332 {
333     if ((a > 0) & (b > 0)) {
334         return (int)min(a, b);
335     } else if ((a < 0) & (b < 0)) {
336         return (int)max(a, b);
337     } else {
338         return 0;
339     }
340 }
341 
342 /**
343  * return a mterm that is the greatest common divisor of two mterms
344  */
gcd(const mterm & m1,const mterm & m2)345 mterm gcd(const mterm& m1, const mterm& m2)
346 {
347     // cerr << "GCD of " << m1 << " and " << m2 << endl;
348 
349     Tree  c = (sameMagnitude(m1.fCoef, m2.fCoef)) ? m1.fCoef : tree(1);  // common coefficient (real gcd not needed)
350     mterm R(c);
351     for (MP::const_iterator p1 = m1.fFactors.begin(); p1 != m1.fFactors.end(); p1++) {
352         Tree               t  = p1->first;
353         MP::const_iterator p2 = m2.fFactors.find(t);
354         if (p2 != m2.fFactors.end()) {
355             int v1 = p1->second;
356             int v2 = p2->second;
357             int c1  = common(v1, v2);
358             if (c1 != 0) {
359                 R.fFactors[t] = c1;
360             }
361         }
362     }
363     // cerr << "GCD of " << m1 << " and " << m2 << " is : " << R << endl;
364     return R;
365 }
366 
367 /**
368  * We say that a "contains" b if a/b > 0. For example 3 contains 2 and
369  * -4 contains -2, but 3 doesn't contains -2 and -3 doesn't contains 1
370  */
contains(int a,int b)371 static bool contains(int a, int b)
372 {
373     return (b == 0) || (a / b > 0);
374 }
375 
376 /**
377  * Check if M accept N has a divisor. We can say that N is
378  * a divisor of M if M = N*Q and the complexity is preserved :
379  * complexity(M) = complexity(N)+complexity(Q)
380  * x**u has divisor x**v if u >= v
381  * x**-u has divisor x**-v if -u <= -v
382  */
hasDivisor(const mterm & n) const383 bool mterm::hasDivisor(const mterm& n) const
384 {
385     if (n.fFactors.size() == 0) {
386         // n is a pure number
387         return sameMagnitude(fCoef, n.fCoef);
388     }
389     for (MP::const_iterator p1 = n.fFactors.begin(); p1 != n.fFactors.end(); p1++) {
390         // for each factor f**q of m
391         Tree f = p1->first;
392         int  v = p1->second;
393 
394         // check that f is also a factor of *this
395         MP::const_iterator p2 = fFactors.find(f);
396         if (p2 == fFactors.end()) return false;
397 
398         // analyze quantities
399         int u = p2->second;
400         if (!contains(u, v)) return false;
401     }
402     // cerr << __LINE__ << ":" << __func__ << *this << " is divisible by " << n << endl;
403     return true;
404 }
405 
406 /**
407  * produce the canonical tree correspoding to a mterm
408  */
409 
410 /**
411  * Build a power term of type f**q -> (((f.f).f)..f) with q>0
412  */
buildPowTerm(Tree f,int q)413 static Tree buildPowTerm(Tree f, int q)
414 {
415     faustassert(f);
416     faustassert(q > 0);
417     if (q > 1) {
418         return sigPow(f, q);
419     } else {
420         return f;
421     }
422 }
423 
424 /**
425  * Combine R and A doing R = R*A or R = A
426  */
combineMulLeft(Tree & R,Tree A)427 static void combineMulLeft(Tree& R, Tree A)
428 {
429     if (R && A)
430         R = sigMul(R, A);
431     else if (A)
432         R = A;
433     else
434         throw faustexception("ERROR in combineMulLeft\n");
435 }
436 
437 /**
438  * Combine R and A doing R = R*A or R = A
439  */
combineDivLeft(Tree & R,Tree A)440 static void combineDivLeft(Tree& R, Tree A)
441 {
442     if (R && A)
443         R = sigDiv(R, A);
444     else if (A)
445         R = sigDiv(tree(1.0f), A);
446     else
447         throw faustexception("ERROR in combineDivLeft\n");
448 }
449 
450 /**
451  * Do M = M * f**q or D = D * f**-q
452  */
combineMulDiv(Tree & M,Tree & D,Tree f,int q)453 static void combineMulDiv(Tree& M, Tree& D, Tree f, int q)
454 {
455 #ifdef TRACE
456     cerr << "combineMulDiv (" << M << "/" << D << "*" << ppsig(f) << "**" << q << endl;
457 #endif
458     if (f) {
459         faustassert(q != 0);
460         if (q > 0) {
461             combineMulLeft(M, buildPowTerm(f, q));
462         } else if (q < 0) {
463             combineMulLeft(D, buildPowTerm(f, -q));
464         }
465     }
466 }
467 
468 /**
469  * returns a normalized (canonical) tree expression of structure :
470  * 		((v1/v2)*(c1/c2))*(s1/s2)
471  */
signatureTree() const472 Tree mterm::signatureTree() const
473 {
474     return normalizedTree(true);
475 }
476 
477 /**
478  * returns a normalized (canonical) tree expression of structure :
479  * 		((k*(v1/v2))*(c1/c2))*(s1/s2)
480  * In signature mode the fCoef factor is ommited
481  * In negativeMode the sign of the fCoef factor is inverted
482  */
normalizedTree(bool signatureMode,bool negativeMode) const483 Tree mterm::normalizedTree(bool signatureMode, bool negativeMode) const
484 {
485 #ifdef TRACE
486     cout << "normalizedTree " << *this << endl;
487 #endif
488 
489     if (fFactors.empty() || isZero(fCoef)) {
490         // it's a pure number
491         if (signatureMode) return tree(1);
492         if (negativeMode)
493             return minusNum(fCoef);
494         else
495             return fCoef;
496     } else {
497         // it's not a pure number, it has factors
498         Tree A[4], B[4];
499 
500         // group by order
501         for (int order = 0; order < 4; order++) {
502             A[order] = 0;
503             B[order] = 0;
504             for (auto p : fFactors) {
505                 Tree f = p.first;   // f = factor
506                 int  q = p.second;  // q = power of f
507                 if (f && q && getSigOrder(f) == order) {
508                     combineMulDiv(A[order], B[order], f, q);
509                 }
510             }
511         }
512 #if 1
513         if (A[0] != 0) cerr << "A[0] == " << *A[0] << endl;
514         if (B[0] != 0) cerr << "B[0] == " << *B[0] << endl;
515         // en principe ici l'ordre zero est vide car il correspond au coef numerique
516         faustassert(A[0] == 0);
517         faustassert(B[0] == 0);
518 #endif
519 
520         // we only use a coeficient if it differes from 1 and if we are not in signature mode
521         if (!(signatureMode || isOne(fCoef))) {
522             A[0] = (negativeMode) ? minusNum(fCoef) : fCoef;
523         }
524 
525         if (signatureMode) {
526             A[0] = 0;
527         } else if (negativeMode) {
528             if (isMinusOne(fCoef)) {
529                 A[0] = 0;
530             } else {
531                 A[0] = minusNum(fCoef);
532             }
533         } else if (isOne(fCoef)) {
534             A[0] = 0;
535         } else {
536             A[0] = fCoef;
537         }
538 
539         // combine each order separately : R[i] = A[i]/B[i]
540         Tree RR = 0;
541         for (int order = 0; order < 4; order++) {
542             if (A[order] && B[order])
543                 combineMulLeft(RR, sigDiv(A[order], B[order]));
544             else if (A[order])
545                 combineMulLeft(RR, A[order]);
546             else if (B[order])
547                 combineDivLeft(RR, B[order]);
548         }
549         if (RR == 0) RR = tree(1);  // a verifier *******************
550 
551         faustassert(RR);
552 #ifdef TRACE
553         cout << "Normalized Tree of " << *this << " is " << ppsig(RR) << endl;
554 #endif
555         return RR;
556     }
557 }
558