Rename interpretor to interpreter.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / compiler / signals / sigraterules.cpp
diff --git a/interpreter/preprocessor/faust-0.9.47mr3/compiler/signals/sigraterules.cpp b/interpreter/preprocessor/faust-0.9.47mr3/compiler/signals/sigraterules.cpp
new file mode 100644 (file)
index 0000000..daac27a
--- /dev/null
@@ -0,0 +1,862 @@
+/************************************************************************
+ ************************************************************************
+    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 <fstream>
+#include <time.h>
+
+
+#include "sigtype.hh"
+#include "sigprint.hh"
+#include "ppsig.hh"
+//#include "prim.hh"
+#include "prim2.hh"
+#include "xtended.hh"
+#include "recursivness.hh"
+
+#include "sigtyperules.hh"
+#include "sigraterules.hh"
+
+
+
+//--------------------------------------------------------------------------
+// Uncomment to activate type inference tracing
+
+//#define TRACE(x) x
+#define TRACE(x) 0;
+
+
+
+
+
+/**
+
+========================================== RATE INFERENCE =========================================
+                                         [Public functions]
+
+
+*/
+
+/**************************************************************************************************
+
+                                        Internal prototypes
+
+ **************************************************************************************************/
+
+static Tree inferreMultiRates(Tree lsig1, bool& success);
+static ostream&  printRateEnvironment(ostream& fout, Tree E);
+static ostream&  printRateEnvironmentList(ostream& fout, Tree LE);
+static void doInferreRate(Tree sig, int* rate, Tree& renv);
+static void inferreRate(Tree sig, int* rate, Tree& E);
+static Tree addToMultiRates(Tree E1, Tree LE, bool& success);
+static Tree addRecursiveSignals(Tree lsig);
+static Tree doAddRecursiveSignals(Tree sig, Tree accSig);
+static Tree flatRateEnvironmentList(Tree lre);
+
+static int computeRate(Tree sig, Tree renv, property<int>& rateProperty);
+
+
+
+/**************************************************************************************************
+ **************************************************************************************************
+ **************************************************************************************************
+
+                                        Public Functions
+
+ **************************************************************************************************
+ **************************************************************************************************
+ **************************************************************************************************/
+
+/**
+  * Inferre the rate of a list of signals.
+  */
+Tree inferreMultiRates(Tree lsig1, bool& success)
+{
+    vector<Tree>    sigs;
+    vector<Tree>    envs;
+    vector<int>     rates;
+
+    Tree lsig2 = addRecursiveSignals(lsig1);
+    TRACE(cerr << "lsig2 = " << *lsig2 << endl);
+
+    while (isList(lsig2)) {
+        Tree s = hd(lsig2); lsig2 = tl(lsig2);
+        Tree E; int r; inferreRate(s, &r, E);
+        if (r==0) {
+            success = false;
+            cerr << "ERROR inferreMultiRates failed 1" << endl;
+            return nil;
+        }
+        sigs.push_back(s);
+        envs.push_back(E);
+        rates.push_back(r);
+    }
+
+    // combines all the rate environements
+    Tree LE = nil;
+    success = true;
+    for (unsigned int i=0; success && i<envs.size(); i++) {
+        LE = addToMultiRates(envs[i], LE, success);
+    }
+    TRACE(cerr << "***multirates :"; printRateEnvironmentList(cerr, LE); cerr << endl);
+    Tree RE = flatRateEnvironmentList(LE);
+    TRACE(cerr << "***flat rate  :"; printRateEnvironment(cerr, RE); cerr << endl);
+
+    return RE;
+}
+
+
+/**
+  * Print a rate environment
+  */
+ostream&  printRateEnvironment(ostream& fout, Tree E)
+{
+    string sep = "";
+    fout << "rates {";
+    while (isList(E)) {
+        fout << sep << ppsig(hd(hd(E))) << ":" << tree2int(tl(hd(E)));
+        sep=",";
+        E = tl(E);
+    }
+    fout << "}";
+    return fout;
+}
+
+
+/**
+  * Print a list of rate environments
+  */
+ostream&  printRateEnvironmentList(ostream& fout, Tree LE)
+{
+    string sep = "";
+    fout << "multi{";
+    while (isList(LE)) {
+        fout << sep; printRateEnvironment(fout, hd(LE));
+        sep="++";
+        LE = tl(LE);
+    }
+    fout << "}";
+    return fout;
+}
+
+
+
+/**************************************************************************************************
+ **************************************************************************************************
+ **************************************************************************************************
+
+                                        IMPLEMENTATION
+
+ **************************************************************************************************
+ **************************************************************************************************
+ **************************************************************************************************/
+
+
+/**
+  * Greatest common divisor
+  */
+static int TRACED_gcd(int a, int b);
+
+static int gcd(int a, int b)
+{
+    int r = TRACED_gcd(a,b);
+    //cerr << TABBER << "gcd(" << a << ',' << b <<") = " << r << endl;
+    return r;
+}
+
+
+static int TRACED_gcd(int a, int b)
+{
+    return (b==0) ? a : gcd (b, a%b);
+}
+
+/**
+  * Least common multiple
+  */
+static int lcm(int a, int b)
+{
+    int r = (a*b)/gcd(a,b);
+    //cerr << TABBER << "lcm(" << a << ',' << b <<") = " << r << endl;
+    return r;
+}
+
+
+/**
+ * Add to a list of existing signals lsig the list of recursive signals apprearing in lsig
+ */
+
+static Tree addRecursiveSignals(Tree lsig)
+{
+    CTree::startNewVisit();
+
+    Tree lsig2 = lsig;
+    while (isList(lsig)) {
+        lsig2 = doAddRecursiveSignals(hd(lsig), lsig2);
+        lsig = tl(lsig);
+    }
+    return lsig2;
+}
+
+
+static Tree doAddRecursiveSignals(Tree sig, Tree accSig)
+{
+    TRACE(cerr << ++TABBER << "doAddRecursiveSignals(" << *sig << ',' << *accSig << ')' << endl);
+    if ( ! sig->isAlreadyVisited() ) {
+        int     i;
+        Tree    rsig, id, body;
+        sig->setVisited();
+        if (isProj(sig,&i,rsig) && isRec(rsig, id, body)) {
+            Tree p = nth(body,i);
+            accSig = doAddRecursiveSignals(p, cons(p,accSig));
+        } else {
+            assert(!isProj(sig,&i,rsig));
+
+            vector<Tree>    subsigs;
+            getSubSignals(sig,subsigs,false);
+            for (unsigned int i=0; i<subsigs.size(); i++) {
+                accSig = doAddRecursiveSignals(subsigs[i], accSig);
+            }
+        }
+    }
+    TRACE(cerr << --TABBER << "doAddRecursiveSignals(" << *sig << ',' << *accSig << ") -> " << *accSig << endl);
+    return accSig;
+}
+
+/** *********************************** RATE ENVIRONMENTS ************************************************
+
+A rate environement E = {(s1,r1), (s2,r2), ...} is a set of pairs associating a signal and a rate. The
+signals are unique : if (s1,r1) and (s2,r2) are in E then s1=s2 => r1=r2.
+
+The environment is kept ordered
+
+
+**********************************************************************************************************/
+
+
+
+
+/**
+  * Add a pair signal s1 x rate r1 to rate environment E
+  */
+static Tree addRateEnv(Tree s1, int r1, Tree E)
+{
+    if (isList(E)) {
+        Tree s2 = hd(hd(E));
+        if (s1 < s2) {
+            return cons(cons(s1,tree(r1)),E);
+        } else if (s1 == s2) {
+            return cons(cons(s1,tree(r1)),tl(E));
+        } else {
+            return cons(hd(E), addRateEnv(s1,r1,tl(E)));
+        }
+    } else {
+        return cons(cons(s1,tree(r1)),nil);
+    }
+}
+
+
+/**
+  * multiply by n all the rates of rate environment E
+  * E={(s1,r1),...} -> E'={(s1,n.r1),...}
+  */
+static Tree TRACED_multRateEnv(int n, Tree E);
+
+static Tree multRateEnv(int n, Tree E)
+{
+    TRACE(cerr << ++TABBER << "multRateEnv(" << n << ", " << *E << ")" << endl);
+    Tree result = TRACED_multRateEnv(n, E);
+    TRACE(cerr << --TABBER << "multRateEnv(" << n << ", " << *E << ") -> " << *result << endl);
+    return result;
+
+}
+
+
+static Tree TRACED_multRateEnv(int n, Tree E)
+{
+    if (isList(E)) {
+        Tree p = hd(E);
+        Tree k = hd(p);
+        int  r = tree2int(tl(p));
+        Tree q = cons(k, tree(r*n));
+        return cons(q, multRateEnv(n, tl(E)));
+    } else {
+        return nil;
+    }
+}
+
+
+/**
+  * Get value associated to key k in "function" l
+  * returns true if a value was found.
+  */
+
+static bool getRateEnv(Tree k, int* i, Tree l)
+{
+    if (isNil(l)) {
+        return false;
+    } else {
+        assert (isList(l));
+        Tree r = hd(hd(l));
+        if (k < r) {
+            return false;   // not found
+        } else if (k == r) {
+            *i = tree2int(tl(hd(l)));
+            return true;
+        } else {
+            return getRateEnv(k,i,tl(l));
+        }
+    }
+}
+
+
+
+/**
+  * two rate environments are compatible if common rates
+  * are linked by the same ratio
+  */
+
+static bool checkRatesCompatible(Tree R1, Tree R2, int n1, int n2)
+{
+    if (isNil(R1) || isNil(R2)) {
+        return true;
+    } else {
+        Tree p1 = hd (R1);
+        Tree p2 = hd (R2);
+
+        Tree k1 = hd (p1);
+        Tree k2 = hd (p2);
+
+        if (k1 < k2) {
+            return checkRatesCompatible(tl(R1), R2, n1, n2);
+        } else if (k1 > k2) {
+            return checkRatesCompatible(R1, tl(R2), n1, n2);
+        } else {
+            Tree v1 = tl (p1);
+            Tree v2 = tl (p2);
+
+            if (tree2int(v1)*n1 == tree2int(v2)*n2) {
+                return checkRatesCompatible(tl(R1), tl(R2), n1, n2);
+            } else {
+                return false;
+            }
+        }
+    }
+}
+
+
+
+/**
+  * Two rate environments are independent if they don't have any
+  * signals in common
+  */
+
+static bool areRatesIndependent(Tree R1, Tree R2)
+{
+    if (isNil(R1) || isNil(R2)) {
+        return true;
+    } else {
+        Tree p1 = hd (R1);
+        Tree p2 = hd (R2);
+
+        Tree s1 = hd (p1);
+        Tree s2 = hd (p2);
+
+        if (s1 < s2) {
+            return areRatesIndependent(tl(R1), R2);
+        } else if (s2 < s1) {
+            return areRatesIndependent(R1, tl(R2));
+        } else {
+            return false; // s1 and s2 are in common
+        }
+    }
+}
+
+
+
+
+/**
+  * Two rate environments are compatible if common rates
+  * are linked by the same ratio
+  */
+
+static bool areRatesCompatible(Tree R1, Tree R2, int& n1, int& n2)
+{
+    if (isNil(R1) || isNil(R2)) {
+
+        n1 = 1; n2 = 1;
+        return true;
+
+    } else {
+
+        Tree p1 = hd (R1);
+        Tree p2 = hd (R2);
+
+        Tree k1 = hd (p1);
+        Tree k2 = hd (p2);
+
+        if (k1 < k2) {
+
+            return areRatesCompatible(tl(R1), R2, n1, n2);
+
+        } else if (k1 > k2) {
+
+            return areRatesCompatible(R1, tl(R2), n1, n2);
+
+        } else {
+
+            // we have a common expression
+            Tree v1 = tl (p1);
+            Tree v2 = tl (p2);
+
+            int  r1 = tree2int(v1);
+            int  r2 = tree2int(v2);
+
+            int  m = lcm(r1, r2);
+
+            // we update the n1 and n2 coefficients
+            n1 = m/r1;
+            n2 = m/r2;
+
+            // and we check that the rest of the environments are compatible
+            return checkRatesCompatible(tl(R1), tl(R2), n1, n2);
+        }
+    }
+}
+
+
+/**
+  * Merge two compatible rate environments.  Rate environments are
+  * compatible if common expressions have same rate.
+  * Returns the merge environment and success flag
+  */
+static Tree TRACED_mergeRateEnvironment(Tree R1, Tree R2, bool& success);
+
+static Tree mergeRateEnvironment(Tree R1, Tree R2, bool& success)
+{
+    TRACE(cerr << ++TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ")" << endl);
+    Tree result = TRACED_mergeRateEnvironment(R1, R2, success);
+    if (success) {
+        TRACE(cerr << --TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ") -> " << *result << endl);
+    } else {
+        TRACE(cerr << --TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ") -> FAILED" << endl);
+    }
+    return result;
+}
+
+
+
+
+static Tree TRACED_mergeRateEnvironment(Tree R1, Tree R2, bool& success)
+{
+    if (isNil(R1)) {
+
+        success = true;
+        return R2;
+
+    } else if (isNil(R2)) {
+
+            success = true;
+            return R1;
+
+    } else {
+
+        Tree p1 = hd (R1);
+        Tree p2 = hd (R2);
+
+        Tree k1 = hd (p1);
+        Tree k2 = hd (p2);
+
+        if (k1 < k2) {
+
+            return cons(p1, mergeRateEnvironment(tl(R1), R2, success));
+
+        } else if (k2 < k1) {
+
+            return cons(p2, mergeRateEnvironment(R1, tl(R2), success));
+
+        } else {
+
+            // we have a common expression
+            Tree r1 = tl (p1);
+            Tree r2 = tl (p2);
+
+            if (r1 == r2) {
+                // fine, same rate
+                return cons(p2, mergeRateEnvironment(tl(R1), tl(R2), success));
+            } else {
+                success = false;
+                return nil;
+            }
+        }
+    }
+}
+
+/**
+ * Merge a list of independent rate environments into a single rate environment
+ */
+static Tree flatRateEnvironmentList(Tree lre)
+{
+    Tree    e = nil;
+    bool    success = true;
+    while (isList(lre)) {
+        e = mergeRateEnvironment(hd(lre),e, success);
+        assert(success); // can't failed if environments are independant
+        lre = tl(lre);
+    }
+    return e;
+}
+
+/**
+
+========================================== RATE INFERENCE =========================================
+
+
+*/
+
+
+property<Tree>   gInferreRateProperty;
+
+static void setInferreRateProperty(Tree sig, int rate, Tree renv)
+{
+    gInferreRateProperty.set(sig, cons(tree(rate),renv));
+}
+
+static bool getInferreRateProperty(Tree sig, int* rate, Tree& renv)
+{
+    Tree p;
+    if (gInferreRateProperty.get(sig, p)) {
+        *rate = tree2int(hd(p));
+        renv = tl(p);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+/**
+  * Inferre rate (and rate environment) of a single signal.
+  * Use a property to cache previous results
+  */
+static void inferreRate(Tree sig, int* rate, Tree& E)
+{
+    TRACE(cerr << ++TABBER << "inferreRate(" << ppsig(sig) << ")" << endl);
+    if (! getInferreRateProperty(sig, rate, E)) {
+        doInferreRate(sig, rate, E);
+        setInferreRateProperty(sig, *rate, E);
+    }
+    TRACE(cerr << --TABBER << "inferreRate(" << ppsig(sig) << ") = " << *rate << " with " << *E << endl);
+}
+
+
+/**
+  * Checks that w denotes a positive constant integer signal n
+  * returns n or exit
+  */
+static int checkSignalDenotesSize(Tree w, Tree sig)
+{
+    // checks that w denotes a positive constant integer signal n
+    SimpleType*  st = isSimpleType(getCertifiedSigType(w));
+
+    if (st && st->nature()==kInt) {
+        interval i = st->getInterval();
+        if (i.valid && i.lo >= 0 && i.lo == i.hi) {
+            return int(i.lo);
+        }
+    }
+    cerr << "ERROR in expression : " << ppsig(sig) << endl;
+    cerr << *w << " is not a positive constant integer" << endl;
+    exit(1);
+}
+
+/**
+  * Inferre the rate (and the rate environment) of a signal.
+  * A zero rate indicates an impossibility
+  */
+static void doInferreRate(Tree sig, int* rate, Tree& E)
+{
+    Tree    w, x, rsig, id, body;
+    int     i, in;
+
+    if ( isSigVectorize(sig, w, x) )  {
+
+        // -- rate(vectorize(n,x)) = rate(x)/n
+
+        VectorType* vt  = isVectorType(getCertifiedSigType(sig)); assert(vt);
+        int         n   = vt->size(); assert(n>0);
+
+        int r; inferreRate(x, &r, E);
+        if ((r%n) == 0) {
+            // fine, the rate of x can be divided by n
+            // (note: this is compatible with r==0 indicating that x has no rate)
+            *rate = r/n;
+        } else {
+            // we need to scale the rates involved in x
+            int m = lcm(n,r);
+            *rate = m/n;
+            E = multRateEnv(m/r, E);
+        }
+
+    } else if ( isSigDownSample(sig, w, x) )  {
+
+        // -- rate(down(n,x) = rate(x)/n
+
+        int n = checkSignalDenotesSize(w, sig);
+
+        int r; inferreRate(x, &r, E);
+
+        if ((r%n) == 0) {
+            // fine, the rate of x can be divided by n
+            // (note: this is compatible with r==0 indicating that x has no rate)
+            *rate = r/n;
+        } else {
+            // we need to scale the rates involved in x
+            int m = lcm(n,r);
+            *rate = m/n;
+            E = multRateEnv(m/r, E);
+        }
+
+    } else if ( isSigUpSample(sig, w, x) )  {
+
+        // -- rate(up(n,x) = rate(x)*n
+
+        int n = checkSignalDenotesSize(w, sig);
+        int r; inferreRate(x, &r, E);
+        *rate = r*n;
+
+    } else if ( isSigSerialize(sig, x)) {
+
+        // -- rate(serialize(x) = rate(x)*n    [with Type(x) = vector(n,T)]
+
+        VectorType* vt = isVectorType(getCertifiedSigType(x)); assert(vt);
+
+        int r; inferreRate(x, &r, E);
+        *rate = vt->size() * r;
+
+    } else if ( isSigInput(sig, &in)) {
+
+        // -- rate(input(x)) = 1
+
+        *rate   = 1;
+        E       = addRateEnv(sig,1,nil);
+
+    } else if (isProj(sig,&i,rsig) && isRec(rsig, id, body)) {
+
+        // -- rate(proj(i, x=(E0,E1,...))) = 1
+
+        *rate   = 1;
+        E       = addRateEnv(sig,1,nil);
+
+    } else {
+
+        // -- rate(op())        = 1
+        // -- rate(op(s1, s2))  = lcm(rate(s1), rate(s2))
+
+        vector<Tree> subsigs;
+        unsigned int n = getSubSignals(sig, subsigs, false);
+
+        if (n == 0) {
+            // -- rate(op())        = 1
+           *rate = 1;
+           E  = nil;
+
+        } else {
+            // -- rate(op(s1, s2))  = lcm(rate(s1), rate(s2))
+
+            vector<int>     subrates(n);
+            vector<Tree>    subenvs(n);
+
+            int lcmrate = 1;
+            for (unsigned int i=0; i<n; i++) {
+                inferreRate(subsigs[i], &subrates[i], subenvs[i]);
+                lcmrate = lcm(subrates[i], lcmrate);
+            }
+
+            // Try to merge all (scaled) rate environments
+            Tree M = nil;
+            bool success = false;
+
+            for (unsigned int i=0; i<n; i++) {
+                M = mergeRateEnvironment(M, multRateEnv(lcmrate/subrates[i], subenvs[i]), success);
+                if (! success) {
+                    // merge failed
+                    *rate = 0; E = nil;
+                    return;
+                }
+            }
+            // merge successful
+            *rate = lcmrate; E = M;
+        }
+    }
+}
+
+
+/**
+  * Try to add a rate environment E1 to a list of independent rate environments LE
+  * Returns a list of independent rate environments
+  */
+static Tree addToMultiRates(Tree E1, Tree LE, bool& success);
+static Tree TRACED_addToMultiRates(Tree E1, Tree LE, bool& success);
+
+static Tree addToMultiRates(Tree E1, Tree LE, bool& success)
+{
+    TRACE(cerr << ++TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ")" << endl);
+    Tree result = TRACED_addToMultiRates(E1, LE, success);
+    if (success) {
+        TRACE(cerr << --TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ") -> " << *result << endl);
+    } else {
+        TRACE(cerr << --TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ") -> FAILED" << endl);
+    }
+    return result;
+}
+
+
+static Tree TRACED_addToMultiRates(Tree E1, Tree LE, bool& success)
+{
+    if (isNil(LE)) {
+        success = true;
+        return cons(E1,nil);
+    } else {
+        Tree E2 = hd(LE);
+        if (areRatesIndependent(E1,E2)) {
+            return cons(E2, addToMultiRates(E1, tl(LE), success));
+        } else {
+            int n1, n2;
+            if (areRatesCompatible(E1, E2, n1, n2)) {
+                Tree M = mergeRateEnvironment(multRateEnv(n1,E1), multRateEnv(n2,E2), success);
+                if (success) {
+                    return addToMultiRates(M, tl(LE), success);
+                } else {
+                    return nil;
+                }
+            } else {
+                return nil;
+            }
+        }
+    }
+}
+
+
+
+RateInferrer::RateInferrer(Tree lsig)
+{
+    TRACE(cerr << "ENTRE RateInferrer constructor of " << *lsig << endl);
+    if (! (isList(lsig) | isNil(lsig))) {
+        lsig = cons(lsig,nil);
+    }
+    fFullList = addRecursiveSignals(lsig);
+    fRateEnv = inferreMultiRates(lsig, fSuccess);
+    if (fSuccess) {
+        // nit the rate properties for the expressions in the environment
+        for (Tree L=fRateEnv; isList(L); L = tl(L)) {
+            Tree p = hd(L);
+            fRateProperty.set(hd(p),tree2int(tl(p)));
+        }
+    }
+    TRACE(cerr << "EXIT RateInferrer constructor" << *lsig << endl);
+}
+
+// returns the rate of sig assuming that sig is a subexpression of lsig
+int RateInferrer::rate(Tree sig)
+{
+    int     r;
+
+    if (!fSuccess) {
+        return 0;
+    } else if (fRateProperty.get(sig, r)) {
+        return r;
+    } else {
+        r = computeRate(sig);
+        fRateProperty.set(sig, r);
+        return r;
+    }
+}
+
+int RateInferrer::computeRate(Tree sig)
+{
+    Tree    n, x, rsig, id, body;
+    int     i;
+
+    if ( isSigInput(sig, &i)) {
+
+        TRACE(cerr << "ERROR: Input " << i << " should have a rate" << endl);
+        return 0;
+
+    } else if ( isProj(sig,&i,rsig) && isRec(rsig, id, body) ) {
+
+        TRACE(cerr << "ERROR: Recursive signal " << *sig << " should have a rate" << endl);
+        return 0;
+
+    } else if ( isSigVectorize(sig, n, x) ) {
+
+        VectorType* vt = isVectorType(getCertifiedSigType(sig));
+        assert(vt);
+        return rate(x) / vt->size();
+
+    } else if ( isSigSerialize(sig, x)) {
+
+        VectorType* vt = isVectorType(getCertifiedSigType(x));
+        assert(vt);
+        return vt->size() * rate(x);
+
+    } else if ( isSigUpSample(sig, n, x) ) {
+
+        int i = checkSignalDenotesSize(n,sig);
+        return rate(x) * i;
+
+    } else if ( isSigDownSample(sig, n, x) ) {
+
+        int i = checkSignalDenotesSize(n,sig);
+        int r = rate(x);
+        assert(r%i == 0);
+        return r/i;
+
+    } else {
+
+        vector<Tree> subsigs;
+        vector<int> subrates;
+        int n = getSubSignals(sig, subsigs, false);
+        if (n == 0) {
+            // we don't depend of any subsignals, then the rate is 1
+            return 1;
+        } else {
+            // we depend on subsignals, the rate is the highest one
+            // moreover the highest one is a multiple of all other
+            // rates
+            int maxrate = 1;
+            int lcmrate = 1;
+            for (unsigned int i=0; i<subsigs.size(); i++) {
+                int r = rate(subsigs[i]);
+                maxrate = max(r, maxrate);
+                lcmrate = lcm(r, lcmrate);
+                if (lcmrate != maxrate) {
+                    return 0; // rates of arguments are incompatible
+                }
+            }
+            return maxrate;
+        }
+    }
+}
+
+