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");
}
}
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);
}
Aggregations