Search in sources :

Example 1 with Function

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();
}
Also used : Add(gov.sandia.n2a.language.operator.Add) Function(gov.sandia.n2a.language.Function) Divide(gov.sandia.n2a.language.operator.Divide) Min(gov.sandia.n2a.language.function.Min) Max(gov.sandia.n2a.language.function.Max) AND(gov.sandia.n2a.language.operator.AND) Multiply(gov.sandia.n2a.language.operator.Multiply) OperatorBinary(gov.sandia.n2a.language.OperatorBinary)

Example 2 with Function

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);
    }
}
Also used : Operator(gov.sandia.n2a.language.Operator) EquationSet(gov.sandia.n2a.eqset.EquationSet) Variable(gov.sandia.n2a.eqset.Variable) AccessVariable(gov.sandia.n2a.language.AccessVariable) Visitor(gov.sandia.n2a.language.Visitor) Constant(gov.sandia.n2a.language.Constant) Text(gov.sandia.n2a.language.type.Text) ReadMatrix(gov.sandia.n2a.language.function.ReadMatrix) Function(gov.sandia.n2a.language.Function) Type(gov.sandia.n2a.language.Type) 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) Output(gov.sandia.n2a.language.function.Output)

Example 3 with Function

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;
}
Also used : Operator(gov.sandia.n2a.language.Operator) Function(gov.sandia.n2a.language.Function) AccessVariable(gov.sandia.n2a.language.AccessVariable) AccessVariable(gov.sandia.n2a.language.AccessVariable) Constant(gov.sandia.n2a.language.Constant) Scalar(gov.sandia.n2a.language.type.Scalar)

Aggregations

Function (gov.sandia.n2a.language.Function)3 AccessVariable (gov.sandia.n2a.language.AccessVariable)2 Constant (gov.sandia.n2a.language.Constant)2 Operator (gov.sandia.n2a.language.Operator)2 EquationSet (gov.sandia.n2a.eqset.EquationSet)1 Variable (gov.sandia.n2a.eqset.Variable)1 BuildMatrix (gov.sandia.n2a.language.BuildMatrix)1 OperatorBinary (gov.sandia.n2a.language.OperatorBinary)1 Type (gov.sandia.n2a.language.Type)1 Visitor (gov.sandia.n2a.language.Visitor)1 Input (gov.sandia.n2a.language.function.Input)1 Max (gov.sandia.n2a.language.function.Max)1 Min (gov.sandia.n2a.language.function.Min)1 Output (gov.sandia.n2a.language.function.Output)1 ReadMatrix (gov.sandia.n2a.language.function.ReadMatrix)1 AND (gov.sandia.n2a.language.operator.AND)1 Add (gov.sandia.n2a.language.operator.Add)1 Divide (gov.sandia.n2a.language.operator.Divide)1 Multiply (gov.sandia.n2a.language.operator.Multiply)1 Matrix (gov.sandia.n2a.language.type.Matrix)1