/** * Author: Christoph Hillebold <c.hillebold@student.tugraz.at> */ package at.iaik.suraq.main; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.TreeMap; import java.util.Vector; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.smtlib.formula.AndFormula; import at.iaik.suraq.smtlib.formula.EqualityFormula; import at.iaik.suraq.smtlib.formula.Formula; import at.iaik.suraq.smtlib.formula.ImpliesFormula; import at.iaik.suraq.smtlib.formula.NotFormula; import at.iaik.suraq.smtlib.formula.OrFormula; import at.iaik.suraq.smtlib.formula.PropositionalVariable; import at.iaik.suraq.smtlib.formula.Term; import at.iaik.suraq.util.FormulaCache; import at.iaik.suraq.util.Util; /** * Graph-based Reduction to Propositional Logic. * * @author chillebold * */ public class GraphReduction { /** * this flag activates or deactivates the GraphReduction */ private static boolean _isActive = false; /** * activates some unnessasary debug output - only use if you debug the * GraphReduction */ private static boolean _debug = false; /** * not used: activate this to activate circle finding after the basic * algorithm. */ private static boolean _additionalCircles = false; /** * not used: finding additional Circles is implemented using MultiThreading * to reduce execution time */ private static boolean _supportMultithreading = false; /** * not used: finding additional Circles is implemented using MultiThreading * to reduce execution time * */ protected List<GraphReductionThread> threads = null; /** * not used: using Multithreading on finding additional circles there is a * max. count of Threads this value is overwritten, if the cpu has more than * 2 cores: we use n-1 threads! */ private static int _maxThreads = 2; /** * a cache for PropositionalVariables using their name as a key */ protected Map<String, PropositionalVariable> propCache = new HashMap<String, PropositionalVariable>(); /** * this stores the made replacements for further use. maybe you want to * invert this Map to Map<String, EqualityFormula> */ protected Map<EqualityFormula, String> replacements = null; /** * not used: this is currently not used but still in the code for * DepthFirstSearch in the Graph */ protected Stack<GraphElement> visitedDFS = null; /** * used for counting the found circles */ protected long circlecounter = 0; /** * Store for all found circles */ protected final List<List<PropositionalVariable>> circles = new Vector<List<PropositionalVariable>>(); /** * Temporary store for all found circles. Transfered to circles and cleaned. */ protected final List<List<PropositionalVariable>> circles2 = new Vector<List<PropositionalVariable>>(); /** * Store for storing circles in a hashSet (so they should be unique). Hash * of Hashset is the sum of the Hashes. we could overthink this, but I think * the HashSets should have the same order. */ protected final HashSet<HashSet<PropositionalVariable>> hashCircles = new HashSet<HashSet<PropositionalVariable>>(); /**************************************************************************************** * Developer Notes: - A large amount of code of this transformation is in * EqualityFormula:replaceEquivalences - There should not be any * uninterpreted functions nor Arrays, etc. in the Formula - There are two * implementations of the GraphReduction: - one tries to find circles and * builds only nessasary constraints - the other makes the graph chord-free * and generates constraints for each triangle ****************************************************************************************/ /** * Generates a propositionalVariable out of a name * * @param equivalenceName * @return */ private PropositionalVariable generatePropositionalVariable( String equivalenceName) { if (propCache.containsKey(equivalenceName)) { return propCache.get(equivalenceName); } PropositionalVariable p = PropositionalVariable.create(equivalenceName); propCache.put(equivalenceName, p); return p; } /** * computes Statistics in O(vertices.size()) time and prints to System.out * * @param vertices */ protected void writeStats(Collection<GraphElement> vertices) { int count = vertices.size(); int sum_neighbours = 0; int min_neighbours = Integer.MAX_VALUE; int max_neighbours = Integer.MIN_VALUE; for (GraphElement vertex : vertices) { int neighbours = vertex.getNeighbours().size(); sum_neighbours += neighbours; if (neighbours > max_neighbours) max_neighbours = neighbours; if (neighbours < min_neighbours) min_neighbours = neighbours; } int edges = sum_neighbours / 2; float average_neighbours = ((float) sum_neighbours) / ((float) count); System.out .println("***************************************************"); System.out .println("* Statistic of Graph-based reduction to prop. logic"); System.out.println("* - Count of vertices: " + count); System.out.println("* - Count of edges: " + edges); System.out.println("* - Average Neighbours: " + average_neighbours); System.out.println("* - Min. Neighbours: " + min_neighbours); System.out.println("* - Max. Neighbours: " + max_neighbours); System.out .println("***************************************************"); if (GraphReduction._debug) { for (GraphElement vertex : vertices) { System.out.println("Vertex: " + vertex); } } } /** * Performs the Graph Based Reduction to Propositional Logic * * @param formula * @param noDependenceVars * @return * @throws IOException */ public Formula perform(Formula formula, Set<Token> noDependenceVars) throws IOException { // isActive & Intro if (!GraphReduction._isActive) { System.out .println("INFO: Didn't perform Graph-Based Reduction to Propositional Logic, because it is inactive."); return formula; } System.out .println("ImpliesFormulaGR: Welcome to the Graph-Based Reduction to Propositional Logic."); replacements = new TreeMap<EqualityFormula, String>(); // do NOT clean up replacements, we need them later! // 1.1 find all equivalences, replace them by Propositional Vars with a // new name // 1.2 save the replacements to the given structure // 1.3 set noDependenceVars for the replaced term if any containing term // is noDepVar formula = formula.replaceEquivalences(formula, replacements, noDependenceVars); // 2.1 Build Graph Collection<GraphElement> vertices = generateGraph(replacements); System.out.println("GR: Built " + vertices.size() + " vertices out of " + replacements.keySet().size() + " replacements."); writeStats(vertices); Formula btrans = null; int method = 2; // define method here, 2 is the only one working if (method == 1) // Try to find circles without making chordal { System.out .println("GR: Try to find circles without making chord-free... "); btrans = generateBtransCircles(formula, vertices); } else if (method == 2 || method == 3) // make graph chordal and find // all triangles { System.out.println("GR: Make the Graph chord-free... "); makeGraphChordal(formula, vertices); writeStats(vertices); int countTriangles = countTriangles(vertices); System.out.println("GR: There are " + countTriangles + " triangles."); System.out .println("GR: Find all triangles and generate Btrans... "); if (method == 2) { btrans = generateBtrans(vertices); } else if (method == 3) // warning: this can easily be several GB... { btrans = this.generateBtransToFile(vertices, "./btrans.txt"); } } // delete all NoDepVars that are not propositional vars HashSet<Token> toDelete = new HashSet<Token>(noDependenceVars); Set<PropositionalVariable> pVars = new HashSet<PropositionalVariable>(); formula.getPropositionalVariables(pVars, new HashSet<SMTLibObject>()); toDelete.removeAll(pVars); noDependenceVars.removeAll(toDelete); return ImpliesFormula.create(btrans, formula); } /** * Counts all unique Triangle * * @param vertices * @return */ protected int countTriangles(Collection<GraphElement> vertices) { // reset the visited flag of the vertices for (GraphElement vertex : vertices) { resetVisited(vertex); } int count = 0; // go through all vertices and see if their neighbours are connected for (GraphElement vertex : vertices) { // "remove" the watched element by setting it visited. vertex.setVisited(true); int size = vertex.getNeighbours().size(); Object[] neighbours = vertex.getNeighbours().toArray(); // are any two neighbours connected with each other? // then we would have found a triangle for (int i = 0; i < size; i++) { GraphElement ni = (GraphElement) neighbours[i]; if (!ni.isVisited()) for (int j = i + 1; j < size; j++) { GraphElement nj = (GraphElement) neighbours[j]; if (!nj.isVisited()) if (ni.isConnectedWith(nj)) { count++; } } } } return count; } /** * Generates the Btrans-Formula out of the given vertices that are chordal. * All Vertices must be VISITED before calling this method! This method sets * all vertices to UNVISITED again. * * @param vertices * @return Btrans-Formula */ protected Formula generateBtrans(Collection<GraphElement> vertices) // throws // IOException { // for progress statistic during the algorithm: long step = vertices.size() / 100; if (step == 0) step = 1; // to avoid divide by zero error long cnt = 0; // collect all triangles ArrayList<Formula> btransparts = new ArrayList<Formula>(); btransparts.ensureCapacity(3 * vertices.size()); for (GraphElement vertex : vertices) { if (cnt++ % step == 0) { System.out.println("GR: generateBtrans... (cur:" + btransparts.size() + ")" + cnt / step + "% von vertices#: " + vertices.size()); } vertex.setVisited(false); int size = vertex.getNeighbours().size(); Object[] neighbours = vertex.getNeighbours().toArray(); for (int i = 0; i < size; i++) { GraphElement ni = (GraphElement) neighbours[i]; if (ni.isVisited()) for (int j = i + 1; j < size; j++) { GraphElement nj = (GraphElement) neighbours[j]; if (nj.isVisited()) if (ni.isConnectedWith(nj)) // && || // nj.isConnectedWith(ni) { // found a triangle: vertex - ni - nj String t1 = vertex.getEquivalenceName(ni); String t2 = vertex.getEquivalenceName(nj); String t3 = ni.getEquivalenceName(nj); btransparts.add(generateBtransElemCNF(t1, t2, t3)); btransparts.add(generateBtransElemCNF(t2, t3, t1)); btransparts.add(generateBtransElemCNF(t3, t1, t2)); } } } } vertices = null; // Statistic FormulaCache.printStatistic(); return AndFormula.generate(btransparts); } // generateBtrans /** * writes the Btrans-Formula out to a given file and returns a * PropositionalVariable 'Btrans' instead. * * @param vertices * @param filename * output file of the Btrans-Formula * @return a PropositionalVariable 'Btrans' */ protected PropositionalVariable generateBtransToFile( Collection<GraphElement> vertices, String filename) { // for progress statistic during the algorithm: long step = vertices.size() / 1000; if (step == 0) step = 1; long cnt = 0; ArrayList<Formula> btransparts = new ArrayList<Formula>( 3 * vertices.size()); File file = new File(filename); FileWriter fstream = null; try { fstream = new FileWriter(file); fstream.write("and\n"); for (GraphElement vertex : vertices) { if (cnt++ % step == 0) { System.out.println("GR: generateBtrans... (cur:" + btransparts.size() + ")" + (float) cnt / (float) step / 10.0 + "% von vertices#: " + vertices.size()); } vertex.setVisited(false); int size = vertex.getNeighbours().size(); Object[] neighbours = vertex.getNeighbours().toArray(); for (int i = 0; i < size; i++) { GraphElement ni = (GraphElement) neighbours[i]; if (ni.isVisited()) for (int j = i + 1; j < size; j++) { GraphElement nj = (GraphElement) neighbours[j]; if (nj.isVisited()) if (ni.isConnectedWith(nj)) { // found a triangle: vertex - ni - nj String t1 = vertex.getEquivalenceName(ni); String t2 = vertex.getEquivalenceName(nj); String t3 = ni.getEquivalenceName(nj); btransparts.add(generateBtransElem(t1, t2, t3)); btransparts.add(generateBtransElem(t2, t3, t1)); btransparts.add(generateBtransElem(t3, t1, t2)); } } } // save to file because we have too less memory try { // debug message System.out.println("* btrans #" + cnt + "/" + vertices.size() + ": " + btransparts.size() + ", neighbors: " + size); for (Formula formula : btransparts) { fstream.write(formula.toString()); } // and clear the buffer!!! btransparts.clear(); } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException("FileError"); } } } catch (IOException ex) { ex.printStackTrace(); } finally { try { if (fstream != null) fstream.close(); } catch (IOException ex2) { ex2.printStackTrace(); } } vertices = null; btransparts = null; return PropositionalVariable.create("Btrans"); } // generateBtransToFile /** * Helps to generate the Btrans-Formula out of a triangle in CNF (!a v !b v * c) * * @param a * @param b * @param c * @return */ protected OrFormula generateBtransElemCNF(String a, String b, String c) { List<Formula> part1 = new ArrayList<Formula>(3); part1.add(NotFormula.create(generatePropositionalVariable(a))); part1.add(NotFormula.create(generatePropositionalVariable(b))); part1.add(generatePropositionalVariable(c)); OrFormula or = OrFormula.generate(part1); return or; } /** * Helps to generate the Btrans-Formula out of a triangle (a ^ b => c) * * @param a * @param b * @param c * @return */ protected ImpliesFormula generateBtransElem(String a, String b, String c) { List<Formula> part1 = new ArrayList<Formula>(2); part1.add(generatePropositionalVariable(a)); part1.add(generatePropositionalVariable(b)); AndFormula and = AndFormula.generate(part1); ImpliesFormula implies = ImpliesFormula.create(and, generatePropositionalVariable(c)); return implies; } /** * Resets the isVisited Flag of each vertex recursively * * @param current */ protected void resetVisited(GraphElement current) { current.setVisited(false); for (GraphElement neighbour : current.getNeighbours()) { if (neighbour.isVisited()) { resetVisited(neighbour); } } } /** * Makes the Graph chordal * * @param topLevelFormula * @param vertices */ protected void makeGraphChordal(Formula topLevelFormula, Collection<GraphElement> vertices) { System.out.println("There are " + vertices.size() + " vertices."); // for progress statistics during the algorithm: long step = vertices.size() / 100 + 1; long cnt = 0; for (GraphElement vertex : vertices) { if (cnt++ % step == 0) { System.out.println("GR: makeChordFreeGraph... " + cnt / step + "%"); } vertex.setVisited(true); int size = vertex.getNeighbours().size(); Object[] neighbours = vertex.getNeighbours().toArray(); for (int i = 0; i < size; i++) { GraphElement ni = (GraphElement) neighbours[i]; if (ni.isVisited()) // vertex was already "deleted" (visited) continue; for (int j = i + 1; j < size; j++) { GraphElement nj = (GraphElement) neighbours[j]; if (nj.isVisited()) // vertex was already "deleted" continue; if (!ni.isConnectedWith(nj)) // && || nj.isConnectedWith(ni) { // add a chord String token = GraphReduction.getVarName( topLevelFormula, ni.getVarname(), nj.getVarname()); ni.addNeighbour(nj, token); nj.addNeighbour(ni, token); } } } } } // makeChordFreeGraph /** * Generates a name for the Equivalence between the two variables ti and tj. * The Result of this method is unique, regardless of the order of ti and * tj. * * @param topLevelFormula * @param ti * name of the variable 1 * @param tj * name of the variable 2 * @return name for the Equivalence between the two variables ti and tj */ public static String getVarName(Formula topLevelFormula, String ti, String tj) { // sort the two strings, so that the result is everytime the same if (ti.compareTo(tj) > 0) { String help = tj; tj = ti; ti = help; } String newName = "eq_" + ti + "_" + tj; return Util.freshVarNameCached(topLevelFormula, newName); } /** * Generates a Graph out of given replacements. The vertices of the graph * are the former variables and the connections are the equalities. Every * GraphElement in the Graph is a vertex and knows it's neighbours. * * @param replacements * @return a Collection of vertices (former Variables) that are connected * (former equalities) */ protected Collection<GraphElement> generateGraph( Map<EqualityFormula, String> replacements) { Map<String, GraphElement> vertices = new HashMap<String, GraphElement>(); for (EqualityFormula replacement : replacements.keySet()) { List<Term> terms = replacement.getTerms(); if (terms.size() < 2) { throw new RuntimeException( "GR: An equality had less than two subterms."); } // Look for a matching vertex for the first variable String name1 = terms.get(0).toString(); GraphElement g1; if (vertices.containsKey(name1)) { g1 = vertices.get(name1); } else { g1 = new GraphElement(name1); vertices.put(name1, g1); } // Look for a matching vertex for the second variable String name2 = terms.get(1).toString(); GraphElement g2; if (vertices.containsKey(name2)) { g2 = vertices.get(name2); } else { g2 = new GraphElement(name2); vertices.put(name2, g2); } String token = replacements.get(replacement); g1.addNeighbour(g2, token); g2.addNeighbour(g1, token); } return vertices.values(); } // generateGraph // /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// // // GETTER AND SETTER // /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// public static void setDebug(boolean isDebug) { GraphReduction._debug = isDebug; } public static boolean isDebug() { return GraphReduction._debug; } public static void setActive(boolean isActive) { if (isActive == false) System.err.println("GraphReduction was set inactive."); else System.err.println("GraphReduction was set active."); GraphReduction._isActive = isActive; } public static boolean isActive() { return GraphReduction._isActive; } public Map<EqualityFormula, String> getReplacements() { return replacements; } // /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// // // Begin of Experimental Parts!!! // /////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////// /** * Generates BtransCircles without making the Graph chordal. Unfortunatly we * didn't either find enough circles or too many circles. This method uses * DepthFirstSearch to find small circles first * * @param topLevelFormula * @param vertices * @return */ protected Formula generateBtransCircles(Formula topLevelFormula, Collection<GraphElement> vertices) { // search for circles with DFS circlecounter = 0; // reset the counter visitedDFS = new Stack<GraphElement>(); visitedDFS.ensureCapacity(vertices.size()); circles.clear(); circles2.clear(); for (GraphElement vertex : vertices) { // if(!vertex.isVisitedOnce()) { System.out.print("\n next:"); this.resetVisited(vertex); vertex.setVisited(true); // depthFirstSearch(vertex, vertex, null); depthFirstSearchHash(vertex, vertex, null); } } circles.addAll(circles2); circles2.clear(); System.out.println("\nThere are " + circlecounter + " circles"); // may one iteration be enough? // Runtime: O(circles^2 * elementspercircle^2) // Memory: O(circles^2 * elementspercircle) int circlesize = circles.size(); if (GraphReduction._additionalCircles) { if (GraphReduction._supportMultithreading) { int cpus = Runtime.getRuntime().availableProcessors(); if (cpus > GraphReduction._maxThreads) GraphReduction._maxThreads = cpus - 1; int singleSize = circlesize / GraphReduction._maxThreads; int last_index = 0; threads = new ArrayList<GraphReductionThread>(); for (int i = 1; i <= GraphReduction._maxThreads; i++) { int index = singleSize * i; if (i == GraphReduction._maxThreads) // the last Thread // takes the rest index = circlesize; threads.add(new GraphReductionThread(this, last_index, index)); last_index = index; } for (int i = 0; i < GraphReduction._maxThreads; i++) { System.out.println("Starting Thread..."); threads.get(i).start(); } for (int i = 0; i < GraphReduction._maxThreads; i++) { try { threads.get(i).join(); System.out.println("Thread joined"); } catch (InterruptedException e) { e.printStackTrace(); } } threads.clear(); } else { for (int i = 0; i < circlesize; i++) { System.out.println("Search Circles #" + i + "/" + circlesize + " Circles: " + circlecounter); for (int j = i + 1; j < circlesize; j++) { getSubFormula(circles.get(i), circles.get(j)); } } } circles.addAll(circles2); circles2.clear(); System.out.println("\nFinally there are " + circlecounter + " circles"); } // generate Btrans List<Formula> btransList = new ArrayList<Formula>(); System.out.println("#circles: " + circles.size()); for (List<PropositionalVariable> circle : circles) { int size = circle.size(); for (int i = 0; i < size; i++) { List<PropositionalVariable> newList = new ArrayList<PropositionalVariable>( circle); PropositionalVariable c = newList.remove(i); btransList.add(ImpliesFormula.create( AndFormula.generate(newList), c)); } } System.out.println("#hashCircles: " + hashCircles.size()); for (HashSet<PropositionalVariable> circle : hashCircles) { int size = circle.size(); for (int i = 0; i < size; i++) { List<PropositionalVariable> newList = new ArrayList<PropositionalVariable>( circle); PropositionalVariable c = newList.remove(i); btransList.add(ImpliesFormula.create( AndFormula.generate(newList), c)); } } return AndFormula.generate(btransList); } // generateBtransCircles /** * The idea of this Method is to compare each two circles found and find * common strings. By doing so, additional circles can be found and added to * the circlelist. I assume, that this is not finding all circles either, * but it found most nessasary circles. This algorithm defenitely fails if * the datastructure of the circles is a HashList, because it needs to be * sorted. At least it requires the elements in the same order * * @param circle1 * @param circle2 * @return */ protected List<PropositionalVariable> getSubFormula( List<PropositionalVariable> circle1, List<PropositionalVariable> circle2) { int csize1 = circle1.size(); int csize2 = circle2.size(); // Annahmen durch vorhergehende Algorithmen: // jedes element im circle kommt max. 1x vor!!! // daher kann bei gemeinsamkeiten i und j erhoeht werden!!! // auch sind nie zwei circles vollstaendig identisch // (while-endlosschleife) for (int forward = -1; forward < 2; forward += 2) // {-1,+1} { for (int i = 0; i < csize1; i++) { for (int j = i; j < csize2; j++) { // interessant sind nur teilfolgen groesser gleich 3... if (circle1.get(i).equals(circle2.get(j))) if (circle1.get((i + 1) % csize1) .equals(circle2.get((j + 1 * forward + csize2) % csize2))) if (circle1.get((i + 2) % csize1).equals( circle2.get((j + 2 * forward + csize2) % csize2))) { int i_start = i; int j_start = j; int circle_size = 0; while (circle1.get((i) % csize1).equals( circle2.get((j + csize2) % csize2))) { circle_size++; i++; j += forward; } if (GraphReduction._debug) System.out .println("Found duplicate circle of size " + circle_size); List<PropositionalVariable> new_circle = new ArrayList<PropositionalVariable>( circle_size); // copy everything from the end of the common // term (incl. the last common term) // to the first common term (incl.) for (int copy_i = i - csize1 - 1; copy_i <= i_start; copy_i++) { new_circle.add(circle1 .get((copy_i + csize1) % csize1)); } // now copy from the second circle everything // from the last common term (excl.) // to the first common term (excl.) if (forward == 1) { for (int copy_j = j - csize2; j < j_start; j++) { new_circle .add(circle2 .get((copy_j + csize2) % csize2)); } } else // if(foward == -1) { for (int copy_j = j + csize2; j > j_start; j--) { new_circle .add(circle2 .get((copy_j + csize2) % csize2)); } } this.addCircle(new_circle); // evtl. return hier? // return null; // seems to work for median // tests } } } } return null; } // getSubFormula // protected int depthFirstSearch(GraphElement current, GraphElement last, // int remainingDepth) protected void depthFirstSearchHash(GraphElement start, GraphElement current, GraphElement last) { // int minRemainingDepth = remainingDepth; current.setVisited(true); visitedDFS.push(current); for (GraphElement neighbour : current.getNeighbours()) { if (neighbour != last) { if (visitedDFS.contains(neighbour)) { // if(remainingDepth == 0) { // we have had this neighbour - this is a circle int circle_start = visitedDFS.indexOf(neighbour); int circle_end = visitedDFS.size(); HashSet<PropositionalVariable> circle = new HashSet<PropositionalVariable>( circle_end - circle_start + 1); for (int i = circle_start; i < circle_end; i++) { int j = i + 1; if (j == circle_end) j = circle_start; GraphElement circle_elem = visitedDFS.get(i); GraphElement next_elem = visitedDFS.get(j); String token = circle_elem .getEquivalenceName(next_elem); PropositionalVariable pv = generatePropositionalVariable(token); circle.add(pv); } this.addHashCircle(circle); } } // else else if (!neighbour.isVisited()) // else if(!visitedDFS.contains(neighbour) && // !neighbour.isVisited()) { // if(remainingDepth > 0 && !neighbour.isVisited()) // if(!neighbour.isVisited()) { // this is a new neighbor that was not visited until now depthFirstSearchHash(start, neighbour, current); // int tmp = depthFirstSearch(neighbour, current, // remainingDepth-1); // if(tmp < minRemainingDepth) // minRemainingDepth = tmp; } } } } if (visitedDFS.pop() != current) { throw new RuntimeException("DFS Search failed."); } // return minRemainingDepth; } // depthFirstSearchHash // protected int depthFirstSearch(GraphElement current, GraphElement last, // int remainingDepth) protected void depthFirstSearch(GraphElement start, GraphElement current, GraphElement last) { // int minRemainingDepth = remainingDepth; current.setVisited(true); visitedDFS.push(current); for (GraphElement neighbour : current.getNeighbours()) { if (neighbour != last) { if (visitedDFS.contains(neighbour)) { // if(remainingDepth == 0) { // we have had this neighbour - this is a circle if (circlecounter % 10000 == 0) System.out.print(" " + circlecounter); int circle_start = visitedDFS.indexOf(neighbour); int circle_end = visitedDFS.size(); List<PropositionalVariable> circle = new ArrayList<PropositionalVariable>( circle_end - circle_start + 1); for (int i = circle_start; i < circle_end; i++) { int j = i + 1; if (j == circle_end) j = circle_start; GraphElement circle_elem = visitedDFS.get(i); GraphElement next_elem = visitedDFS.get(j); String token = circle_elem .getEquivalenceName(next_elem); PropositionalVariable pv = generatePropositionalVariable(token); circle.add(pv); } this.addCircle(circle); } } else if (!neighbour.isVisited()) // else if(!visitedDFS.contains(neighbour) && // !neighbour.isVisited()) { // if(remainingDepth > 0 && !neighbour.isVisited()) // if(!neighbour.isVisited()) { // this is a new neighbor that was not visited until now depthFirstSearch(start, neighbour, current); // int tmp = depthFirstSearch(neighbour, current, // remainingDepth-1); // if(tmp < minRemainingDepth) // minRemainingDepth = tmp; } } } } if (visitedDFS.pop() != current) { throw new RuntimeException("DFS Search failed."); } // return minRemainingDepth; } // depthFirstSearch protected synchronized List<List<PropositionalVariable>> getCircles() { return circles; } protected synchronized void addCircle(List<PropositionalVariable> circle) { circlecounter++; circles2.add(circle); if (circlecounter % 10000 == 0) System.out.print(" " + circlecounter); } protected synchronized void addHashCircle( HashSet<PropositionalVariable> circle) { if (!hashCircles.contains(circle)) { circlecounter++; hashCircles.add(circle); if (circlecounter % 10000 == 0) System.out.print(" " + circlecounter); } } protected synchronized List<GraphReductionThread> getThreads() { return threads; } }