diff --git a/.vscode/launch.json b/.vscode/launch.json
index fabc344..af5db31 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -30,7 +30,7 @@
"name": "Run Incremental",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
- "args": "simulation -net src/test/resources/example2.net -runs 1000 -i \"[Service1:throughput=0.98:0.01],[Service2:utilization=0.98:0.01],[Service2:unavailable=0.98:0.01]\""
+ "args": "simulation -net src/test/resources/example2.net -runs 1000 -indices \"[Service1:throughput=0.98:0.01],[Service2:utilization=0.98:0.01],[Service2:unavailable=0.98:0.01]\""
},
{
"type": "java",
diff --git a/pom.xml b/pom.xml
index b0a0f94..3682dd2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,5 +41,10 @@
jfreechart
1.5.5
+
+ net.sourceforge.argparse4j
+ argparse4j
+ 0.9.0
+
\ No newline at end of file
diff --git a/src/main/java/net/berack/upo/valpre/InteractiveConsole.java b/src/main/java/net/berack/upo/valpre/InteractiveConsole.java
index adb323d..a013ec5 100644
--- a/src/main/java/net/berack/upo/valpre/InteractiveConsole.java
+++ b/src/main/java/net/berack/upo/valpre/InteractiveConsole.java
@@ -143,8 +143,7 @@ public class InteractiveConsole {
switch (choice) {
case 1 -> new SimulationBuilder(net).setSeed(seed).setMaxRuns(100).setParallel(true).setCsv(csv).run();
case 2 -> new SimulationBuilder(net).setSeed(seed).setMaxRuns(1000).setParallel(true).setCsv(csv).run();
- case 3 -> new SimulationBuilder(net).setSeed(seed).setMaxRuns(1000).setParallel(true).setCsv(csv).run();
- case 4 -> {
+ case 3 -> {
var indices = ask("Confidence indices with format [node:stat=confidence:relativeError];[..]\n");
new SimulationBuilder(net).setSeed(seed).setMaxRuns(10000).parseConfidenceIndices(indices).setCsv(csv)
.run();
diff --git a/src/main/java/net/berack/upo/valpre/Main.java b/src/main/java/net/berack/upo/valpre/Main.java
index 8135468..f5833db 100644
--- a/src/main/java/net/berack/upo/valpre/Main.java
+++ b/src/main/java/net/berack/upo/valpre/Main.java
@@ -2,95 +2,93 @@ package net.berack.upo.valpre;
import java.io.File;
import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.HashMap;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.Namespace;
public class Main {
- public static void main(String[] args) {
- if (args.length == 0)
- exit("No program specified!");
+ private final static String NAME;
+ /**
+ * The name of the program, used for the help message.
+ */
+ static {
+ var name = "valpre";
try {
- var program = args[0];
- var subArgs = Arrays.copyOfRange(args, 1, args.length);
- switch (program) {
+ var uri = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
+ name = new File(uri).getName();
+ } catch (URISyntaxException e) {
+ }
+ NAME = name;
+ }
+
+ /**
+ * The main method of the program. It parses the arguments and runs the
+ * simulation or the plotter.
+ *
+ * @param args the arguments to parse
+ */
+ public static void main(String[] args) {
+ try {
+ var param = Main.getParameters(args);
+ var command = param.getString("command");
+
+ switch (command) {
case "simulation" -> {
- var param = Main.getParameters(program, subArgs);
- new SimulationBuilder(param.get("net"))
- .setCsv(param.get("csv"))
- .setMaxRuns(param.getOrDefault("runs", Integer::parseInt, 100))
- .setSeed(param.getOrDefault("seed", Long::parseLong, 0L))
- .setParallel(param.get("p") != null)
- .parseEndCriteria(param.get("end"))
- .parseConfidenceIndices(param.get("i"))
+ new SimulationBuilder(param.getString("net"))
+ .setCsv(param.getString("csv"))
+ .setMaxRuns(param.getInt("runs"))
+ .setSeed(param.getLong("seed"))
+ .setParallel(param.getBoolean("p"))
+ .parseEndCriteria(param.getString("end"))
+ .parseConfidenceIndices(param.getString("indices"))
.run();
}
case "plot" -> {
- var param = Main.getParameters(program, subArgs);
- var csv = param.get("csv");
+ var csv = param.getString("csv");
var plot = new Plot(csv);
plot.show();
}
case "interactive" -> new InteractiveConsole().run();
- default -> exit("Invalid program!");
+ default -> throw new RuntimeException("Invalid program!"); // Should never happen
}
} catch (Exception e) {
- exit(e.getMessage());
- }
- }
-
- /**
- * Get the parameters from the arguments.
- *
- * @param program the program to run
- * @param args the arguments to parse
- * @return the parameters
- */
- private static Parameters getParameters(String program, String[] args) {
- var arguments = new HashMap();
- arguments.put("p", false);
- arguments.put("seed", true);
- arguments.put("runs", true);
- arguments.put("net", true);
- arguments.put("end", true);
- arguments.put("csv", true);
- arguments.put("i", true);
-
- var descriptions = new HashMap();
- descriptions.put("p", "Add this if you want the simulation to use threads (one each run).");
- descriptions.put("seed", "The seed of the simulation.");
- descriptions.put("runs", "How many runs the simulator should run.");
- descriptions.put("end", "When the simulation should end. Format is \"[ClassName:param1,..,paramN];[..]\"");
- descriptions.put("net", "The file net to use. Use example1.net or example2.net for the provided ones.");
- descriptions.put("i", "The confidence indices to use for the simulation. If active then p is ignored."
- + " Format is \"[node:stat=confidence:relativeError];[..]\"");
-
- var csvDesc = switch (program) {
- case "simulation" -> "The filename for saving every run statistics.";
- case "plot" -> "The filename that contains the previous saved runs.";
- default -> "";
- };
- descriptions.put("csv", csvDesc);
-
- return Parameters.getArgsOrHelper(args, "-", arguments, descriptions);
- }
-
- /**
- * Exit the program with an error message.
- */
- public static void exit(String message) {
- try {
- var uri = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
- var name = new File(uri).getName();
- System.err.println(message);
- System.out.println("Usage: java -jar " + name + ".jar [simulation|plot|interactive] [args]");
- System.out.println("simulation args: -net [-csv ] [-runs ] [-seed ]"
- + "[-p] [-end ] [-i ]");
- System.out.println("plot args: -csv ");
- System.out.println("interactive: no args needed");
+ System.err.println(e.getMessage());
System.exit(1);
- } catch (URISyntaxException e) {
- e.printStackTrace();
}
}
+
+ /**
+ * Parses the arguments of the program. It uses the argparse4j library to parse
+ * the arguments and return a Namespace object with the parsed arguments.
+ *
+ * @param args the arguments to parse
+ * @return a Namespace object with the parsed arguments
+ */
+ private static Namespace getParameters(String[] args) {
+ var parser = ArgumentParsers.newFor(NAME).build()
+ .defaultHelp(true)
+ .description("Build a network simulation and/or plot the results of a simulation.");
+ var subparser = parser.addSubparsers().title("commands").description("valid commands").help("subcommand help");
+
+ var sim = subparser.addParser("simulation").help("Run a simulation of the network.");
+ sim.addArgument("-net").help("The file net to use.").required(true);
+ sim.addArgument("-csv").help("The filename for saving every run statistics.");
+ sim.addArgument("-runs").type(Integer.class).help("How many runs the simulator should run.").setDefault(100);
+ sim.addArgument("-seed").type(Long.class).help("The seed of the simulation.").setDefault(0L);
+ sim.addArgument("-p").action(Arguments.storeTrue()).help("Parallel (one thread each run).").setDefault(false);
+ sim.addArgument("-end").help("When the simulation should end. Format:\n\"[ClassName:param1,..,paramN];[..]\"");
+ sim.addArgument("-indices").help("The confidence indices to use for the simulation. If active -p is ignored."
+ + " Format:\n\"[node:stat=confidence:relativeError];[..]\"");
+
+ var plot = subparser.addParser("plot").help("Plot the results of a simulation.");
+ plot.addArgument("-csv").help("The filename for the csv file to plot.").required(true);
+
+ var _ = subparser.addParser("interactive").help("Run the interactive console.");
+ // Interactive console does not need any arguments
+
+ var namespace = parser.parseArgsOrFail(args);
+ namespace.getAttrs().put("command", args[0]);
+ return namespace;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/berack/upo/valpre/NetExamples.java b/src/main/java/net/berack/upo/valpre/NetExamples.java
index 768daa5..d5bc27c 100644
--- a/src/main/java/net/berack/upo/valpre/NetExamples.java
+++ b/src/main/java/net/berack/upo/valpre/NetExamples.java
@@ -67,9 +67,6 @@ public final class NetExamples {
new double[] { 1 / (avg * 0.5), 1 / (avg * 1.5) },
new double[] { 0.5f, 0.5f });
- System.out.println("Normal: " + normal.mean);
- System.out.println("Uniform: " + uniform.min + " - " + uniform.max);
-
for (var spawn : spawnTotals) {
System.out.println("Spawn: " + spawn);
var nets = new Net[] {
diff --git a/src/main/java/net/berack/upo/valpre/Parameters.java b/src/main/java/net/berack/upo/valpre/Parameters.java
deleted file mode 100644
index 9c5eff4..0000000
--- a/src/main/java/net/berack/upo/valpre/Parameters.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package net.berack.upo.valpre;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-
-/**
- * Class that helps with parsing the parameters passed as input in the console.
- */
-public class Parameters {
- private final Map arguments;
- private final String prefix;
- private Map parameters;
-
- /**
- * Constructs a new Parameters object with the specified prefix and arguments.
- * The arguments can be with value, in that case in the map the boolean should
- * be true, otherwise it is only an argument that is a flag
- *
- * @param prefix the prefix to be used
- * @param arguments a map of arguments where the key is a string and if the
- * boolean is true then the argument expect a value
- * @throws IllegalArgumentException if the arguments map is null or empty
- */
- public Parameters(String prefix, Map arguments) {
- if (arguments == null || arguments.size() == 0)
- throw new IllegalArgumentException();
- this.arguments = arguments;
- this.prefix = prefix;
- }
-
- /**
- * Get the size of the parameters.
- *
- * @return the size of the parameters
- */
- public int size() {
- return this.parameters.size();
- }
-
- /**
- * Get the value of the argument passed as input.
- *
- * @param key the key of the argument
- * @return the value of the argument
- */
- public String get(String key) {
- if (this.parameters == null)
- return null;
- return this.parameters.get(key);
- }
-
- /**
- * Get the value from the arguments or the default value if it is not present.
- *
- * @param key The key to get the value from.
- * @param parse The function to parse the value.
- * @param value The default value if the key is not present.
- * @return The value from the arguments or the default value if it is not
- * present.
- */
- public T getOrDefault(String key, Function parse, T value) {
- var arg = this.get(key);
- return arg != null ? parse.apply(arg) : value;
- }
-
- /**
- * Return a string with the standard spaced enough
- *
- * @param eventualDescription the description for the argument, if not present
- * the argument will be shown anyway/
- * @return a string of arguments
- */
- public String helper(Map eventualDescription) {
- var size = 0;
- var parameters = new HashMap();
-
- for (var param : this.arguments.entrySet()) {
- var string = this.prefix + param.getKey();
- if (param.getValue())
- string += " ";
-
- parameters.put(param.getKey(), string);
- size = Math.max(size, string.length());
- }
- size += 2; // spacing
-
- var builder = new StringBuilder();
- for (var param : parameters.entrySet()) {
- var key = param.getKey();
- var args = param.getValue();
-
- builder.append(" ");
- builder.append(args);
-
- var desc = eventualDescription.get(key);
- if (desc != null) {
- builder.append(" ".repeat(size - args.length()));
- builder.append(desc);
- }
- builder.append("\n");
- }
-
- return builder.toString();
- }
-
- /**
- * Parse the arguments passed and build a map of Argument --> Value that can
- * be used to retrieve the information. In the case that the arguments are not
- * in the correct format then an exception is thrown.
- * To get the arguments use the {@link #get(String)} method.
- *
- * @param args the arguments in input
- * @throws IllegalArgumentException if the arguments are not formatted correctly
- * or if there is an unknown argument or there
- * are not arguments in the input
- */
- public void parse(String[] args) {
- if (args == null || args.length == 0)
- throw new IllegalArgumentException("No arguments passed");
-
- var result = new HashMap();
- for (var i = 0; i < args.length; i += 1) {
- var current = args[i];
- var next = i + 1 < args.length ? args[i + 1] : null;
-
- var updateI = this.parseSingle(current, next, result);
- if (updateI)
- i += 1;
- }
-
- this.parameters = result;
- }
-
- /**
- * Parse one single argument and put it into the map.
- *
- * @param current the current argument
- * @param next the next argument if present
- * @param result the map where to insert the value
- * @throws IllegalArgumentException if the arguments are not formatted correctly
- * or if there is an unknown argument
- * @return true if the next argument is used
- */
- private boolean parseSingle(String current, String next, Map result) {
- if (!current.startsWith(this.prefix))
- throw new IllegalArgumentException("Missing prefix [" + current + "]");
- current = current.substring(this.prefix.length());
-
- var value = this.arguments.get(current);
- if (value != null) {
- result.put(current, value ? next : "");
- return value;
- }
-
- var finalSize = result.size() + current.length();
- for (var letter : current.split(""))
- if (this.arguments.get(letter) != null)
- result.put(current, "");
-
- if (finalSize != result.size())
- throw new IllegalArgumentException("Unknown argument [" + current + "]");
- return false;
- }
-
- /**
- * Parse the arguments passed and returns a map of Argument --> Value that can
- * be used to retrieve the information. In the case that the arguments are not
- * in the correct format then an exception is thrown and the helper is printed.
- * If the arguments passed are 0 then the helper is printed.
- *
- * @param args the arguments in input
- * @param prefix the prefix to be used
- * @param arguments a map of arguments where the key is a string and if the
- * boolean is true then the argument expect a value
- * @param descriptions a map of descriptions for the arguments
- * @throws IllegalArgumentException if the arguments are not formatted correctly
- * or if there is an unknown argument
- * @return a map of the values
- */
- public static Parameters getArgsOrHelper(String[] args, String prefix, Map arguments,
- Map descriptions) {
-
- var param = new Parameters(prefix, arguments);
- try {
- param.parse(args);
- return param;
- } catch (IllegalArgumentException e) {
- System.out.println(e.getMessage());
- System.out.println(param.helper(descriptions));
- throw new IllegalArgumentException("Invalid arguments");
- }
- }
-}