EndCriteria&NetBuilder
- Add end criteria parsing and update simulation parameters - added net builder from console
This commit is contained in:
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -46,5 +46,12 @@
|
|||||||
"mainClass": "net.berack.upo.valpre.Main",
|
"mainClass": "net.berack.upo.valpre.Main",
|
||||||
"args": "plot -csv example2.csv"
|
"args": "plot -csv example2.csv"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "java",
|
||||||
|
"name": "Build Net",
|
||||||
|
"request": "launch",
|
||||||
|
"mainClass": "net.berack.upo.valpre.Main",
|
||||||
|
"args": "net"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ import java.net.URISyntaxException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import net.berack.upo.valpre.sim.EndCriteria;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length == 0)
|
if (args.length == 0)
|
||||||
@@ -16,20 +18,23 @@ public class Main {
|
|||||||
var param = Main.getParameters(program, subArgs);
|
var param = Main.getParameters(program, subArgs);
|
||||||
switch (program) {
|
switch (program) {
|
||||||
case "simulation" -> {
|
case "simulation" -> {
|
||||||
var net = param.get("net");
|
new Simulation(param.get("net"))
|
||||||
var csv = param.get("csv");
|
.setCsv(param.get("csv"))
|
||||||
var runs = param.getOrDefault("runs", Integer::parseInt, 100);
|
.setRuns(param.getOrDefault("runs", Integer::parseInt, 100))
|
||||||
var seed = param.getOrDefault("seed", Long::parseLong, 2007539552L);
|
.setSeed(param.getOrDefault("seed", Long::parseLong, 2007539552L))
|
||||||
var p = param.getOrDefault("p", Boolean::parseBoolean, false);
|
.setParallel(param.get("p") != null)
|
||||||
|
.setEndCriteria(EndCriteria.parse(param.get("end")))
|
||||||
var sim = new Simulation(net, seed, runs, p, csv);
|
.run();
|
||||||
sim.run();
|
|
||||||
}
|
}
|
||||||
case "plot" -> {
|
case "plot" -> {
|
||||||
var csv = param.get("csv");
|
var csv = param.get("csv");
|
||||||
var plot = new Plot(csv);
|
var plot = new Plot(csv);
|
||||||
plot.show();
|
plot.show();
|
||||||
}
|
}
|
||||||
|
case "net" -> {
|
||||||
|
var net = new NetBuilderInteractive();
|
||||||
|
net.run();
|
||||||
|
}
|
||||||
default -> exit("Invalid program!");
|
default -> exit("Invalid program!");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -50,12 +55,14 @@ public class Main {
|
|||||||
arguments.put("seed", true);
|
arguments.put("seed", true);
|
||||||
arguments.put("runs", true);
|
arguments.put("runs", true);
|
||||||
arguments.put("net", true);
|
arguments.put("net", true);
|
||||||
|
arguments.put("end", true);
|
||||||
arguments.put("csv", true);
|
arguments.put("csv", true);
|
||||||
|
|
||||||
var descriptions = new HashMap<String, String>();
|
var descriptions = new HashMap<String, String>();
|
||||||
descriptions.put("p", "Add this if you want the simulation to use threads (one each run).");
|
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("seed", "The seed of the simulation.");
|
||||||
descriptions.put("runs", "How many runs the simulator should run.");
|
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("net", "The file net to use. Use example1.net or example2.net for the provided ones.");
|
||||||
|
|
||||||
var csvDesc = switch (program) {
|
var csvDesc = switch (program) {
|
||||||
@@ -65,6 +72,8 @@ public class Main {
|
|||||||
};
|
};
|
||||||
descriptions.put("csv", csvDesc);
|
descriptions.put("csv", csvDesc);
|
||||||
|
|
||||||
|
if (program.equals("net"))
|
||||||
|
return null;
|
||||||
return Parameters.getArgsOrHelper(args, "-", arguments, descriptions);
|
return Parameters.getArgsOrHelper(args, "-", arguments, descriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +85,10 @@ public class Main {
|
|||||||
var uri = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
|
var uri = Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
|
||||||
var name = new File(uri).getName();
|
var name = new File(uri).getName();
|
||||||
System.out.println(message);
|
System.out.println(message);
|
||||||
System.out.println("Usage: java -jar " + name + ".jar [simulation|plot] [args]");
|
System.out.println("Usage: java -jar " + name + ".jar [simulation|plot|net] [args]");
|
||||||
|
System.out.println("simulation args: -net <net> -csv <csv> [-runs <runs>] [-seed <seed>] [-p]");
|
||||||
|
System.out.println("plot args: -csv <csv>");
|
||||||
|
System.out.println("net args: none");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
182
src/main/java/net/berack/upo/valpre/NetBuilderInteractive.java
Normal file
182
src/main/java/net/berack/upo/valpre/NetBuilderInteractive.java
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package net.berack.upo.valpre;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import net.berack.upo.valpre.rand.Distribution;
|
||||||
|
import net.berack.upo.valpre.sim.Net;
|
||||||
|
import net.berack.upo.valpre.sim.ServerNode;
|
||||||
|
|
||||||
|
public class NetBuilderInteractive {
|
||||||
|
|
||||||
|
private final Net net = new Net();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the interactive net builder.
|
||||||
|
*
|
||||||
|
* @param args the arguments
|
||||||
|
*/
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
var choice = choose("Choose the next step to do:",
|
||||||
|
"Add a node", "Add a connection", "Print Nodes", "Save the net", "Exit");
|
||||||
|
switch (choice) {
|
||||||
|
case 1 -> {
|
||||||
|
var node = this.buildNode();
|
||||||
|
this.net.addNode(node);
|
||||||
|
}
|
||||||
|
case 2 -> {
|
||||||
|
var source = ask("Enter the source node: ");
|
||||||
|
var target = ask("Enter the target node: ");
|
||||||
|
var weight = ask("Enter the weight: ", Double::parseDouble, 0.0);
|
||||||
|
var sourceNode = this.net.getNode(source);
|
||||||
|
var targetNode = this.net.getNode(target);
|
||||||
|
this.net.addConnection(sourceNode, targetNode, weight);
|
||||||
|
}
|
||||||
|
case 3 -> this.printNodes();
|
||||||
|
case 4 -> this.net.save(ask("Enter the filename: "));
|
||||||
|
case 5 -> System.exit(0);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print the nodes in the net.
|
||||||
|
*/
|
||||||
|
private void printNodes() {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.append("Nodes:\n");
|
||||||
|
for (var i = 0; i < this.net.size(); i++) {
|
||||||
|
var name = this.net.getNode(i).name;
|
||||||
|
builder.append(name).append(" -> ");
|
||||||
|
for (var connection : this.net.getChildren(i))
|
||||||
|
builder.append(connection.child.name).append("(").append(connection.weight).append("), ");
|
||||||
|
builder.delete(builder.length() - 2, builder.length());
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
System.out.print(builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a node.
|
||||||
|
*
|
||||||
|
* @return the node
|
||||||
|
*/
|
||||||
|
private ServerNode buildNode() {
|
||||||
|
var choice = choose("Choose the type of node to create:", "Source", "Queue");
|
||||||
|
var name = ask("Node name: ");
|
||||||
|
var distribution = askDistribution("Service distribution");
|
||||||
|
|
||||||
|
return switch (choice) {
|
||||||
|
case 1 -> {
|
||||||
|
var limit = ask("Arrivals limit (0 for Int.Max): ", Integer::parseInt, 1);
|
||||||
|
if (limit <= 0)
|
||||||
|
limit = Integer.MAX_VALUE;
|
||||||
|
yield ServerNode.createLimitedSource(name, distribution, limit);
|
||||||
|
}
|
||||||
|
case 2 -> {
|
||||||
|
var servers = ask("Number of servers: ", Integer::parseInt, 1);
|
||||||
|
var unavailable = askDistribution("Unavailable distribution");
|
||||||
|
yield ServerNode.createQueue(name, servers, distribution, unavailable);
|
||||||
|
}
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user for a distribution.
|
||||||
|
*
|
||||||
|
* @return the distribution
|
||||||
|
*/
|
||||||
|
public static Distribution askDistribution(String ask) {
|
||||||
|
var choice = choose(ask + ":", "Exponential", "Uniform", "Erlang",
|
||||||
|
"UnavailableTime", "Normal", "NormalBoxMuller", "None");
|
||||||
|
|
||||||
|
return switch (choice) {
|
||||||
|
case 1 -> {
|
||||||
|
var lambda = ask("Lambda: ", Double::parseDouble, 1.0);
|
||||||
|
yield new Distribution.Exponential(lambda);
|
||||||
|
}
|
||||||
|
case 2 -> {
|
||||||
|
var min = ask("Min: ", Double::parseDouble, 0.0);
|
||||||
|
var max = ask("Max: ", Double::parseDouble, 1.0);
|
||||||
|
yield new Distribution.Uniform(min, max);
|
||||||
|
}
|
||||||
|
case 3 -> {
|
||||||
|
var k = ask("K: ", Integer::parseInt, 1);
|
||||||
|
var lambda = ask("Lambda: ", Double::parseDouble, 1.0);
|
||||||
|
yield new Distribution.Erlang(k, lambda);
|
||||||
|
}
|
||||||
|
case 4 -> {
|
||||||
|
var probability = ask("Probability: ", Double::parseDouble, 0.0);
|
||||||
|
var unavailable = askDistribution("Unavailable distribution");
|
||||||
|
yield new Distribution.UnavailableTime(probability, unavailable);
|
||||||
|
}
|
||||||
|
case 5 -> {
|
||||||
|
var mean = ask("Mean: ", Double::parseDouble, 0.0);
|
||||||
|
var stdDev = ask("Standard deviation: ", Double::parseDouble, 1.0);
|
||||||
|
yield new Distribution.Normal(mean, stdDev);
|
||||||
|
}
|
||||||
|
case 6 -> {
|
||||||
|
var mean = ask("Mean: ", Double::parseDouble, 0.0);
|
||||||
|
var stdDev = ask("Standard deviation: ", Double::parseDouble, 1.0);
|
||||||
|
yield new Distribution.NormalBoxMuller(mean, stdDev);
|
||||||
|
}
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user a question.
|
||||||
|
*
|
||||||
|
* @param ask the question to ask
|
||||||
|
* @return the answer
|
||||||
|
*/
|
||||||
|
private static String ask(String ask) {
|
||||||
|
return ask(ask, Function.identity(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user a question.
|
||||||
|
*
|
||||||
|
* @param ask the question to ask
|
||||||
|
* @param parser the parser to use
|
||||||
|
* @param defaultValue the default value
|
||||||
|
* @return the answer
|
||||||
|
*/
|
||||||
|
private static <T> T ask(String ask, Function<String, T> parser, T defaultValue) {
|
||||||
|
System.out.print(ask);
|
||||||
|
try {
|
||||||
|
var line = System.console().readLine();
|
||||||
|
return parser.apply(line);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Invalid input: " + e.getMessage());
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user to choose an option.
|
||||||
|
*
|
||||||
|
* @param ask the question to ask
|
||||||
|
* @param options the options to choose from
|
||||||
|
* @return the choice
|
||||||
|
*/
|
||||||
|
private static int choose(String ask, String... options) {
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.append(ask).append("\n");
|
||||||
|
for (int i = 0; i < options.length; i++) {
|
||||||
|
builder.append(i + 1).append(". ").append(options[i]).append("\n");
|
||||||
|
}
|
||||||
|
builder.append("> ");
|
||||||
|
|
||||||
|
var string = builder.toString();
|
||||||
|
var choice = 0;
|
||||||
|
while (choice < 1 || choice > options.length)
|
||||||
|
choice = ask(string, Integer::parseInt, 0);
|
||||||
|
|
||||||
|
return choice;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import java.io.IOException;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import com.esotericsoftware.kryo.KryoException;
|
import com.esotericsoftware.kryo.KryoException;
|
||||||
|
|
||||||
|
import net.berack.upo.valpre.sim.EndCriteria;
|
||||||
import net.berack.upo.valpre.sim.Net;
|
import net.berack.upo.valpre.sim.Net;
|
||||||
import net.berack.upo.valpre.sim.SimulationMultiple;
|
import net.berack.upo.valpre.sim.SimulationMultiple;
|
||||||
import net.berack.upo.valpre.sim.stats.CsvResult;
|
import net.berack.upo.valpre.sim.stats.CsvResult;
|
||||||
@@ -14,27 +15,20 @@ import net.berack.upo.valpre.sim.stats.CsvResult;
|
|||||||
* and runs the simulation with the given parameters.
|
* and runs the simulation with the given parameters.
|
||||||
*/
|
*/
|
||||||
public class Simulation {
|
public class Simulation {
|
||||||
public final String csv;
|
private String csv;
|
||||||
public final int runs;
|
private int runs;
|
||||||
public final long seed;
|
private long seed;
|
||||||
public final boolean parallel;
|
private boolean parallel;
|
||||||
public final Net net;
|
private Net net;
|
||||||
|
private EndCriteria[] endCriteria;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new simulation with the given arguments.
|
* Create a new simulation for the given net.
|
||||||
*
|
*
|
||||||
* @param args The arguments for the simulation.
|
* @param netFile the net file to load
|
||||||
* @throws IOException if the file is has a problem
|
* @throws IOException if the file has a problem
|
||||||
*/
|
*/
|
||||||
public Simulation(String netFile, long seed, int runs, boolean parallel, String csv) throws IOException {
|
public Simulation(String netFile) throws IOException {
|
||||||
if (runs <= 0)
|
|
||||||
throw new IllegalArgumentException("Runs must be greater than 0!");
|
|
||||||
|
|
||||||
this.runs = runs;
|
|
||||||
this.seed = seed;
|
|
||||||
this.csv = csv;
|
|
||||||
this.parallel = parallel;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var file = Parameters.getFileOrExample(netFile);
|
var file = Parameters.getFileOrExample(netFile);
|
||||||
this.net = Net.load(file);
|
this.net = Net.load(file);
|
||||||
@@ -46,6 +40,83 @@ public class Simulation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new simulation for the given net.
|
||||||
|
*
|
||||||
|
* @param net the net
|
||||||
|
* @throws IllegalArgumentException if the net is null
|
||||||
|
*/
|
||||||
|
public Simulation(Net net) {
|
||||||
|
if (net == null)
|
||||||
|
throw new IllegalArgumentException("Net needed!");
|
||||||
|
this.net = net;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of runs for the simulation.
|
||||||
|
*
|
||||||
|
* @param runs the number of runs
|
||||||
|
* @throws IllegalArgumentException if the runs are less than 1
|
||||||
|
* @return this simulation
|
||||||
|
*/
|
||||||
|
public Simulation setRuns(int runs) {
|
||||||
|
if (runs <= 0)
|
||||||
|
throw new IllegalArgumentException("Runs must be greater than 0!");
|
||||||
|
|
||||||
|
this.runs = runs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the seed for the simulation.
|
||||||
|
*
|
||||||
|
* @param seed the seed
|
||||||
|
* @return this simulation
|
||||||
|
*/
|
||||||
|
public Simulation setSeed(long seed) {
|
||||||
|
this.seed = seed;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the simulation should run in parallel.
|
||||||
|
* The parallelization is done by running each simulation in a separate thread.
|
||||||
|
*
|
||||||
|
* @param parallel if the simulation should run in parallel
|
||||||
|
* @return this simulation
|
||||||
|
*/
|
||||||
|
public Simulation setParallel(boolean parallel) {
|
||||||
|
this.parallel = parallel;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the CSV file to save the results.
|
||||||
|
*
|
||||||
|
* @param csv the CSV file
|
||||||
|
* @return this simulation
|
||||||
|
*/
|
||||||
|
public Simulation setCsv(String csv) {
|
||||||
|
this.csv = csv;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the end criteria for the simulation.
|
||||||
|
* Can be an empty array if no criteria are needed.
|
||||||
|
* Cannot be null.
|
||||||
|
*
|
||||||
|
* @param criterias the end criteria
|
||||||
|
* @return this simulation
|
||||||
|
* @throws IllegalArgumentException if the criteria are null
|
||||||
|
*/
|
||||||
|
public Simulation setEndCriteria(EndCriteria... criterias) {
|
||||||
|
if (criterias == null)
|
||||||
|
throw new IllegalArgumentException("End criteria cannot be null!");
|
||||||
|
this.endCriteria = criterias;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the simulation with the given parameters.
|
* Run the simulation with the given parameters.
|
||||||
* At the end it prints the results and saves them to a CSV file if requested.
|
* At the end it prints the results and saves them to a CSV file if requested.
|
||||||
@@ -58,7 +129,9 @@ public class Simulation {
|
|||||||
public void run() throws InterruptedException, ExecutionException, KryoException, IOException {
|
public void run() throws InterruptedException, ExecutionException, KryoException, IOException {
|
||||||
var nano = System.nanoTime();
|
var nano = System.nanoTime();
|
||||||
var sim = new SimulationMultiple(this.net);
|
var sim = new SimulationMultiple(this.net);
|
||||||
var summary = this.parallel ? sim.runParallel(this.seed, this.runs) : sim.run(this.seed, this.runs);
|
var summary = this.parallel
|
||||||
|
? sim.runParallel(this.seed, this.runs, this.endCriteria)
|
||||||
|
: sim.run(this.seed, this.runs, this.endCriteria);
|
||||||
nano = System.nanoTime() - nano;
|
nano = System.nanoTime() - nano;
|
||||||
|
|
||||||
System.out.print(summary);
|
System.out.print(summary);
|
||||||
|
|||||||
@@ -12,6 +12,45 @@ public interface EndCriteria {
|
|||||||
*/
|
*/
|
||||||
public boolean shouldEnd(Simulation run);
|
public boolean shouldEnd(Simulation run);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the given string to create an array of end criteria.
|
||||||
|
* The string passed must be in the following format:
|
||||||
|
* [criteria1];[criteria2];...;[criteriaN]
|
||||||
|
*
|
||||||
|
* and each criteria must be in the following format:
|
||||||
|
* ClassName:param1,param2,...,paramN
|
||||||
|
*
|
||||||
|
* If the string is empty or null, an empty array is returned.
|
||||||
|
* If one of the criteria is not valid, an exception is thrown.
|
||||||
|
*
|
||||||
|
* @param criterias The string to parse.
|
||||||
|
* @return An array of end criteria.
|
||||||
|
* @throws IllegalArgumentException If one of the criteria is not valid.
|
||||||
|
*/
|
||||||
|
public static EndCriteria[] parse(String criterias) {
|
||||||
|
if (criterias == null || criterias.isEmpty())
|
||||||
|
return new EndCriteria[0];
|
||||||
|
|
||||||
|
var criteria = criterias.split(";");
|
||||||
|
var endCriteria = new EndCriteria[criteria.length];
|
||||||
|
for (int i = 0; i < criteria.length; i++) {
|
||||||
|
var current = criteria[i].substring(1, criteria[i].length() - 1); // Remove the brackets
|
||||||
|
var parts = current.split(":");
|
||||||
|
if (parts.length != 2)
|
||||||
|
throw new IllegalArgumentException("Invalid criteria: " + current);
|
||||||
|
|
||||||
|
var className = parts[0];
|
||||||
|
var params = parts[1].split(",");
|
||||||
|
endCriteria[i] = switch (className) {
|
||||||
|
case "MaxArrivals" -> new MaxArrivals(params[0], Integer.parseInt(params[1]));
|
||||||
|
case "MaxDepartures" -> new MaxDepartures(params[0], Integer.parseInt(params[1]));
|
||||||
|
case "MaxTime" -> new MaxTime(Double.parseDouble(params[0]));
|
||||||
|
default -> throw new IllegalArgumentException("Invalid criteria: " + current);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return endCriteria;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends the simulation when the given node has reached the specified number of
|
* Ends the simulation when the given node has reached the specified number of
|
||||||
* arrivals.
|
* arrivals.
|
||||||
|
|||||||
Reference in New Issue
Block a user