use of gov.sandia.n2a.language.Function in project n2a by frothga.
the class Variable method flattenExpressions.
public void flattenExpressions(Variable v) {
if (assignment != v.assignment && !(// This line and the next say that * and / are compatible with each other, so ignore that case.
(assignment == MULTIPLY && v.assignment == DIVIDE) || (assignment == DIVIDE && v.assignment == MULTIPLY))) {
Backend.err.get().println("WARNING: Flattened variable " + v.container.prefix() + "." + v.nameString() + " has different combining operator than target (" + container.prefix() + "." + nameString() + "). Resolving in favor of higher-precedence operator.");
v.assignment = assignment = Math.max(v.assignment, assignment);
}
if (v.assignment == REPLACE) {
// We want equations from the lower level to override any pre-existing equations in the upper level.
// Why? Because the lower-level equations represent an elaboration of the model, and are thus more specific.
// Note that Internal executes contained populations after the upper-level equations, so the contained
// populations take precedence even without flattening.
NavigableSet<EquationEntry> equations0 = equations;
equations = new TreeSet<EquationEntry>();
// First add the lower-level equations, so they take precedence.
for (EquationEntry e2 : v.equations) add(e2);
for (EquationEntry e0 : equations0) add(e0);
} else {
// For combiners, it is necessary to create new equations for every combination of conditions.
// Of course, unconditional equations and equations with matching conditions can be combined more directly.
// First step is to augment both equation sets with an unconditional form, if they lack it.
EquationEntry query = new EquationEntry(this, "");
EquationEntry e = find(query);
// expression and condition are null; we deal with this below
if (e == null)
add(query);
query = new EquationEntry(v, "");
e = v.find(query);
if (e == null)
v.add(query);
NavigableSet<EquationEntry> equations0 = equations;
equations = new TreeSet<EquationEntry>();
for (EquationEntry e0 : equations0) {
for (EquationEntry e1 : v.equations) {
if (// Condition strings are exactly the same. TODO: compare ASTs for actual logic equivalence.
e0.compareTo(e1) == 0) {
e = new EquationEntry(this, "");
e.condition = e0.condition;
} else if (e0.condition == null) {
// If so, then only those equations should be merged, so skip this one.
if (find(e1) != null)
continue;
e = new EquationEntry(this, "");
e.condition = e1.condition;
} else if (e1.condition == null) {
// Check if e0.condition exists in v.equations
if (v.find(e0) != null)
continue;
e = new EquationEntry(this, "");
e.condition = e0.condition;
} else {
e = new EquationEntry(this, "");
AND and = new AND();
e.condition = and;
and.operand0 = e0.condition;
and.operand1 = e1.condition;
}
if (e.condition != null)
e.ifString = e.condition.render();
// merge expressions
if (e0.expression == null) {
// which could also be null
e.expression = e1.expression;
} else if (e1.expression == null) {
e.expression = e0.expression;
} else // Both expressions exist
{
OperatorBinary op = null;
Function f = null;
switch(v.assignment) {
case ADD:
op = new Add();
break;
case MULTIPLY:
op = new Multiply();
break;
case DIVIDE:
op = new Divide();
break;
case MIN:
f = new Min();
break;
case MAX:
f = new Max();
break;
}
if (op != null) {
op.operand0 = e0.expression;
op.operand1 = e1.expression;
e.expression = op;
} else if (f != null) {
f.operands[0] = e0.expression;
f.operands[1] = e1.expression;
e.expression = f;
}
}
if (e.expression != null)
equations.add(e);
}
}
}
v.equations.clear();
}
use of gov.sandia.n2a.language.Function in project n2a by frothga.
the class JobC method generateStatic.
public void generateStatic(final EquationSet s, final StringBuilder result) {
for (EquationSet p : s.parts) generateStatic(p, result);
// Generate static definitions
final BackendDataC bed = (BackendDataC) s.backendData;
class CheckStatic extends Visitor {
public boolean global;
public boolean visit(Operator op) {
if (op instanceof Constant) {
Type m = ((Constant) op).value;
if (m instanceof Matrix) {
Matrix A = (Matrix) m;
int rows = A.rows();
int cols = A.columns();
String matrixName = "Matrix" + matrixNames.size();
matrixNames.put(op, matrixName);
if (rows == 3 && cols == 1)
result.append("Vector3 " + matrixName + " = Matrix<float>");
else
result.append("Matrix<float> " + matrixName);
result.append(" (\"" + A + "\");\n");
}
// Don't try to descend tree from here
return false;
}
if (op instanceof Function) {
Function f = (Function) op;
if (// We need to auto-generate the column name.
f instanceof Output && f.operands.length < 3) {
String stringName = "columnName" + stringNames.size();
stringNames.put(op, stringName);
if (global) {
bed.setGlobalNeedPath(s);
bed.globalColumns.add(stringName);
} else {
bed.setLocalNeedPath(s);
bed.localColumns.add(stringName);
}
}
// Detect functions that need static handles
if (f.operands.length > 0) {
Operator operand0 = f.operands[0];
if (operand0 instanceof Constant) {
Constant c = (Constant) operand0;
Type o = c.value;
if (o instanceof Text) {
String fileName = ((Text) o).value;
if (op instanceof ReadMatrix) {
if (!matrixNames.containsKey(fileName)) {
String matrixName = "Matrix" + matrixNames.size();
matrixNames.put(fileName, matrixName);
result.append("MatrixInput * " + matrixName + " = matrixHelper (\"" + fileName + "\");\n");
}
} else if (f instanceof Input) {
if (!inputNames.containsKey(fileName)) {
String inputName = "Input" + inputNames.size();
inputNames.put(fileName, inputName);
result.append("InputHolder * " + inputName + " = inputHelper (\"" + fileName + "\");\n");
}
} else if (f instanceof Output) {
if (!outputNames.containsKey(fileName)) {
String outputName = "Output" + outputNames.size();
outputNames.put(fileName, outputName);
result.append("OutputHolder * " + outputName + " = outputHelper (\"" + fileName + "\");\n");
}
}
}
} else // Dynamic file name (no static handle)
{
if (f instanceof ReadMatrix) {
matrixNames.put(op, "Matrix" + matrixNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
} else if (f instanceof Input) {
inputNames.put(op, "Input" + inputNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
} else if (f instanceof Output) {
outputNames.put(op, "Output" + outputNames.size());
stringNames.put(operand0, "fileName" + stringNames.size());
}
}
}
// Functions could be nested, so continue descent.
return true;
}
return true;
}
}
CheckStatic checkStatic = new CheckStatic();
for (Variable v : s.ordered) {
checkStatic.global = v.hasAttribute("global");
v.visit(checkStatic);
}
}
use of gov.sandia.n2a.language.Function 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;
}
ReplaceInit replaceInit = new ReplaceInit();
for (final Variable v : variables) {
// Note: some variables get tagged "initOnly" by other means, so don't re-process
if (v.hasAny(new String[] { "initOnly", "constant", "dummy" }))
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;
for (EquationEntry e : v.equations) {
if (e.condition == null) {
firesDuringInit++;
firesDuringUpdate++;
update = e;
} else {
// init
replaceInit.init = 1;
replaceInit.live = 1;
Operator test = e.condition.deepCopy().transform(replaceInit).simplify(v);
boolean fires = true;
if (test instanceof Constant) {
Constant c = (Constant) test;
if (c.value instanceof Scalar && ((Scalar) c.value).value == 0)
fires = false;
}
if (fires)
firesDuringInit++;
// update
replaceInit.init = 0;
replaceInit.live = 1;
test = e.condition.deepCopy().transform(replaceInit).simplify(v);
fires = true;
if (test instanceof Constant) {
Constant c = (Constant) test;
if (c.value instanceof Scalar && ((Scalar) c.value).value == 0)
fires = false;
}
if (fires) {
firesDuringUpdate++;
update = e;
}
}
}
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 && v.assignment == Variable.REPLACE) {
// Determine if our single update equation depends only on constants and initOnly variables
class VisitInitOnly extends Visitor {
// until something falsifies it
boolean isInitOnly = true;
public boolean visit(Operator op) {
if (isInitOnly) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
// constant has already been replaced. Therefore, only the "initOnly" attribute matters here.
if (av.reference == null || av.reference.variable == null)
isInitOnly = false;
Variable r = av.reference.variable;
if (!r.hasAttribute("initOnly"))
isInitOnly = false;
// Also verify that the variables we depend on are available during the appropriate phase of init
if (// Note that temporaries are always available.
isInitOnly && !r.hasAttribute("temporary")) {
if (// we are a $variable, so we can only depend on $index and $init
v.name.startsWith("$")) {
if (!"$index,$init,$live".contains(r.name))
isInitOnly = false;
} else // we are a regular variable, so can only depend on $variables
{
if (!r.name.startsWith("$"))
isInitOnly = false;
}
}
} else if (op instanceof Function) {
Function f = (Function) op;
if (!f.canBeInitOnly())
isInitOnly = false;
}
}
return isInitOnly;
}
}
VisitInitOnly visitor = new VisitInitOnly();
if (update.condition != null)
update.condition.visit(visitor);
if (visitor.isInitOnly) {
update.expression.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