From ce44d7ee5314f2802829236785e93f1ef85f6e00 Mon Sep 17 00:00:00 2001
From: tempiaa <tempiaa@eurecom.fr>
Date: Mon, 20 Jul 2020 17:50:47 +0200
Subject: [PATCH] General internal action loop detector using leadsTo pragmas

---
 .../modelchecker/AvatarModelChecker.java      | 67 ++++++++++++++-----
 .../modelchecker/SpecificationActionLoop.java | 45 +++++++++++--
 .../modelchecker/SpecificationState.java      |  4 ++
 3 files changed, 96 insertions(+), 20 deletions(-)

diff --git a/src/main/java/avatartranslator/modelchecker/AvatarModelChecker.java b/src/main/java/avatartranslator/modelchecker/AvatarModelChecker.java
index 84bbba7817..cf467c079f 100644
--- a/src/main/java/avatartranslator/modelchecker/AvatarModelChecker.java
+++ b/src/main/java/avatartranslator/modelchecker/AvatarModelChecker.java
@@ -114,6 +114,7 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
     
     // Internal-action loop
     private boolean studyActionLoop;
+    private int partialHash;
     private ArrayList<SpecificationActionLoop> actionLoops;
     
     //Debug counterexample
@@ -159,6 +160,7 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
         freeIntermediateStateCoding = true;
         verboseInfo = true;
         compressionFactor = 1;
+        partialHash = -1;
     }
 
     public AvatarSpecification getInitialSpec() {
@@ -545,7 +547,7 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
                             iter.remove();
                         }
                     }
-                    System.out.println("Dimensions of lead states to elaborate: " + safetyLeadStates.size());
+//                    System.out.println("Dimensions of lead states to elaborate: " + safetyLeadStates.size());
                     safetyLeadStates = null;
                 }
                 if (!stoppedBeforeEnd) {
@@ -572,6 +574,7 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
             ignoreConcurrenceBetweenInternalActions = true;
             actionLoops = new ArrayList<SpecificationActionLoop>();
             List<ArrayList<AvatarTransition>> internalLoops;
+            int i = 0;
             for(AvatarBlock block : spec.getListOfBlocks()) {
                 internalLoops = block.getStateMachine().checkStaticInternalLoops();    
                 if (internalLoops != null && internalLoops.isEmpty() == false) {
@@ -590,28 +593,56 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
 //                            sap.setResult();
 //                        }
 //                    }
-                    SpecificationActionLoop sap = new SpecificationActionLoop(internalLoops, spec);
-                    if (!sap.hasError()) {
+                    SpecificationActionLoop sap = new SpecificationActionLoop(internalLoops);
+//                    sap.init(spec);
+//                    if (!sap.hasError()) {
+//                        actionLoops.add(sap);
+//                        do {
+//                            safety = sap.getReachability();
+//                            startModelChecking(nbOfThreads);
+//                            resetModelChecking();
+//                            if (sap.hasProperty()) {
+//                                safety = sap.getProperty();
+//                                startModelChecking(nbOfThreads);
+//                                resetModelChecking();
+//                            }
+//                            if (sap.setCover()) {
+//                                break;
+//                            }
+//                        } while (sap.increasePointer());
+//                        sap.setResult();
+//
+//                    }
+                    sap.initLeadsTo(spec);
+                    if(!sap.hasError()) {
                         actionLoops.add(sap);
-                        do {
-                            safety = sap.getReachability();
-                            startModelChecking(nbOfThreads);
+                        safety = sap.getPropertyLeadsTo();
+                        safetyLeadStates = Collections.synchronizedMap(new HashMap<Integer, SpecificationState>());
+                        ignoreEmptyTransitions = false;
+                        partialHash = i; //restrict the hashing to only the current block
+                        startModelChecking(nbOfThreads);
+                        partialHash = -1;
+                        safety.initLead();
+                        Iterator<Map.Entry<Integer,SpecificationState>> iter = safetyLeadStates.entrySet().iterator();
+                        while (iter.hasNext()) {
+                            SpecificationState state = iter.next().getValue();
                             resetModelChecking();
-                            if (sap.hasProperty()) {
-                                safety = sap.getProperty();
-                                startModelChecking(nbOfThreads);
-                                resetModelChecking();
-                            }
-                            if (sap.setCover()) {
+                            startModelChecking(state, nbOfThreads);
+                            if (safety.result == false) {
                                 break;
+                            } else {
+                                //free memory
+                                iter.remove();
                             }
-                        } while (sap.increasePointer());
-                        sap.setResult();
-
+                        }
+                        safetyLeadStates = null;
+                        sap.setResultLeadsTo();
                     }
                 }
+                i++;
             }
             ignoreConcurrenceBetweenInternalActions = ignoreConcurrence;
+            ignoreEmptyTransitions = emptyTr;
             studySafety = false;
         }
         
@@ -2178,7 +2209,11 @@ public class AvatarModelChecker implements Runnable, myutil.Graph {
                         if (!ignoreConcurrenceBetweenInternalActions) {
                             state = reduceCombinatorialExplosionProperty(state);
                         }
-                        safetyLeadStates.put(state.getHash(state.getBlockValues()), state);
+                        if (partialHash == -1) {
+                            safetyLeadStates.put(state.getHash(state.getBlockValues()), state);
+                        } else {
+                            safetyLeadStates.put(state.getPartialHash(partialHash), state);
+                        }
                         newState.property = false;
                     }
                     addToPending = 1;
diff --git a/src/main/java/avatartranslator/modelchecker/SpecificationActionLoop.java b/src/main/java/avatartranslator/modelchecker/SpecificationActionLoop.java
index d49c6af052..0bab01b859 100644
--- a/src/main/java/avatartranslator/modelchecker/SpecificationActionLoop.java
+++ b/src/main/java/avatartranslator/modelchecker/SpecificationActionLoop.java
@@ -23,16 +23,15 @@ public class SpecificationActionLoop {
     private int pointer;
 
     
-    public SpecificationActionLoop(List<ArrayList<AvatarTransition>> paths, AvatarSpecification spec) {
+    public SpecificationActionLoop(List<ArrayList<AvatarTransition>> paths) {
         //this.path = path;
         this.error = false;
         pointer = 0;
         internalLoops = paths;
-        init(spec);
     }
     
     
-    private void init(AvatarSpecification spec) {
+    public void init(AvatarSpecification spec) {
         Map<AvatarStateMachineElement, Set<AvatarTransition>> map = new HashMap<>();
         
         for (List<AvatarTransition> list : internalLoops) {
@@ -89,8 +88,36 @@ public class SpecificationActionLoop {
             }
             i++;
         }
-
+    }
+    
+    
+    public void initLeadsTo(AvatarSpecification spec) {
+        Set<AvatarStateMachineElement> stateSet = new HashSet<>();
+        
+        for (List<AvatarTransition> list : internalLoops) {       
+            for (AvatarTransition at : list) {
+                stateSet.add(at.getNext(0));
+            }
+        }
+        
+        properties = new SafetyProperty[1];
+        
+        AvatarBlock block = (AvatarBlock) internalLoops.get(0).get(0).getBlock();
+        
+        int i = 0;
+        StringBuilder formula = new StringBuilder();
+        for (AvatarStateMachineElement el : stateSet) {
+            if (i != 0) {
+                formula.append("||");
+            }
+            formula.append(el.getName());
+            i++;
+        }
         
+        SafetyProperty property = new SafetyProperty(formula.toString() + "-->!(" + formula.toString() + ")");
+        property.analyzeProperty(block, spec);
+        error |= property.hasError();
+        properties[0] = property;
     }
     
     public boolean hasError() {
@@ -118,6 +145,10 @@ public class SpecificationActionLoop {
         return null;
     }
     
+    public SafetyProperty getPropertyLeadsTo() {
+        return properties[0];
+    }
+    
     public boolean increasePointer() {
         if (pointer < states.length - 1) {
             pointer++;
@@ -166,6 +197,10 @@ public class SpecificationActionLoop {
         }
     }
     
+    public void setResultLeadsTo() {
+        result = !properties[0].result;
+    }
+    
     public boolean getResult() {
         return result;
     }
@@ -175,6 +210,8 @@ public class SpecificationActionLoop {
         
         if(internalLoops == null) {
             return "";
+        } else if (cover == null) {
+            return "In block " + internalLoops.get(0).get(0).getBlock().getName();
         }
         
         int i = 0;
diff --git a/src/main/java/avatartranslator/modelchecker/SpecificationState.java b/src/main/java/avatartranslator/modelchecker/SpecificationState.java
index 2d4533bad7..05d53ec188 100644
--- a/src/main/java/avatartranslator/modelchecker/SpecificationState.java
+++ b/src/main/java/avatartranslator/modelchecker/SpecificationState.java
@@ -95,6 +95,10 @@ public class SpecificationState implements Comparable<SpecificationState>  {
         }
         return hashValue;
     }
+    
+    public int getPartialHash(int index) {
+        return Arrays.hashCode(blocks[index].values);
+    }
 
     public void setInit(AvatarSpecification _spec, boolean _ignoreEmptyTransitions) {
         int cpt = 0;
-- 
GitLab