46
46
import java .lang .reflect .Method ;
47
47
import java .util .ArrayList ;
48
48
import java .util .HashMap ;
49
- import java .util .HashSet ;
50
49
import java .util .LinkedHashMap ;
51
50
import java .util .List ;
52
51
import java .util .Map ;
53
52
import java .util .Set ;
53
+ import java .util .StringJoiner ;
54
54
import java .util .prefs .Preferences ;
55
55
56
56
import javax .swing .Box ;
85
85
import edu .mit .csail .sdg .alloy4 .Util ;
86
86
import edu .mit .csail .sdg .alloy4 .Version ;
87
87
import edu .mit .csail .sdg .alloy4graph .GraphViewer ;
88
- import kodkod .ast .Decls ;
89
- import kodkod .ast .Expression ;
90
- import kodkod .ast .Formula ;
91
- import kodkod .ast .Node ;
92
- import kodkod .ast .QuantifiedFormula ;
93
- import kodkod .ast .Relation ;
94
- import kodkod .ast .Variable ;
95
- import kodkod .ast .visitor .AbstractReplacer ;
96
- import kodkod .instance .PardinusBounds ;
97
- import kodkod .instance .TemporalInstance ;
98
- import kodkod .util .nodes .PrettyPrinter ;
88
+ import edu .mit .csail .sdg .ast .Expr ;
89
+ import edu .mit .csail .sdg .ast .ExprConstant ;
90
+ import edu .mit .csail .sdg .ast .ExprVar ;
91
+ import edu .mit .csail .sdg .ast .Sig ;
92
+ import edu .mit .csail .sdg .translator .A4Solution ;
93
+ import edu .mit .csail .sdg .translator .A4Tuple ;
94
+ import edu .mit .csail .sdg .translator .A4TupleSet ;
99
95
100
96
/**
101
97
* GUI main window for the visualizer.
@@ -141,7 +137,10 @@ public final class VizGUI implements ComponentListener {
141
137
private final JButton projectionButton , openSettingsButton , closeSettingsButton , magicLayout ,
142
138
loadSettingsButton , saveSettingsButton , saveAsSettingsButton , resetSettingsButton , updateSettingsButton ,
143
139
openEvaluatorButton , closeEvaluatorButton , enumerateButton , vizButton , treeButton ,
144
- txtButton , tableButton , leftNavButton , rightNavButton , cnfgButton , forkButton , initButton /* , dotButton, xmlButton */ ; // [HASLab]
140
+ txtButton , tableButton , leftNavButton , rightNavButton , cnfgButton , forkButton , initButton , pathButton /*
141
+ * , dotButton,
142
+ * xmlButton
143
+ */ ; // [HASLab]
145
144
146
145
/**
147
146
* This list must contain all the display mode buttons (that is, vizButton,
@@ -158,15 +157,19 @@ public final class VizGUI implements ComponentListener {
158
157
/** The "show next" menu item. */
159
158
private final JMenuItem enumerateMenu ;
160
159
161
- /** The "fork next " menu item. */
160
+ /** The "fresh config " menu item. */
162
161
// [HASLab]
163
162
private final JMenuItem cnfgMenu ;
164
163
164
+ /** The "fresh path" menu item. */
165
+ // [HASLab]
166
+ private final JMenuItem pathMenu ;
167
+
165
168
/** The "fork next" menu item. */
166
169
// [HASLab]
167
170
private final JMenuItem forkMenu ;
168
171
169
- /** The "fork next " menu item. */
172
+ /** The "fork init " menu item. */
170
173
// [HASLab]
171
174
private final JMenuItem initMenu ;
172
175
@@ -183,6 +186,9 @@ public final class VizGUI implements ComponentListener {
183
186
*/
184
187
private int settingsOpen = 0 ;
185
188
189
+ // [HASLab]
190
+ private boolean seg_iteration = false ;
191
+
186
192
/**
187
193
* The current states and visualization settings; null if none is loaded.
188
194
*/
@@ -645,6 +651,7 @@ else if (height < 100)
645
651
JMenu instanceMenu = menu (mb , "&Instance" , null );
646
652
enumerateMenu = menuItem (instanceMenu , "Show Next Solution" , 'N' , 'N' , doNext ());
647
653
cnfgMenu = menuItem (instanceMenu , "Show Fresh Configuration" , 'C' , 'C' , doConfig ()); // [HASLab]
654
+ pathMenu = menuItem (instanceMenu , "Show Fresh Path" , 'P' , 'P' , doPath ()); // [HASLab]
648
655
initMenu = menuItem (instanceMenu , "Show Fresh Initial State" , 'I' , 'I' , doInit ()); // [HASLab]
649
656
forkMenu = menuItem (instanceMenu , "Show Different Post-state" , 'F' , 'F' , doFork ()); // [HASLab]
650
657
leftNavMenu = menuItem (instanceMenu , "Show Previous State" , KeyEvent .VK_LEFT , KeyEvent .VK_LEFT , leftNavListener ); // [HASLab]
@@ -701,6 +708,7 @@ public void actionPerformed(ActionEvent e) {
701
708
toolbar .add (closeEvaluatorButton = OurUtil .button ("Close Evaluator" , "Close the evaluator" , "images/24_settings_close2.gif" , doCloseEvalPanel ()));
702
709
toolbar .add (enumerateButton = OurUtil .button ("Next" , "Show a fresh solution" , "images/24_history.gif" , doNext ()));
703
710
toolbar .add (cnfgButton = OurUtil .button ("Fresh Config" , "Show a fresh configuration" , "images/24_history.gif" , doConfig ())); // [HASLab]
711
+ toolbar .add (pathButton = OurUtil .button ("Fresh Path" , "Show a fresh path" , "images/24_history.gif" , doPath ())); // [HASLab]
704
712
toolbar .add (initButton = OurUtil .button ("Fresh Init" , "Show a fresh initial state" , "images/24_history.gif" , doInit ())); // [HASLab]
705
713
toolbar .add (forkButton = OurUtil .button ("Fork" , "Show a different post-state" , "images/24_history.gif" , doFork ())); // [HASLab]
706
714
toolbar .add (leftNavButton = OurUtil .button (new String (Character .toChars (0x2190 )), "Show the previous state" , "images/24_history.gif" , leftNavListener ));
@@ -876,6 +884,10 @@ private void updateDisplay() {
876
884
initMenu .setEnabled (!isMeta && settingsOpen == 0 && enumerator != null ); // [HASLab]
877
885
initMenu .setVisible (isTrace ); // [HASLab]
878
886
initButton .setVisible (!isMeta && settingsOpen == 0 && enumerator != null && isTrace ); // [HASLab]
887
+ pathMenu .setEnabled (!isMeta && settingsOpen == 0 && enumerator != null && !seg_iteration ); // [HASLab]
888
+ pathMenu .setVisible (isTrace ); // [HASLab]
889
+ pathButton .setVisible (!isMeta && settingsOpen == 0 && enumerator != null && isTrace ); // [HASLab]
890
+ pathButton .setEnabled (!seg_iteration ); // [HASLab]
879
891
cnfgMenu .setEnabled (!isMeta && settingsOpen == 0 && enumerator != null ); // [HASLab]
880
892
cnfgMenu .setVisible (isTrace ); // [HASLab]
881
893
cnfgButton .setVisible (!isMeta && settingsOpen == 0 && enumerator != null && isTrace ); // [HASLab]
@@ -1127,6 +1139,8 @@ public void loadXML(final String fileName, boolean forcefully, int state) {
1127
1139
current = state ; // [HASLab]
1128
1140
final String xmlFileName = Util .canon (fileName );
1129
1141
File f = new File (xmlFileName );
1142
+ if (!forcefully )
1143
+ seg_iteration = false ;
1130
1144
if (forcefully || !xmlFileName .equals (this .xmlFileName )) {
1131
1145
for (int i = 0 ; i < statepanes ; i ++) { // [HASLab]
1132
1146
try {
@@ -1443,46 +1457,107 @@ private Runner doExportXml() {
1443
1457
}
1444
1458
1445
1459
// [HASLab]
1446
- // reuses the Pardinus instance to formula translation, so needs some tweaks to the Alloy level
1460
+ // ad hoc implementation since alloy lacks a proper pretty printer
1461
+ // also, prints conjunctions as lists, which can't be parsed
1447
1462
private Runner doExportLTL () {
1448
1463
if (wrap )
1449
1464
return wrapMe ();
1450
1465
if (myStates .isEmpty ())
1451
1466
return null ;
1452
- TemporalInstance inst = (TemporalInstance ) myStates .get (myStates .size () - 1 ).getOriginalInstance ().originalA4 .debugExtractKInstance ();
1453
- Formula rels = Formula .TRUE ;
1454
- for (Relation r : inst .state (0 ).relations ())
1455
- if (!(r .toString ().startsWith ("Int/" ) || r .toString ().startsWith ("seq/" ) || r .isAtom ()))
1456
- rels = rels .and (r .eq (r ));
1457
- Formula form = null ;
1458
- Map <Object ,Expression > reifs = new HashMap <Object ,Expression >();
1459
- form = inst .formulate (reifs , rels , true , new PardinusBounds (inst .state (0 ).universe ()), false );
1460
- Expression unvs = Expression .UNIV ;
1461
- for (int i = 1 ; i < inst .prefixLength (); i ++)
1462
- unvs = Expression .UNIV .union (unvs .prime ());
1463
- Decls decs = null ;
1464
- for (Expression rs : reifs .values ()) {
1465
- if (decs == null )
1466
- decs = ((Variable ) rs ).oneOf (unvs );
1467
- else
1468
- decs = decs .and (((Variable ) rs ).oneOf (unvs ));
1469
- }
1470
- form = ((QuantifiedFormula ) form ).formula ().forSome (decs );
1471
- // [HASLab] normalize variable names
1472
- AbstractReplacer repls = new AbstractReplacer (new HashSet <Node >()) {
1473
1467
1474
- @ Override
1475
- public Expression visit (Variable v ) {
1476
- final Expression ret = lookup (v );
1477
- if (ret != null )
1478
- return ret ;
1479
- String n = v .name ().replace ("$" , "" );
1480
- return cache (v , Variable .nary (n , v .arity ()));
1468
+ Map <String ,ExprVar > reifs = new HashMap <String ,ExprVar >();
1469
+ A4Solution inst = myStates .get (myStates .size () - 1 ).getOriginalInstance ().originalA4 ;
1470
+
1471
+ StringJoiner config = new StringJoiner (" and " );
1472
+ for (Sig s : inst .getAllReachableSigs ()) {
1473
+ if (s .isPrivate != null || s .isVariable != null || s .equals (Sig .UNIV ) || s .equals (Sig .NONE ))
1474
+ continue ;
1475
+ A4TupleSet ts = inst .eval (s );
1476
+ Expr tupleset = null ;
1477
+ for (A4Tuple t : ts ) {
1478
+ Expr tuple = null ;
1479
+ for (int ai = 0 ; ai < t .arity (); ai ++) {
1480
+ Expr atom ;
1481
+ if (t .atom (ai ).matches ("-?\\ d+" )) {
1482
+ atom = ExprConstant .makeNUMBER (Integer .valueOf (t .atom (ai )));
1483
+ } else {
1484
+ atom = reifs .computeIfAbsent ("_" + t .atom (ai ).replace ("$" , "" ).replace ("/" , "_" ), k -> ExprVar .make (null , k ));
1485
+ }
1486
+ tuple = tuple == null ? atom : tuple .product (tuple );
1487
+ }
1488
+ tupleset = tupleset == null ? tuple : tupleset .plus (tuple );
1481
1489
}
1490
+ if (tupleset == null ) {
1491
+ tupleset = ExprConstant .EMPTYNESS ;
1492
+ for (int ai = 0 ; ai < ts .arity () - 1 ; ai ++)
1493
+ tupleset = tupleset .product (ExprConstant .EMPTYNESS );
1494
+ }
1495
+ config .add (s .equal (tupleset ).toString ());
1496
+ }
1482
1497
1483
- };
1484
- form = form .accept (repls );
1485
- OurDialog .showtext ("Text Viewer" , PrettyPrinter .print (form , 4 ).replaceAll ("Int\\ [(-?\\ d*)\\ ]" , "$1" ).replaceFirst ("some" , "some disj" ));
1498
+ List <String > states = new ArrayList <String >();
1499
+ for (int i = 0 ; i < inst .getTraceLength (); i ++) {
1500
+ StringJoiner state = new StringJoiner (" and " );
1501
+ for (Sig s : inst .getAllReachableSigs ()) {
1502
+ if (s .isPrivate != null || (s .isVariable == null && !s .equals (Sig .UNIV )))
1503
+ continue ;
1504
+ A4TupleSet ts = inst .eval (s , i );
1505
+ Expr tupleset = null ;
1506
+ for (A4Tuple t : ts ) {
1507
+ Expr tuple = null ;
1508
+ for (int ai = 0 ; ai < t .arity (); ai ++) {
1509
+ Expr atom ;
1510
+ if (t .atom (ai ).matches ("-?\\ d+" )) {
1511
+ atom = ExprConstant .makeNUMBER (Integer .valueOf (t .atom (ai )));
1512
+ } else {
1513
+ atom = reifs .computeIfAbsent ("_" + t .atom (ai ).replace ("$" , "" ).replace ("/" , "_" ), k -> ExprVar .make (null , k ));
1514
+ }
1515
+ tuple = tuple == null ? atom : tuple .product (tuple );
1516
+ }
1517
+ tupleset = tupleset == null ? tuple : tupleset .plus (tuple );
1518
+ }
1519
+ if (tupleset == null ) {
1520
+ tupleset = ExprConstant .EMPTYNESS ;
1521
+ for (int ai = 0 ; ai < ts .arity () - 1 ; ai ++)
1522
+ tupleset = tupleset .product (ExprConstant .EMPTYNESS );
1523
+ }
1524
+ state .add (s .equal (tupleset ).toString ());
1525
+ }
1526
+ states .add (state .toString ());
1527
+ }
1528
+ StringBuilder sb = new StringBuilder ();
1529
+ sb .append ("some disj " );
1530
+ StringJoiner sj = new StringJoiner ("," );
1531
+ for (ExprVar v : reifs .values ())
1532
+ sj .add (v .toString ());
1533
+ sb .append (sj .toString ());
1534
+ sb .append (" : " );
1535
+ Expr unvs = Sig .UNIV ;
1536
+ for (int i = 0 ; i < inst .getTraceLength () - 1 ; i ++)
1537
+ unvs = Sig .UNIV .plus (unvs .prime ());
1538
+ sb .append (unvs .toString ());
1539
+ sb .append (" {\n " );
1540
+ sb .append (config .toString ());
1541
+ sb .append ("\n \n " );
1542
+ StringJoiner statesj = new StringJoiner (";\n " );
1543
+ for (String s : states )
1544
+ statesj .add (s );
1545
+ sb .append (statesj .toString ());
1546
+ sb .append ("\n \n " );
1547
+ for (int i = 0 ; i < inst .getLoopState (); i ++)
1548
+ sb .append ("after " );
1549
+ sb .append (" {\n " );
1550
+ for (int i = inst .getLoopState (); i < inst .getTraceLength (); i ++) {
1551
+ StringBuilder sa = new StringBuilder ("" );
1552
+ for (int j = inst .getLoopState (); j < inst .getTraceLength (); j ++)
1553
+ sa .append ("after " );
1554
+ sa .append ("(" );
1555
+ sa .append (states .get (i ));
1556
+ sa .append (")" );
1557
+ sb .append (" (" + states .get (i ) + ") implies " + sa .toString () + "\n " );
1558
+ }
1559
+ sb .append (" }\n }\n " );
1560
+ OurDialog .showtext ("Text Viewer" , sb .toString ());
1486
1561
return null ;
1487
1562
}
1488
1563
@@ -1619,6 +1694,7 @@ private Runner doConfig() {
1619
1694
OurDialog .alert ("Cannot display the next solution since the analysis engine is not loaded with the visualizer." );
1620
1695
} else {
1621
1696
try {
1697
+ seg_iteration = false ;
1622
1698
enumerator .compute (new String [] {
1623
1699
xmlFileName , -1 + ""
1624
1700
});
@@ -1629,6 +1705,32 @@ private Runner doConfig() {
1629
1705
return null ;
1630
1706
}
1631
1707
1708
+ /**
1709
+ * This method attempts to derive the next satisfying instance.
1710
+ */
1711
+ // [HASLab]
1712
+ private Runner doPath () {
1713
+ if (wrap )
1714
+ return wrapMe ();
1715
+ if (settingsOpen != 0 )
1716
+ return null ;
1717
+ if (xmlFileName .length () == 0 ) {
1718
+ OurDialog .alert ("Cannot display the next solution since no instance is currently loaded." );
1719
+ } else if (enumerator == null ) {
1720
+ OurDialog .alert ("Cannot display the next solution since the analysis engine is not loaded with the visualizer." );
1721
+ } else {
1722
+ try {
1723
+ seg_iteration = false ;
1724
+ enumerator .compute (new String [] {
1725
+ xmlFileName , -2 + ""
1726
+ });
1727
+ } catch (Throwable ex ) {
1728
+ OurDialog .alert (ex .getMessage ());
1729
+ }
1730
+ }
1731
+ return null ;
1732
+ }
1733
+
1632
1734
/** This method attempts to derive the next satisfying instance. */
1633
1735
// [HASLab] simulator
1634
1736
private Runner doFork () {
@@ -1642,6 +1744,7 @@ private Runner doFork() {
1642
1744
OurDialog .alert ("Cannot display the next solution since the analysis engine is not loaded with the visualizer." );
1643
1745
} else {
1644
1746
try {
1747
+ seg_iteration = true ;
1645
1748
enumerator .compute (new String [] {
1646
1749
xmlFileName , current + 1 + ""
1647
1750
});
@@ -1665,6 +1768,7 @@ private Runner doInit() {
1665
1768
OurDialog .alert ("Cannot display the next solution since the analysis engine is not loaded with the visualizer." );
1666
1769
} else {
1667
1770
try {
1771
+ seg_iteration = true ;
1668
1772
enumerator .compute (new String [] {
1669
1773
xmlFileName , 0 + ""
1670
1774
});
0 commit comments