Search in sources :

Example 31 with AccessVariable

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;
}
Also used : Operator(gov.sandia.n2a.language.Operator) AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) Visitor(gov.sandia.n2a.language.Visitor) TreeSet(java.util.TreeSet) Constant(gov.sandia.n2a.language.Constant)

Example 32 with AccessVariable

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();
}
Also used : Operator(gov.sandia.n2a.language.Operator) EquationSet(gov.sandia.n2a.eqset.EquationSet) AccessVariable(gov.sandia.n2a.language.AccessVariable) Constant(gov.sandia.n2a.language.Constant) ConnectionBinding(gov.sandia.n2a.eqset.EquationSet.ConnectionBinding) Renderer(gov.sandia.n2a.language.Renderer)

Example 33 with AccessVariable

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);
}
Also used : AccessVariable(gov.sandia.n2a.language.AccessVariable) HashMap(java.util.HashMap) EquationEntry(gov.sandia.n2a.eqset.EquationEntry) MNode(gov.sandia.n2a.db.MNode) CannotRedoException(javax.swing.undo.CannotRedoException)

Example 34 with AccessVariable

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;
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet) Variable(gov.sandia.n2a.eqset.Variable) UnresolvedVariable(gov.sandia.n2a.eqset.EquationSet.UnresolvedVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessElement(gov.sandia.n2a.language.AccessElement) EquationEntry(gov.sandia.n2a.eqset.EquationEntry) UnconvertibleException(javax.measure.UnconvertibleException) IncommensurableException(javax.measure.IncommensurableException)

Example 35 with AccessVariable

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);
}
Also used : Add(gov.sandia.n2a.language.operator.Add) Operator(gov.sandia.n2a.language.Operator) Constant(gov.sandia.n2a.language.Constant) Grid(gov.sandia.n2a.language.function.Grid) Uniform(gov.sandia.n2a.language.function.Uniform) Scalar(gov.sandia.n2a.language.type.Scalar) Input(gov.sandia.n2a.language.function.Input) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Matrix(gov.sandia.n2a.language.type.Matrix) SquareRoot(gov.sandia.n2a.language.function.SquareRoot) BuildMatrix(gov.sandia.n2a.language.BuildMatrix) Output(gov.sandia.n2a.language.function.Output) OR(gov.sandia.n2a.language.operator.OR) AccessVariable(gov.sandia.n2a.language.AccessVariable) Log(gov.sandia.n2a.language.function.Log) Modulo(gov.sandia.n2a.language.operator.Modulo) Text(gov.sandia.n2a.language.type.Text) Tangent(gov.sandia.n2a.language.function.Tangent) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) Type(gov.sandia.n2a.language.Type) AND(gov.sandia.n2a.language.operator.AND) Event(gov.sandia.n2a.language.function.Event) Norm(gov.sandia.n2a.language.function.Norm) Gaussian(gov.sandia.n2a.language.function.Gaussian) AccessElement(gov.sandia.n2a.language.AccessElement) Exp(gov.sandia.n2a.language.function.Exp) Power(gov.sandia.n2a.language.operator.Power)

Aggregations

AccessVariable (gov.sandia.n2a.language.AccessVariable)42 Operator (gov.sandia.n2a.language.Operator)31 Visitor (gov.sandia.n2a.language.Visitor)16 Variable (gov.sandia.n2a.eqset.Variable)15 Constant (gov.sandia.n2a.language.Constant)15 Scalar (gov.sandia.n2a.language.type.Scalar)13 ArrayList (java.util.ArrayList)12 EquationEntry (gov.sandia.n2a.eqset.EquationEntry)11 TreeSet (java.util.TreeSet)11 EquationSet (gov.sandia.n2a.eqset.EquationSet)10 Type (gov.sandia.n2a.language.Type)9 Instance (gov.sandia.n2a.language.type.Instance)7 ConnectionBinding (gov.sandia.n2a.eqset.EquationSet.ConnectionBinding)6 VariableReference (gov.sandia.n2a.eqset.VariableReference)6 Output (gov.sandia.n2a.language.function.Output)6 Transformer (gov.sandia.n2a.language.Transformer)5 Event (gov.sandia.n2a.language.function.Event)5 Text (gov.sandia.n2a.language.type.Text)5 MNode (gov.sandia.n2a.db.MNode)4 AccessElement (gov.sandia.n2a.language.AccessElement)4