@@ -38,6 +38,7 @@ public class PVerifierCodeGenerator : ICodeGenerator
38
38
private Dictionary < Invariant , HashSet < Invariant > > _invariantDependencies ;
39
39
private HashSet < Invariant > _provenInvariants ;
40
40
private Scope _globalScope ;
41
+ private Invariant _defaultInv ;
41
42
42
43
public bool HasCompilationStage => true ;
43
44
@@ -161,17 +162,18 @@ public void Compile(ICompilerConfiguration job)
161
162
162
163
Console . WriteLine ( ) ;
163
164
}
164
-
165
+
165
166
succeededInv . ExceptWith ( failedInv ) ;
166
167
job . Output . WriteInfo ( $ "\n 🎉 Verified { succeededInv . Count } invariants!") ;
167
168
foreach ( var inv in succeededInv )
168
169
{
169
- job . Output . WriteInfo ( $ "✅ { inv . Name . Replace ( "_PGROUP_" , ": " ) } ") ;
170
- }
171
-
172
- if ( ! missingDefault && failMessages . Count == 0 )
173
- {
174
- job . Output . WriteInfo ( $ "✅ default P proof obligations") ;
170
+ if ( ! inv . IsDefault ) {
171
+ job . Output . WriteInfo ( $ "✅ { inv . Name . Replace ( "_PGROUP_" , ": " ) } ") ;
172
+ }
173
+ else {
174
+ job . Output . WriteInfo ( $ "✅ default P proof obligations") ;
175
+ }
176
+
175
177
}
176
178
177
179
MarkProvenInvariants ( succeededInv ) ;
@@ -244,9 +246,18 @@ private void ProcessFailureMessages(List<Match> collection, string[] query, stri
244
246
var line = query [ int . Parse ( feedback . Second . ToString ( ) ) - 1 ] ;
245
247
var step = feedback . First . ToString ( ) . Contains ( "[Step #0]" ) ? "(base case)" : "" ;
246
248
var matchName = Regex . Match ( line , @"// Failed to verify invariant (.*) at (.*)" ) ;
247
- var invName = matchName . Groups [ 1 ] . Value . Replace ( "_PGROUP_" , ": " ) ;
248
- failedInv . Add ( invName ) ;
249
- failMessages . Add ( $ "{ reason } { line . Split ( "//" ) . Last ( ) } { step } ") ;
249
+ if ( matchName . Success ) {
250
+ var invName = matchName . Groups [ 1 ] . Value . Replace ( "_PGROUP_" , ": " ) ;
251
+ failedInv . Add ( invName ) ;
252
+ failMessages . Add ( $ "{ reason } { line . Split ( "// " ) . Last ( ) } { step } ") ;
253
+ }
254
+
255
+ var matchDefault = Regex . Match ( line ,
256
+ @"(// Failed to verify that (.*) never receives (.*) in (.*)|// Failed to ensure unique action IDs at (.*)|// Failed to ensure increasing action IDs at (.*)|// Failed to ensure that received is a subset of sent at (.*))" ) ;
257
+ if ( matchDefault . Success ) {
258
+ failedInv . Add ( "default" ) ;
259
+ failMessages . Add ( $ "{ reason } { line . Split ( "// " ) . Last ( ) } ") ;
260
+ }
250
261
}
251
262
}
252
263
}
@@ -277,6 +288,9 @@ private void ProcessFailureMessages(List<Match> collection, string[] query, stri
277
288
278
289
return ( succeededInv , failedInv . Select ( x =>
279
290
{
291
+ if ( x == "default" ) {
292
+ return _defaultInv ;
293
+ }
280
294
_globalScope . Get ( x , out Invariant i ) ;
281
295
return i ;
282
296
} ) . ToHashSet ( ) , failMessages ) ;
@@ -300,7 +314,7 @@ public IEnumerable<CompiledFile> GenerateCode(ICompilerConfiguration job, Scope
300
314
var filenamePrefix = $ "{ job . ProjectName } _";
301
315
List < CompiledFile > files = [ ] ;
302
316
// if there are no proof commands, then create two:
303
- // - one called default for checking that everything is handled
317
+ // - one called default for checking that everything is handled and sanity checkings
304
318
// - one with all the invariants as goals
305
319
if ( ! globalScope . ProofCommands . Any ( ) )
306
320
{
@@ -341,7 +355,7 @@ bool emitCode (ProofCommand cmd) => job.TargetProofBlocks.Count == 0 ||
341
355
if ( proofCmd . Goals . Count == 1 && proofCmd . Goals [ 0 ] . IsDefault )
342
356
{
343
357
proofCmd . Name = "default" ;
344
- proofCmd . Goals = [ ] ;
358
+ _defaultInv = proofCmd . Goals [ 0 ] ;
345
359
_commands . Add ( proofCmd ) ;
346
360
_proofCommandToFiles . Add ( proofCmd , [ ] ) ;
347
361
files . AddRange ( CompileToFile ( $ "{ filenamePrefix } default", proofCmd ) ) ;
@@ -424,29 +438,26 @@ private List<CompiledFile> CompileToFile(string name, ProofCommand cmd)
424
438
files . Add ( _src ) ;
425
439
GenerateMain ( null , null , null , cmd ) ;
426
440
}
427
- else
441
+ foreach ( var m in machines )
428
442
{
429
- foreach ( var m in machines )
443
+ if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( m . Name ) )
430
444
{
431
- if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( m . Name ) )
445
+ foreach ( var s in m . States )
432
446
{
433
- foreach ( var s in m . States )
447
+ if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( s . Name ) )
434
448
{
435
- if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( s . Name ) )
436
- {
437
- _src = GenerateCompiledFile ( cmd , name , m , s , null ) ;
438
- files . Add ( _src ) ;
439
- GenerateMain ( m , s , null , cmd ) ;
440
- }
449
+ _src = GenerateCompiledFile ( cmd , name , m , s , null ) ;
450
+ files . Add ( _src ) ;
451
+ GenerateMain ( m , s , null , cmd , cmd . Name == "default" ) ;
452
+ }
441
453
442
- foreach ( var e in events . Where ( e => ! e . IsNullEvent && ! e . IsHaltEvent && s . HasHandler ( e ) ) )
454
+ foreach ( var e in events . Where ( e => ! e . IsNullEvent && ! e . IsHaltEvent && s . HasHandler ( e ) ) )
455
+ {
456
+ if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( e . Name ) )
443
457
{
444
- if ( _ctx . Job . CheckOnly == null || _ctx . Job . CheckOnly . Contains ( e . Name ) )
445
- {
446
- _src = GenerateCompiledFile ( cmd , name , m , s , e ) ;
447
- files . Add ( _src ) ;
448
- GenerateMain ( m , s , e , cmd ) ;
449
- }
458
+ _src = GenerateCompiledFile ( cmd , name , m , s , e ) ;
459
+ files . Add ( _src ) ;
460
+ GenerateMain ( m , s , e , cmd , cmd . Name == "default" ) ;
450
461
}
451
462
}
452
463
}
@@ -458,7 +469,7 @@ private List<CompiledFile> CompileToFile(string name, ProofCommand cmd)
458
469
}
459
470
460
471
private void BuildDependencies ( Scope globalScope )
461
- {
472
+ {
462
473
foreach ( var cmd in globalScope . ProofCommands )
463
474
{
464
475
foreach ( var goal in cmd . Goals )
@@ -1041,11 +1052,8 @@ private void GenerateSpecHandlers(List<Machine> specs)
1041
1052
/********************************
1042
1053
* Traverse the P AST and generate the UCLID5 code using the types and helpers defined above
1043
1054
*******************************/
1044
- private void GenerateMain ( Machine machine , State state , Event @event , ProofCommand cmd )
1055
+ private void GenerateMain ( Machine machine , State state , Event @event , ProofCommand cmd , bool generateSanityChecks = false )
1045
1056
{
1046
- // cmd.Proof is default iff all the others are null
1047
- Trace . Assert ( ( cmd . Name == "default" ) == ( machine is null && state is null && @event is null ) ) ;
1048
-
1049
1057
EmitLine ( "module main {" ) ;
1050
1058
1051
1059
var machines = ( from m in _globalScope . AllDecls . OfType < Machine > ( ) where ! m . IsSpec select m ) . ToList ( ) ;
@@ -1095,10 +1103,10 @@ private void GenerateMain(Machine machine, State state, Event @event, ProofComma
1095
1103
EmitLine ( "" ) ;
1096
1104
1097
1105
// global functions
1098
- GenerateGlobalProcedures ( _globalScope . AllDecls . OfType < Function > ( ) , cmd . Goals ) ;
1106
+ GenerateGlobalProcedures ( _globalScope . AllDecls . OfType < Function > ( ) , cmd . Goals , generateSanityChecks ) ;
1099
1107
1100
1108
// Spec support
1101
- GenerateSpecProcedures ( specs , cmd . Goals ) ; // generate spec methods, called by spec handlers
1109
+ GenerateSpecProcedures ( specs , cmd . Goals , generateSanityChecks ) ; // generate spec methods, called by spec handlers
1102
1110
GenerateSpecHandlers ( specs ) ; // will populate _specListenMap, which is used when ever there is a send statement
1103
1111
EmitLine ( "" ) ;
1104
1112
@@ -1126,7 +1134,9 @@ private void GenerateMain(Machine machine, State state, Event @event, ProofComma
1126
1134
1127
1135
foreach ( var inv in cmd . Goals )
1128
1136
{
1129
- EmitLine ( $ "define { InvariantPrefix } { inv . Name } (): boolean = { ExprToString ( inv . Body ) } ;") ;
1137
+ if ( ! inv . IsDefault ) {
1138
+ EmitLine ( $ "define { InvariantPrefix } { inv . Name } (): boolean = { ExprToString ( inv . Body ) } ;") ;
1139
+ }
1130
1140
}
1131
1141
1132
1142
EmitLine ( "" ) ;
@@ -1154,7 +1164,7 @@ private void GenerateMain(Machine machine, State state, Event @event, ProofComma
1154
1164
GenerateOptionTypes ( ) ;
1155
1165
EmitLine ( "" ) ;
1156
1166
1157
- if ( cmd . Name == "default" )
1167
+ if ( cmd . Name == "default" && machine == null && state == null && @event == null )
1158
1168
{
1159
1169
GenerateInitBlock ( machines , specs , _globalScope . AllDecls . OfType < AssumeOnStart > ( ) ) ;
1160
1170
EmitLine ( "" ) ;
@@ -1172,17 +1182,17 @@ private void GenerateMain(Machine machine, State state, Event @event, ProofComma
1172
1182
else
1173
1183
{
1174
1184
// non-handler functions for handlers
1175
- GenerateMachineProcedures ( machine , cmd . Goals ) ; // generate machine methods, called by handlers below
1185
+ GenerateMachineProcedures ( machine , cmd . Goals , generateSanityChecks ) ; // generate machine methods, called by handlers below
1176
1186
EmitLine ( "" ) ;
1177
1187
1178
1188
// generate the handlers
1179
1189
if ( @event != null )
1180
1190
{
1181
- GenerateEventHandler ( state , @event , cmd . Goals , cmd . Premises ) ;
1191
+ GenerateEventHandler ( state , @event , cmd . Goals , cmd . Premises , generateSanityChecks ) ;
1182
1192
}
1183
1193
else
1184
1194
{
1185
- GenerateEntryHandler ( state , cmd . Goals , cmd . Premises ) ;
1195
+ GenerateEntryHandler ( state , cmd . Goals , cmd . Premises , generateSanityChecks ) ;
1186
1196
}
1187
1197
1188
1198
EmitLine ( "" ) ;
@@ -1394,14 +1404,16 @@ private void GenerateEntryHandler(State s, List<Invariant> goals, List<Invariant
1394
1404
EmitLine ( $ "\t requires { EventOrGotoAdtIsGoto ( action ) } ;") ;
1395
1405
EmitLine ( $ "\t requires { GotoAdtIsS ( g , s ) } ;") ;
1396
1406
EmitLine ( $ "\t requires { MachineStateAdtInS ( targetMachineState , s . OwningMachine , s ) } ;") ;
1407
+
1408
+ EmitLine ( $ "\t requires { InvariantPrefix } Unique_Actions();") ;
1409
+ EmitLine ( $ "\t requires { InvariantPrefix } Increasing_Action_Count();") ;
1410
+ EmitLine ( $ "\t requires { InvariantPrefix } Received_Subset_Sent();") ;
1411
+
1397
1412
if ( generateSanityChecks )
1398
1413
{
1399
- EmitLine ( $ "\t requires { InvariantPrefix } Unique_Actions();") ;
1400
- EmitLine ( $ "\t ensures { InvariantPrefix } Unique_Actions();") ;
1401
- EmitLine ( $ "\t requires { InvariantPrefix } Increasing_Action_Count();") ;
1402
- EmitLine ( $ "\t ensures { InvariantPrefix } Increasing_Action_Count();") ;
1403
- EmitLine ( $ "\t requires { InvariantPrefix } Received_Subset_Sent();") ;
1404
- EmitLine ( $ "\t ensures { InvariantPrefix } Received_Subset_Sent();") ;
1414
+ EmitLine ( $ "\t ensures { InvariantPrefix } Unique_Actions(); // Failed to ensure unique action IDs at { GetLocation ( s ) } ") ;
1415
+ EmitLine ( $ "\t ensures { InvariantPrefix } Increasing_Action_Count(); // Failed to ensure increasing action IDs at { GetLocation ( s ) } ") ;
1416
+ EmitLine ( $ "\t ensures { InvariantPrefix } Received_Subset_Sent(); // Failed to ensure that received is a subset of sent at { GetLocation ( s ) } ") ;
1405
1417
}
1406
1418
1407
1419
foreach ( var reqs in requires )
@@ -1411,9 +1423,11 @@ private void GenerateEntryHandler(State s, List<Invariant> goals, List<Invariant
1411
1423
1412
1424
foreach ( var inv in goals )
1413
1425
{
1414
- EmitLine ( $ "\t requires { InvariantPrefix } { inv . Name } ();") ;
1415
- EmitLine (
1426
+ if ( ! inv . IsDefault ) {
1427
+ EmitLine ( $ "\t requires { InvariantPrefix } { inv . Name } ();") ;
1428
+ EmitLine (
1416
1429
$ "\t ensures { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( s ) } ") ;
1430
+ }
1417
1431
}
1418
1432
1419
1433
EmitLine ( "{" ) ;
@@ -1479,28 +1493,32 @@ private void GenerateEventHandler(State s, Event ev, List<Invariant> goals, List
1479
1493
EmitLine ( $ "\t requires { MachineStateAdtInS ( targetMachineState , s . OwningMachine , s ) } ;") ;
1480
1494
EmitLine ( $ "\t requires { EventOrGotoAdtIsEvent ( action ) } ;") ;
1481
1495
EmitLine ( $ "\t requires { EventAdtIsE ( e , ev ) } ;") ;
1482
- if ( generateSanityChecks )
1483
- {
1484
- EmitLine ( $ "\t requires { InvariantPrefix } Unique_Actions();") ;
1485
- EmitLine ( $ "\t ensures { InvariantPrefix } Unique_Actions();") ;
1486
- EmitLine ( $ "\t requires { InvariantPrefix } Increasing_Action_Count();") ;
1487
- EmitLine ( $ "\t ensures { InvariantPrefix } Increasing_Action_Count();") ;
1488
- EmitLine ( $ "\t requires { InvariantPrefix } Received_Subset_Sent();") ;
1489
- EmitLine ( $ "\t ensures { InvariantPrefix } Received_Subset_Sent();") ;
1490
- }
1496
+
1497
+ EmitLine ( $ "\t requires { InvariantPrefix } Unique_Actions();") ;
1498
+ EmitLine ( $ "\t requires { InvariantPrefix } Increasing_Action_Count();") ;
1499
+ EmitLine ( $ "\t requires { InvariantPrefix } Received_Subset_Sent();") ;
1491
1500
1492
1501
var handler = s . AllEventHandlers . ToDictionary ( ) [ ev ] ;
1493
1502
1503
+ if ( generateSanityChecks )
1504
+ {
1505
+ EmitLine ( $ "\t ensures { InvariantPrefix } Unique_Actions(); // Failed to ensure unique action IDs at { GetLocation ( handler ) } ") ;
1506
+ EmitLine ( $ "\t ensures { InvariantPrefix } Increasing_Action_Count(); // Failed to ensure increasing action IDs at { GetLocation ( handler ) } ") ;
1507
+ EmitLine ( $ "\t ensures { InvariantPrefix } Received_Subset_Sent(); // Failed to ensure that received is a subset of sent at { GetLocation ( handler ) } ") ;
1508
+ }
1509
+
1494
1510
foreach ( var reqs in requires )
1495
1511
{
1496
1512
EmitLine ( $ "\t requires { InvariantPrefix } { reqs . Name } ();") ;
1497
1513
}
1498
1514
1499
1515
foreach ( var inv in goals )
1500
1516
{
1501
- EmitLine ( $ "\t requires { InvariantPrefix } { inv . Name } ();") ;
1502
- EmitLine (
1503
- $ "\t ensures { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( handler ) } ") ;
1517
+ if ( ! inv . IsDefault ) {
1518
+ EmitLine ( $ "\t requires { InvariantPrefix } { inv . Name } ();") ;
1519
+ EmitLine (
1520
+ $ "\t ensures { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( handler ) } ") ;
1521
+ }
1504
1522
}
1505
1523
1506
1524
switch ( handler )
@@ -1515,8 +1533,8 @@ private void GenerateEventHandler(State s, Event ev, List<Invariant> goals, List
1515
1533
var name = f . Name == "" ? $ "{ BuiltinPrefix } { f . Owner . Name } _f{ line } " : f . Name ;
1516
1534
var payload = f . Signature . Parameters . Count > 0 ? $ ", { EventAdtSelectPayload ( e , ev ) } " : "" ;
1517
1535
EmitLine ( "{" ) ;
1518
- EmitLine ( $ "{ received } = { received } [{ label } -> true];") ;
1519
1536
EmitLine ( $ "call { name } ({ target } { payload } );") ;
1537
+ EmitLine ( $ "{ received } = { received } [{ label } -> true];") ;
1520
1538
foreach ( var reqs in requires )
1521
1539
{
1522
1540
EmitLine ( $ "assume { InvariantPrefix } { reqs . Name } ();") ;
@@ -1811,25 +1829,27 @@ private void GenerateStmt(IPStmt stmt, Machine specMachine, List<Invariant> goal
1811
1829
EmitLine ( $ "while ({ checker } != { collection } )") ;
1812
1830
foreach ( var inv in goals )
1813
1831
{
1814
- EmitLine (
1815
- $ "\t invariant { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( fstmt ) } ") ;
1832
+ if ( ! inv . IsDefault ) {
1833
+ EmitLine ( $ "\t invariant { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( fstmt ) } ") ;
1834
+ }
1835
+
1816
1836
}
1817
1837
1818
1838
if ( generateSanityChecks )
1819
1839
{
1820
- EmitLine ( $ "\t invariant { InvariantPrefix } Unique_Actions();") ;
1821
- EmitLine ( $ "\t invariant { InvariantPrefix } Increasing_Action_Count();") ;
1822
- EmitLine ( $ "\t invariant { InvariantPrefix } Received_Subset_Sent();") ;
1823
- // ensure uniqueness for the new ones too
1824
- EmitLine (
1825
- $ "\t invariant forall (a1: { LabelAdt } , a2: { LabelAdt } ) :: (a1 != a2 && { LocalPrefix } sent[a1] && { LocalPrefix } sent[a2]) ==> { LabelAdtSelectActionCount ( "a1" ) } != { LabelAdtSelectActionCount ( "a2" ) } ;") ;
1826
- EmitLine (
1827
- $ "\t invariant forall (a: { LabelAdt } ) :: { LocalPrefix } sent[a] ==> { LabelAdtSelectActionCount ( "a" ) } < { BuiltinPrefix } ActionCount;") ;
1828
-
1829
- // ensure we only ever add sends
1830
- EmitLine (
1831
- $ "\t invariant forall (e: { LabelAdt } ) :: { StateAdtSelectSent ( StateVar ) } [e] ==> { LocalPrefix } sent[e];") ;
1840
+ EmitLine ( $ "\t invariant { InvariantPrefix } Unique_Actions(); // Failed to ensure unique action IDs at { GetLocation ( fstmt ) } ") ;
1841
+ EmitLine ( $ "\t invariant { InvariantPrefix } Increasing_Action_Count(); // Failed to ensure increasing action IDs at { GetLocation ( fstmt ) } ") ;
1842
+ EmitLine ( $ "\t invariant { InvariantPrefix } Received_Subset_Sent(); // Failed to ensure that received is a subset of sent at { GetLocation ( fstmt ) } ") ;
1832
1843
}
1844
+
1845
+ // ensure uniqueness for the new ones too
1846
+ EmitLine (
1847
+ $ "\t invariant forall (a1: { LabelAdt } , a2: { LabelAdt } ) :: (a1 != a2 && { LocalPrefix } sent[a1] && { LocalPrefix } sent[a2]) ==> { LabelAdtSelectActionCount ( "a1" ) } != { LabelAdtSelectActionCount ( "a2" ) } ;") ;
1848
+ EmitLine (
1849
+ $ "\t invariant forall (a: { LabelAdt } ) :: { LocalPrefix } sent[a] ==> { LabelAdtSelectActionCount ( "a" ) } < { BuiltinPrefix } ActionCount;") ;
1850
+ // ensure we only ever add sends
1851
+ EmitLine (
1852
+ $ "\t invariant forall (e: { LabelAdt } ) :: { StateAdtSelectSent ( StateVar ) } [e] ==> { LocalPrefix } sent[e];") ;
1833
1853
1834
1854
// user given invariants
1835
1855
foreach ( var inv in fstmt . Invariants )
@@ -1860,13 +1880,16 @@ private void GenerateStmt(IPStmt stmt, Machine specMachine, List<Invariant> goal
1860
1880
EmitLine ( $ "while ({ checker } != { collection } )") ;
1861
1881
foreach ( var inv in goals )
1862
1882
{
1863
- EmitLine (
1864
- $ "\t invariant { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( fstmt ) } ") ;
1883
+ if ( ! inv . IsDefault ) {
1884
+ EmitLine ( $ "\t invariant { InvariantPrefix } { inv . Name } (); // Failed to verify invariant { inv . Name . Replace ( "_PGROUP_" , ": " ) } at { GetLocation ( fstmt ) } ") ;
1885
+ }
1865
1886
}
1866
1887
1867
- EmitLine ( $ "\t invariant { InvariantPrefix } Unique_Actions();") ;
1868
- EmitLine ( $ "\t invariant { InvariantPrefix } Increasing_Action_Count();") ;
1869
- EmitLine ( $ "\t invariant { InvariantPrefix } Received_Subset_Sent();") ;
1888
+ if ( generateSanityChecks ) {
1889
+ EmitLine ( $ "\t invariant { InvariantPrefix } Unique_Actions(); // Failed to ensure unique action IDs at { GetLocation ( fstmt ) } ") ;
1890
+ EmitLine ( $ "\t invariant{ InvariantPrefix } Increasing_Action_Count(); // Failed to ensure increasing action IDs at { GetLocation ( fstmt ) } ") ;
1891
+ EmitLine ( $ "\t invariant { InvariantPrefix } Received_Subset_Sent(); // Failed to ensure that received is a subset of sent at { GetLocation ( fstmt ) } ") ;
1892
+ }
1870
1893
// ensure uniqueness for the new ones too
1871
1894
EmitLine (
1872
1895
$ "\t invariant forall (a1: { LabelAdt } , a2: { LabelAdt } ) :: (a1 != a2 && { LocalPrefix } sent[a1] && { LocalPrefix } sent[a2]) ==> { LabelAdtSelectActionCount ( "a1" ) } != { LabelAdtSelectActionCount ( "a2" ) } ;") ;
0 commit comments