import fi.uef.cs.tra.Edge; import fi.uef.cs.tra.Graph; import fi.uef.cs.tra.Vertex; import java.text.DecimalFormat; import java.util.*; public class TRAII_24_X5_test { private static final TRAII_24_X5 myClass = new TRAII_24_X5_simo(); /* <-- Own id here */ static DecimalFormat df = new DecimalFormat("#.##"); static objectComparator oC = new objectComparator(); public static void main(String[] args) { int vertices = 6; int cycles = 2; int tests = 5; // how many different graphs to test int print = 6; // amount of printing Random rnd = new Random(); if (args.length > 0) vertices = Integer.parseInt(args[0]); if (args.length > 1) cycles = Integer.parseInt(args[1]); int seed = vertices + cycles + tests; if (args.length > 2) seed = Integer.parseInt(args[2]); if (args.length > 3) print = Integer.parseInt(args[3]); rnd.setSeed(seed); if (args.length > 3) tests = Integer.parseInt(args[3]); boolean ok = true; // some fixed tests testX5(7, 2, 0, rnd, print); testX5(10, 3, 1, rnd, print); testX5(12, 4, 2, rnd, print); // more fixed tests for (int i = 0; i < tests; i++) { ok &= testX5(vertices + i*2, 1+(i+2) / 5, i/2, rnd, print); } // large graphs for (int i = 0; i < tests; i++) { ok &= testX5(10*vertices + i*2, i+2 , i, rnd, 1); } System.out.println("\nAll tests: " + ok); } static boolean testX5(int n, int components, int cyclic, Random rnd, int print) { boolean ok = true; if (print > 0) System.out.println("\nTest n=" + n + " components=" + components + " cyclic=" + cyclic); float[] expected = new float[1]; Graph G = createInput(n, components, cyclic, expected, rnd); if ((print > 2 && n < 10) || (print > 5 && n < 100)) System.out.println("G=" + GraphMaker.toString(G, 1)); List resultVertices = new LinkedList<>(); Float resultWeigth = myClass.heaviestComponentWithCycle(G, resultVertices); if (print > 0) System.out.println("Result = " + df.format(resultWeigth) + ((resultVertices.size() < 20) ? (" component = " + resultVertices) : "") ); if (isClose(resultWeigth, expected[0])) { System.out.println("Correct expected component weigth: " + df.format(resultWeigth)); } else { System.out.println("Wrong component weigth: " + df.format(resultWeigth) + " (expected = " + df.format(expected[0]) + ")"); ok = false; } if (! resultVertices.isEmpty()) System.out.println("Is correct maximal component: " + (ok &= isComponent(G, resultVertices))); return ok; } /** * Input generation * @param n number of vertices * @param components goal number of components * @param cyclic how many cyclic compmponents * @param res resulting heaviest cyclic component weigth (index 0 of 1-element array) * @param rnd random number generator * @return generated graph */ static Graph createInput(int n, int components, int cyclic, float[] res , Random rnd) { Graph G = new Graph(); float result = Float.NaN; while (n > 0) { // vertex count for component int nc0 = n/components; int nc = 1 + nc0/2 + (nc0>0 ? rnd.nextInt(nc0*2) : 0); if (cyclic > 0 && n >= 4 && nc <= 4) nc = 4; if (nc > n) nc = n; // System.out.println("createInput: n= " + n + " nc= " + nc + " cyclic=" + cyclic); if (nc > 3 && cyclic > 0) { float cW = GraphMaker.addCycledComponent(G, nc, 10); cyclic--; if (Float.isNaN(result) || result < cW) result = cW; } else GraphMaker.addTree(G, nc, 10); n -= nc; if (components > 1) components--; } Graph GC = GraphMaker.shuffleCopy(G); GraphMaker.nameVertices(GC, ""); res[0] = result; return GC; } /** * Comparator for objects. Vertices use weights, thus messing TreeSet. * @param */ private static class objectComparator implements Comparator { @Override public int compare(T o1, T o2) { if (o1 == o2) return 0; else { if (System.identityHashCode(o1) < System.identityHashCode(o2)) return -1; else return 1; } } } /** * Compare two float, tolerate rounding errors. * @param f1 first float * @param f2 second float * @return true of floats are close anough, false otherwise */ static boolean isClose(float f1, float f2) { if (Float.isNaN(f1) && Float.isNaN(f2)) return true; return Math.abs(f1 - f2) < 0.05; } /** * Checks if component of list L is a) connected, b) maximal. * Maximal means that there are no other connected vertices that are not in list L. * @param G input graph * @param L component to be checked * @return true if component is ok, false otherwise */ static boolean isComponent(Graph G, List L) { boolean ok = true; if (G.vertexCount() == 0 && L.isEmpty()) return true; // both empty else if (G.vertexCount() == 0) { System.out.println("Empty graph has no component!"); return false; } else if (L.isEmpty()) { System.out.println("Non-empty graph should have a component"); return false; } // both have elements // find rererence TreeSet vrt = new TreeSet<>(new objectComparator<>()); vrt.add(L.get(0)); followers_r(vrt, L.get(0)); // elements of L to a set TreeSet LS = new TreeSet(oC); LS.addAll(L); // compare both wayt if (! LS.containsAll(vrt)) { System.out.println("Component list misses vertices"); ok = false; } if (! vrt.containsAll(LS)) { System.out.println("Component list has extra vertices"); ok = false; } return ok; } /** * Recursive set of followers * @param S result set * @param start vertex to process */ static void followers_r(Set S, Vertex start) { for (Vertex v : start.neighbors()) if (S.add(v)) followers_r(S, v); } /** * Print the subgraph induced by vertices in list L. * @param L vertices */ static void printComponent(Collection L) { TreeSet vertices = new TreeSet<>(oC); vertices.addAll(L); for (Vertex v : L) { System.out.print(v + " :"); for(Edge e : v.edges()) { if (vertices.contains(e.getStartPoint()) && vertices.contains(e.getEndPoint())) System.out.print(" " + e.getEndPoint(v).getLabel() + "{" + e.getWeight() + "}"); } System.out.println(); } } } // class()