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