Rename interpretor to interpreter.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / compiler / normalize / simplify.cpp
diff --git a/interpreter/preprocessor/faust-0.9.47mr3/compiler/normalize/simplify.cpp b/interpreter/preprocessor/faust-0.9.47mr3/compiler/normalize/simplify.cpp
new file mode 100644 (file)
index 0000000..0b47d35
--- /dev/null
@@ -0,0 +1,379 @@
+/************************************************************************
+ ************************************************************************
+    FAUST compiler
+       Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
+    ---------------------------------------------------------------------
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+
+
+#include <stdio.h>
+#include <assert.h>
+#include "list.hh"
+#include "signals.hh"
+#include "sigtype.hh"
+#include "recursivness.hh"
+#include "sigtyperules.hh"
+#include "sigorderrules.hh"
+#include "sigprint.hh"
+#include "ppsig.hh"
+#include "simplify.hh"
+#include "num.hh"
+#include "xtended.hh"
+#include <map>
+#include "compatibility.hh"
+
+#include "normalize.hh"
+
+#undef TRACE
+
+// declarations
+Tree SIMPLIFIED = tree(symbol("sigSimplifiedProp"));
+//static Tree binequiv (Tree sig, int opnum, Tree a, Tree b);
+static Tree simplification (Tree sig);
+static Tree sigMap (Tree key, tfun f, Tree t);
+
+static Tree traced_simplification(Tree sig)
+{
+       assert(sig);
+#ifdef TRACE
+    cerr << ++TABBER << "Start simplification of : " << ppsig(sig) << endl;
+       /*
+       fprintf(stderr, "\nStart simplification of : ");
+       printSignal(sig, stderr);
+       fprintf(stderr, "\n");
+       */
+#endif
+       Tree r = simplification(sig);
+       assert(r!=0);
+#ifdef TRACE
+    cerr << --TABBER << "Simplification of : " << ppsig(sig) << " Returns : " << ppsig(r) << endl;
+       /*
+       fprintf(stderr, "Simplification of : ");
+       printSignal(sig, stderr);
+       fprintf(stderr, " -> ");
+       printSignal(r, stderr);
+       fprintf(stderr, "\n");
+       */
+#endif
+       return r;
+}
+
+Tree simplify (Tree sig)
+{
+       return sigMap(SIMPLIFIED, traced_simplification, sig);
+}
+
+
+// Implementation
+
+static Tree simplification (Tree sig)
+{
+       assert(sig);
+       int             opnum;
+       Tree    t1, t2, t3, t4;
+
+       xtended* xt = (xtended*) getUserData(sig);
+       // primitive elements
+       if (xt)
+       {
+               //return 3;
+               vector<Tree> args;
+               for (int i=0; i<sig->arity(); i++) { args.push_back( sig->branch(i) ); }
+
+        // to avoid negative power to further normalization
+        if (xt != gPowPrim) {
+            return xt->computeSigOutput(args);
+        } else {
+            return normalizeAddTerm(xt->computeSigOutput(args));
+        }
+
+       } else if (isSigBinOp(sig, &opnum, t1, t2)) {
+
+               BinOp* op = gBinOpTable[opnum];
+
+               Node n1 = t1->node();
+               Node n2 = t2->node();
+
+               if (isNum(n1) && isNum(n2))             return tree(op->compute(n1,n2));
+
+               else if (op->isLeftNeutral(n1))         return t2;
+
+               else if (op->isRightNeutral(n2))        return t1;
+
+               else                                                            return normalizeAddTerm(sig);
+
+       } else if (isSigDelay1(sig, t1)) {
+
+               return normalizeDelay1Term (t1);
+
+       } else if (isSigFixDelay(sig, t1, t2)) {
+
+               return normalizeFixedDelayTerm (t1, t2);
+
+       } else if (isSigIntCast(sig, t1)) {
+
+               Tree    tx;
+               int             i;
+               double  x;
+               Node    n1 = t1->node();
+
+               if (isInt(n1, &i))                      return t1;
+               if (isDouble(n1, &x))           return tree(int(x));
+               if (isSigIntCast(t1, tx))       return t1;
+
+               return sig;
+
+       } else if (isSigFloatCast(sig, t1)) {
+
+               Tree    tx;
+               int             i;
+               double  x;
+               Node    n1 = t1->node();
+
+               if (isInt(n1, &i))                              return tree(double(i));
+               if (isDouble(n1, &x))                   return t1;
+               if (isSigFloatCast(t1, tx))     return t1;
+
+               return sig;
+
+     } else if (isSigSelect2(sig, t1, t2, t3)){
+
+        Node n1 = t1->node();
+
+        if (isZero(n1)) return t2;
+        if (isNum(n1))  return t3;
+
+        if (t2==t3) return t2;
+
+        return sig;
+
+    } else if (isSigSelect3(sig, t1, t2, t3, t4)){
+
+        Node n1 = t1->node();
+
+        if (isZero(n1)) return t2;
+        if (isOne(n1))  return t3;
+        if (isNum(n1))  return t4;
+
+        if (t3==t4) return simplification(sigSelect2(t1,t2,t3));
+
+        return sig;
+
+       } else {
+
+               return sig;
+       }
+}
+
+/**
+ * Recursively transform a graph by applying a function f.
+ * map(f, foo[t1..tn]) = f(foo[map(f,t1)..map(f,tn)])
+ */
+static Tree sigMap (Tree key, tfun f, Tree t)
+{
+    //printf("start sigMap\n");
+    Tree p,id,body;
+
+    if (getProperty(t, key, p)) {
+
+        return (isNil(p)) ? t : p;     // truc pour eviter les boucles
+
+    } else if (isRec(t, id, body)) {
+
+        setProperty(t, key, nil);      // avoid infinite loop
+        return rec(id, sigMap(key, f, body));
+
+    } else {
+
+        Tree r1=nil;
+        switch (t->arity()) {
+
+            case 0 :
+                r1 = t;
+                break;
+            case 1 :
+                r1 = tree(t->node(), sigMap(key,f,t->branch(0)));
+                break;
+            case 2 :
+                r1 = tree(t->node(), sigMap(key,f,t->branch(0)), sigMap(key,f,t->branch(1)));
+                break;
+            case 3 :
+                r1 = tree(t->node(), sigMap(key,f,t->branch(0)), sigMap(key,f,t->branch(1)),
+                                           sigMap(key,f,t->branch(2)));
+                break;
+            case 4 :
+                r1 = tree(t->node(), sigMap(key,f,t->branch(0)), sigMap(key,f,t->branch(1)),
+                                           sigMap(key,f,t->branch(2)), sigMap(key,f,t->branch(3)));
+                break;
+        }
+        Tree r2 = f(r1);
+        if (r2 == t) {
+            setProperty(t, key, nil);
+        } else {
+            setProperty(t, key, r2);
+        }
+        return r2;
+    }
+}
+
+
+
+
+
+/**
+ * Like SigMap, recursively transform a graph by applying a
+ * function f. But here recursive trees are also renamed.
+ * map(f, foo[t1..tn]) = f(foo[map(f,t1)..map(f,tn)])
+ */
+static Tree sigMapRename (Tree key, Tree env, tfun f, Tree t)
+{
+    //printf("start sigMap\n");
+    Tree p,id,body;
+
+    if (getProperty(t, key, p)) {
+
+        return (isNil(p)) ? t : p;     // truc pour eviter les boucles
+
+    } else if (isRec(t, id, body)) {
+
+        assert(isRef(t,id)); // controle temporaire
+
+        Tree id2;
+        if (searchEnv(id, id2, env)) {
+            // déjà en cours de visite de cette recursion
+            return ref(id2);
+        } else {
+            // premiere visite de cette recursion
+            id2 = tree(Node(unique("renamed")));
+            Tree body2 = sigMapRename(key, pushEnv(id, id2, env), f, body);
+            return rec(id2,body2);
+        }
+
+    } else {
+
+        Tree r1=nil;
+        switch (t->arity()) {
+
+            case 0 :
+                r1 = t;
+                break;
+            case 1 :
+                r1 = tree(t->node(),    sigMapRename(key,env,f,t->branch(0)));
+                break;
+            case 2 :
+                r1 = tree(t->node(),    sigMapRename(key,env,f,t->branch(0)),
+                                        sigMapRename(key,env,f,t->branch(1)));
+                break;
+            case 3 :
+                r1 = tree(t->node(),    sigMapRename(key,env,f,t->branch(0)),
+                                        sigMapRename(key,env,f,t->branch(1)),
+                                        sigMapRename(key,env,f,t->branch(2)));
+                break;
+            case 4 :
+                r1 = tree(t->node(),    sigMapRename(key,env,f,t->branch(0)),
+                                        sigMapRename(key,env,f,t->branch(1)),
+                                        sigMapRename(key,env,f,t->branch(2)),
+                                        sigMapRename(key,env,f,t->branch(3)));
+                break;
+        }
+        Tree r2 = f(r1);
+        if (r2 == t) {
+            setProperty(t, key, nil);
+        } else {
+            setProperty(t, key, r2);
+        }
+        return r2;
+    }
+}
+
+#if 0
+static void eraseProperties (Tree key, Tree t)
+{
+       //printf("start sigMap\n");
+       Tree p,id,body;
+
+       if (getProperty(t, key, p)) {
+               // already erased, nothing to do
+
+       } else if (isRec(t, id, body)) {
+               t->clearProperties();
+        Tree r=rec(id, body);
+        assert(r==t);
+               setProperty(t, key, nil);       // avoid infinite loop
+               eraseProperties(key, body);
+
+       } else {
+
+               for (int i=0; i<t->arity(); i++) {
+                       eraseProperties(key,t->branch(i));
+               }
+       }
+}
+
+void eraseAllProperties(Tree t)
+{
+    cerr << "begin eraseAllProperties" << endl;
+       eraseProperties(tree(Node(unique("erase_"))), t);
+    cerr << "end eraseAllProperties" << endl;
+}
+#endif
+
+/**
+ * Converts regular tables into doc tables in order to
+ * facilitate the mathematical documentation generation
+ */
+
+Tree DOCTABLES = tree(symbol("DocTablesProp"));
+
+static Tree docTableConverter (Tree sig);
+
+static Tree NULLENV = tree(symbol("NullRenameEnv"));
+
+Tree docTableConvertion (Tree sig)
+{
+    Tree r  = sigMapRename(DOCTABLES, NULLENV, docTableConverter, sig);
+    return r;
+}
+
+
+// Implementation
+
+static Tree docTableConverter (Tree sig)
+{
+    Tree tbl, tbl2, id, id2, size, igen, isig, ridx, widx, wsig;
+
+    if (isSigRDTbl(sig, tbl, ridx)) {
+        // we are in a table to convert
+        if (isSigTable(tbl, id, size, igen)) {
+            // it's a read only table
+            assert(isSigGen(igen, isig));
+            return sigDocAccessTbl(sigDocConstantTbl(size,isig),ridx);
+        } else {
+            // it's a read write table
+            assert(isSigWRTbl(tbl,id,tbl2,widx,wsig));
+            assert(isSigTable(tbl2, id2, size, igen));
+            assert(isSigGen(igen, isig));
+
+            return sigDocAccessTbl(sigDocWriteTbl(size,isig,widx,wsig),ridx);
+        }
+
+    } else {
+        // nothing to convert
+        return sig;
+    }
+}