use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class Variable method simplify.
public boolean simplify() {
changed = false;
TreeSet<EquationEntry> nextEquations = new TreeSet<EquationEntry>();
EquationEntry defaultEquation = null;
EquationEntry alwaysTrue = null;
visited = null;
for (EquationEntry e : equations) {
if (e.expression != null) {
e.expression = e.expression.simplify(this, false);
}
if (e.condition == null) {
defaultEquation = e;
} else {
e.condition = e.condition.simplify(this, false);
e.ifString = e.condition.render();
}
if (e.expression instanceof AccessVariable) {
if (// Vacuous assignment
((AccessVariable) e.expression).reference.variable == this) {
// Simulator always copies value to next cycle when no equation fires,
// so there is never need for an explicit equation to do this.
changed = true;
e.expression.releaseDependencies(this);
if (e.condition == null)
defaultEquation = null;
else
e.condition.releaseDependencies(this);
continue;
}
} else if (e.condition instanceof Constant) {
if (// Will never fire
e.condition.getDouble() == 0) {
// Drop equation
changed = true;
if (e.expression != null)
e.expression.releaseDependencies(this);
continue;
} else // Will always fire
{
if (alwaysTrue == null)
alwaysTrue = e;
}
}
nextEquations.add(e);
}
if (// alwaysTrue requires an explicit (non-null) condition. The default equation is never selected.
!nextEquations.isEmpty() && nextEquations.first() == alwaysTrue) {
changed = true;
equations.clear();
equations.add(alwaysTrue);
for (EquationEntry e : nextEquations) {
if (e == alwaysTrue)
continue;
if (e.expression != null)
e.expression.releaseDependencies(this);
if (e.condition != null)
e.condition.releaseDependencies(this);
}
// Make the equation unconditional, since it always fires anyway.
EquationEntry e = equations.first();
e.condition = null;
e.ifString = "";
} else {
equations = nextEquations;
if (equations.isEmpty()) {
if (hasAttribute("temporary")) {
changed = true;
addAttribute("constant");
EquationEntry e = new EquationEntry(this, "");
equations.add(e);
// This is the default value for a temporary when no equation fires.
e.expression = new Constant(0);
}
} else if (equations.size() > 1) {
// contract with the user allows us to choose another equation instead.
if (defaultEquation != null && defaultEquation.expression instanceof Constant) {
nextEquations = new TreeSet<EquationEntry>();
nextEquations.add(defaultEquation);
// Add any equations that don't match the default equation.
for (EquationEntry e : equations) {
if (!(e.expression instanceof Constant) || !((Constant) defaultEquation.expression).value.equals(((Constant) e.expression).value)) {
nextEquations.add(e);
}
}
equations = nextEquations;
}
}
}
// Check if we have become eligible to execute in the global context.
// Only applies to external write references.
// for convenience
Variable rv = reference.variable;
if (rv.container != container && rv.hasAttribute("global") && !hasAny("global", "local")) {
class CheckGlobal implements Visitor {
boolean allGlobal = true;
public boolean visit(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
Variable target = av.reference.variable;
if (!target.hasAttribute("global"))
allGlobal = false;
}
return allGlobal;
}
}
CheckGlobal check = new CheckGlobal();
visit(check);
if (check.allGlobal) {
changed = true;
addAttribute("global");
convertToGlobal();
}
}
// This is a special case needed by some models that use pins.
if (// Note: uses can be null when "externalWrite" is set. This can happen during EquationSet.simplify().
uses != null && hasAttribute("externalWrite")) {
// Determine if self is constant.
boolean constant = equations.isEmpty();
boolean replaced = false;
double value = 0;
if (!constant && equations.size() == 1) {
EquationEntry e = equations.first();
if (e.condition == null && e.expression.isScalar()) {
constant = true;
replaced = true;
value = e.expression.getDouble();
}
}
if (constant) {
// Scan all our writers to see if they are constant.
for (Variable u : uses.keySet()) {
if ((assignment == ADD || assignment == MULTIPLY || assignment == DIVIDE) && !u.isSingletonRelativeTo(container)) {
// Can't predict how many of these operations there will be at run time,
// so can't predict result.
constant = false;
break;
}
if (!u.hasAttribute("constant")) {
constant = false;
break;
}
double uvalue = u.equations.first().expression.getDouble();
switch(assignment) {
case ADD:
value += uvalue;
break;
case MULTIPLY:
value *= uvalue;
break;
case DIVIDE:
value /= uvalue;
break;
case MIN:
value = Math.min(value, uvalue);
break;
case MAX:
value = Math.max(value, uvalue);
break;
default:
// REPLACE
if (value != uvalue) {
if (replaced) {
// Can only set the value once.
constant = false;
} else {
replaced = true;
value = uvalue;
}
}
}
if (!constant)
break;
}
}
if (constant) {
changed = true;
EquationEntry e;
if (equations.isEmpty()) {
e = new EquationEntry(this, "");
equations.add(e);
} else {
e = equations.first();
}
e.expression = new Constant(value);
addAttribute("constant");
removeAttribute("externalWrite");
removeDependencies();
}
}
return changed;
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class ChangeVariable method changeExpression.
public static String changeExpression(Operator expression, Object renamed, EquationSet container) {
Renderer r = new Renderer() {
public boolean render(Operator op) {
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
// Safety checks. We won't modify code unless we are confident that it can be done correctly.
// Must be fully resolved.
boolean safe = av.reference != null && av.reference.variable != null;
if (safe && av.reference.variable != renamed) {
// If the endpoint is not "renamed", then "renamed" must occur along the resolution path.
safe = false;
for (Object o : av.reference.resolution) {
if (o == renamed || o instanceof ConnectionBinding && ((ConnectionBinding) o).variable == renamed) {
safe = true;
break;
}
}
}
if (!safe) {
// This is the original text from the parser.
result.append(av.name);
return true;
}
// Walk the resolution path and emit a new variable name.
// The working target of resolution.
EquationSet current = container;
// Where the resolution actually is, based on emitted path so far.
EquationSet home = container;
String path = "";
int last = av.reference.resolution.size() - 1;
for (int i = 0; i <= last; i++) {
Object o = av.reference.resolution.get(i);
if (// We are following the containment hierarchy.
o instanceof EquationSet) {
EquationSet s = (EquationSet) o;
if (// descend into one of our contained populations
s.container == current) {
path += emitPath(home, current, s.name);
path += s.name + ".";
home = s;
}
// else ascend to our container
// The resolution for the ascent will be handled as soon as we need to reference a sub-part or variable.
current = s;
} else if (// We are following a part reference (which means we are a connection)
o instanceof ConnectionBinding) {
ConnectionBinding c = (ConnectionBinding) o;
String name = c.variable.nameString();
path += emitPath(home, current, name);
path += name + ".";
home = c.endpoint;
current = c.endpoint;
}
}
String name = av.reference.variable.nameString();
path += emitPath(home, current, name);
if (av.reference.variable.hasAttribute("instance")) {
// Get rid of trailing dot.
if (!path.isEmpty())
path = path.substring(0, path.length() - 1);
} else {
path += name;
}
result.append(path);
return true;
}
if (op instanceof Constant) {
Constant c = (Constant) op;
if (c.unitValue != null) {
result.append(c.unitValue);
return true;
}
}
return false;
}
};
expression.render(r);
return r.result.toString();
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class ChangeVariable method changeReferences.
/**
* Given variable "v", change all places where its code references "renamed".
* The name change is already embedded in the compiled model. We simply re-render the code.
* @param renamed The object that has a new name, for safety checks.
* This code is called by both ChangeVariable and ChangePart, so "renamed" can be either a Variable or an EquationSet.
* @param mv The database object associated with the compiled variable.
* @param v The compiled variable, which is part of the fully-compiled model.
*/
public static String changeReferences(Object renamed, MNode mv, Variable v) {
if (// single-line equation
v.equations.size() == 1) {
EquationEntry ee = v.equations.first();
String ifString = "";
if (ee.condition != null)
ifString = "@" + changeExpression(ee.condition, renamed, v.container);
mv.set(v.combinerString() + changeExpression(ee.expression, renamed, v.container) + ifString);
} else // multi-line equation
{
try // Mostly, to trap parse errors when mapping keys.
{
// Create a mapping from equation entries to database nodes.
// The idea here is to re-render the keys just like they have been for EquationEntry.ifString.
// This lets us use ifString as the key.
Map<String, MNode> map = new HashMap<String, MNode>();
for (MNode e : mv) {
String key = e.key();
if (!key.startsWith("@"))
continue;
key = key.substring(1);
if (!key.isEmpty())
key = Operator.parse(key).render();
map.put(key, e);
}
// Modify each equation entry and post to db.
for (EquationEntry ee : v.equations) {
MNode me = map.get(ee.ifString);
me.set(changeExpression(ee.expression, renamed, v.container));
String ifString = "@";
if (ee.condition != null)
ifString += changeExpression(ee.condition, renamed, v.container);
mv.move(me.key(), ifString);
}
} catch (Exception e) {
}
}
// The name of v can also change, since it might describe a path through a changed part or connection binding. See EquationSet.resolveLHS().
AccessVariable av = new AccessVariable(v.nameString());
av.reference = v.reference;
return changeExpression(av, renamed, v.container);
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class ExportJob method fakeConnectionTarget.
/**
* Replace any entries of the form A=connect() with A=N2A_fakePart.
*/
public static boolean fakeConnectionTarget(EquationSet s) {
boolean result = false;
for (Variable v : s.variables) {
if (// may be due to unreadable part names in connect()
v.equations.size() == 0) {
String value = s.source.get(v.nameString());
if (!Operator.containsConnect(value))
continue;
try {
v.add(new EquationEntry("N2A_fakePart"));
result = true;
} catch (Exception e) {
}
} else if (// could be a properly-parsed connect() line
v.equations.size() == 1) {
EquationEntry e = v.equations.first();
// connect() appears like AccessElement during initial parse
if (!(e.expression instanceof AccessElement))
continue;
AccessElement ae = (AccessElement) e.expression;
AccessVariable av = (AccessVariable) ae.operands[0];
if (!av.name.equals("connect"))
continue;
av.name = "N2A_fakePart";
e.expression = av;
result = true;
}
}
for (EquationSet p : s.parts) if (fakeConnectionTarget(p))
result = true;
return result;
}
use of gov.sandia.n2a.language.AccessVariable in project n2a by frothga.
the class RendererPython method render.
public boolean render(Operator op) {
if (op instanceof Add) {
Add a = (Add) op;
// Check if this is a string expression
if (a.name != null) {
result.append(a.name);
return true;
}
return false;
}
if (op instanceof AccessElement) {
AccessElement ae = (AccessElement) op;
ae.operands[0].render(this);
if (ae.operands.length >= 2) {
result.append("[");
ae.operands[1].render(this);
if (ae.operands.length >= 3) {
result.append(",");
ae.operands[2].render(this);
}
result.append("]");
}
return true;
}
if (op instanceof AccessVariable) {
AccessVariable av = (AccessVariable) op;
result.append(job.resolve(av.reference, this, false));
return true;
}
if (op instanceof AND) {
AND and = (AND) op;
and.render(this, " and ");
return true;
}
if (op instanceof BuildMatrix) {
BuildMatrix b = (BuildMatrix) op;
result.append(b.name);
return true;
}
if (op instanceof Constant) {
Constant c = (Constant) op;
Type o = c.value;
if (o instanceof Scalar) {
result.append(print(((Scalar) o).value));
return true;
}
if (o instanceof Text) {
result.append("\"" + o.toString() + "\"");
return true;
}
if (o instanceof Matrix) {
result.append(c.name);
return true;
}
return false;
}
if (op instanceof Event) {
Event e = (Event) op;
// The cast to bool gets rid of the specific numeric value from flags.
// If used in a numeric expression, it will convert to either 1 or 0.
result.append("bool (flags & 0x1 << " + e.eventType.valueIndex + ")");
return true;
}
if (op instanceof Exp) {
Exp e = (Exp) op;
Operator a = e.operands[0];
result.append("exp(");
a.render(this);
result.append(")");
return true;
}
if (op instanceof Gaussian) {
Gaussian g = (Gaussian) op;
result.append("gaussian(");
if (g.operands.length > 0) {
g.operands[0].render(this);
}
result.append(")");
return true;
}
if (op instanceof Grid) {
// TODO: needs library implementation
Grid g = (Grid) op;
boolean raw = g.operands.length >= 5 && g.operands[4].getString().contains("raw");
result.append("grid");
if (raw)
result.append("Raw");
result.append("(");
int count = Math.min(4, g.operands.length);
if (count > 0)
g.operands[0].render(this);
for (int i = 1; i < count; i++) {
result.append(", ");
g.operands[i].render(this);
}
result.append(")");
return true;
}
if (op instanceof Input) {
// TODO: needs library implementation
Input i = (Input) op;
String mode = "";
if (i.operands.length == 2)
mode = i.operands[1].getString();
else if (i.operands.length >= 4)
mode = i.operands[3].getString();
if (mode.contains("columns")) {
result.append(i.name + "->getColumns ()");
} else {
Operator op1 = i.operands[1];
Operator op2 = i.operands[2];
result.append(i.name + ".get");
if (mode.contains("raw"))
result.append("Raw");
result.append("(");
op1.render(this);
result.append(", ");
op2.render(this);
result.append(")");
}
return true;
}
if (op instanceof Log) {
Log l = (Log) op;
Operator a = l.operands[0];
result.append("log(");
a.render(this);
return true;
}
if (op instanceof Modulo) {
Modulo m = (Modulo) op;
Operator a = m.operand0;
Operator b = m.operand1;
a.render(this);
result.append(" % ");
b.render(this);
return true;
}
if (op instanceof Norm) {
Norm n = (Norm) op;
Operator A = n.operands[0];
result.append("numpy.linalg.norm(");
A.render(this);
result.append(", ");
n.operands[1].render(this);
result.append(")");
return true;
}
if (op instanceof OR) {
OR or = (OR) op;
or.render(this, " or ");
return true;
}
if (op instanceof Output) {
Output o = (Output) op;
result.append(o.name + "->trace (Simulator::instance.currentEvent->t, ");
if (// column name is explicit
o.hasColumnName) {
o.operands[2].render(this);
} else // column name is generated, so use prepared string value
{
result.append(o.columnName);
}
result.append(", ");
o.operands[1].render(this);
result.append(")");
return true;
}
if (op instanceof Power) {
Power p = (Power) op;
Operator a = p.operand0;
Operator b = p.operand1;
result.append("pow(");
a.render(this);
result.append(", ");
b.render(this);
result.append(")");
return true;
}
if (op instanceof ReadMatrix) {
ReadMatrix r = (ReadMatrix) op;
String mode = "";
int lastParm = r.operands.length - 1;
if (lastParm > 0) {
if (r.operands[lastParm] instanceof Constant) {
Constant c = (Constant) r.operands[lastParm];
if (c.value instanceof Text) {
mode = ((Text) c.value).value;
}
}
}
if (mode.equals("rows")) {
result.append(r.name + "->rows ()");
} else if (mode.equals("columns")) {
result.append(r.name + "->columns ()");
} else {
result.append(r.name + "->get");
if (mode.equals("raw"))
result.append("Raw");
result.append("(");
r.operands[1].render(this);
result.append(", ");
r.operands[2].render(this);
result.append(")");
}
return true;
}
if (op instanceof SquareRoot) {
SquareRoot s = (SquareRoot) op;
Operator a = s.operands[0];
result.append("sqrt(");
a.render(this);
return true;
}
if (op instanceof Tangent) {
Tangent t = (Tangent) op;
Operator a = t.operands[0];
result.append("tan(");
a.render(this);
result.append(")");
return true;
}
if (op instanceof Uniform) {
Uniform u = (Uniform) op;
result.append("uniform(");
if (u.operands.length > 0) {
u.operands[0].render(this);
}
result.append(")");
return true;
}
return super.render(op);
}
Aggregations