Skip to content

Commit

Permalink
More optimal implementation of delay()
Browse files Browse the repository at this point in the history
Changes the definition of single-parameter delay() to be one sim cycle.
  • Loading branch information
frothga committed Sep 2, 2024
1 parent 3251953 commit da19876
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 12 deletions.
7 changes: 0 additions & 7 deletions N2A/src/gov/sandia/n2a/backend/c/RendererC.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,6 @@ else if (useExponent)
if (op instanceof Delay)
{
Delay d = (Delay) op;
if (d.operands.length == 1)
{
result.append ("(");
d.operands[0].render (this);
result.append (")");
return true;
}
result.append ("delay" + d.index + ".step (" + job.SIMULATOR + "currentEvent->t, ");
d.operands[1].render (this);
result.append (", ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

/**
Provides a set of temporary values for use within a single function.
This handles formal temporaries (those with =: as an assignment), as well as buffering for cyclic dependencies.
This handles formal temporaries (those with =; as an assignment), as well as buffering for cyclic dependencies.
Note: buffered variables that are accessed by external equation sets ("externalRead" and "externalWrite") have two entries in the
main table of values, since many different function invocations may access them before they are finalized.
**/
Expand Down
2 changes: 1 addition & 1 deletion N2A/src/gov/sandia/n2a/eqset/EquationSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -3839,7 +3839,7 @@ public void findConstants ()
protected boolean findConstantsEval ()
{
boolean changed = false;
for (Variable v : variables)
for (Variable v : new ArrayList<Variable> (variables)) // Buffer so that Variable.simplify() can add new variables. In that case, Variable.simplify() should return true so that another cycle can include the new variable in optimizations.
{
if (v.simplify ()) changed = true;

Expand Down
8 changes: 7 additions & 1 deletion N2A/src/gov/sandia/n2a/language/AccessVariable.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2013-2023 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
Copyright 2013-2024 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
Under the terms of Contract DE-NA0003525 with NTESS,
the U.S. Government retains certain rights in this software.
*/
Expand Down Expand Up @@ -117,6 +117,12 @@ public Operator simplify (Variable from, boolean evalOnly)
// temporary that is made externally visible via a second variable.
if (! v2.hasAny ("externalRead", "externalWrite")) return this;
}
else // Referencing variable in same equation set
{
// If the intermediate variable is explicitly marked state, then is has been deliberately inserted
// to create a 1-cycle delay. Don't optimize this away.
if (v.hasAttribute ("state")) return this;
}

// Fold aliased variable
from.changed = true;
Expand Down
69 changes: 67 additions & 2 deletions N2A/src/gov/sandia/n2a/language/function/Delay.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
Copyright 2020-2024 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
Under the terms of Contract DE-NA0003525 with NTESS,
the U.S. Government retains certain rights in this software.
*/
Expand All @@ -9,13 +9,20 @@
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.TreeSet;

import gov.sandia.n2a.backend.internal.InstanceTemporaries;
import gov.sandia.n2a.backend.internal.Simulator;
import gov.sandia.n2a.eqset.EquationEntry;
import gov.sandia.n2a.eqset.Variable;
import gov.sandia.n2a.eqset.VariableReference;
import gov.sandia.n2a.eqset.EquationSet.ExponentContext;
import gov.sandia.n2a.language.AccessVariable;
import gov.sandia.n2a.language.Function;
import gov.sandia.n2a.language.Operator;
import gov.sandia.n2a.language.Type;
import gov.sandia.n2a.language.operator.Multiply;
import gov.sandia.n2a.language.operator.NOT;
import gov.sandia.n2a.language.type.Instance;
import gov.sandia.n2a.language.type.Scalar;

Expand Down Expand Up @@ -44,6 +51,65 @@ public boolean canBeConstant ()
return false;
}

public Operator simplify (Variable from, boolean evalOnly)
{
for (int i = 0; i < operands.length; i++) operands[i] = operands[i].simplify (from, evalOnly);
if (evalOnly) return this; // Everything below involves structural changes.

// Ensure that every Delay call is by itself as the sole expression for some variable.

if (from.equations.size () == 1 && from.equations.first ().expression == this) // Already on private variable.
{
if (operands.length == 1) // But delay() itself can be removed in favor of state buffering.
{
from.addAttribute ("state");
from.removeAttribute ("temporary");

// Construct the expression: !$init * operand[0]
// This should return 0 in the init cycle, and a delayed value of operand[0] in all subsequent cycles.

Multiply mult = new Multiply ();
mult.parent = parent;

Variable init = from.container.find (new Variable ("$init"));
VariableReference avref = new VariableReference ();
avref.variable = init;
AccessVariable avinit = new AccessVariable (avref);

NOT not = new NOT ();
not.operand = avinit;
mult.operand0 = not;
mult.operand0.parent = mult;

mult.operand1 = operands[0];
mult.operand1.parent = mult;

return mult;
}
return this; // Already moved to our own variable.
}

// Add a new variable for this Delay.
// TODO: check if there is already a delay variable that matches Delay.
Variable d = new Variable ("delay1");
int index = 2;
while (from.container.find (d) != null) d.name = "delay" + index++;
from.container.add (d);
d.reference = new VariableReference ();
d.reference.variable = d;
from.addDependencyOn (d);

d.equations = new TreeSet<EquationEntry> ();
EquationEntry e = new EquationEntry (d, "");
d.equations.add (e);
e.expression = this;
e.expression.parent = null; // This will later be changed to "from".

VariableReference r = new VariableReference ();
r.variable = d;
return new AccessVariable (r);
}

public void determineExponent (ExponentContext context)
{
for (int i = 0; i < operands.length; i++) operands[i].determineExponent (context);
Expand Down Expand Up @@ -108,7 +174,6 @@ public Type eval (Instance context)
Type tempValue = operands[0].eval (context);
Simulator simulator = Simulator.instance.get ();
if (simulator == null) return tempValue;
if (operands.length < 2) return tempValue; // Zero delay, which generally introduces one cycle of delay in an expression like: A = delay(B)

double value = ((Scalar) tempValue).value;
double delay = ((Scalar) operands[1].eval (context)).value;
Expand Down

0 comments on commit da19876

Please sign in to comment.