use of gov.sandia.n2a.language.Operator in project n2a by frothga.
the class EquationSet method findLethalVariables.
public void findLethalVariables() {
for (EquationSet s : parts) {
s.findLethalVariables();
}
// Determine if $n can decrease
Variable n = find(new Variable("$n"));
if (n != null) {
for (EquationEntry e : n.equations) {
// Even if each expression is constant, $n could still change during operation if it is a multi-conditional.
if (e.condition != null && !(e.condition instanceof Constant)) {
lethalN = true;
break;
}
if (!(e.expression instanceof Constant)) {
lethalN = true;
break;
}
}
}
// Conservatively, assume any order of derivative could decrease $n.
if (find(new Variable("$n", 1)) != null)
lethalN = true;
// Determine if $p has an assignment less than 1
Variable p = find(new Variable("$p"));
if (p != null) {
// Determine if any equation is capable of setting $p to something besides 1
ReplacePhaseIndicators replacePhase = new ReplacePhaseIndicators();
for (EquationEntry e : p.equations) {
if (e.expression.isScalar() && e.expression.getDouble() >= 1)
continue;
// If this occurs anywhere but connect, then $p is lethal.
if (e.condition != null) {
replacePhase.init = 1;
Operator test = e.condition.deepCopy().transform(replacePhase).simplify(p, true);
if (// Does not fire during init phase
test.isScalar() && test.getDouble() == 0) {
replacePhase.init = 0;
test = e.condition.deepCopy().transform(replacePhase).simplify(p, true);
// Does not fire during update phase
if (test.isScalar() && test.getDouble() == 0)
continue;
}
}
lethalP = true;
break;
}
}
if (find(new Variable("$p", 1)) != null)
lethalP = true;
// Determine if any splits kill this part
for (// my splits are the parts I can split into
ArrayList<EquationSet> split : // my splits are the parts I can split into
splits) {
if (!split.contains(this)) {
lethalType = true;
break;
}
}
}
use of gov.sandia.n2a.language.Operator in project n2a by frothga.
the class EquationSet method purgeInitOnlyTemporary.
/**
* findInitOnly() propagates the "initOnly" attribute through temporaries, but the final
* attribute set of a variable cannot contain both, as they are mutually contradictory.
* "initOnly" requires storage, while "temporary" forbids it. We give "temporary"
* precedence, because we prioritize memory efficiency over time efficiency.
*/
public void purgeInitOnlyTemporary() {
for (EquationSet p : parts) p.purgeInitOnlyTemporary();
for (Variable v : variables) {
if (v.hasAll("temporary", "initOnly")) {
v.removeAttribute("initOnly");
// If there are no regular update equations, then convert init equations into
// regular update equations, because their values would continue to hold if the
// variable were stored.
// Test for presence of regular update equations.
// See findInitOnlyRecursive() for similar code.
boolean firesDuringUpdate = false;
ReplacePhaseIndicators replacePhase = new ReplacePhaseIndicators();
replacePhase.init = 0;
for (EquationEntry e : v.equations) {
if (e.condition == null) {
firesDuringUpdate = true;
break;
} else {
Operator test = e.condition.deepCopy().transform(replacePhase).simplify(v, true);
if (!test.isScalar() || test.getDouble() != 0) {
firesDuringUpdate = true;
break;
}
}
}
// See Variable.simplify() for similar code.
if (!firesDuringUpdate) {
class ReplaceInit implements Transformer {
public Operator transform(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
if (av.name.equals("$init"))
return new Constant(1);
}
return null;
}
}
;
ReplaceInit replaceInit = new ReplaceInit();
TreeSet<EquationEntry> nextEquations = new TreeSet<EquationEntry>();
for (EquationEntry e : v.equations) {
e.condition = e.condition.transform(replaceInit).simplify(v, false);
e.ifString = e.condition.render();
if (e.condition.isScalar()) {
// but only one will remain after adding to nextEquations.
if (// Will always fire.
e.condition.getDouble() != 0) {
e.condition = null;
e.ifString = "";
nextEquations.add(e);
}
} else {
nextEquations.add(e);
}
}
v.equations = nextEquations;
}
}
}
}
use of gov.sandia.n2a.language.Operator in project n2a by frothga.
the class EquationSet method findExternal.
/**
* Marks variables with "externalRead" and "externalWrite", as needed.
* Determines whether an external write should be evaluated in the local or global context.
* Depends on results of:
* resolveLHS(), resolveRHS() -- Establishes references and dependencies between variables.
* flatten() -- Changes references and dependencies. In some cases, folds expressions together so dependencies go away.
*/
public void findExternal() {
for (EquationSet p : parts) p.findExternal();
class Externalizer implements Visitor {
Variable v;
boolean allGlobal;
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable target = av.reference.variable;
if (// v references something other than itself, which implies that the target is outside this equation set.
target.container != v.container) {
target.addAttribute("externalRead");
target.removeAttribute("temporary");
}
if (!target.hasAny("global", "constant"))
allGlobal = false;
}
return true;
}
}
Externalizer externalizer = new Externalizer();
for (Variable v : variables) {
externalizer.v = v;
externalizer.allGlobal = true;
v.visit(externalizer);
// for convenience
Variable vr = v.reference.variable;
if (vr != v) {
v.addAttribute("reference");
vr.addAttribute("externalWrite");
vr.removeAttribute("temporary");
if (externalizer.allGlobal && !v.hasAttribute("local") && vr.hasAttribute("global")) {
v.addAttribute("global");
v.convertToGlobal();
}
}
}
}
use of gov.sandia.n2a.language.Operator 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.Operator in project n2a by frothga.
the class EquationSet method findInitOnlyRecursive.
public boolean findInitOnlyRecursive() {
boolean changed = false;
for (EquationSet s : parts) {
if (s.findInitOnlyRecursive())
changed = true;
}
ReplacePhaseIndicators replacePhase = new ReplacePhaseIndicators();
VisitInitOnly visitor = new VisitInitOnly();
for (final Variable v : variables) {
// unless it can be established that the value does not change after the init cycle of the target.
if (v.hasAny("initOnly", "constant", "dummy", "externalWrite", "reference"))
continue;
// Count equations
int firesDuringInit = 0;
int firesDuringUpdate = 0;
// If we have a single update equation, then we may still be initOnly if it depends only on constants or other initOnly variables. Save the update equation for analysis.
EquationEntry update = null;
EquationEntry init = null;
for (EquationEntry e : v.equations) {
// unless we can be absolutely certain it will not.
if (e.condition == null) {
firesDuringInit++;
firesDuringUpdate++;
update = e;
init = e;
} else {
// The following tests do simplification of the expression, rather than substitution
// with a fake Instance. We don't really know the values of variables until runtime.
// To be completely certain of an expression's value, it must reduce to a Scalar using only
// values that we can know now (specifically, the state of the phase indicators).
// init
replacePhase.init = 1;
Operator test = e.condition.deepCopy().transform(replacePhase).simplify(v, true);
if (!test.isScalar() || test.getDouble() != 0) {
firesDuringInit++;
init = e;
}
// update
replacePhase.init = 0;
test = e.condition.deepCopy().transform(replacePhase).simplify(v, true);
if (!test.isScalar() || test.getDouble() != 0) {
firesDuringUpdate++;
update = e;
}
}
}
// Used in the last case below.
int count = v.equations.size();
if (firesDuringUpdate == 0) {
if (firesDuringInit > 0 && v.derivative == null) {
v.addAttribute("initOnly");
changed = true;
}
} else if (// last chance to be "initOnly": must be exactly one equation that is not a combining operator
firesDuringUpdate == 1 && firesDuringInit == 1 && update == init && v.assignment == Variable.REPLACE) {
// Determine if our single update equation depends only on constants and initOnly variables
visitor.isInitOnly = true;
if (update.condition != null)
update.condition.visit(visitor);
if (visitor.isInitOnly)
update.expression.visit(visitor);
if (visitor.isInitOnly) {
v.addAttribute("initOnly");
changed = true;
}
} else if (count > 0 && firesDuringInit == count && firesDuringUpdate == count) {
visitor.isInitOnly = true;
for (EquationEntry e : v.equations) e.visit(visitor);
if (visitor.isInitOnly) {
v.addAttribute("initOnly");
changed = true;
}
}
if (firesDuringUpdate > 0 && v.derivative != null && !v.hasAttribute("initOnly"))
v.addAttribute("updates");
else
v.removeAttribute("updates");
}
return changed;
}
Aggregations