Search in sources :

Example 1 with OperatorLogical

use of gov.sandia.n2a.language.OperatorLogical in project n2a by frothga.

the class EquationSet method determinePoll.

/**
 *        Checks if connection requires polling.
 *        The result is a metadata tag on $p. If the tag exists, polling is required and the tag gives the time period
 *        (0 for every cycle, >0 for quantity of time to complete one poll).
 *        The user can specify this tag ahead of time. Specifying -1 will suppress polling even if it is required.
 *        Specifying poll >= 0 will not force polling if it is not required. Instead, the tag will be cleared by this function.
 *        Depends on results of: findInitOnly()
 *        Must be run before purgeInitOnlyTemporary(), because that function removes information critical for our processing.
 *        findConnectionMatrix() will clear the metadata tag if it succeeds, because that kind of connection is a one-time process,
 *        no need for polling.
 */
public void determinePoll() {
    for (EquationSet s : parts) s.determinePoll();
    if (connectionBindings == null)
        return;
    Variable p = find(new Variable("$p"));
    if (p == null)
        return;
    // Look up metadata to determine polling period.
    // Default is full poll every cycle. After determinePoll() finishes, the default will be no polling. This simplifies later processing.
    String pollString = p.metadata.getOrDefault("0", "poll");
    double pollValue = new UnitValue(pollString).get();
    if (// Don't do analysis if polling is suppressed in any case.
    pollValue < 0) {
        p.metadata.clear("poll");
        return;
    }
    List<EquationEntry> fires = new ArrayList<EquationEntry>();
    // All equations in "fires" return 0 or 1.
    boolean firesBoolean = true;
    ReplacePhaseIndicators replacePhase = new ReplacePhaseIndicators();
    // And other indicators are 0
    replacePhase.connect = 1;
    for (EquationEntry e : p.equations) {
        // Assume a condition always fires, unless we can prove it does not.
        boolean couldFire = true;
        boolean alwaysFires = true;
        if (e.condition != null) {
            Operator test = e.condition.deepCopy().transform(replacePhase).simplify(p, true);
            if (test.isScalar())
                couldFire = alwaysFires = test.getDouble() != 0;
            else
                alwaysFires = false;
        }
        if (couldFire) {
            fires.add(e);
            Operator expression = e.expression.deepCopy().transform(replacePhase).simplify(p, true);
            if (expression.isScalar()) {
                double value = expression.getDouble();
                if (value != 0 && value != 1)
                    firesBoolean = false;
            } else {
                firesBoolean = false;
            }
        }
        if (alwaysFires)
            break;
    }
    if (// $p has default value (1 at connect)
    fires.isEmpty()) {
        p.metadata.clear("poll");
        return;
    }
    boolean needsPoll;
    if (fires.size() > 1) {
        // Multiple connect conditions means unpredictable, so needs polling.
        // The exception is if $p is initOnly and all equations are either 0 or 1.
        // In that case, polling is unneeded because the existence of the part is
        // already known at init time.
        System.out.println("fires " + fires.size() + " " + prefix());
        needsPoll = !p.hasAttribute("initOnly") || !firesBoolean;
    } else {
        // Determine if the single expression for $p requires polling.
        // The possibilities for NOT polling are:
        // * a Scalar that is either 1 or 0
        // * a boolean expression that depends on nothing more than initOnly variables
        // Everything else requires polling. For example:
        // * a Scalar in (0,1) -- requires random draw
        // * a boolean expression that can vary during regular updates
        EquationEntry e = fires.get(0);
        if (e.expression.isScalar()) {
            double value = e.expression.getDouble();
            needsPoll = value > 0 && value < 1;
        } else {
            // The default is to poll, unless we can prove that we don't need to.
            needsPoll = true;
            VisitInitOnly visitor = new VisitInitOnly();
            if (e.condition != null)
                e.condition.visit(visitor);
            if (visitor.isInitOnly)
                e.expression.visit(visitor);
            if (visitor.isInitOnly) {
                // We have an initOnly equation. Now determine if the result is in (0,1).
                // The only values we can be sure about are logical results, which are exactly 1 or 0, and therefore not in (0,1).
                needsPoll = !(e.expression instanceof OperatorLogical);
            }
        }
    }
    if (needsPoll) {
        // If poll is not otherwise specified, then do full poll at every cycle.
        if (p.metadata.child("poll") == null)
            p.metadata.set("0", "poll");
    } else {
        p.metadata.clear("poll");
    }
}
Also used : Operator(gov.sandia.n2a.language.Operator) AccessVariable(gov.sandia.n2a.language.AccessVariable) ArrayList(java.util.ArrayList) UnitValue(gov.sandia.n2a.language.UnitValue) OperatorLogical(gov.sandia.n2a.language.OperatorLogical)

Example 2 with OperatorLogical

use of gov.sandia.n2a.language.OperatorLogical in project n2a by frothga.

the class RendererCfp method render.

public boolean render(Operator op) {
    if (op == latch) {
        latch = null;
        return super.render(op);
    }
    // one or more exponent parameters to the end of the usual function call.
    if (operatorsWithExponent.contains(op.getClass()))
        return super.render(op);
    // These are ordered to trap specific cases before more general ones.
    if (op instanceof OperatorLogical) {
        // Return the boolean itself if being consumed by a condition or by another logical operator.
        if (op.parent == null || op.parent instanceof OperatorLogical)
            return super.render(op);
        result.append("(");
        escalate(op);
        result.append(" ? ");
        if (op instanceof NOT) {
            result.append("0 : " + print(1, op.exponentNext) + ")");
        } else {
            result.append(print(1, op.exponentNext) + " : 0)");
        }
        return true;
    }
    if (op instanceof Multiply || op instanceof MultiplyElementwise) {
        OperatorBinary b = (OperatorBinary) op;
        // Explanation of shift -- The exponent of the result will be the sum of the exponents
        // of the two operands. That new exponent will be associated with bit position 2*MSB.
        // We want the exponent at bit position MSB.
        // Exponent at MSB position after a direct integer multiply.
        int exponentRaw = b.operand0.exponentNext + b.operand1.exponentNext - Operator.MSB;
        int shift = exponentRaw - b.exponentNext;
        if (shift == 0) {
            escalate(b);
        } else {
            if (b.getType() instanceof Matrix) {
                if (shift > 0) {
                    result.append("shift (");
                    escalate(b);
                    result.append(", " + shift + ")");
                } else {
                    if (b instanceof Multiply || b.operand0.isScalar() || b.operand1.isScalar()) {
                        result.append("multiply (");
                    } else // MultiplyElementwise and both operands are matrices
                    {
                        result.append("multiplyElementwise (");
                    }
                    if (b.operand0.isScalar()) {
                        // Always put the scalar in second position, so we need only one form of multiply().
                        b.operand1.render(this);
                        result.append(", ");
                        b.operand0.render(this);
                    } else {
                        b.operand0.render(this);
                        result.append(", ");
                        b.operand1.render(this);
                    }
                    result.append(", " + -shift + ")");
                }
            } else {
                if (shift > 0) {
                    result.append("(");
                    escalate(b);
                    result.append(" << " + shift);
                    result.append(")");
                } else {
                    if (!parentAccepts64bit(b))
                        result.append("(int32_t) ");
                    result.append("(");
                    if (!provides64bit(b.operand0))
                        result.append("(int64_t) ");
                    escalate(b);
                    result.append(" >> " + -shift);
                    result.append(")");
                }
            }
        }
        return true;
    }
    if (op instanceof Divide) {
        Divide d = (Divide) op;
        // Explanation of shift -- In a division, the quotient is effectively down-shifted by
        // the number of bits in the denominator, and its exponent is the difference between
        // the exponents of the numerator and denominator.
        // Exponent in MSB from a direct integer division.
        int exponentRaw = d.operand0.exponentNext - d.operand1.exponentNext + Operator.MSB;
        int shift = exponentRaw - d.exponentNext;
        if (shift == 0) {
            escalate(d);
        } else {
            if (d.getType() instanceof Matrix) {
                if (shift > 0) {
                    result.append("divide (");
                    d.operand0.render(this);
                    result.append(", ");
                    d.operand1.render(this);
                    result.append(", " + shift + ")");
                } else {
                    result.append("shift (");
                    escalate(d);
                    result.append(", " + shift + ")");
                }
            } else {
                if (shift > 0) {
                    if (!parentAccepts64bit(d))
                        result.append("(int32_t) ");
                    result.append("((");
                    if (!provides64bit(d.operand0))
                        result.append("(int64_t) ");
                    // OperatorBinary.render() will add parentheses around operand0 if it has lower
                    // precedence than division. This includes the case where it has lower precedence
                    // than shift, so we are safe.
                    d.render(this, " << " + shift + ") / ");
                    result.append(")");
                } else {
                    result.append("(");
                    escalate(d);
                    result.append(" >> " + -shift + ")");
                }
            }
        }
        return true;
    }
    if (op instanceof Modulo) {
        Modulo m = (Modulo) op;
        int shift = m.exponent - m.exponentNext;
        if (m.operand0.exponentNext == m.operand1.exponentNext) {
            if (shift == 0)
                return super.render(m);
            result.append("(");
            escalate(m);
            result.append(printShift(shift) + ")");
        } else {
            if (shift != 0)
                result.append("(");
            result.append("modFloor (");
            m.operand0.render(this);
            result.append(", ");
            m.operand1.render(this);
            result.append(", " + m.operand0.exponentNext + ", " + m.operand1.exponentNext + ")");
            if (shift != 0)
                result.append(printShift(shift) + ")");
        }
        return true;
    }
    if (// Add, Subtract, Negate, Transpose
    op instanceof OperatorArithmetic) {
        int exponentOperand;
        if (op instanceof OperatorBinary)
            exponentOperand = ((OperatorBinary) op).operand0.exponentNext;
        else
            exponentOperand = ((OperatorUnary) op).operand.exponentNext;
        int shift = exponentOperand - op.exponentNext;
        if (shift == 0)
            return super.render(op);
        if (op.getType() instanceof Matrix) {
            result.append("shift (");
            escalate(op);
            result.append(", " + shift + ")");
        } else {
            result.append("(");
            // In C++, shift is just below addition in precedence.
            boolean needParens = op.precedence() > new Add().precedence();
            if (needParens)
                result.append("(");
            escalate(op);
            if (needParens)
                result.append(")");
            result.append(printShift(shift));
            result.append(")");
        }
        return true;
    }
    // These are listed in alphabetical order, with a catch-all at the end.
    if (// Actually just an operator, not a function
    op instanceof AccessVariable) {
        AccessVariable av = (AccessVariable) op;
        int shift = av.exponent - av.exponentNext;
        if (shift != 0) {
            if (av.getType() instanceof Matrix)
                result.append("shift ");
            result.append("(");
        }
        result.append(job.resolve(av.reference, this, false));
        if (useExponent && shift != 0) {
            if (av.getType() instanceof Matrix) {
                result.append(", " + shift);
            } else {
                result.append(printShift(shift));
            }
            result.append(")");
        }
        return true;
    }
    if (op instanceof Ceil) {
        Ceil f = (Ceil) op;
        Operator a = f.operands[0];
        // Ceil always sets operands[0].exponentNext to be same as f.exponentNext, so no shift is necessary.
        if (// LSB is above decimal, so ceil() operation is impossible.
        f.exponentNext >= Operator.MSB) {
            a.render(this);
        } else if (// All bits are below decimal
        f.exponentNext < 0) {
            result.append("0");
        } else {
            // Create a mask for bits below the decimal point.
            // When this mask is added to the number, it will add 1 to the first bit position
            // above the decimal if any bit is set under the mask. Afterward, used AND to remove
            // any residual bits below the decimal.
            // This works for both positive and negative numbers.
            int zeroes = Operator.MSB - f.exponentNext;
            int wholeMask = 0xFFFFFFFF << zeroes;
            int decimalMask = ~wholeMask;
            boolean needParens = a.precedence() >= new Add().precedence();
            result.append("(");
            if (needParens)
                result.append("(");
            a.render(this);
            if (needParens)
                result.append(")");
            result.append(" + " + decimalMask + " & " + wholeMask + ")");
        }
        return true;
    }
    if (op instanceof Cosine) {
        Cosine c = (Cosine) op;
        Operator a = c.operands[0];
        int shift = c.exponent - c.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("cos (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Event) {
        // See comment on OperatorLogical above. Since event() returns a boolean, we follow the same behavior here.
        if (op.parent == null || op.parent instanceof OperatorLogical)
            return super.render(op);
        Event e = (Event) op;
        int exponentRaw = Operator.MSB - e.eventType.valueIndex;
        int shift = exponentRaw - e.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("(flags & (" + bed.localFlagType + ") 0x1 << " + e.eventType.valueIndex + ")");
        if (shift != 0) {
            result.append(printShift(shift));
            result.append(")");
        }
        return true;
    }
    if (op instanceof Floor) {
        // See Ceil above for similar code.
        Floor f = (Floor) op;
        Operator a = f.operands[0];
        if (f.exponentNext >= Operator.MSB) {
            a.render(this);
        } else if (f.exponentNext < 0) {
            result.append("0");
        } else {
            // Mask off bits below the decimal point. This works for both positive and negative numbers.
            int zeroes = Operator.MSB - f.exponentNext;
            int wholeMask = 0xFFFFFFFF << zeroes;
            boolean needParens = a.precedence() >= new AND().precedence();
            result.append("(");
            if (needParens)
                result.append("(");
            a.render(this);
            if (needParens)
                result.append(")");
            result.append(" & " + wholeMask + ")");
        }
        return true;
    }
    if (op instanceof HyperbolicTangent) {
        HyperbolicTangent ht = (HyperbolicTangent) op;
        Operator a = ht.operands[0];
        int shift = ht.exponent - ht.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("tanh (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Round) {
        Round r = (Round) op;
        Operator a = r.operands[0];
        int shift = a.exponentNext - r.exponentNext;
        int decimalPlaces = Math.max(0, Operator.MSB - a.exponentNext);
        int mask = 0xFFFFFFFF << decimalPlaces;
        int half = 0;
        if (decimalPlaces > 0)
            half = 0x1 << decimalPlaces - 1;
        if (shift != 0)
            result.append("(");
        // Bitwise operators are low precedence, so we parenthesize them regardless.
        result.append("(");
        boolean needParens = a.precedence() > new Add().precedence();
        if (needParens)
            result.append("(");
        a.render(this);
        if (needParens)
            result.append(")");
        result.append(" + " + half + " & " + mask);
        // Close parens around bitwise operator
        result.append(")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (op instanceof Signum) {
        Signum s = (Signum) op;
        Operator a = s.operands[0];
        int one = 0x1 << Operator.MSB - s.exponentNext;
        boolean needParens = a.precedence() >= new LT().precedence();
        if (needParens)
            result.append("(");
        a.render(this);
        if (needParens)
            result.append(")");
        result.append(" < 0 ? " + -one + ":" + one + ")");
        return true;
    }
    if (op instanceof Sine) {
        Sine s = (Sine) op;
        Operator a = s.operands[0];
        int shift = s.exponent - s.exponentNext;
        if (shift != 0)
            result.append("(");
        result.append("sin (");
        a.render(this);
        result.append(", " + a.exponentNext + ")");
        if (shift != 0)
            result.append(printShift(shift) + ")");
        return true;
    }
    if (// AbsoluteValue, Grid, Max, Min
    op instanceof Function) {
        int shift = op.exponent - op.exponentNext;
        if (shift == 0)
            return super.render(op);
        if (op.getType() instanceof Matrix) {
            result.append("shift (");
            escalate(op);
            result.append(", " + shift + ")");
        } else {
            result.append("(");
            escalate(op);
            result.append(printShift(shift) + ")");
        }
        return true;
    }
    return super.render(op);
}
Also used : Add(gov.sandia.n2a.language.operator.Add) Operator(gov.sandia.n2a.language.Operator) LT(gov.sandia.n2a.language.operator.LT) Sine(gov.sandia.n2a.language.function.Sine) Divide(gov.sandia.n2a.language.operator.Divide) Function(gov.sandia.n2a.language.Function) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Matrix(gov.sandia.n2a.language.type.Matrix) HyperbolicTangent(gov.sandia.n2a.language.function.HyperbolicTangent) Multiply(gov.sandia.n2a.language.operator.Multiply) Round(gov.sandia.n2a.language.function.Round) OperatorArithmetic(gov.sandia.n2a.language.OperatorArithmetic) Floor(gov.sandia.n2a.language.function.Floor) AccessVariable(gov.sandia.n2a.language.AccessVariable) Modulo(gov.sandia.n2a.language.operator.Modulo) OperatorLogical(gov.sandia.n2a.language.OperatorLogical) MultiplyElementwise(gov.sandia.n2a.language.operator.MultiplyElementwise) OperatorBinary(gov.sandia.n2a.language.OperatorBinary) Signum(gov.sandia.n2a.language.function.Signum) NOT(gov.sandia.n2a.language.operator.NOT) AND(gov.sandia.n2a.language.operator.AND) Event(gov.sandia.n2a.language.function.Event) Ceil(gov.sandia.n2a.language.function.Ceil) Cosine(gov.sandia.n2a.language.function.Cosine)

Aggregations

AccessVariable (gov.sandia.n2a.language.AccessVariable)2 Operator (gov.sandia.n2a.language.Operator)2 OperatorLogical (gov.sandia.n2a.language.OperatorLogical)2 BuildMatrix (gov.sandia.n2a.language.BuildMatrix)1 Function (gov.sandia.n2a.language.Function)1 OperatorArithmetic (gov.sandia.n2a.language.OperatorArithmetic)1 OperatorBinary (gov.sandia.n2a.language.OperatorBinary)1 UnitValue (gov.sandia.n2a.language.UnitValue)1 Ceil (gov.sandia.n2a.language.function.Ceil)1 Cosine (gov.sandia.n2a.language.function.Cosine)1 Event (gov.sandia.n2a.language.function.Event)1 Floor (gov.sandia.n2a.language.function.Floor)1 HyperbolicTangent (gov.sandia.n2a.language.function.HyperbolicTangent)1 ReadMatrix (gov.sandia.n2a.language.function.ReadMatrix)1 Round (gov.sandia.n2a.language.function.Round)1 Signum (gov.sandia.n2a.language.function.Signum)1 Sine (gov.sandia.n2a.language.function.Sine)1 AND (gov.sandia.n2a.language.operator.AND)1 Add (gov.sandia.n2a.language.operator.Add)1 Divide (gov.sandia.n2a.language.operator.Divide)1