use of gov.sandia.n2a.language.operator.Add 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.operator.Add in project n2a by frothga.
the class Output method isStringExpression.
/**
* Determines if the given operator is a string expression.
* This is the case if any operator it depends on is a string.
* If an operand is a variable, then its equations must contain a string.
*/
public static boolean isStringExpression(Variable v, Operator op) {
class StringVisitor extends Visitor {
boolean foundString;
Variable from;
public StringVisitor(Variable from) {
this.from = from;
from.visited = null;
}
public boolean visit(Operator op) {
if (op instanceof Constant) {
Constant c = (Constant) op;
if (c.value instanceof Text)
foundString = true;
return false;
}
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable v = av.reference.variable;
// Prevent infinite recursion
Variable p = from;
while (p != null) {
if (p == v)
return false;
p = p.visited;
}
v.visited = from;
from = v;
v.visit(this);
from = v.visited;
return false;
}
// no reason to dig any further
if (foundString)
return false;
// Add is the only operator that can propagate string values. All other operators and functions return scalars or matrices.
return op instanceof Add;
}
}
StringVisitor visitor = new StringVisitor(v);
op.visit(visitor);
return visitor.foundString;
}
use of gov.sandia.n2a.language.operator.Add in project n2a by frothga.
the class JobC method prepareDynamicObjects.
/**
* Build complex sub-expressions into a single local variable that can be referenced by the equation.
*/
public void prepareDynamicObjects(Operator op, final CRenderer context, final boolean init, final String pad) throws Exception {
// Pass 1 -- Strings and matrix expressions
Visitor visitor1 = new Visitor() {
public boolean visit(Operator op) {
if (op instanceof BuildMatrix) {
BuildMatrix m = (BuildMatrix) op;
int rows = m.getRows();
int cols = m.getColumns();
String matrixName = "Matrix" + matrixNames.size();
matrixNames.put(m, matrixName);
if (rows == 3 && cols == 1)
context.result.append(pad + "Vector3 " + matrixName + ";\n");
else
context.result.append(pad + "Matrix<float> " + matrixName + " (" + rows + ", " + cols + ");\n");
for (int r = 0; r < rows; r++) {
if (cols == 1) {
context.result.append(pad + matrixName + "[" + r + "] = ");
m.operands[0][r].render(context);
context.result.append(";\n");
} else {
for (int c = 0; c < cols; c++) {
context.result.append(pad + matrixName + "(" + r + "," + c + ") = ");
m.operands[c][r].render(context);
context.result.append(";\n");
}
}
}
return false;
}
if (op instanceof Add) {
Add a = (Add) op;
String stringName = stringNames.get(a);
if (stringName != null) {
context.result.append(pad + "String " + stringName + ";\n");
for (Operator o : flattenAdd(a)) {
context.result.append(pad + stringName + " += ");
o.render(context);
context.result.append(";\n");
}
return false;
}
}
return true;
}
};
op.visit(visitor1);
// Pass 2 -- Input functions
Visitor visitor2 = new Visitor() {
public boolean visit(Operator op) {
if (op instanceof ReadMatrix) {
ReadMatrix r = (ReadMatrix) op;
if (!(r.operands[0] instanceof Constant)) {
String matrixName = matrixNames.get(r);
String stringName = stringNames.get(r.operands[0]);
context.result.append(pad + "MatrixInput * " + matrixName + " = matrixHelper (" + stringName + ");\n");
}
return false;
}
if (op instanceof Input) {
Input i = (Input) op;
if (!(i.operands[0] instanceof Constant)) {
String inputName = inputNames.get(i);
String stringName = stringNames.get(i.operands[0]);
context.result.append(pad + "InputHolder * " + inputName + " = inputHelper (" + stringName + ");\n");
if (!context.global) {
context.result.append(pad + inputName + "->epsilon = " + resolve(context.bed.dt.reference, context, false) + " / 1000;\n");
}
// Detect time flag
String mode = "";
if (i.operands.length > 3) {
// just assuming it's a constant string
mode = i.operands[3].toString();
} else if (i.operands[1] instanceof Constant) {
Constant c = (Constant) i.operands[1];
if (c.value instanceof Text)
mode = c.toString();
}
if (mode.contains("time")) {
context.result.append(pad + inputName + "->time = true;\n");
}
}
// I/O functions can be nested
return true;
}
if (op instanceof Output) {
Output o = (Output) op;
if (!(o.operands[0] instanceof Constant)) {
String outputName = outputNames.get(o);
String stringName = stringNames.get(o.operands[0]);
context.result.append(pad + "OutputHolder * " + outputName + " = outputHelper (" + stringName + ");\n");
// Detect raw flag
if (o.operands.length > 3) {
Operator op3 = o.operands[3];
if (op3 instanceof Constant) {
if (op3.toString().contains("raw")) {
context.result.append(pad + outputName + "->raw = true;\n");
}
}
}
}
return true;
}
return true;
}
};
op.visit(visitor2);
}
Aggregations