Add incremental run support and confidence index handling in simulation
This commit is contained in:
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -25,6 +25,13 @@
|
|||||||
"mainClass": "net.berack.upo.valpre.Main",
|
"mainClass": "net.berack.upo.valpre.Main",
|
||||||
"args": "simulation -net example3.net -runs 1000 -p -seed 0"
|
"args": "simulation -net example3.net -runs 1000 -p -seed 0"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "java",
|
||||||
|
"name": "Run Incremental",
|
||||||
|
"request": "launch",
|
||||||
|
"mainClass": "net.berack.upo.valpre.Main",
|
||||||
|
"args": "simulation -net example3.net -runs 1000 -seed 0 -i \"[Service1:throughput=0.98:0.01],[Service2:utilization=0.98:0.01],[Service2:unavailable=0.98:0.01]\""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "java",
|
"type": "java",
|
||||||
"name": "Run10",
|
"name": "Run10",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public class Main {
|
|||||||
.setSeed(param.getOrDefault("seed", Long::parseLong, 2007539552L))
|
.setSeed(param.getOrDefault("seed", Long::parseLong, 2007539552L))
|
||||||
.setParallel(param.get("p") != null)
|
.setParallel(param.get("p") != null)
|
||||||
.setEndCriteria(EndCriteria.parse(param.get("end")))
|
.setEndCriteria(EndCriteria.parse(param.get("end")))
|
||||||
|
.parseConfidenceIndices(param.get("i"))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
case "plot" -> {
|
case "plot" -> {
|
||||||
@@ -58,6 +59,7 @@ public class Main {
|
|||||||
arguments.put("net", true);
|
arguments.put("net", true);
|
||||||
arguments.put("end", true);
|
arguments.put("end", true);
|
||||||
arguments.put("csv", true);
|
arguments.put("csv", true);
|
||||||
|
arguments.put("i", 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).");
|
||||||
@@ -65,6 +67,8 @@ public class Main {
|
|||||||
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("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.");
|
||||||
|
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) {
|
var csvDesc = switch (program) {
|
||||||
case "simulation" -> "The filename for saving every run statistics.";
|
case "simulation" -> "The filename for saving every run statistics.";
|
||||||
@@ -85,7 +89,8 @@ public class Main {
|
|||||||
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|net] [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("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("plot args: -csv <csv>");
|
||||||
System.out.println("net args: none");
|
System.out.println("net args: none");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package net.berack.upo.valpre;
|
|||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import com.esotericsoftware.kryo.KryoException;
|
import com.esotericsoftware.kryo.KryoException;
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ 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;
|
||||||
import net.berack.upo.valpre.sim.stats.NodeStats;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for running the simulation. It parses the arguments
|
* This class is responsible for running the simulation. It parses the arguments
|
||||||
@@ -21,10 +19,10 @@ public class SimulationBuilder {
|
|||||||
private String csv;
|
private String csv;
|
||||||
private int runs;
|
private int runs;
|
||||||
private long seed;
|
private long seed;
|
||||||
private boolean parallel;
|
|
||||||
private Net net;
|
private Net net;
|
||||||
private EndCriteria[] endCriteria;
|
private EndCriteria[] endCriteria;
|
||||||
private ConfidenceIndices confidences;
|
private ConfidenceIndices confidences;
|
||||||
|
private Type type = Type.Normal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new simulation for the given net.
|
* Create a new simulation for the given net.
|
||||||
@@ -92,7 +90,8 @@ public class SimulationBuilder {
|
|||||||
* @return this simulation
|
* @return this simulation
|
||||||
*/
|
*/
|
||||||
public SimulationBuilder setParallel(boolean parallel) {
|
public SimulationBuilder setParallel(boolean parallel) {
|
||||||
this.parallel = parallel;
|
if (parallel && !this.confidences.isEmpty())
|
||||||
|
this.type = Type.Parallel;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,24 +132,51 @@ public class SimulationBuilder {
|
|||||||
* @param confidence the confidence level expressed as a percentage [0,1]
|
* @param confidence the confidence level expressed as a percentage [0,1]
|
||||||
* @param relError the relative error expressed as a percentage [0,1]
|
* @param relError the relative error expressed as a percentage [0,1]
|
||||||
* @return this simulation
|
* @return this simulation
|
||||||
* @throws IllegalArgumentException if the node is invalid
|
* @throws IllegalArgumentException if any of the input parameters is invalid
|
||||||
* @throws IllegalArgumentException if the stat is invalid
|
|
||||||
* @throws IllegalArgumentException if the confidence is invalid
|
|
||||||
* @throws IllegalArgumentException if the relative error is invalid
|
|
||||||
*/
|
*/
|
||||||
public SimulationBuilder addConfidenceIndex(String node, String stat, double confidence, double relError) {
|
public SimulationBuilder addConfidenceIndex(String node, String stat, double confidence, double relError) {
|
||||||
if (!List.of(NodeStats.getOrderOfApply()).contains(stat))
|
|
||||||
throw new IllegalArgumentException("Invalid statistic: " + stat);
|
|
||||||
if (confidence <= 0 || confidence > 1)
|
|
||||||
throw new IllegalArgumentException("Confidence must be between 0 and 1");
|
|
||||||
if (relError <= 0 || relError > 1)
|
|
||||||
throw new IllegalArgumentException("Relative error must be between 0 and 1");
|
|
||||||
|
|
||||||
var index = this.net.getNodeIndex(node);
|
var index = this.net.getNodeIndex(node);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
throw new IllegalArgumentException("Invalid node: " + node);
|
throw new IllegalArgumentException("Invalid node: " + node);
|
||||||
|
|
||||||
this.confidences.add(index, stat, confidence, relError);
|
this.confidences.add(index, stat, confidence, relError);
|
||||||
|
this.type = Type.Incremental;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the confidence indices from a string and add them to the simulation.
|
||||||
|
* If the string is null then nothing is done and the builder is returned.
|
||||||
|
* The string must be in the following format:
|
||||||
|
* "[node1:stat1=confidence1:relError1],..,[nodeN:statN=confidenceN:relErrorN]".
|
||||||
|
*
|
||||||
|
* @param indices the indices to parse
|
||||||
|
* @return this simulation
|
||||||
|
* @throws IllegalArgumentException if indices are not in the correct format
|
||||||
|
* @throws IllegalArgumentException if the values are invalid
|
||||||
|
*/
|
||||||
|
public SimulationBuilder parseConfidenceIndices(String indices) {
|
||||||
|
if (indices == null)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
for (var index : indices.split(",")) {
|
||||||
|
var parts = index.split("=");
|
||||||
|
if (parts.length != 2)
|
||||||
|
throw new IllegalArgumentException("Invalid confidence index: " + index);
|
||||||
|
var first = parts[0].split(":");
|
||||||
|
if (first.length != 2)
|
||||||
|
throw new IllegalArgumentException("Invalid confidence index: " + index);
|
||||||
|
var second = parts[1].split(":");
|
||||||
|
if (second.length != 2)
|
||||||
|
throw new IllegalArgumentException("Invalid confidence index: " + index);
|
||||||
|
|
||||||
|
var node = first[0].substring(1);
|
||||||
|
var stat = first[1];
|
||||||
|
var confidence = Double.parseDouble(second[0]);
|
||||||
|
var relError = Double.parseDouble(second[1].substring(0, second[1].length() - 1));
|
||||||
|
this.addConfidenceIndex(node, stat, confidence, relError);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +191,11 @@ public class SimulationBuilder {
|
|||||||
public void run() throws InterruptedException, ExecutionException, IOException {
|
public void run() throws InterruptedException, ExecutionException, 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
|
var summary = switch (this.type) {
|
||||||
? sim.runParallel(this.seed, this.runs, this.endCriteria)
|
case Incremental -> sim.runIncremental(this.seed, this.runs, this.confidences, this.endCriteria);
|
||||||
: sim.run(this.seed, this.runs, this.endCriteria);
|
case Parallel -> sim.runParallel(this.seed, this.runs, this.endCriteria);
|
||||||
|
case Normal -> sim.run(this.seed, this.runs, this.endCriteria);
|
||||||
|
};
|
||||||
nano = System.nanoTime() - nano;
|
nano = System.nanoTime() - nano;
|
||||||
|
|
||||||
System.out.print(summary);
|
System.out.print(summary);
|
||||||
@@ -178,4 +206,11 @@ public class SimulationBuilder {
|
|||||||
System.out.println("Data saved to " + this.csv);
|
System.out.println("Data saved to " + this.csv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner class to handle the type of simulation.
|
||||||
|
*/
|
||||||
|
private static enum Type {
|
||||||
|
Incremental, Parallel, Normal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class ConfidenceIndices {
|
|||||||
private final String[] nodes;
|
private final String[] nodes;
|
||||||
private final NodeStats[] confidences;
|
private final NodeStats[] confidences;
|
||||||
private final NodeStats[] relativeErrors;
|
private final NodeStats[] relativeErrors;
|
||||||
|
private boolean isEmpty = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new confidence indices object for the given network.
|
* Create a new confidence indices object for the given network.
|
||||||
@@ -36,6 +37,15 @@ public class ConfidenceIndices {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of confidence indices added to the simulation.
|
||||||
|
*
|
||||||
|
* @return the number of confidence indices
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return this.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a confidence index to the simulation. The simulation will stop when the
|
* Add a confidence index to the simulation. The simulation will stop when the
|
||||||
* relative error of the confidence index is less than the given value.
|
* relative error of the confidence index is less than the given value.
|
||||||
@@ -44,15 +54,24 @@ public class ConfidenceIndices {
|
|||||||
* @param stat The statistic to calculate the confidence index for.
|
* @param stat The statistic to calculate the confidence index for.
|
||||||
* @param confidence The confidence level of the confidence index.
|
* @param confidence The confidence level of the confidence index.
|
||||||
* @param relError The relative error of the confidence index.
|
* @param relError The relative error of the confidence index.
|
||||||
|
* @throws IllegalArgumentException If the node is invalid, the confidence is
|
||||||
|
* not between 0 and 1, or the relative error
|
||||||
|
* is not between 0 and 1.
|
||||||
|
* @throws IllegalArgumentException If the statistic is invalid.
|
||||||
*/
|
*/
|
||||||
public void add(int node, String stat, double confidence, double relError) {
|
public void add(int node, String stat, double confidence, double relError) {
|
||||||
if (node < 0 || node >= this.nodes.length)
|
if (node < 0 || node >= this.nodes.length)
|
||||||
throw new IllegalArgumentException("Invalid node: " + node);
|
throw new IllegalArgumentException("Invalid node: " + node);
|
||||||
|
if (confidence <= 0 || confidence > 1)
|
||||||
|
throw new IllegalArgumentException("Confidence must be between 0 and 1");
|
||||||
|
if (relError <= 0 || relError > 1)
|
||||||
|
throw new IllegalArgumentException("Relative error must be between 0 and 1");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Field field = NodeStats.class.getField(stat);
|
Field field = NodeStats.class.getField(stat);
|
||||||
field.set(this.confidences[node], confidence);
|
field.set(this.confidences[node], confidence);
|
||||||
field.set(this.relativeErrors[node], relError);
|
field.set(this.relativeErrors[node], relError);
|
||||||
|
this.isEmpty = false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalArgumentException("Invalid statistic: " + stat);
|
throw new IllegalArgumentException("Invalid statistic: " + stat);
|
||||||
}
|
}
|
||||||
@@ -94,7 +113,7 @@ public class ConfidenceIndices {
|
|||||||
|
|
||||||
error.merge(relError, (err, rel) -> err - rel);
|
error.merge(relError, (err, rel) -> err - rel);
|
||||||
for (var value : error)
|
for (var value : error)
|
||||||
if (value > 0)
|
if (!value.isInfinite() && !value.isNaN() && value > 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,20 +129,19 @@ public class ConfidenceIndices {
|
|||||||
* @param errors the relative errors of the statistics
|
* @param errors the relative errors of the statistics
|
||||||
* @return the errors of the statistics
|
* @return the errors of the statistics
|
||||||
*/
|
*/
|
||||||
public String[] getErrors(NodeStats[] errors) {
|
public String[] getIndices(NodeStats[] errors) {
|
||||||
var statistics = NodeStats.getOrderOfApply();
|
var statistics = NodeStats.getOrderOfApply();
|
||||||
var retValues = new ArrayList<String>();
|
var retValues = new ArrayList<String>();
|
||||||
|
|
||||||
for (var i = 0; i < this.relativeErrors.length; i++) {
|
for (var i = 0; i < this.relativeErrors.length; i++) {
|
||||||
var error = errors[i].clone();
|
var error = errors[i].clone();
|
||||||
var relError = this.relativeErrors[i];
|
|
||||||
error.merge(relError, (err, rel) -> err - rel);
|
|
||||||
|
|
||||||
var j = 0;
|
for (var stat : statistics) {
|
||||||
for (var value : error) {
|
var err = error.of(stat);
|
||||||
if (value > 0)
|
if (!Double.isFinite(err))
|
||||||
retValues.add("%s:%s=%0.3f".formatted(this.nodes[i], statistics[j], value));
|
continue;
|
||||||
j += 1;
|
|
||||||
|
retValues.add("%s:%s=%.3f".formatted(this.nodes[i], stat, err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,11 +101,11 @@ public class SimulationMultiple {
|
|||||||
* @return The statistics the network.
|
* @return The statistics the network.
|
||||||
* @throws IllegalArgumentException If the confidence is not set.
|
* @throws IllegalArgumentException If the confidence is not set.
|
||||||
*/
|
*/
|
||||||
public void runIncremental(long seed, int runs, ConfidenceIndices confidences, EndCriteria... criterias) {
|
public Result.Summary runIncremental(long seed, int runs, ConfidenceIndices confidences, EndCriteria... criterias) {
|
||||||
if (confidences == null)
|
if (confidences == null)
|
||||||
throw new IllegalArgumentException("Confidence must be not null");
|
throw new IllegalArgumentException("Confidence must be not null");
|
||||||
|
|
||||||
var rng = new Rng(seed);
|
var rng = new Rng(seed); // Only one RNG for all the simulations
|
||||||
var results = new Result.Summary(rng.getSeed());
|
var results = new Result.Summary(rng.getSeed());
|
||||||
var output = new StringBuilder();
|
var output = new StringBuilder();
|
||||||
var stop = false;
|
var stop = false;
|
||||||
@@ -121,7 +121,7 @@ public class SimulationMultiple {
|
|||||||
var errors = confidences.calcRelativeErrors(results);
|
var errors = confidences.calcRelativeErrors(results);
|
||||||
stop = confidences.isOk(errors);
|
stop = confidences.isOk(errors);
|
||||||
|
|
||||||
var errString = confidences.getErrors(errors);
|
var errString = confidences.getIndices(errors);
|
||||||
var oneSting = String.join("], [", errString);
|
var oneSting = String.join("], [", errString);
|
||||||
|
|
||||||
output.append('[').append(oneSting).append("]");
|
output.append('[').append(oneSting).append("]");
|
||||||
@@ -129,8 +129,8 @@ public class SimulationMultiple {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("\nSimulation ended");
|
System.out.println(); // remove last printed line
|
||||||
System.out.println(results);
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user