Add argparse4j dependency; remove Parameters class and update simulation argument handling
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -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",
|
||||
|
||||
5
pom.xml
5
pom.xml
@@ -41,5 +41,10 @@
|
||||
<artifactId>jfreechart</artifactId>
|
||||
<version>1.5.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.argparse4j</groupId>
|
||||
<artifactId>argparse4j</artifactId>
|
||||
<version>0.9.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -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();
|
||||
|
||||
@@ -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<String, Boolean>();
|
||||
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<String, String>();
|
||||
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 <net> [-csv <csv>] [-runs <runs>] [-seed <seed>]"
|
||||
+ "[-p] [-end <end>] [-i <indices>]");
|
||||
System.out.println("plot args: -csv <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;
|
||||
}
|
||||
}
|
||||
@@ -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[] {
|
||||
|
||||
@@ -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<String, Boolean> arguments;
|
||||
private final String prefix;
|
||||
private Map<String, String> 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<String, Boolean> 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> T getOrDefault(String key, Function<String, T> parse, T value) {
|
||||
var arg = this.get(key);
|
||||
return arg != null ? parse.apply(arg) : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string with the standard <arggument> <description> 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<String, String> eventualDescription) {
|
||||
var size = 0;
|
||||
var parameters = new HashMap<String, String>();
|
||||
|
||||
for (var param : this.arguments.entrySet()) {
|
||||
var string = this.prefix + param.getKey();
|
||||
if (param.getValue())
|
||||
string += " <value>";
|
||||
|
||||
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<String, String>();
|
||||
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<String, String> 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<String, Boolean> arguments,
|
||||
Map<String, String> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user