11package simulator ;
22
33
4+ import common .iterable .IterableArray ;
5+ import common .iterable .Range ;
6+ import common .iterable .Reducible ;
47import parser .State ;
58import parser .ast .Expression ;
69import parser .ast .LabelList ;
710import prism .PrismException ;
811import prism .PrismLangException ;
12+ import prism .PrismUtils ;
913
10- import java .util .BitSet ;
11- import java .util .HashMap ;
12- import java .util .List ;
13- import java .util .Map ;
14+ import java .util .*;
15+ import java .util .function .Predicate ;
1416
1517/**
1618 * This class will evaluate labels. Therefore, it's wrapped around a {@link LabelList}.
@@ -23,13 +25,47 @@ public class LabelEvaluator
2325 Map <State , BitSet > stateValues = new HashMap <>();
2426 /** The labelList that will be evaluated */
2527 LabelList labelList ;
28+ int [] evaluationOrder ;
2629
2730 /**
2831 * Creates new object that will evaluate and cache the given {@link LabelList}.
2932 */
30- public LabelEvaluator (LabelList labelList )
33+ public LabelEvaluator (LabelList labelList ) throws PrismLangException
3134 {
3235 this .labelList = labelList ;
36+ this .evaluationOrder = fixEvaluationOrder (labelList );
37+ }
38+
39+ /**
40+ * Fix an order on the labels such that l1 < l2 if l2 depends on l1
41+ * @param labels
42+ * @return an int array of the label indices in ascending order
43+ * @throws PrismLangException In case a label depencies could not be computed.
44+ */
45+ private int [] fixEvaluationOrder (LabelList labels ) throws PrismLangException
46+ {
47+ boolean [][] deps = labels .getLabelDependencies ();
48+ assert PrismUtils .findCycle (deps ) == -1 : "label dependencies must not contain a cylce" ;
49+
50+ int numLabels = labels .size ();
51+ Integer [] order = new Range (numLabels ).collect (new Integer [numLabels ]);
52+ Arrays .sort (order , new Comparator <Integer >()
53+ {
54+ @ Override
55+ public int compare (Integer row , Integer col )
56+ {
57+ int i = row ;
58+ int j = col ;
59+ if (deps [i ][j ]) { // i depends on j
60+ return +1 ;
61+ }
62+ if (deps [j ][i ]) { // j depends on i
63+ return -1 ;
64+ }
65+ return Integer .compare (i , j );
66+ }
67+ });
68+ return Reducible .unboxInt (new IterableArray .Of <>(order )).collect (new int [numLabels ]);
3369 }
3470
3571 /**
@@ -60,7 +96,7 @@ public Map<String, Boolean> getLabelValues(State state) throws PrismLangExceptio
6096 labelValueMap .put (labelList .getLabelName (i ), value .get (i ));
6197 }
6298 return labelValueMap ;
63- }
99+ }
64100
65101 /**
66102 * This method provides all values of a certain label. They will be ordered by the given statesList. <br>
@@ -112,36 +148,13 @@ private BitSet evaluateState(State state) throws PrismLangException
112148 int numLabels = labelList .size ();
113149 Map <String , Boolean > labelValues = new HashMap <>(numLabels );
114150 BitSet values = new BitSet ();
115- for (int labelIndex = numLabels ; labelIndex >= 0 ; labelIndex --) {
116- boolean labelValue = evaluateLabel (labelList .getLabelName (labelIndex ), labelValues , state );
117- values .set (labelIndex , labelValue );
151+ for (int i : evaluationOrder ) {
152+ Expression label = labelList .getLabel (i );
153+ boolean labelValue = label .evaluateBoolean (null , labelValues , state );
154+ labelValues .put (labelList .getLabelName (i ), labelValue );
155+ values .set (i , labelValue );
118156 }
119157 stateValues .put (state , values );
120158 return values ;
121159 }
122-
123- /**
124- * Helper function to recursively evaluate label values. The value will be stored inside the given map.
125- *
126- * @param name The name of the label.
127- * @param labelValues The already known values of all labels.
128- */
129- private boolean evaluateLabel (String name , Map <String , Boolean > labelValues , State state ) throws PrismLangException
130- {
131- // check if value is already known
132- if (labelValues .containsKey (name )) {
133- return labelValues .get (name );
134- }
135- // get expression
136- Expression label = labelList .getLabel (labelList .getLabelIndex (name ));
137- // check if all the (other) label dependencies are evaluated
138- for (String dependency : label .getAllLabels ()){
139- // evaluate other label first
140- evaluateLabel (dependency , labelValues , state );
141- }
142- // all dependencies are fulfilled
143- boolean labelValue = label .evaluateBoolean (null , labelValues , state );
144- labelValues .put (name , labelValue );
145- return labelValue ;
146- }
147160}
0 commit comments