From 11e841e7ae2278fcdc92a116bf3ca3eca97cbec0 Mon Sep 17 00:00:00 2001 From: ethankelly <72452934+ethankelly@users.noreply.github.com> Date: Sat, 27 Mar 2021 15:40:49 +0000 Subject: [PATCH] Runs on command line user input --- .idea/artifacts/Equations_jar.xml | 10 + Equations.txt | 50 ++++ src/META-INF/MANIFEST.MF | 3 + src/io/github/ethankelly/Equations.java | 54 ---- src/io/github/ethankelly/Graph.java | 14 +- src/io/github/ethankelly/GraphGenerator.java | 261 +++++++++++++++++-- src/io/github/ethankelly/Main.java | 70 ++--- 7 files changed, 339 insertions(+), 123 deletions(-) create mode 100644 .idea/artifacts/Equations_jar.xml create mode 100644 Equations.txt create mode 100644 src/META-INF/MANIFEST.MF diff --git a/.idea/artifacts/Equations_jar.xml b/.idea/artifacts/Equations_jar.xml new file mode 100644 index 0000000..cbd737f --- /dev/null +++ b/.idea/artifacts/Equations_jar.xml @@ -0,0 +1,10 @@ + + + $PROJECT_DIR$/out/artifacts/Equations_jar + + + + + + + \ No newline at end of file diff --git a/Equations.txt b/Equations.txt new file mode 100644 index 0000000..30b8d72 --- /dev/null +++ b/Equations.txt @@ -0,0 +1,50 @@ + *** Equations for an SIR model on a Toast Graph *** + +0: 0 1 1 1 +1: 1 0 1 0 +2: 1 1 0 1 +3: 1 0 1 0 +Numbers of equations of each size: [8, 10, 16, 8] + +[〈S3〉] = - β〈S3 I0〉- β〈S3 I2〉 +[〈S2〉] = - β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈S1〉] = - β〈S1 I0〉- β〈S1 I2〉 +[〈S0〉] = - β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I3〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉 +[〈I2〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉 +[〈I1〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉 +[〈I0〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉 +[〈I3〉, 〈S2〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I3〉, 〈S0〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I2〉, 〈S3〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I2〉, 〈S1〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I2〉, 〈S0〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I1〉, 〈S2〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I1〉, 〈S0〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I0〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I0〉, 〈S2〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I0〉, 〈S1〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I3〉, 〈S0〉, 〈S2〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I3〉, 〈S0〉, 〈S1〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I2〉, 〈S0〉, 〈S3〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I2〉, 〈S0〉, 〈S1〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I2〉, 〈I3〉, 〈S0〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉+ γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I1〉, 〈S2〉, 〈S3〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I1〉, 〈S0〉, 〈S3〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I1〉, 〈S0〉, 〈S2〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I1〉, 〈I2〉, 〈S3〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I1〉, 〈I2〉, 〈S0〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I0〉, 〈S2〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I0〉, 〈S1〉, 〈S2〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S1 I0〉- β〈S1 I2〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I0〉, 〈I3〉, 〈S2〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I0〉, 〈I2〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I0〉, 〈I2〉, 〈S1〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I0〉, 〈I1〉, 〈S2〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I3〉, 〈S0〉, 〈S1〉, 〈S2〉] = γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S1 I0〉- β〈S1 I2〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉 +[〈I2〉, 〈I3〉, 〈S0〉, 〈S1〉] = γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉+ γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S1 I0〉- β〈S1 I2〉 +[〈I1〉, 〈S0〉, 〈S2〉, 〈S3〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I1〉, 〈I2〉, 〈S0〉, 〈S3〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I1〉, 〈I2〉, 〈I3〉, 〈S0〉] = γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉+ γ〈S3 I0〉+ γ〈S3 I2〉- γ〈I3〉- β〈S0 I1〉- β〈S0 I2〉- β〈S0 I3〉 +[〈I0〉, 〈S1〉, 〈S2〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉- β〈S1 I0〉- β〈S1 I2〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I0〉, 〈I1〉, 〈S2〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉- β〈S2 I0〉- β〈S2 I1〉- β〈S2 I3〉- β〈S3 I0〉- β〈S3 I2〉 +[〈I0〉, 〈I1〉, 〈I2〉, 〈S3〉] = γ〈S0 I1〉+ γ〈S0 I2〉+ γ〈S0 I3〉- γ〈I0〉+ γ〈S1 I0〉+ γ〈S1 I2〉- γ〈I1〉+ γ〈S2 I0〉+ γ〈S2 I1〉+ γ〈S2 I3〉- γ〈I2〉- β〈S3 I0〉- β〈S3 I2〉 diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..edd213a --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: io.github.ethankelly.Main + diff --git a/src/io/github/ethankelly/Equations.java b/src/io/github/ethankelly/Equations.java index d33c33c..dfbb39c 100644 --- a/src/io/github/ethankelly/Equations.java +++ b/src/io/github/ethankelly/Equations.java @@ -78,58 +78,4 @@ public static List generateEquations(Tuple tuples) { return equations; } - - public static void main(String[] args) throws FileNotFoundException { - PrintStream o = new PrintStream("TLTEquations.txt"); - System.setOut(o); - - char[] states = new char[]{'S', 'I', 'R', 'P'}; - // TRIANGLE - Graph triangle = new Graph(3); - triangle.addEdge(0, 1); - triangle.addEdge(1, 2); - triangle.addEdge(2, 0); - Tuple triangleNE = new Tuple(triangle, states); - - System.out.println(" *** TRIANGLE GRAPH ***\n\n" + triangle + "Numbers of equations of each size: " - + Arrays.toString(triangleNE.findNumbers(triangleNE.getTuples())) + "\n"); - Equations.generateEquations(triangleNE).forEach(System.out::println); - - // LOLLIPOP - Graph lollipop = new Graph(4); - lollipop.addEdge(0, 1); - lollipop.addEdge(0, 2); - lollipop.addEdge(0, 3); - lollipop.addEdge(2, 3); - Tuple lollipopNE = new Tuple(lollipop, states); - - System.out.println("\n *** LOLLIPOP GRAPH ***\n\n" + lollipop + "Numbers of equations of each size: " - + Arrays.toString(lollipopNE.findNumbers(lollipopNE.getTuples())) + "\n"); - Equations.generateEquations(lollipopNE).forEach(System.out::println); - - // TOAST - Graph toast = new Graph(4); - toast.addEdge(0, 1); - toast.addEdge(0, 2); - toast.addEdge(0, 3); - toast.addEdge(1, 2); - toast.addEdge(2, 3); - Tuple toastNE = new Tuple(toast, states); - - System.out.println("\n *** TOAST GRAPH ***\n\n" + toast + "Numbers of equations of each size: " - + Arrays.toString(toastNE.findNumbers(toastNE.getTuples())) + "\n"); - Equations.generateEquations(toastNE).forEach(System.out::println); - - // Creating another File object that represents the disk file and assign to output stream - PrintStream er = new PrintStream("ErdosRenyiTest.txt"); - System.setOut(er); - - // ERDOS-RENYI - Graph erdosRenyi = GraphGenerator.erdosRenyi(5, 0.5); - Tuple erdosRenyiNE = new Tuple(erdosRenyi, states); - - System.out.println(" *** ERDOS-RENYI GRAPH ***\n\n" + erdosRenyi + "Numbers of equations of each size: " - + Arrays.toString(erdosRenyiNE.findNumbers(erdosRenyiNE.getTuples())) + "\n"); - Equations.generateEquations(erdosRenyiNE).forEach(System.out::println); - } } diff --git a/src/io/github/ethankelly/Graph.java b/src/io/github/ethankelly/Graph.java index 7feea65..9519210 100644 --- a/src/io/github/ethankelly/Graph.java +++ b/src/io/github/ethankelly/Graph.java @@ -23,6 +23,8 @@ * @author Ethan Kelly */ public class Graph { + + private String name; private int numVertices; private int numEdges; private boolean[][] adjMatrix; @@ -33,10 +35,11 @@ public class Graph { * * @param numVertices the number of vertices to create in the graph. */ - public Graph(int numVertices) { + public Graph(int numVertices, String name) { this.numVertices = numVertices; this.adjMatrix = new boolean[numVertices][numVertices]; this.transmissionMatrix = new int[numVertices][numVertices]; + this.name = name; } /** @@ -244,4 +247,13 @@ public int[][] getTransmissionMatrix() { public void setTransmissionMatrix(int[][] transmissionMatrix) { this.transmissionMatrix = transmissionMatrix; } + + public Graph setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return this.name; + } } diff --git a/src/io/github/ethankelly/GraphGenerator.java b/src/io/github/ethankelly/GraphGenerator.java index 03388c8..1777b9a 100644 --- a/src/io/github/ethankelly/GraphGenerator.java +++ b/src/io/github/ethankelly/GraphGenerator.java @@ -1,5 +1,10 @@ package io.github.ethankelly; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.InputMismatchException; +import java.util.Scanner; import java.util.stream.IntStream; /** @@ -20,7 +25,7 @@ public class GraphGenerator { */ public static Graph getToastGraph() { // TOAST - Graph toast = new Graph(4); + Graph toast = new Graph(4, "Toast"); toast.addEdge(0, 1); toast.addEdge(0, 2); toast.addEdge(0, 3); @@ -34,7 +39,7 @@ public static Graph getToastGraph() { */ public static Graph getLollipopGraph() { // LOLLIPOP - Graph lollipop = new Graph(4); + Graph lollipop = new Graph(4, "Lollipop"); lollipop.addEdge(0, 1); lollipop.addEdge(0, 2); lollipop.addEdge(0, 3); @@ -47,13 +52,233 @@ public static Graph getLollipopGraph() { */ public static Graph getTriangleGraph() { // TRIANGLE - Graph triangle = new Graph(3); + Graph triangle = new Graph(3, "Triangle"); triangle.addEdge(0, 1); triangle.addEdge(1, 2); triangle.addEdge(2, 0); return triangle; } + static String[] getUserInput() { + Scanner scan = new Scanner(System.in); + String[] arguments = new String[5]; + + getUserStates(scan, arguments); + getUserGraphSelection(scan, arguments); + + System.out.println("Thanks! Generating equations now..."); + + scan.close(); + return arguments; + } + + private static void getUserGraphSelection(Scanner scan, String[] arguments) { + System.out.println("Now, select a graph. Type \"help\" to see the list of graphs that can be randomly generated."); + + if (scan.nextLine().equalsIgnoreCase("help")) { + System.out.println(""" + Enter any of the following currently available graph types for generation: + 1. Toast + 2. Triangle + 3. Lollipop + 4. Simple + 5. Erdős–Rényi + 6. Complete + 7. Bipartite + 8. Complete Bipartite + 9. Path + 10. Binary Tree + 11. Cycle + 12. Eulerian Path + 13. Eulerian Cycle + 14. Wheel + 15. Star + 16. Regular + 17. Tree + Please enter either the number corresponding to the desired graph type or the name of the graph."""); + } + + try { + arguments[1] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered either an integer or graph name."); + e.printStackTrace(); + } + // 1, 2 and 3 don't require further input + if (!arguments[1].equalsIgnoreCase("toast") && + !arguments[1].equalsIgnoreCase("triangle") && + !arguments[1].equalsIgnoreCase("lollipop") && + !arguments[1].equals("1") && !arguments[1].equals("2") && !arguments[1].equals("3")) { + // 6, 9, 10, 11, 14, 15, 17 just need vertices + System.out.println("Please enter the desired number of vertices in your selected graph."); + try { + arguments[2] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number of vertices."); + e.printStackTrace(); + } + // 7 and 8 need two sets of vertices + if (arguments[1].equalsIgnoreCase("bipartite") || arguments[1].equals("7") || + arguments[1].equalsIgnoreCase("complete bipartite") || arguments[1].equals("8")) { + System.out.println("Please enter the number of vertices for the first partition."); + try { + arguments[2] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number of vertices."); + e.printStackTrace(); + } + System.out.println("Please enter the number of vertices for the second partition."); + try { + arguments[3] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number of vertices."); + e.printStackTrace(); + } + // 7 further needs a number of edges + if (arguments[1].equalsIgnoreCase("bipartite") || arguments[1].equals("7")) { + System.out.println("Please enter the desired number of edges in your selected graph."); + try { + arguments[4] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number of edges."); + e.printStackTrace(); + } + } + // 4, 12 and 13 need vertices and edges + } else if (arguments[1].equalsIgnoreCase("simple") || arguments[1].equals("4") || + arguments[1].equalsIgnoreCase("eulerian path") || arguments[1].equals("12") || + arguments[1].equalsIgnoreCase("eulerian cycle") || arguments[1].equals("13")) { + System.out.println("Please enter the desired number of edges in your selected graph."); + try { + arguments[3] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number of edges."); + e.printStackTrace(); + } + // 16 needs a value for k + } else if (arguments[1].equalsIgnoreCase("regular") || arguments[1].equals("16")) { + System.out.println("Please enter the value of k for the k-regular graph."); + try { + arguments[3] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered an integer number."); + e.printStackTrace(); + } + } else if (arguments[1].equalsIgnoreCase("erdos renyi") || + arguments[1].equalsIgnoreCase("erdős rényi") || arguments[1].equals("5")) { + System.out.println("Please enter a probability for the Erdős-Rényi graph."); + try { + arguments[3] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered a decimal number."); + e.printStackTrace(); + } + } + } + } + + private static void getUserStates(Scanner scan, String[] arguments) { + System.out.println(""" + + *** COMPARTMENTAL GRAPH MODEL EQUATIONS GENERATOR *** + + Welcome to the Equations Generation program. This software generates the full system of differential + equations required to describe a particular compartmental model of disease on a specified graph. A text + file will be generated in the same directory as you are running this software from. If you choose to run + the jar again, this text file will be overwritten unless you move it elsewhere or delete it. + + To begin, please enter the states required in the model. Currently, this can be either of: + * SIR + * SIRP + where S represents Susceptible, I is Infected, R is Recovered and P is Protected."""); + try { + arguments[0] = scan.nextLine(); + } catch (InputMismatchException e) { + System.out.println("You should have entered characters representing the required states."); + e.printStackTrace(); + } + } + + static Graph getGraph(String[] args) { + Graph graph; + switch (args[1].toLowerCase()) { + case "1", "toast" -> graph = getToastGraph(); + case "2", "triangle" -> graph = getTriangleGraph(); + case "3", "lollipop" -> graph = getLollipopGraph(); + case "4", "simple" -> { + // Requires number of vertices and number of edges + int[] parsed = parseIntegers(new String[] {args[2], args[3]}); + graph = simple(parsed[0], parsed[1]); + } + case "5", "erdos renyi", "erdős rényi", "er" -> { + // Requires number of vertices and a probability + int numVertices = parseIntegers(new String[] {args[2]})[0]; + double p = parseDoubles(new String[] {args[3]})[0]; + graph = erdosRenyi(numVertices, p); + } + case "6", "complete" -> graph = complete(parseIntegers(new String[] {args[2]})[0]); + case "7", "bipartite" -> { + // Requires 2 numbers of vertices and a number of edges + int[] parsed = parseIntegers(new String[] {args[2], args[3], args[4]}); + graph = bipartite(parsed[0], parsed[1], parsed[2]); + } + case "8", "complete bipartite" -> { + // Requires 2 numbers of vertices + int[] parsed = parseIntegers(new String[] {args[2], args[3]}); + graph = completeBipartite(parsed[0], parsed[1]); + } + case "9", "path" -> graph = path(parseIntegers(new String[] {args[2]})[0]); + case "10", "binary tree" -> graph = binaryTree(parseIntegers(new String[] {args[2]})[0]); + case "11", "cycle" -> graph = cycle(parseIntegers(new String[] {args[2]})[0]); + case "12", "eulerian path" -> { + // Requires number of vertices and number of edges + int[] parsed = parseIntegers(new String[] {args[2], args[3]}); + graph = eulerianPath(parsed[0], parsed[1]); + } + case "13", "eulerian cycle" -> { + // Requires number of vertices and number of edges + int[] parsed = parseIntegers(new String[] {args[2], args[3]}); + graph = eulerianCycle(parsed[0], parsed[1]); + } + case "14", "wheel" -> graph = wheel(parseIntegers(new String[] {args[2]})[0]); + case "15", "star" -> graph = star(parseIntegers(new String[] {args[2]})[0]); + case "16", "regular" -> { + // Requires number of vertices and value of k + int[] parsed = parseIntegers(new String[] {args[2], args[3]}); + graph = regular(parsed[0], parsed[1]); + } + case "17", "tree" -> graph = tree(parseIntegers(new String[] {args[2]})[0]); + default -> throw new IllegalStateException("Unexpected graph type: " + args[1].toLowerCase()); + } + return graph; + } + + public static int[] parseIntegers(String[] args) { + int[] toReturn = new int[args.length]; + for (int i = 0; i < args.length; i++) { + try { + toReturn[i] = Integer.parseInt(args[i]); + } catch (NumberFormatException e) { + System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); + System.out.println("Could not parse integer: " + e); + } + } + return toReturn; + } + + public static double[] parseDoubles(String[] args) { + double[] toReturn = new double[args.length]; + for (int i = 0; i < args.length; i++) { + try { + toReturn[i] = Double.parseDouble(args[i]); + } catch (NumberFormatException e) { + System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); + System.out.println("Could not parse double: " + e); + } + } + return toReturn; + } + /** * The Edge class is used to represent an edge as a pair of vertex locations (v, w) where v < w, between which the * edge exists. @@ -110,7 +335,7 @@ public int compareTo(Edge that) { public static Graph simple(int numVertices, int numEdges) { assert numEdges <= numVertices * (numVertices - 1) / 2 : "Too many edges."; assert numEdges >= 0 : "Too few edges."; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Simple"); g.setNumEdges(0); Set set = new Set<>(); while (g.getNumEdges() < numEdges) { @@ -137,7 +362,7 @@ public static Graph simple(int numVertices, int numEdges) { */ public static Graph erdosRenyi(int numVertices, double probability) { assert !(probability < 0.0) && !(probability > 1.0) : "Probability must be between 0 and 1"; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Erdős–Rényi"); for (int v = 0; v < numVertices; v++) for (int w = v + 1; w < numVertices; w++) if (StdRandom.bernoulli(probability)) @@ -153,7 +378,7 @@ public static Graph erdosRenyi(int numVertices, double probability) { * @return the complete graph on the given number of vertices. */ public static Graph complete(int numVertices) { - return erdosRenyi(numVertices, 1.0); + return erdosRenyi(numVertices, 1.0).setName("Complete"); } /** @@ -167,7 +392,7 @@ public static Graph complete(int numVertices) { * @return a complete bipartite graph on {@code numVer1} and {@code numVer2} vertices. */ public static Graph completeBipartite(int numVer1, int numVer2) { - return bipartite(numVer1, numVer2, numVer1 * numVer2); + return bipartite(numVer1, numVer2, numVer1 * numVer2).setName("Complete Bipartite"); } /** @@ -184,7 +409,7 @@ public static Graph completeBipartite(int numVer1, int numVer2) { public static Graph bipartite(int numVer1, int numVer2, int numEdges) { assert numEdges <= numVer1 * numVer2 : "Too many edges"; assert numEdges >= 0 : "Too few edges"; - Graph g = new Graph(numVer1 + numVer2); + Graph g = new Graph(numVer1 + numVer2, "Bipartite"); int[] vertices = IntStream.range(0, numVer1 + numVer2).toArray(); StdRandom.shuffle(vertices); @@ -217,7 +442,7 @@ public static Graph bipartite(int numVer1, int numVer2, double probability) { assert !(probability < 0.0) && !(probability > 1.0) : "Probability must be between 0 and 1"; int[] vertices = IntStream.range(0, numVer1 + numVer2).toArray(); StdRandom.shuffle(vertices); - Graph G = new Graph(numVer1 + numVer2); + Graph G = new Graph(numVer1 + numVer2, "Bipartite"); for (int i = 0; i < numVer1; i++) for (int j = 0; j < numVer2; j++) if (StdRandom.bernoulli(probability)) @@ -233,7 +458,7 @@ public static Graph bipartite(int numVer1, int numVer2, double probability) { * @return a path graph on {@code numVertices} vertices */ public static Graph path(int numVertices) { - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Path"); // Generate an array: [0, 1, ..., numVertices] and randomly shuffle it. int[] vertices = IntStream.range(0, numVertices).toArray(); StdRandom.shuffle(vertices); @@ -253,7 +478,7 @@ public static Graph path(int numVertices) { * @return a complete binary tree graph on {@code numVertices} vertices */ public static Graph binaryTree(int numVertices) { - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Binary Tree"); // Generate an array: [0, 1, ..., numVertices] and randomly shuffle it. int[] vertices = IntStream.range(0, numVertices).toArray(); StdRandom.shuffle(vertices); @@ -273,7 +498,7 @@ public static Graph binaryTree(int numVertices) { * @return a cycle graph on {@code numVertices} vertices. */ public static Graph cycle(int numVertices) { - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Cycle"); // Generate an array: [0, 1, ..., numVertices] and randomly shuffle it. int[] vertices = IntStream.range(0, numVertices).toArray(); StdRandom.shuffle(vertices); @@ -299,7 +524,7 @@ public static Graph eulerianPath(int numVertices, int numEdges) { // Catch incorrect input of number of edges or vertices assert numEdges >= 0 : "negative number of edges"; assert numVertices > 0 : "An Eulerian path must have at least one vertex"; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Eulerian Path"); // Fill an array of length equal to the number of edges with uniformly random values int[] vertices = IntStream.range(0, numEdges + 1).map(i -> StdRandom.uniform(numVertices)).toArray(); // Connect consecutive (i, i+1) vertices @@ -319,7 +544,7 @@ public static Graph eulerianPath(int numVertices, int numEdges) { public static Graph eulerianCycle(int numVertices, int numEdges) { assert numEdges > 0 : "An Eulerian cycle must have at least one edge"; assert numVertices > 0 : "An Eulerian cycle must have at least one vertex"; - Graph G = new Graph(numVertices); + Graph G = new Graph(numVertices, "Eulerian Cycle"); // Fill an array of length equal to the number of edges with uniformly random values int[] vertices = IntStream.range(0, numEdges).map(i -> StdRandom.uniform(numVertices)).toArray(); // Connect consecutive (i, i+1) vertices @@ -339,7 +564,7 @@ public static Graph eulerianCycle(int numVertices, int numEdges) { */ public static Graph wheel(int numVertices) { assert numVertices > 1 : "Number of vertices must be at least 2"; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Wheel"); // Generate an array: [0, 1, ..., numVertices] and randomly shuffle it. int[] vertices = IntStream.range(0, numVertices).toArray(); StdRandom.shuffle(vertices); @@ -364,7 +589,7 @@ public static Graph wheel(int numVertices) { */ public static Graph star(int numVertices) { assert numVertices > 0 : "Number of vertices must be at least 1"; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Star"); // Generate an array: [0, 1, ..., numVertices] and randomly shuffle it. int[] vertices = IntStream.range(0, numVertices).toArray(); StdRandom.shuffle(vertices); @@ -387,7 +612,7 @@ public static Graph star(int numVertices) { */ public static Graph regular(int numVertices, int k) { assert numVertices * k % 2 == 0 : "Number of vertices * k must be even"; - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, k + "-Regular"); // Create k copies of each vertex int[] vertices = new int[numVertices * k]; @@ -412,7 +637,7 @@ public static Graph regular(int numVertices, int k) { * @return a uniformly random tree on {@code numVertices} vertices. */ public static Graph tree(int numVertices) { - Graph g = new Graph(numVertices); + Graph g = new Graph(numVertices, "Tree"); if (numVertices == 1) return g; diff --git a/src/io/github/ethankelly/Main.java b/src/io/github/ethankelly/Main.java index 83189eb..1f84dd1 100644 --- a/src/io/github/ethankelly/Main.java +++ b/src/io/github/ethankelly/Main.java @@ -1,61 +1,31 @@ package io.github.ethankelly; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.PrintStream; import java.util.Arrays; public class Main { - /** - * Takes command-line args to generate equations for a compartmental model on a specified graph. - * - * @param args command-line args - * @throws FileNotFoundException if the files cannot be written to. - */ - public static void main(String[] args) throws FileNotFoundException { - // Creating a File object that represents the disk file and assign to output stream - PrintStream o = new PrintStream("data/Tuples.txt"); - System.setOut(o); + /** + * Takes command-line args to generate equations for a compartmental model on a specified graph. + * + * @param args command-line args + * @throws FileNotFoundException if the files cannot be written to. + */ + public static void main(String[] args) throws FileNotFoundException { + String[] arguments = GraphGenerator.getUserInput(); + char[] states = arguments[0].toUpperCase().toCharArray(); + Graph graph = GraphGenerator.getGraph(arguments); + Tuple tuples = new Tuple(graph, states); - char[] states = args[0].toUpperCase().toCharArray(); - Graph graph; - Tuple tuples; + // Creating a File object that represents the disk file and assign to output stream + PrintStream o = new PrintStream(new FileOutputStream("Equations.txt")); + System.setOut(o); + System.out.println(" *** Equations for an " + arguments[0].toUpperCase() + " model on a " + graph.getName() + + " Graph ***\n\n" + graph + "Numbers of equations of each size: " + + Arrays.toString(tuples.findNumbers(tuples.getTuples())) + "\n"); + Equations.generateEquations(tuples).forEach(System.out::println); + } - switch(args[1].toLowerCase()) { - case "toast" -> { - graph = GraphGenerator.getToastGraph(); - tuples = new Tuple(graph, states); - } - case "triangle" -> { - graph = GraphGenerator.getTriangleGraph(); - tuples = new Tuple(graph, states); - } - case "lollipop" -> { - graph = GraphGenerator.getLollipopGraph(); - tuples = new Tuple(graph, states); - } - case "erdos-renyi" -> { - int numVertices = 0; - try { - numVertices = Integer.parseInt(args[1]); - } catch (NumberFormatException e) { - System.out.println("Second argument should have been an integer"); - } - - double p = 0; - try { - p = Double.parseDouble(args[2]); - } catch (NumberFormatException e) { - System.out.println("Third argument should have been a double"); - } - graph = GraphGenerator.erdosRenyi(numVertices, p); - tuples = new Tuple(graph, states); - } - default -> throw new IllegalStateException("Unexpected value: " + args[1].toLowerCase()); - } - - System.out.println(" *** " + args[1].toUpperCase() + " GRAPH ***\n\n" + graph + - "Numbers of equations of each size: " + Arrays.toString(tuples.findNumbers(tuples.getTuples())) + "\n"); - tuples.getTuples().forEach(System.out::println); - } }