From 9ca1929c483e855b9d5017a5e3f0368e98c85ea9 Mon Sep 17 00:00:00 2001 From: jah12014 Date: Sun, 1 Apr 2018 14:00:57 -0400 Subject: [PATCH] Refactoring for better OOP structure Split different equiv test cases into separate minimization classes --- .../src/IncrementalMinimization.java | 449 ++---------------- .../src/IncrementalNaive.java | 101 ++++ .../src/IncrementalRecursive.java | 252 ++++++++++ .../src/TestIncrementalMinimization.java | 96 ++-- .../src/TimeBudgetExceededException.java | 25 + 5 files changed, 489 insertions(+), 434 deletions(-) create mode 100644 IncrementalMinimization/src/IncrementalNaive.java create mode 100644 IncrementalMinimization/src/IncrementalRecursive.java create mode 100644 IncrementalMinimization/src/TimeBudgetExceededException.java diff --git a/IncrementalMinimization/src/IncrementalMinimization.java b/IncrementalMinimization/src/IncrementalMinimization.java index 669a3285..053f2c8f 100644 --- a/IncrementalMinimization/src/IncrementalMinimization.java +++ b/IncrementalMinimization/src/IncrementalMinimization.java @@ -21,30 +21,7 @@ public class IncrementalMinimization { - @SuppressWarnings("rawtypes") //Throwable subclasses can not be made generic - private static class TimeBudgetExceeded extends TimeoutException - { - - private final SFA returnAut; - - public TimeBudgetExceeded(String message, SFA returnAut) - { - super(message); - this.returnAut = returnAut; - } - - public TimeBudgetExceeded(SFA returnAut) - { - this("Time budget exceeded", returnAut); - } - - public SFA getReturnAut() - { - return returnAut; - } - } - - private class EquivTest //tests for equality of two given states in the automata + protected class EquivTest //tests for equality of two given states in the automata { protected class EquivRecord { @@ -178,307 +155,9 @@ public Integer getMaxDepth() throws DebugException throw new DebugException("Not in debug"); } } - - private class EquivTestRecursive extends EquivTest - { - private class ResultDependencies - { - private boolean result; - private boolean isindependent; - private HashMap, Boolean> dependencyTest; //List of pairs of states that must be equivalent for current result to hold. - private HashSet> dependencies; - - public ResultDependencies(boolean result) - { - this.result = result; - this.isindependent = true; - this.dependencyTest = new HashMap, Boolean>(); - this.dependencies = new HashSet>(); - } - - public ResultDependencies(boolean result, List dependency) - { - this(result); - addDependency(dependency); - this.isindependent = false; - } - - public boolean resultIsIndependent() - { - return isindependent; - } - - public void addDependency(List pair) - { - if (isEquiv()) - { - dependencyTest.put(pair, false); - dependencies.add(pair); - isindependent = false; - } - else - { - throw new IllegalStateException("False result has no dependencies"); - } - } - - public void removeDependency(List pair) - { - dependencyTest.put(pair, true); - dependencies.remove(pair); - if (dependencies.isEmpty()) - { - isindependent = true; - } - } - - public boolean isDependency(List pair) - { - return dependencies.contains(pair); - } - - public void combineWithResult(ResultDependencies other) - { - result = result && other.isEquiv(); - if(!result) - { - dependencies.clear(); - } - else - { - HashMap, Boolean> otherDepends = other.getDependencyTests(); - for (List pair : otherDepends.keySet()) - { - Boolean otherSatisfied = otherDepends.get(pair); - if(otherSatisfied) - { - removeDependency(pair); - } - else - { - if(!dependencyTest.containsKey(pair)) - { - addDependency(pair); - } - else - { - if(!dependencyTest.get(pair)) - { - assert(isDependency(pair)); - } - } - } - } - } - } - - public boolean isEquiv() - { - return result; - } - - public HashMap, Boolean> getDependencyTests() - { - return dependencyTest; - } - - public void updateDepenencies() - { - List> checked = new LinkedList>(); - for (List pair : dependencies) - { - if(!path.contains(pair)) - { - dependencyTest.put(pair, true); - checked.add(pair); - } - } - dependencies.removeAll(checked); - } - } - - private HashMap, ResultDependencies> equivDepends; - public EquivTestRecursive(DisjointSets equivClasses, HashSet> equiv, - HashSet> path) - { - super(equivClasses, equiv, path); - this.equivDepends = new HashMap, ResultDependencies>(); - } - - public ResultDependencies isEquivRecursive(Integer p, Integer q) throws TimeoutException - { - if (isKnownNotEqual(p,q)) - { - return new ResultDependencies(false); - } - List pair = normalize(p,q); - if (path.contains(pair)) - { - ResultDependencies r = new ResultDependencies(true); - r.addDependency(pair); - return r; - } - path.add(pair); - Collection> outp = new ArrayList>(aut.getInputMovesFrom(p)); - Collection> outq = new ArrayList>(aut.getInputMovesFrom(q)); - ResultDependencies thisResult = new ResultDependencies(true); - while (!outp.isEmpty() && !outq.isEmpty()) - { - List> nonDisjointGuards = findNonDisjointMoves(outp,outq); - SFAInputMove pMove = nonDisjointGuards.get(0); - SFAInputMove qMove = nonDisjointGuards.get(1); - //note: we don't actually need to generate a witness, only need to know pMove,qMove are non-disjoint - Integer pNextClass = equivClasses.find(pMove.to); - Integer qNextClass = equivClasses.find(qMove.to); - List nextPair = normalize(pNextClass, qNextClass); - if ( !pNextClass.equals(qNextClass) && !equiv.contains(nextPair)) - { - equiv.add(nextPair); - equivDepends.put(nextPair, null); - if(path.contains(nextPair)) - { - thisResult.addDependency(nextPair); - } - else - { - ResultDependencies nextResult = isEquivRecursive(pNextClass, qNextClass); - if(!nextResult.isEquiv()) - { - return nextResult; - } - else - { - equivDepends.put(nextPair, nextResult); - path.remove(nextPair); - thisResult.combineWithResult(nextResult); - } - } - } - else if (equiv.contains(nextPair)) - { - ResultDependencies dependencies = equivDepends.get(nextPair); - if (dependencies == null && !pair.equals(nextPair)) - { - thisResult.addDependency(nextPair); - } - else if(!pair.equals(nextPair)) - { - thisResult.combineWithResult(dependencies); - } - } - outp.remove(pMove); - outq.remove(qMove); - P newPGuard = ba.MkAnd(pMove.guard, ba.MkNot(qMove.guard)); - if (ba.IsSatisfiable(newPGuard)) - { - outp.add(new SFAInputMove(pMove.from, pMove.to, newPGuard)); - } - P newQGuard = ba.MkAnd(qMove.guard, ba.MkNot(pMove.guard)); - if (ba.IsSatisfiable(newQGuard)) - { - outq.add(new SFAInputMove(qMove.from, qMove.to, newQGuard)); - } - } - thisResult.removeDependency(pair); - thisResult.updateDepenencies(); - if(thisResult.resultIsIndependent()) - { - equivClasses.union(p,q); - } - else - { - equiv.add(pair); - equivDepends.put(pair, thisResult); - } - return thisResult; - } - - @Override - public boolean isEquiv(Integer pStart, Integer qStart) throws TimeoutException - { - ResultDependencies finalResult = isEquivRecursive(pStart, qStart); - return finalResult.isEquiv(); - } - } - - private class EquivTestUpfront extends EquivTest - { - - private final ArrayList

minterms; - - public EquivTestUpfront(DisjointSets equivClasses, ArrayList

minterms, - HashSet> equiv, HashSet> path) - { - super(equivClasses, equiv, path); - this.minterms = minterms; - } - - private Integer mintermTransition(Integer state, P minterm) throws TimeoutException - { - Integer toState = null; - for (SFAInputMove t : aut.getInputMovesFrom(state)) - { - if (ba.IsSatisfiable(ba.MkAnd(minterm, t.guard))) - { - //aut is deterministic and complete. So, always one and exactly one transition per minterm. - toState = t.to; - break; - } - } - assert(toState != null); - return toState; - } - - @Override - public boolean isEquiv(Integer pStart, Integer qStart) throws TimeoutException, TimeBudgetExceeded - { - if (isKnownNotEqual(pStart,qStart)) - { - return false; - } - EquivRecord start = new EquivRecord(pStart,qStart,path); - Stack testStack = new Stack(); - testStack.add(start); - while (!testStack.isEmpty()) - { - EquivRecord curEquivTest = testStack.pop(); - Integer p = curEquivTest.pState; - Integer q = curEquivTest.qState; - HashSet> curPath = curEquivTest.curPath; - List pair = normalize(p,q); - HashSet> newPath = new HashSet>(curPath); - newPath.add(pair); - for (P minterm : minterms) - { - Integer pNextClass = equivClasses.find(mintermTransition(p, minterm)); - Integer qNextClass = equivClasses.find(mintermTransition(q, minterm)); - List nextPair = normalize(pNextClass, qNextClass); - if (!pNextClass.equals(qNextClass) && !equiv.contains(nextPair)) - { - equiv.add(nextPair); - if(isKnownNotEqual(pNextClass, qNextClass)) - { - return false; - } - if(!newPath.contains(nextPair)) - { - equiv.add(nextPair); - EquivRecord nextTest = new EquivRecord(pNextClass, qNextClass, newPath); - testStack.push(nextTest); - } - } - } - } - equiv.add(normalize(pStart, qStart)); - return true; - } - - } - private class StateComparator implements Comparator { - public int compare(Integer a, Integer b) { int diff = distanceToFinalMap.get(a) - distanceToFinalMap.get(b); @@ -491,54 +170,11 @@ public int compare(Integer a, Integer b) return diff; } } - } - @SuppressWarnings("unchecked") - public static SFA incrementalMinimize(SFA aut, BooleanAlgebra ba, long budget, boolean upfront) - throws TimeoutException - { - try - { - IncrementalMinimization min = new IncrementalMinimization(aut, ba, false); - return min.minimize(budget, upfront, false, false); - } - catch(TimeBudgetExceeded e) - { - return e.getReturnAut(); - } - catch(DebugException e) - { - throw new RuntimeException(e); //impossible to get here. - } - } - - public static SFA incrementalMinimize(SFA aut, BooleanAlgebra ba, boolean upfront) throws TimeoutException - { - return incrementalMinimize(aut, ba, Long.MAX_VALUE, upfront); - } - - public static SFA incrementalMinimize(SFA aut, BooleanAlgebra ba) throws TimeoutException - { - return incrementalMinimize(aut, ba, Long.MAX_VALUE, false); //Default time budget 200+ years (i.e. there is none) - } - - public static SFA incrRecursiveMin(SFA aut, BooleanAlgebra ba) throws TimeoutException - { - IncrementalMinimization recMin = new IncrementalMinimization(aut,ba, false); - try - { - return recMin.minimize(Long.MAX_VALUE, false, false, true); - } - catch (DebugException e) - { - throw new RuntimeException(e); - } - } - - private final SFA aut; - private final BooleanAlgebra ba; - private final int num_pairs; + protected final SFA aut; + protected final BooleanAlgebra ba; + protected final int num_pairs; private HashSet> neq; private LinkedHashMap distanceToFinalMap; @@ -548,7 +184,7 @@ public static SFA incrRecursiveMin(SFA aut, BooleanAlgebra private Long singularRecord = null; private boolean debug; - public IncrementalMinimization(SFA aut, BooleanAlgebra ba, boolean debug) throws TimeoutException + public IncrementalMinimization(SFA aut, BooleanAlgebra ba) throws TimeoutException { if (!aut.isDeterministic()) { @@ -556,7 +192,7 @@ public IncrementalMinimization(SFA aut, BooleanAlgebra ba, boolean deb } this.aut = aut.mkTotal(ba); this.ba = ba; - this.debug=debug; + this.debug=false; this.num_pairs = aut.getStates().size() * aut.getStates().size(); this.neq = new HashSet>(num_pairs, 0.9f); //won't exceed initial capacity this.distanceToFinalMap = generateDistanceToFinalMap(); @@ -621,7 +257,14 @@ public String toString() return distanceMap; } - private List normalize(Integer p, Integer q) + protected EquivTest makeEquivTest(DisjointSets equivClasses) + { + HashSet> equiv = new HashSet>(num_pairs,0.9f); + HashSet> path = new HashSet>(num_pairs,0.9f); + return new EquivTest(equivClasses, equiv, path); + } + + protected List normalize(Integer p, Integer q) { List pair; if(stateComp.compare(p, q) < 0) @@ -635,12 +278,7 @@ private List normalize(Integer p, Integer q) return pair; } - private boolean isSinkState(Integer p) - { - return distanceToFinalMap.get(p) == Integer.MAX_VALUE; - } - - private boolean isKnownNotEqual(Integer p, Integer q) + protected boolean isKnownNotEqual(Integer p, Integer q) { List normalizedPair = normalize(p,q); if (neq.contains(normalizedPair)) @@ -658,7 +296,7 @@ else if (!distanceToFinalMap.get(p).equals(distanceToFinalMap.get(q))) } } - private SFA mergeSFAStates(DisjointSets equivClasses) throws TimeoutException + protected SFA mergeSFAStates(DisjointSets equivClasses) throws TimeoutException { //new SFA created with minimum states HashMap> classes = equivClasses.getSets(); @@ -681,13 +319,13 @@ private SFA mergeSFAStates(DisjointSets equivClasses) throws Timeo return minAut; } - private void updateRecord(DisjointSets equivClasses) + protected void updateRecord(DisjointSets equivClasses) { Long time = System.nanoTime(); record.put(time, equivClasses.getSets().size()); } - private void timeCheck(long endTime, DisjointSets equivClasses) throws TimeoutException + protected void timeCheck(long endTime, DisjointSets equivClasses) throws TimeoutException { if(System.nanoTime() > endTime) { @@ -695,7 +333,7 @@ private void timeCheck(long endTime, DisjointSets equivClasses) throws SFA curAut = mergeSFAStates(equivClasses); double exceeded = (new Double(System.nanoTime()-endTime))/1000000; System.out.println(String.format("Exceeded by %f ms", exceeded)); - throw new TimeBudgetExceeded(curAut); + throw new TimeBudgetExceededException(curAut); /* Current time budget implementation intended to test % of automata minimization given * a set period of time. However, it does not necessarily return this mostly minimized * automata exactly after the budget is met (this is definitely possible, just not with @@ -705,10 +343,11 @@ private void timeCheck(long endTime, DisjointSets equivClasses) throws } } - public SFA minimize(long budget, boolean upfront, boolean recordMinimization, boolean recursive) + public SFA minimize(long budget, boolean recordMinimization, boolean debug) throws TimeoutException, DebugException { this.startTime = System.nanoTime(); + this.debug = debug; long endTime = startTime + budget; if (endTime < 0) //indicates overflow { @@ -722,11 +361,6 @@ public SFA minimize(long budget, boolean upfront, boolean recordMinimizati } return SFA.getEmptySFA(ba); } - ArrayList

upfront_minterms = null; - if(upfront) - { - upfront_minterms = MintermTree.generate_minterms(aut, ba); - } DisjointSets equivClasses = new DisjointSets(); for(Integer q : aut.getStates()) { @@ -757,26 +391,11 @@ else if(equivClasses.find(p) == equivClasses.find(q)) continue; } //TODO: look into efficiency of HashSet operations, ideally should be O(1) for searching, inserting, removing - HashSet> equiv = new HashSet>(num_pairs,0.9f); - HashSet> path = new HashSet>(num_pairs,0.9f); timeCheck(endTime, equivClasses); - EquivTest pEquiv; - if(upfront) - { - pEquiv = new EquivTestUpfront(equivClasses, upfront_minterms, equiv, path); - - } - else if (recursive) - { - pEquiv = new EquivTestRecursive(equivClasses, equiv, path); - } - else - { - pEquiv = new EquivTest(equivClasses, equiv, path); - } + EquivTest pEquiv = makeEquivTest(equivClasses); boolean isequiv = pEquiv.isEquiv(p, q); - equiv = pEquiv.getEquiv(); - path = pEquiv.getPath(); + HashSet> equiv = pEquiv.getEquiv(); + HashSet> path = pEquiv.getPath(); if(isequiv) { //p,q found equivalent. Other pairs may be found equivalent. @@ -809,6 +428,26 @@ else if (recursive) return mergeSFAStates(equivClasses); } + public SFA minimize(long budget) throws TimeoutException + { + SFA minAut = null; + try + { + minAut = minimize(budget, false, false); + } + catch (DebugException e) + { + //We never get a debug exception here. + } + assert(minAut != null); + return minAut; + } + + public SFA minimize() throws TimeoutException + { + return minimize(Long.MAX_VALUE); + } + public LinkedHashMap getRecord() throws TimeoutException { LinkedHashMap actualRecord = new LinkedHashMap(); diff --git a/IncrementalMinimization/src/IncrementalNaive.java b/IncrementalMinimization/src/IncrementalNaive.java new file mode 100644 index 00000000..93eda39b --- /dev/null +++ b/IncrementalMinimization/src/IncrementalNaive.java @@ -0,0 +1,101 @@ +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Stack; + +import org.sat4j.specs.TimeoutException; + +import theory.BooleanAlgebra; +import automata.sfa.SFA; +import automata.sfa.SFAInputMove; + + +public class IncrementalNaive extends IncrementalMinimization +{ + + private class EquivTestNaive extends EquivTest + { + + public EquivTestNaive(DisjointSets equivClasses, HashSet> equiv, + HashSet> path) + { + super(equivClasses, equiv, path); + } + + private Integer mintermTransition(Integer state, P minterm) throws TimeoutException + { + Integer toState = null; + for (SFAInputMove t : aut.getInputMovesFrom(state)) + { + if (ba.IsSatisfiable(ba.MkAnd(minterm, t.guard))) + { + //aut is deterministic and complete. So, always one and exactly one transition per minterm. + toState = t.to; + break; + } + } + assert(toState != null); + return toState; + } + + @Override + public boolean isEquiv(Integer pStart, Integer qStart) throws TimeoutException + { + if (isKnownNotEqual(pStart,qStart)) + { + return false; + } + EquivRecord start = new EquivRecord(pStart,qStart,path); + Stack testStack = new Stack(); + testStack.add(start); + while (!testStack.isEmpty()) + { + EquivRecord curEquivTest = testStack.pop(); + Integer p = curEquivTest.pState; + Integer q = curEquivTest.qState; + HashSet> curPath = curEquivTest.curPath; + List pair = normalize(p,q); + HashSet> newPath = new HashSet>(curPath); + newPath.add(pair); + for (P minterm : minterms) + { + Integer pNextClass = equivClasses.find(mintermTransition(p, minterm)); + Integer qNextClass = equivClasses.find(mintermTransition(q, minterm)); + List nextPair = normalize(pNextClass, qNextClass); + if (!pNextClass.equals(qNextClass) && !equiv.contains(nextPair)) + { + equiv.add(nextPair); + if(isKnownNotEqual(pNextClass, qNextClass)) + { + return false; + } + if(!newPath.contains(nextPair)) + { + equiv.add(nextPair); + EquivRecord nextTest = new EquivRecord(pNextClass, qNextClass, newPath); + testStack.push(nextTest); + } + } + } + } + equiv.add(normalize(pStart, qStart)); + return true; + } + } + + private final ArrayList

minterms; + + public IncrementalNaive(SFA aut, BooleanAlgebra ba) throws TimeoutException + { + super(aut,ba); + minterms = MintermTree.generate_minterms(aut, ba); + } + + @Override + protected EquivTest makeEquivTest(DisjointSets equivClasses) + { + HashSet> equiv = new HashSet>(num_pairs,0.9f); + HashSet> path = new HashSet>(num_pairs,0.9f); + return new EquivTestNaive(equivClasses, equiv, path); + } +} diff --git a/IncrementalMinimization/src/IncrementalRecursive.java b/IncrementalMinimization/src/IncrementalRecursive.java new file mode 100644 index 00000000..d9b3a069 --- /dev/null +++ b/IncrementalMinimization/src/IncrementalRecursive.java @@ -0,0 +1,252 @@ +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import org.sat4j.specs.TimeoutException; + +import theory.BooleanAlgebra; +import automata.sfa.SFA; +import automata.sfa.SFAInputMove; + + +public class IncrementalRecursive extends IncrementalMinimization +{ + private class EquivTestRecursive extends EquivTest + { + private class ResultDependencies + { + private boolean result; + private boolean isindependent; + private HashMap, Boolean> dependencyTest; //List of pairs of states that must be equivalent for current result to hold. + private HashSet> dependencies; + + public ResultDependencies(boolean result) + { + this.result = result; + this.isindependent = true; + this.dependencyTest = new HashMap, Boolean>(); + this.dependencies = new HashSet>(); + } + + public ResultDependencies(boolean result, List dependency) + { + this(result); + addDependency(dependency); + this.isindependent = false; + } + + public boolean resultIsIndependent() + { + return isindependent; + } + + public void addDependency(List pair) + { + if (isEquiv()) + { + dependencyTest.put(pair, false); + dependencies.add(pair); + isindependent = false; + } + else + { + throw new IllegalStateException("False result has no dependencies"); + } + } + + public void removeDependency(List pair) + { + dependencyTest.put(pair, true); + dependencies.remove(pair); + if (dependencies.isEmpty()) + { + isindependent = true; + } + } + + public boolean isDependency(List pair) + { + return dependencies.contains(pair); + } + + public void combineWithResult(ResultDependencies other) + { + result = result && other.isEquiv(); + if(!result) + { + dependencies.clear(); + } + else + { + HashMap, Boolean> otherDepends = other.getDependencyTests(); + for (List pair : otherDepends.keySet()) + { + Boolean otherSatisfied = otherDepends.get(pair); + if(otherSatisfied) + { + removeDependency(pair); + } + else + { + if(!dependencyTest.containsKey(pair)) + { + addDependency(pair); + } + else + { + if(!dependencyTest.get(pair)) + { + assert(isDependency(pair)); + } + } + } + } + } + } + + public boolean isEquiv() + { + return result; + } + + public HashMap, Boolean> getDependencyTests() + { + return dependencyTest; + } + + public void updateDepenencies() + { + List> checked = new LinkedList>(); + for (List pair : dependencies) + { + if(!path.contains(pair)) + { + dependencyTest.put(pair, true); + checked.add(pair); + } + } + dependencies.removeAll(checked); + } + } + + private HashMap, ResultDependencies> equivDepends; + + public EquivTestRecursive(DisjointSets equivClasses, HashSet> equiv, + HashSet> path) + { + super(equivClasses, equiv, path); + this.equivDepends = new HashMap, ResultDependencies>(); + } + + public ResultDependencies isEquivRecursive(Integer p, Integer q) throws TimeoutException + { + if (isKnownNotEqual(p,q)) + { + return new ResultDependencies(false); + } + List pair = normalize(p,q); + if (path.contains(pair)) + { + ResultDependencies r = new ResultDependencies(true); + r.addDependency(pair); + return r; + } + path.add(pair); + Collection> outp = new ArrayList>(aut.getInputMovesFrom(p)); + Collection> outq = new ArrayList>(aut.getInputMovesFrom(q)); + ResultDependencies thisResult = new ResultDependencies(true); + while (!outp.isEmpty() && !outq.isEmpty()) + { + List> nonDisjointGuards = findNonDisjointMoves(outp,outq); + SFAInputMove pMove = nonDisjointGuards.get(0); + SFAInputMove qMove = nonDisjointGuards.get(1); + //note: we don't actually need to generate a witness, only need to know pMove,qMove are non-disjoint + Integer pNextClass = equivClasses.find(pMove.to); + Integer qNextClass = equivClasses.find(qMove.to); + List nextPair = normalize(pNextClass, qNextClass); + if ( !pNextClass.equals(qNextClass) && !equiv.contains(nextPair)) + { + equiv.add(nextPair); + equivDepends.put(nextPair, null); + if(path.contains(nextPair)) + { + thisResult.addDependency(nextPair); + } + else + { + ResultDependencies nextResult = isEquivRecursive(pNextClass, qNextClass); + if(!nextResult.isEquiv()) + { + return nextResult; + } + else + { + equivDepends.put(nextPair, nextResult); + path.remove(nextPair); + thisResult.combineWithResult(nextResult); + } + } + } + else if (equiv.contains(nextPair)) + { + ResultDependencies dependencies = equivDepends.get(nextPair); + if (dependencies == null && !pair.equals(nextPair)) + { + thisResult.addDependency(nextPair); + } + else if(!pair.equals(nextPair)) + { + thisResult.combineWithResult(dependencies); + } + } + outp.remove(pMove); + outq.remove(qMove); + P newPGuard = ba.MkAnd(pMove.guard, ba.MkNot(qMove.guard)); + if (ba.IsSatisfiable(newPGuard)) + { + outp.add(new SFAInputMove(pMove.from, pMove.to, newPGuard)); + } + P newQGuard = ba.MkAnd(qMove.guard, ba.MkNot(pMove.guard)); + if (ba.IsSatisfiable(newQGuard)) + { + outq.add(new SFAInputMove(qMove.from, qMove.to, newQGuard)); + } + } + thisResult.removeDependency(pair); + thisResult.updateDepenencies(); + if(thisResult.resultIsIndependent()) + { + equivClasses.union(p,q); + } + else + { + equiv.add(pair); + equivDepends.put(pair, thisResult); + } + return thisResult; + } + + @Override + public boolean isEquiv(Integer pStart, Integer qStart) throws TimeoutException + { + ResultDependencies finalResult = isEquivRecursive(pStart, qStart); + return finalResult.isEquiv(); + } + } + + public IncrementalRecursive(SFA aut, BooleanAlgebra ba) throws TimeoutException + { + super(aut,ba); + } + + @Override + protected EquivTest makeEquivTest(DisjointSets equivClasses) + { + HashSet> equiv = new HashSet>(num_pairs,0.9f); + HashSet> path = new HashSet>(num_pairs,0.9f); + return new EquivTestRecursive(equivClasses, equiv, path); + } +} diff --git a/IncrementalMinimization/src/TestIncrementalMinimization.java b/IncrementalMinimization/src/TestIncrementalMinimization.java index 31bee3ba..3cfcb4a0 100644 --- a/IncrementalMinimization/src/TestIncrementalMinimization.java +++ b/IncrementalMinimization/src/TestIncrementalMinimization.java @@ -40,7 +40,8 @@ public class TestIncrementalMinimization { @Test - public void testMyAut() throws TimeoutException { + public void testMyAut() throws TimeoutException + { //our algebra is constructed IntegerSolver ba = new IntegerSolver(); IntPred neg = new IntPred(null, new Integer(0)); @@ -86,9 +87,11 @@ public void testMyAut() throws TimeoutException { //SFA is defined SFA aut = SFA.MkSFA(transitions, 0, Arrays.asList(7,8), ba); - SFA incrMinAut = IncrementalMinimization.incrementalMinimize(aut, ba); + IncrementalMinimization incr = new IncrementalMinimization(aut,ba); + SFA incrMinAut = incr.minimize(); SFA stdMinAut = aut.minimize(ba); //auts are equivalent but incrMin is not determinstic! - SFA upfrontMinAut = IncrementalMinimization.incrementalMinimize(aut, ba, true); + IncrementalNaive naive = new IncrementalNaive(aut,ba); + SFA upfrontMinAut = naive.minimize(); Assert.assertTrue(incrMinAut.isDeterministic(ba)); Assert.assertTrue(stdMinAut.isDeterministic(ba)); @@ -127,7 +130,8 @@ public void testCharPred() throws TimeoutException SFA aut = SFA.MkSFA(transitions, 9, Arrays.asList(3,4), ba); aut = aut.determinize(ba).mkTotal(ba); - SFA incrMinAut = IncrementalMinimization.incrementalMinimize(aut, ba); + IncrementalMinimization incr = new IncrementalMinimization(aut,ba); + SFA incrMinAut = incr.minimize(); System.out.println(incrMinAut.getStates()); SFA stdMinAut = aut.minimize(ba); System.out.println(stdMinAut.getStates()); @@ -203,18 +207,19 @@ public void testCompare() throws TimeoutException, IOException SFA incrMinAut; try { - incrMinAut = IncrementalMinimization.incrementalMinimize(aut, ba); + IncrementalMinimization incrMin = new IncrementalMinimization(aut, ba); + incrMinAut = incrMin.minimize(); } catch(TimeoutException e) { System.out.println("Skipping because of Timeout Exception"); //TODO Debug continue; } - catch(OutOfMemoryError e) + /*catch(OutOfMemoryError e) { System.out.println("Skipping because out of heap space"); //TODO Debug continue; - } + }*/ Double incrTime = ((double)(System.nanoTime() - incrStart)/1000000); Assert.assertTrue(incrMinAut.isDeterministic(ba)); Assert.assertTrue(SFA.areEquivalent(incrMinAut, stdMinAut, ba)); @@ -228,18 +233,19 @@ public void testCompare() throws TimeoutException, IOException SFA upfrontMinAut; try { - upfrontMinAut = IncrementalMinimization.incrementalMinimize(aut, ba, true); + IncrementalNaive naiveMin = new IncrementalNaive(aut, ba); + upfrontMinAut = naiveMin.minimize(); } catch(TimeoutException e) { System.out.println("Skipping because of Timeout Exception"); //TODO Debug continue; } - catch(OutOfMemoryError e) + /*catch(OutOfMemoryError e) { System.out.println("Skipping because out of heap space"); //TODO Debug continue; - } + }*/ Double upfrontTime = ((double)(System.nanoTime() - incrDFAStart)/1000000); Assert.assertTrue(upfrontMinAut.stateCount() <= stdMinAut.stateCount()); Assert.assertTrue(SFA.areEquivalent(upfrontMinAut, stdMinAut, ba)); @@ -263,7 +269,8 @@ public void testCompare() throws TimeoutException, IOException SFA recursiveMinAut; try { - recursiveMinAut = IncrementalMinimization.incrRecursiveMin(aut, ba); + IncrementalRecursive incrRec = new IncrementalRecursive(aut, ba); + recursiveMinAut = incrRec.minimize(); } catch(TimeoutException e) { @@ -272,7 +279,16 @@ public void testCompare() throws TimeoutException, IOException } Double recTime = ((double)(System.nanoTime() - recStart)/1000000); Assert.assertTrue(recursiveMinAut.stateCount() <= stdMinAut.stateCount()); - Assert.assertTrue(SFA.areEquivalent(recursiveMinAut, stdMinAut, ba)); + try + { + Assert.assertTrue(SFA.areEquivalent(recursiveMinAut, stdMinAut, ba)); + } + catch(AssertionError e) + { + System.out.println(recursiveMinAut); + System.out.println(stdMinAut); + throw e; + } Assert.assertTrue(SFA.areEquivalent(recursiveMinAut, incrMinAut, ba)); Assert.assertEquals(recursiveMinAut.stateCount(), incrMinAut.stateCount()); @@ -374,21 +390,36 @@ public void testBudget() throws TimeoutException, IOException SFA upfrontIncrAut; try { - incrMinAut = IncrementalMinimization.incrementalMinimize(aut, ba, budget, false); - System.out.println("Incremental minimized."); - upfrontIncrAut = IncrementalMinimization.incrementalMinimize(aut, ba, budget, true); - System.out.println("Upfront incremental minimized.."); + IncrementalMinimization incrMin = new IncrementalMinimization(aut,ba); + incrMinAut = incrMin.minimize(budget); + } + catch(TimeBudgetExceededException e) + { + incrMinAut = e.getReturnAut(); } catch(TimeoutException e) { continue; } - catch(OutOfMemoryError e) + System.out.println("Incremental minimized."); + try + { + IncrementalNaive naiveMin = new IncrementalNaive(aut, ba); + upfrontIncrAut = naiveMin.minimize(budget); + } + catch(TimeBudgetExceededException e) + { + upfrontIncrAut = e.getReturnAut(); + } + catch(TimeoutException e) { continue; } - - //TODO: negative percentages + /*catch(OutOfMemoryError e) + { + continue; + }*/ + System.out.println("Naive incremental minimized.."); int initialCount = aut.stateCount(); String initialStateCount = Integer.toString(initialCount); @@ -522,23 +553,30 @@ public void testRecord() throws IOException, DebugException } System.out.println("Determinized."); - SFA incrMinAut; - LinkedHashMap record; + SFA incrMinAut =null; + LinkedHashMap record = null; try { - IncrementalMinimization recordMin = - new IncrementalMinimization(aut, ba, false); - incrMinAut = recordMin.minimize(Long.MAX_VALUE, false, true, false); - record = recordMin.getRecord(); + IncrementalMinimization incrMin = + new IncrementalMinimization(aut, ba); + incrMinAut = incrMin.minimize(Long.MAX_VALUE, true, false); + record = incrMin.getRecord(); } catch(TimeoutException e) { continue; } - catch(OutOfMemoryError e) + catch(DebugException e) { - continue; + //This will never occur + Assert.fail(); } + /*catch(OutOfMemoryError e) + { + continue; + }*/ + Assert.assertTrue(incrMinAut != null); + Assert.assertTrue(record != null); System.out.println("Minimized."); if(record.size()<=1) { @@ -744,12 +782,12 @@ public void testDepth() throws IOException, TimeoutException int depthSum = 0; for (int i = 0; i < tests; i++) { - IncrementalMinimization dbgTest = new IncrementalMinimization(aut, ba, true); + IncrementalMinimization dbgTest = new IncrementalMinimization(aut, ba); Integer maxDepth = null; SFA minAut = null; try { - minAut = dbgTest.minimize(Long.MAX_VALUE, false, false, false); + minAut = dbgTest.minimize(Long.MAX_VALUE, false, true); } catch (DebugException e) { diff --git a/IncrementalMinimization/src/TimeBudgetExceededException.java b/IncrementalMinimization/src/TimeBudgetExceededException.java new file mode 100644 index 00000000..2f1f27fa --- /dev/null +++ b/IncrementalMinimization/src/TimeBudgetExceededException.java @@ -0,0 +1,25 @@ +import org.sat4j.specs.TimeoutException; + +import automata.sfa.SFA; + +@SuppressWarnings("rawtypes") //throwable subclasses can not be made generic +public class TimeBudgetExceededException extends TimeoutException +{ + private final SFA returnAut; + + public TimeBudgetExceededException(String message, SFA returnAut) + { + super(message); + this.returnAut = returnAut; + } + + public TimeBudgetExceededException(SFA returnAut) + { + this("Time budget exceeded", returnAut); + } + + public SFA getReturnAut() + { + return returnAut; + } +}