Net creation #2

Merged
Berack96 merged 21 commits from net-creation into main 2025-03-16 18:02:38 +01:00
26 changed files with 788 additions and 3409 deletions

23
.vscode/launch.json vendored
View File

@@ -9,56 +9,49 @@
"name": "Run1k Simple",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "simulation -net example1.net -runs 1000 -p"
"args": "simulation -net src/test/resources/example1.net -runs 1000 -p"
},
{
"type": "java",
"name": "Run1k Complex",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "simulation -net example2.net -runs 1000 -p"
},
{
"type": "java",
"name": "Run1k Complex EXP",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "simulation -net example3.net -runs 1000 -p"
"args": "simulation -net src/test/resources/example2.net -runs 1000 -p"
},
{
"type": "java",
"name": "Run Incremental",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "simulation -net example3.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 -i \"[Service1:throughput=0.98:0.01],[Service2:utilization=0.98:0.01],[Service2:unavailable=0.98:0.01]\""
},
{
"type": "java",
"name": "Run10",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "simulation -net example1.net -runs 10 -seed 2007539552"
"args": "simulation -net src/test/resources/example1.net -runs 10 -seed 2007539552"
},
{
"type": "java",
"name": "Plot Simple",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "plot -csv example1.csv"
"args": "plot -csv src/test/resources/example1.csv"
},
{
"type": "java",
"name": "Plot Complex",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "plot -csv example2.csv"
"args": "plot -csv src/test/resources/example2.csv"
},
{
"type": "java",
"name": "Build Net",
"name": "Interactive Net Builder",
"request": "launch",
"mainClass": "net.berack.upo.valpre.Main",
"args": "net"
"args": "interactive"
},
]
}

View File

@@ -16,7 +16,7 @@ Questa libreria è stata confrontata con il tool [JMT](https://jmt.sourceforge.n
Il JAR viene invocato tramite il classico comando java: `java -jar upo-valpre.jar` al quale si aggiungono vari argomenti successivi in base a cosa si vuole fare:
* `java -jar upo-valpre.jar net`\
* `java -jar upo-valpre.jar interactive`\
Usato per avviare una sessione interattiva per la creazione di una rete. Da usare se la rete è relativamente breve da descrivere, altrimenti è più comodo usare il codice della libreria per la generazione della rete.\
Una volta scelta la rete è necessario salvarla in un file per la successiva simulazione e analisi.
* `java -jar upo-valpre.jar simulation -net <file> [other]`\
@@ -34,10 +34,6 @@ Esistono vari tipi di argomenti per scegliere come fare la simulazione:
Mostra (con un ambiente grafico) una finestra nella quale si può scegliere quale nodo vedere e ogni statistica associata ad esso. Di seguito un'immagine di esempio:\
![1738603552417](image/README/1738603552417.png)
Esistono dei file prefatti per vedere eventuali simulazioni che, nel caso vengano passati come parametri, automaticamente vengono usati:
* `example1.net`, `example2.net` e `example3.net` per `simulation -net`
* `example1.csv`, `example2.csv` e `example3.csv` per `plot -csv`
---
### Classi Interne
@@ -61,14 +57,13 @@ I percorsi che invece sono direttamente responsabili per la simulazione sono:
---
### Esempi
Nel jar sono presenti già 3 reti per fare degli esperimenti e/o testare se il tool funziona correttamente. Per tutti e tre gli esempi i comandi usati sono i seguenti, dove viene sostituito un numero al posto dell'asterisco:
- `java -jar .\upo-valpre.jar simulation -net example*.net -runs 100` per fare una simulazione di 100 run e vedere i risultati aggregati.
- `java -jar .\upo-valpre.jar plot -csv example*.csv` per mostrare un'aggregazione con più dettagli di una simulazione di 1000 run.
Nel jar sono presenti già 2 reti per fare degli esperimenti e/o testare se il tool funziona correttamente. Per poter vedere una run usando questi esempi basta far partire il tool in modalità interattiva e scegliere di caricare gli esempi.\
`java -jar upo-valpre.jar interactive`
##### Primo esempio
![1741862746304](image/README/1741862746304.png)\
Il primo è `example1`; è una rete composta da una fonte di clienti (Source) che arrivano con tasso esponenziale (λ=0.222 e quindi media 4.5) e un centro di servizio (Queue) con tasso di servizio distribuito come una normale (μ=3.2, σ=0.6).\
Se si effettua una simulazione con il comando precedente si vedranno i risultati sulla console in questo modo:
Se si effettua una simulazione si vedranno i risultati sulla console in questo modo:
![1741860064265](image/README/1741860064265.png)
Il tool JMT con la stessa rete produce i seguenti risultati che sono molto simili a quelli prodotti dalla libreria:\
@@ -78,15 +73,10 @@ Queue Utilization = 0.7111 con un range [0.6959, 0.7262]
##### Secondo esempio
![1741863043733](image/README/1741863043733.png)\
Il secondo è `example2`; è una rete composta da una fonte di clienti (Source) che arrivano con tasso esponenziale (λ=0.222 e quindi media 4.5), un centro di servizio (Queue) con tasso di servizio distribuito come una normale (μ=3.2, σ=0.6) e un altro centro di servizio (Queue Wait) con tasso di servizio distribuito come una normale (μ=3.2, σ=0.6) e con un tempo di indisponibilità che viene attivato con probabilità 20% e distribuito con una normale (μ=4.2, σ=0.6)\
Se si effettua una simulazione con il comando precedente si vedranno i risultati sulla console in questo modo:
![1741862185715](image/README/1741862185715.png)
##### Terzo esempio
![1741863043733](image/README/1741863043733.png)\
Il terzo è `example3`; è uguale al secondo esempio ma nel quale cambiano i nomi dei nodi e le loro distribuzioni: è una rete composta da una fonte di clienti (Source) che arrivano con tasso esponenziale (λ=1.5 e quindi media 0.666), un centro di servizio (Service1) con tasso di servizio distribuito come una esponenziale (λ=2.0 e quindi media 0.5) e un altro centro di servizio (Service2) con tasso di servizio distribuito come una esponenziale (λ=3.5 e quindi media 0.2857) e con un tempo di indisponibilità che viene attivato con probabilità 10% e distribuito con una eseponenziale (λ=10.0 e quindi media 0.1)\
Se si effettua una simulazione con il comando precedente si vedranno i risultati sulla console in questo modo:
Il secondo esempio è `example2`; è una rete composta da una fonte di clienti (Source) che arrivano con tasso esponenziale (λ=1.5 e quindi media 0.666), un centro di servizio (Service1) con tasso di servizio distribuito come una esponenziale (λ=2.0 e quindi media 0.5) e un altro centro di servizio (Service2) con tasso di servizio distribuito come una esponenziale (λ=3.5 e quindi media 0.2857) e con un tempo di indisponibilità che viene attivato con probabilità 10% e distribuito con una eseponenziale (λ=10.0 e quindi media 0.1)\
Se si effettua una simulazione si vedranno i risultati sulla console in questo modo:
![1741862486547](image/README/1741862486547.png)
Il tool JMT con la stessa rete produce i seguenti risultati che sono molto simili a quelli prodotti dalla libreria:\
Service1 Response Time ~ 1.9866\
Busy2 Response Time ~ 0.2825\
@@ -95,4 +85,3 @@ Service1 Utilization ~ 0.7488\
Calibration Number of Customers ~ 0.0150\
Busy2 Number of Customers ~ 0.4279\
Throughput ~ 1.5000

24
pom.xml
View File

@@ -13,30 +13,6 @@
<maven.compiler.target>23</maven.compiler.target>
</properties>
<build>
<plugins>
<!-- Compilazione Java con Maven -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>23</source>
<target>23</target>
</configuration>
</plugin>
<!-- Maven plugin per eseguire l'applicazione JavaFX -->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>net.berack.upo.valpre.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>

View File

@@ -0,0 +1,267 @@
package net.berack.upo.valpre;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import com.esotericsoftware.kryo.KryoException;
import net.berack.upo.valpre.rand.Distribution;
import net.berack.upo.valpre.sim.Net;
import net.berack.upo.valpre.sim.ServerNode;
/**
* Interactive net builder. This class allows the user to build a net by adding
* nodes and connections. The user can also save the net to a file.
*/
public class InteractiveConsole {
private Net net = new Net();
private final PrintStream out;
private final Scanner scanner;
/**
* Create a new interactive net builder. Uses System.in and System.out.
*/
public InteractiveConsole() {
this(System.out, System.in);
}
/**
* Create a new interactive net builder.
*
* @param out the output stream
* @param in the input stream
*/
public InteractiveConsole(PrintStream out, InputStream in) {
this.out = out;
this.scanner = new Scanner(in);
}
/**
* Run the interactive net builder.
*/
public Net run() {
while (true) {
try {
var choice = choose(this.net + "\nChoose the next step to do:",
"Add a node", "Add a connection", "Save the net", "Load net", "Clear", "Run", "Exit");
switch (choice) {
case 1 -> this.buildNode();
case 2 -> this.buildConnection();
case 3 -> this.net.save(ask("Enter the filename: "));
case 4 -> this.loadNet();
case 5 -> this.net = new Net();
case 6 -> this.simpleRuns();
default -> {
this.scanner.close();
return this.net;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Build a node as a source, terminal, queue, or queue with unavailable time.
*/
private void buildNode() {
var choice = choose("Choose the type of node to create:", "Source", "Terminal", "Queue",
"Queue with unavailable time");
var name = ask("Node name: ");
var distribution = askDistribution("Service distribution");
var node = switch (choice) {
case 1 -> ServerNode.Builder.source(name, distribution);
case 2 -> {
var limit = ask("Arrivals limit (0 for Int.Max): ", Integer::parseInt);
if (limit <= 0)
limit = Integer.MAX_VALUE;
yield ServerNode.Builder.terminal(name, limit, distribution);
}
case 3 -> {
var servers = ask("Number of servers: ", Integer::parseInt);
yield ServerNode.Builder.queue(name, servers, distribution, null);
}
case 4 -> {
var servers = ask("Number of servers: ", Integer::parseInt);
var unavailable = askDistribution("Unavailable distribution");
yield ServerNode.Builder.queue(name, servers, distribution, unavailable);
}
default -> null;
};
if (node != null)
this.net.addNode(node);
}
/**
* Build a connection.
*/
private void buildConnection() {
var source = ask("Enter the source node: ");
var target = ask("Enter the target node: ");
var weight = ask("Enter the weight: ", Double::parseDouble);
var sourceNode = this.net.getNode(source);
var targetNode = this.net.getNode(target);
this.net.addConnection(sourceNode, targetNode, weight);
}
/**
* Load a net from a file or from examples.
*/
private void loadNet() throws KryoException, IOException {
var choice = choose("Choose the type of net to load:", "From file", "From examples");
this.net = switch (choice) {
case 1 -> Net.load(ask("Enter the filename: "));
case 2 -> {
var choice2 = choose("Choose the example to load:",
"Example 1: Source -> Queue",
"Example 2: Source -> Queue -> Queue");
yield switch (choice2) {
case 1 -> NetExamples.getNet1();
case 2 -> NetExamples.getNet2();
default -> null;
};
}
default -> null;
};
}
/**
* Run the simulation with the net.
*/
private void simpleRuns() throws InterruptedException, ExecutionException, IOException {
var choice = choose("Choose what to do:", "100 Run", "1K Runs", "1K Runs + Plot");
switch (choice) {
case 1 -> new SimulationBuilder(net).setMaxRuns(100).setParallel(true).run();
case 2 -> new SimulationBuilder(net).setMaxRuns(1000).setParallel(true).run();
case 3 -> {
var randName = "rand" + System.currentTimeMillis() + ".csv";
new SimulationBuilder(net).setMaxRuns(1000).setParallel(true).setCsv(randName).run();
new Plot(randName).show();
new File(randName).delete();
}
default -> {
}
}
}
/**
* Ask the user for a distribution.
*
* @return the distribution
*/
private 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);
yield new Distribution.Exponential(lambda);
}
case 2 -> {
var min = ask("Min: ", Double::parseDouble);
var max = ask("Max: ", Double::parseDouble);
yield new Distribution.Uniform(min, max);
}
case 3 -> {
var k = ask("K: ", Integer::parseInt);
var lambda = ask("Lambda: ", Double::parseDouble);
yield new Distribution.Erlang(k, lambda);
}
case 4 -> {
var probability = ask("Probability: ", Double::parseDouble);
var unavailable = askDistribution("Unavailable distribution");
yield new Distribution.UnavailableTime(probability, unavailable);
}
case 5 -> {
var mean = ask("Mean: ", Double::parseDouble);
var stdDev = ask("Standard deviation: ", Double::parseDouble);
yield new Distribution.Normal(mean, stdDev);
}
case 6 -> {
var mean = ask("Mean: ", Double::parseDouble);
var stdDev = ask("Standard deviation: ", Double::parseDouble);
yield new Distribution.NormalBoxMuller(mean, stdDev);
}
default -> null;
};
}
/**
* Ask the user a question.
*
* @param ask the question to ask
* @return the answer
*/
private 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 <T> T ask(String ask, Function<String, T> parser) {
var totalRows = ask.chars().filter(ch -> ch == '\n').count();
var ask2 = "\033[" + totalRows + "A" + ask;
var first = true;
try {
while (true) {
this.out.print(first ? ask : ask2);
var line = this.scanner.nextLine();
first = false;
try {
var value = parser.apply(line);
return value;
} catch (Exception e) {
this.out.print("\033[A\033[K"); // clear the line
}
}
} catch (Exception e) {
return null; // normally when the scanner is closed
}
}
/**
* Ask the user to choose an option.
*
* @param ask the question to ask
* @param options the options to choose from
* @return the choice
*/
private 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;
choice = ask(string, val -> {
var x = Integer.parseInt(val);
if (x < 1 || x > options.length)
throw new NumberFormatException(); // retry the question
return x;
});
return choice;
}
}

View File

@@ -31,10 +31,7 @@ public class Main {
var plot = new Plot(csv);
plot.show();
}
case "net" -> {
var net = new NetBuilderInteractive();
net.run();
}
case "interactive" -> new InteractiveConsole().run();
default -> exit("Invalid program!");
}
} catch (Exception e) {
@@ -86,11 +83,11 @@ public class Main {
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|net] [args]");
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("net args: none");
System.out.println("interactive: no args needed");
System.exit(1);
} catch (URISyntaxException e) {
e.printStackTrace();

View File

@@ -1,186 +0,0 @@
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)) {
var child = this.net.getNode(connection.index);
builder.append(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.Builder.sourceLimited(name, limit, distribution);
}
case 2 -> {
var servers = ask("Number of servers: ", Integer::parseInt, 1);
var unavailable = askDistribution("Unavailable distribution");
yield ServerNode.Builder.queue(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;
}
}

View File

@@ -0,0 +1,94 @@
package net.berack.upo.valpre;
import net.berack.upo.valpre.rand.Distribution;
import net.berack.upo.valpre.sim.Net;
import net.berack.upo.valpre.sim.ServerNode;
/**
* This class provides two example networks.
* The first network is composed of a terminal node and a queue node.
* The second network is composed of a terminal node and two queue nodes.
*/
public final class NetExamples {
/**
* Return the first example network.
* The net is composed of a terminal node and a queue node.
* The terminal node generates 10000 jobs with an exponential distribution 4.5.
* The queue node has a capacity of 1 and a service time of 3.2 with a standard
* deviation of 0.6.
* The terminal node is connected to the queue node with a probability of 1.0.
*
* @return the first example network
*/
public static Net getNet1() {
var exp0_22 = new Distribution.Exponential(1.0 / 4.5);
var norm3_2 = new Distribution.NormalBoxMuller(3.2, 0.6);
var spawn = 10000;
return getNet1(spawn, exp0_22, norm3_2);
}
/**
* Return the first example network.
* The net is composed of a terminal node and a queue node.
* The terminal node is connected to the queue node.
*
* @param spawn the number of jobs to generate
* @param source the distribution of the source node
* @param queue the distribution of the queue node
* @return the first example network
*/
public static Net getNet1(int spawn, Distribution source, Distribution queue) {
var net1 = new Net();
net1.addNode(ServerNode.Builder.terminal("Source", spawn, source));
net1.addNode(ServerNode.Builder.queue("Queue", 1, queue));
net1.addConnection(0, 1, 1.0);
return net1;
}
/**
* Return the second example network.
* The net is composed of a terminal node and two queue nodes.
* The terminal node generates 10000 jobs with an exponential distribution 1.5.
* The first queue node has a capacity of 1 and a service time of 2.0.
* The second queue node has a capacity of 1 and a service time of 3.5.
* The second queue node has an unavailable time of 0.1 with an exponential
* distribution of 10.0.
* The terminal node is connected to the first queue node.
* The first queue node is connected to the second queue node.
*
* @return the second example network
*/
public static Net getNet2() {
var exp1_5 = new Distribution.Exponential(1.5);
var exp2 = new Distribution.Exponential(2.0);
var exp3_5 = new Distribution.Exponential(3.5);
var exp10 = new Distribution.Exponential(10.0);
var unExp = new Distribution.UnavailableTime(0.1, exp10);
var spawn = 10000;
return getNet2(spawn, exp1_5, exp2, exp3_5, unExp);
}
/**
* Return the second example network.
* The net is composed of a terminal node and two queue nodes.
* The terminal node is connected to the first queue node.
* The first queue node is connected to the second queue node.
*
* @param spawn the number of jobs to generate
* @param source the distribution of the source node
* @param service1 the distribution of the first queue node
* @param service2 the distribution of the second queue node
* @param unExp the distribution of the unavailable time
* @return the second example network
*/
public static Net getNet2(int spawn, Distribution source, Distribution service1, Distribution service2,
Distribution unExp) {
var net3 = new Net();
net3.addNode(ServerNode.Builder.terminal("Source", spawn, source));
net3.addNode(ServerNode.Builder.queue("Service1", 1, service1));
net3.addNode(ServerNode.Builder.queue("Service2", 1, service2, unExp));
net3.addConnection(0, 1, 1.0);
net3.addConnection(1, 2, 1.0);
return net3;
}
}

View File

@@ -1,8 +1,5 @@
package net.berack.upo.valpre;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@@ -194,23 +191,4 @@ public class Parameters {
throw new IllegalArgumentException("Invalid arguments");
}
}
/**
* Get the file or the example file if it is present.
*
* @param file the file to get
* @return the file or the example file
* @throws FileNotFoundException if the file is not found
*/
public static InputStream getFileOrExample(String file) throws FileNotFoundException {
if (file == null)
return null;
if (file.startsWith("example")) {
var resource = Parameters.class.getClassLoader().getResourceAsStream(file);
if (resource != null)
return resource;
}
return new FileInputStream(file);
}
}

View File

@@ -41,12 +41,7 @@ public class Plot {
* @throws IOException if anything happens while reading the file
*/
public Plot(String csv) throws IOException {
var stream = Parameters.getFileOrExample(csv);
if (stream == null)
throw new IllegalArgumentException("CSV file needed!");
var results = CsvResult.loadResults(stream);
stream.close();
var results = new CsvResult(csv).loadResults();
this.summary = new Result.Summary(results);
var nodes = this.summary.getNodes().toArray(new String[0]);

View File

@@ -2,6 +2,7 @@ package net.berack.upo.valpre;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.ExecutionException;
import com.esotericsoftware.kryo.KryoException;
@@ -13,6 +14,7 @@ import net.berack.upo.valpre.sim.EndCriteria.MaxTime;
import net.berack.upo.valpre.sim.Net;
import net.berack.upo.valpre.sim.SimulationMultiple;
import net.berack.upo.valpre.sim.stats.CsvResult;
import net.berack.upo.valpre.sim.stats.Result;
/**
* This class is responsible for running the simulation. It parses the arguments
@@ -35,10 +37,8 @@ public class SimulationBuilder {
*/
public SimulationBuilder(String netFile) throws IOException {
try {
var file = Parameters.getFileOrExample(netFile);
this.net = Net.load(file);
this.net = Net.load(netFile);
this.confidences = new ConfidenceIndices(this.net);
file.close();
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("Net file needed!");
} catch (KryoException e) {
@@ -230,23 +230,38 @@ public class SimulationBuilder {
* @throws ExecutionException If the simulation has an error.
* @throws IOException If the CSV file has a problem.
*/
public void run() throws InterruptedException, ExecutionException, IOException {
public Result.Summary run() throws InterruptedException, ExecutionException, IOException {
return this.run(System.out);
}
/**
* Run the simulation with the given parameters.
* At the end it prints the results and saves them to a CSV file if requested.
*
* @param out the output stream to print the results
* @throws InterruptedException If the simulation is interrupted.
* @throws ExecutionException If the simulation has an error.
* @throws IOException If the CSV file has a problem.
*/
public Result.Summary run(PrintStream out) throws InterruptedException, ExecutionException, IOException {
var nano = System.nanoTime();
var sim = new SimulationMultiple(this.net);
var summary = switch (this.type) {
case Incremental -> sim.runIncremental(this.seed, this.runs, this.confidences, this.endCriteria);
case Incremental -> sim.runIncremental(this.seed, this.runs, out, this.confidences, 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;
System.out.print(summary);
System.out.println("Final time " + nano / 1e6 + "ms");
out.print(summary);
out.println("Final time " + nano / 1e6 + "ms");
if (csv != null) {
new CsvResult(this.csv).saveResults(summary.getRuns());
System.out.println("Data saved to " + this.csv);
out.println("Data saved to " + this.csv);
}
return summary;
}
/**

View File

@@ -32,6 +32,36 @@ public interface Distribution {
return sample;
}
/**
* Returns a string representation of the distribution.
* In case the distribution is null, an empty string is returned.
*
* @param distribution The distribution to represent.
* @return A string representation of the distribution.
* @throws IllegalArgumentException if the field cannot be accessed
* @throws IllegalAccessException if the field cannot be accessed
*/
public static String toString(Distribution distribution) throws IllegalArgumentException, IllegalAccessException {
if (distribution == null)
return "";
var builder = new StringBuilder();
var dist = distribution.getClass();
builder.append(dist.getSimpleName()).append('(');
for (var param : dist.getFields()) {
var paramValue = param.get(distribution);
var str = paramValue instanceof Distribution
? toString((Distribution) paramValue)
: paramValue;
builder.append(str).append(", ");
}
builder.delete(builder.length() - 2, builder.length()).append(')');
return builder.toString();
}
/**
* Represents an exponential distribution.
*/

View File

@@ -23,11 +23,7 @@ public class Event implements Comparable<Event> {
@Override
public int compareTo(Event other) {
if (this.time < other.time)
return -1;
if (this.time == other.time)
return 0;
return 1;
return Double.compare(this.time, other.time);
}
/**

View File

@@ -75,7 +75,6 @@ public final class Net implements Iterable<ServerNode> {
* @param weight The probability of the child node.
* @throws IndexOutOfBoundsException if one of the two nodes are not in the net
* @throws IllegalArgumentException if the weight is negative or zero
* @throws IllegalArgumentException if the child is a source node
*/
public void addConnection(int parent, int child, double weight) {
if (weight <= 0)
@@ -85,9 +84,6 @@ public final class Net implements Iterable<ServerNode> {
if (parent < 0 || child < 0 || parent > max || child > max)
throw new IndexOutOfBoundsException("One of the nodes does not exist");
if (this.servers.get(child).spawnArrivals > 0)
throw new IllegalArgumentException("Can't connect to a source node");
var list = this.connections.get(parent);
list.removeIf(conn -> conn.index == child);
list.add(new Connection(child, weight));
@@ -170,14 +166,13 @@ public final class Net implements Iterable<ServerNode> {
for (var conn : list)
sum += conn.weight;
var newOne = new Connection[list.size()];
for (var i = 0; i < list.size(); i++) {
var conn = list.get(i);
var newOne = new ArrayList<Connection>();
for (var conn : list) {
var newWeight = conn.weight / sum;
newOne[i] = new Connection(conn.index, newWeight);
newOne.add(new Connection(conn.index, newWeight));
}
this.connections.set(node, List.of(newOne));
this.connections.set(node, newOne);
}
}
@@ -249,6 +244,56 @@ public final class Net implements Iterable<ServerNode> {
}
}
/**
* Create a copy of the net passed as input.
* The new net will have the same nodes and connections.
*
* @param net the net to copy
* @return a new Net object
*/
public static Net copyOf(Net net) {
var newNet = new Net();
for (var index = 0; index < net.size(); index++) {
var node = net.servers.get(index);
var conn = net.connections.get(index);
conn = new ArrayList<>(conn);
newNet.indices.put(node, index);
newNet.servers.add(node);
newNet.connections.add(conn);
}
return newNet;
}
@Override
public String toString() {
var builder = new StringBuilder();
try {
for (var node : this.servers) {
builder.append(node)
.append(" -> ");
for (var child : this.getChildren(this.indices.get(node))) {
var childNode = this.servers.get(child.index);
builder.append(childNode.name)
.append("(")
.append(child.weight)
.append("), ");
}
builder.delete(builder.length() - 2, builder.length())
.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return builder.toString();
}
/**
* A Static inner class used to represent the connection of a node
*/

View File

@@ -18,7 +18,7 @@ public class ServerNode {
/**
* Creates a generic node with the given name and distribution.
* The servers number must be 1 or higher; if lower will be put to 1.
* The spawn number must be 0 or higher; if lower will be put to 0.
* The spawn number must be 0 or higher; if lower will be put to -1 (infinite).
* The queue number must be equal or higher than the servers number; if lower
* will be put to the servers number.
* The service distribution can't be null, otherwise an exception is thrown.
@@ -37,7 +37,7 @@ public class ServerNode {
if (servers <= 0)
servers = 1;
if (spawn < 0)
spawn = 0;
spawn = -1;
if (queue < servers)
queue = servers;
@@ -71,6 +71,28 @@ public class ServerNode {
return Distribution.getPositiveSample(this.unavailable, rng);
}
@Override
public String toString() {
try {
var build = new StringBuilder()
.append(this.name)
.append("[servers:")
.append(this.maxServers)
.append(", queue:")
.append(this.maxQueue)
.append(", spawn:")
.append(this.spawnArrivals)
.append(", ")
.append(Distribution.toString(this.service));
if (this.unavailable != null)
build.append(", u:").append(Distribution.toString(this.unavailable));
return build.append(']').toString();
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ServerNode))
@@ -183,26 +205,27 @@ public class ServerNode {
/**
* Creates a source node with the given name and distribution.
* It swpawns infinite arrivals (Integer.MAX_VALUE).
* It swpawns infinite arrivals (-1).
*
* @param name The name of the node.
* @param distribution The distribution of the inter-arrival times.
* @return The created source node.
*/
public static ServerNode source(String name, Distribution distribution) {
return new Builder(name, distribution).spawn(Integer.MAX_VALUE).build();
return new Builder(name, distribution).spawn(-1).build();
}
/**
* Creates a source node with the given name, distribution, and number of
* Creates a terminal node with the given name, distribution, and number of
* arrivals to spawn.
* Once it has finished spawning the arrivals, it will not spawn anymore.
*
* @param name The name of the node.
* @param service The distribution of the inter-arrival times.
* @param spawnArrivals The number of arrivals to spawn.
* @return The created source node.
*/
public static ServerNode sourceLimited(String name, int spawnArrivals, Distribution service) {
public static ServerNode terminal(String name, int spawnArrivals, Distribution service) {
return new Builder(name, service).spawn(spawnArrivals).build();
}

View File

@@ -69,7 +69,7 @@ public class ServerNodeState {
* @return True if the node should spawn an arrival, false otherwise.
*/
public boolean shouldSpawnArrival() {
return this.node.spawnArrivals > this.stats.numArrivals;
return this.node.spawnArrivals < 0 || this.node.spawnArrivals > this.stats.numArrivals;
}
/**
@@ -158,6 +158,23 @@ public class ServerNodeState {
return null;
}
/**
* Get a random child based on the weights of the children and the random number
* generator passed as input
*
* @param rng the random number generator
* @return the index of the child or -1 if no child is selected
*/
public int getRandomChild(Rng rng) {
var random = rng.random();
for (var child : this.children) {
random -= child.weight;
if (random <= 0)
return child.index;
}
return -1;
}
/**
* Create an arrival event to a child node based on the node and the time passed
* as input
@@ -168,12 +185,7 @@ public class ServerNodeState {
* otherwise
*/
public Event spawnArrivalToChild(double time, Rng rng) {
var random = rng.random();
for (var child : this.children) {
random -= child.weight;
if (random <= 0)
return Event.newArrival(child.index, time);
}
return null;
var child = this.getRandomChild(rng);
return child > -1 ? Event.newArrival(child, time) : null;
}
}

View File

@@ -1,6 +1,5 @@
package net.berack.upo.valpre.sim;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
@@ -98,8 +97,13 @@ public final class Simulation {
case DEPARTURE -> {
state.updateDeparture(time);
// Spawn unavailability if has unavailable time
this.addToFel(state.spawnUnavailableIfPossible(time, this.rng));
// Spawn departure if has requests and server is available
this.addToFel(state.spawnDepartureIfPossible(time, this.rng));
// Spawn arrival to self if is source node
this.addToFel(state.spawnArrivalIfPossilbe(time));
// Spawn arrival to child node if queue is not full otherwise drop
@@ -151,7 +155,7 @@ public final class Simulation {
* @return a list of future events.
*/
public List<Event> getFutureEventList() {
return new ArrayList<>(this.fel);
return List.copyOf(this.fel);
}
/**

View File

@@ -1,5 +1,6 @@
package net.berack.upo.valpre.sim;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -99,16 +100,21 @@ public class SimulationMultiple {
* Run the simulation multiple times with the given seed and end criteria. The
* simulation runs will stop when the relative error of the confidence index is
* less than the given value.
* The results are printed on the console.
* The results are printed on the PrintStream.
*
* @param seed The seed to use for the random number generator.
* @param criterias The criteria to determine when to end the simulation. If
* null then the simulation will run until there are no more
* events.
* @param seed The seed to use for the random number generator.
* @param runs The maximum number of runs to perform.
* @param stream The PrintStream to print the results.
* @param confidences The confidence indices to use to determine when to stop
* the simulation.
* @param criterias The criteria to determine when to end the simulation. If
* null then the simulation will run until there are no more
* events.
* @return The statistics the network.
* @throws IllegalArgumentException If the confidence is not set.
*/
public Result.Summary runIncremental(long seed, int runs, ConfidenceIndices confidences, EndCriteria... criterias) {
public Result.Summary runIncremental(long seed, int runs, PrintStream stream, ConfidenceIndices confidences,
EndCriteria... criterias) {
if (confidences == null)
throw new IllegalArgumentException("Confidence must be not null");
@@ -133,11 +139,11 @@ public class SimulationMultiple {
var oneSting = String.join("], [", errString);
output.append('[').append(oneSting).append("]");
System.out.print(output);
stream.print(output);
}
}
System.out.println(); // remove last printed line
stream.println(); // remove last printed line
return results;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,187 @@
package net.berack.upo.valpre.sim;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import org.junit.Test;
import net.berack.upo.valpre.InteractiveConsole;
import net.berack.upo.valpre.rand.Distribution;
public class TestInteractions {
@Test
public void distributionToString() throws Exception {
var exp = new Distribution.Exponential(1.0);
assertEquals("Exponential(1.0)", Distribution.toString(exp));
var uniform = new Distribution.Uniform(0.0, 1.0);
assertEquals("Uniform(0.0, 1.0)", Distribution.toString(uniform));
var erlang = new Distribution.Erlang(2, 1.0);
assertEquals("Erlang(2, 1.0)", Distribution.toString(erlang));
var normal = new Distribution.Normal(3.2, 0.6);
assertEquals("Normal(3.2, 0.6)", Distribution.toString(normal));
var normalBoxMuller = new Distribution.NormalBoxMuller(3.2, 0.6);
assertEquals("NormalBoxMuller(3.2, 0.6)", Distribution.toString(normalBoxMuller));
var unavailable = new Distribution.UnavailableTime(0.1, exp);
assertEquals("UnavailableTime(0.1, Exponential(1.0))", Distribution.toString(unavailable));
}
@Test
public void nodeToString() {
var exp = new Distribution.Exponential(1.0);
var normal = new Distribution.Normal(3.2, 0.6);
var unavailable = new Distribution.UnavailableTime(0.1, exp);
var node = new ServerNode.Builder("Source", exp).build();
assertEquals("Source[servers:1, queue:100, spawn:0, Exponential(1.0)]", node.toString());
node = new ServerNode.Builder("Queue", normal).build();
assertEquals("Queue[servers:1, queue:100, spawn:0, Normal(3.2, 0.6)]", node.toString());
node = new ServerNode.Builder("Queue", normal).queue(10).servers(5).spawn(100).build();
assertEquals("Queue[servers:5, queue:10, spawn:100, Normal(3.2, 0.6)]", node.toString());
node = new ServerNode.Builder("Queue", normal).queue(10).servers(5).spawn(100).unavailable(unavailable).build();
assertEquals(
"Queue[servers:5, queue:10, spawn:100, Normal(3.2, 0.6), u:UnavailableTime(0.1, Exponential(1.0))]",
node.toString());
}
@Test
public void netToString() {
var net = new Net();
assertEquals("", net.toString());
var node1 = new ServerNode.Builder("Source", new Distribution.Exponential(1)).build();
net.addNode(node1);
assertEquals(node1 + " -\n", net.toString());
var node2 = new ServerNode.Builder("Server", new Distribution.Normal(3.2, 0.6)).build();
net.addNode(node2);
assertEquals(node1 + " -\n" + node2 + " -\n", net.toString());
net.addConnection(0, 1, 1.0);
assertEquals(node1 + " -> Server(1.0)\n" + node2 + " -\n", net.toString());
var node3 = new ServerNode.Builder("Server2", new Distribution.Normal(4.1, 0.1)).build();
net.addNode(node3);
assertEquals(node1 + " -> Server(1.0)\n" + node2 + " -\n" + node3 + " -\n", net.toString());
net.addConnection(0, 2, 1.0);
net.normalizeWeights();
assertEquals(node1 + " -> Server(0.5), Server2(0.5)\n" + node2 + " -\n" + node3 + " -\n", net.toString());
net.addConnection(1, 2, 1.0);
assertEquals(node1 + " -> Server(0.5), Server2(0.5)\n"
+ node2 + " -> Server2(1.0)\n"
+ node3 + " -\n",
net.toString());
var const0 = new Distribution.Uniform(0, 0);
var unavailable = new Distribution.UnavailableTime(0.1, new Distribution.Exponential(1));
var other = ServerNode.Builder.queue("Other", 1, const0, unavailable);
net.addNode(other);
assertEquals(node1 + " -> Server(0.5), Server2(0.5)\n"
+ node2 + " -> Server2(1.0)\n"
+ node3 + " -\n"
+ other + " -\n",
net.toString());
}
@Test(timeout = 1000)
public void netBuilderInteractive() {
// Test the interactive console EXIT
var net = runInteraction("7");
assertEquals("", net.toString());
// Test the interactive console ADD NODE
net = runInteraction("1", "1", "Source", "1", "1.0", "7");
assertEquals("Source[servers:1, queue:100, spawn:-1, Exponential(1.0)] -\n", net.toString());
// Test the interactive console ADD SECOND NODE
net = runInteraction("1", "2", "Terminal", "1", "2.0", "500",
"1", "3", "Queue", "5", "3.2", "0.6", "1",
"7");
assertEquals("Terminal[servers:1, queue:100, spawn:500, Exponential(2.0)] -\n"
+ "Queue[servers:1, queue:100, spawn:0, Normal(3.2, 0.6)] -\n", net.toString());
// Test the interactive console ADD CONNECTION
net = runInteraction("1", "1", "Source", "1", "2.0",
"1", "3", "Queue", "5", "3.2", "0.6", "1",
"2", "Source", "Queue", "1.0",
"7");
assertEquals("Source[servers:1, queue:100, spawn:-1, Exponential(2.0)] -> Queue(1.0)\n"
+ "Queue[servers:1, queue:100, spawn:0, Normal(3.2, 0.6)] -\n", net.toString());
// Test the interactive console CLEAR
net = runInteraction("1", "1", "Source", "1", "2.0",
"1", "3", "Queue", "5", "3.2", "0.6", "1",
"2", "Source", "Queue", "1.0",
"2", "Queue", "Queue", "1.0",
"5", "7");
assertEquals("", net.toString());
// Test the interactive console LOAD
net = runInteraction("4", "1", "src/test/resources/example1.net", "7");
assertEquals("Source[servers:1, queue:100, spawn:10000, Exponential(0.2222222222222222)] -> Queue(1.0)\n"
+ "Queue[servers:1, queue:100, spawn:0, NormalBoxMuller(3.2, 0.6)] -\n",
net.toString());
// Test the interactive console LOAD EXAMPLE 1
net = runInteraction("4", "2", "1", "7");
assertEquals("Source[servers:1, queue:100, spawn:10000, Exponential(0.2222222222222222)] -> Queue(1.0)\n"
+ "Queue[servers:1, queue:100, spawn:0, NormalBoxMuller(3.2, 0.6)] -\n",
net.toString());
// Test the interactive console LOAD EXAMPLE 2
net = runInteraction("4", "2", "2", "7");
assertEquals("Source[servers:1, queue:100, spawn:10000, Exponential(1.5)] -> Service1(1.0)\n"
+ "Service1[servers:1, queue:100, spawn:0, Exponential(2.0)] -> Service2(1.0)\n"
+ "Service2[servers:1, queue:100, spawn:0, Exponential(3.5), u:UnavailableTime(0.1, Exponential(10.0))] -\n",
net.toString());
}
private static Net runInteraction(String... commands) {
var out = new PrintStream(OutputStream.nullOutputStream());
var inputs = String.join("\n", commands);
var bytes = inputs.getBytes();
var in = new ByteArrayInputStream(bytes);
return new InteractiveConsole(out, in).run();
}
/*
* An interaction example is like this:
* 1. Add a node
* - Choose the type of node to create:
* - 1. Source
* - 2. Queue
* - 3. Queue with unavailable time
* - Node name: Name
* - Arrivals limit (0 for Int.Max) / Number of servers: 1
* - Choose the type of service distribution:
* - - 1. Exponential
* - - 2. Uniform
* - - 3. Erlang
* - - 4. UnavailableTime
* - - 5. Normal
* - - 6. NormalBoxMuller
* - - 7. None
* 2. Add a connection
* - Enter the source node: Source
* - Enter the target node: Queue
* - Enter the weight: 1.0
* 3. Save the net
* 4. Load net
* 5. Clear
* 6. Exit
*/
}

View File

@@ -4,6 +4,8 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashSet;
import org.junit.Test;
import org.junit.jupiter.api.AfterAll;
@@ -11,61 +13,26 @@ import org.junit.jupiter.api.BeforeAll;
import com.esotericsoftware.kryo.KryoException;
import net.berack.upo.valpre.NetExamples;
import net.berack.upo.valpre.SimulationBuilder;
import net.berack.upo.valpre.rand.Distribution;
import net.berack.upo.valpre.rand.Rng;
import net.berack.upo.valpre.sim.stats.CsvResult;
import net.berack.upo.valpre.sim.stats.NodeStats;
public class TestSaveExamplesNet {
private static final Distribution exp0_22 = new Distribution.Exponential(1.0 / 4.5);
private static final Distribution exp2 = new Distribution.Exponential(2.0);
private static final Distribution exp1_5 = new Distribution.Exponential(1.5);
private static final Distribution exp3_5 = new Distribution.Exponential(3.5);
private static final Distribution exp10 = new Distribution.Exponential(10.0);
private static final Distribution norm3_2 = new Distribution.NormalBoxMuller(3.2, 0.6);
private static final Distribution norm4_2 = new Distribution.NormalBoxMuller(4.2, 0.6);
private static final Distribution unNorm = new Distribution.UnavailableTime(0.2, norm4_2);
private static final Distribution unExp = new Distribution.UnavailableTime(0.1, exp10);
private static final int spawn = 10000;
private static final String path = "src/main/resources/example%d.%s";
private static final String path = "src/test/resources/example%d.%s";
private static final String netFile1 = path.formatted(1, "net");
private static final String netFile2 = path.formatted(2, "net");
private static final String netFile3 = path.formatted(3, "net");
private static final String csv1 = path.formatted(1, "csv");
private static final String csv2 = path.formatted(2, "csv");
private static final String csv3 = path.formatted(3, "csv");
private static final Net net1 = new Net();
private static final Net net2 = new Net();
private static final Net net3 = new Net();
static {
net1.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp0_22));
net1.addNode(ServerNode.Builder.queue("Queue", 1, norm3_2));
net1.addConnection(0, 1, 1.0);
net2.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp0_22));
net2.addNode(ServerNode.Builder.queue("Queue", 1, norm3_2));
net2.addNode(ServerNode.Builder.queue("Queue Wait", 1, norm3_2, unNorm));
net2.addConnection(0, 1, 1.0);
net2.addConnection(1, 2, 1.0);
net3.addNode(ServerNode.Builder.sourceLimited("Source", spawn, exp1_5));
net3.addNode(ServerNode.Builder.queue("Service1", 1, exp2));
net3.addNode(ServerNode.Builder.queue("Service2", 1, exp3_5, unExp));
net3.addConnection(0, 1, 1.0);
net3.addConnection(1, 2, 1.0);
}
private static final Net net1 = NetExamples.getNet1();
private static final Net net2 = NetExamples.getNet2();
@BeforeAll
public void saveAll() throws IOException {
net1.save(netFile1);
net2.save(netFile2);
net3.save(netFile3);
}
@Test
@@ -85,20 +52,6 @@ public class TestSaveExamplesNet {
public void loadExample2() throws KryoException, IOException {
var sim = new Simulation(Net.load(netFile2), new Rng());
var res = sim.run();
var time = 45417.0;
var maxErr = time / 1000.0;
assertEquals(Rng.DEFAULT, res.seed);
assertEquals(time, res.simulationTime, maxErr);
testNode(res.getStat("Source"), 10000, time, 1.0, 4.5, 0.0, 0.0);
testNode(res.getStat("Queue"), 10000, time, 2.6, 7.2, 4.0, 0.0);
testNode(res.getStat("Queue Wait"), 10000, time, 5.8, 22.3, 19.1, 8497.7);
}
@Test
public void loadExample3() throws KryoException, IOException {
var sim = new Simulation(Net.load(netFile3), new Rng());
var res = sim.run();
var time = 6736.0;
var maxErr = time / 1000.0;
@@ -153,33 +106,26 @@ public class TestSaveExamplesNet {
@Test
@AfterAll
public void multiSimulation1() throws Exception {
new SimulationBuilder(net1)
.setCsv(csv1)
.setMaxRuns(1000)
.setSeed(2007539552L)
.setParallel(true)
.run();
try (var newOut = new PrintStream(OutputStream.nullOutputStream())) {
new SimulationBuilder(net1)
.setCsv(csv1)
.setMaxRuns(1000)
.setSeed(2007539552L)
.setParallel(true)
.run(newOut);
}
}
@Test
@AfterAll
public void multiSimulation2() throws Exception {
new SimulationBuilder(net2)
.setCsv(csv2)
.setMaxRuns(1000)
.setSeed(2007539552L)
.setParallel(true)
.run();
}
@Test
@AfterAll
public void multiSimulation3() throws Exception {
new SimulationBuilder(net3)
.setCsv(csv3)
.setMaxRuns(1000)
.setSeed(2007539552L)
.setParallel(true)
.run();
try (var newOut = new PrintStream(OutputStream.nullOutputStream())) {
new SimulationBuilder(net2)
.setCsv(csv2)
.setMaxRuns(1000)
.setSeed(2007539552L)
.setParallel(true)
.run(newOut);
}
}
}

View File

@@ -5,6 +5,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.HashSet;
@@ -23,7 +24,7 @@ public class TestSimulation {
private static final ServerNode node0;
private static final ServerNode node1;
static {
node0 = ServerNode.Builder.sourceLimited("First", 0, const1);
node0 = ServerNode.Builder.terminal("First", 0, const1);
node1 = ServerNode.Builder.queue("Second", 1, const1);
simpleNet = new Net();
@@ -56,10 +57,10 @@ public class TestSimulation {
node = ServerNode.Builder.source("Source", const1);
assertEquals("Source", node.name);
assertEquals(1, node.maxServers);
assertEquals(Integer.MAX_VALUE, node.spawnArrivals);
assertEquals(-1, node.spawnArrivals);
assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.Builder.sourceLimited("Source", 50, const1);
node = ServerNode.Builder.terminal("Source", 50, const1);
assertEquals("Source", node.name);
assertEquals(1, node.maxServers);
assertEquals(50, node.spawnArrivals);
@@ -196,7 +197,7 @@ public class TestSimulation {
@Test
public void nodeStatsUpdates() {
var net = new Net();
net.addNode(ServerNode.Builder.sourceLimited("Source", 50, const1));
net.addNode(ServerNode.Builder.terminal("Source", 50, const1));
net.addNode(node1);
net.addConnection(0, 1, 1.0);
@@ -393,13 +394,23 @@ public class TestSimulation {
@Test
public void simulation() {
var start = System.nanoTime();
assertThrows(NullPointerException.class, () -> new Simulation(null, rigged));
assertThrows(NullPointerException.class, () -> new Simulation(simpleNet, null));
var sim = new Simulation(simpleNet, rigged);
assertTrue(sim.hasEnded());
assertEquals(0, sim.getEventsProcessed());
assertEquals(0.0, sim.getTime(), DELTA);
var fel = sim.getFutureEventList();
assertEquals(0, fel.size());
var start = System.nanoTime();
sim = new Simulation(simpleNet, rigged);
// knowing that it takes time to allocate the object
// we can use the average time
var endAllocation = System.nanoTime();
var time = (endAllocation + start) / 2;
var diff = 0.5e-6 * (endAllocation - start); // getting the error margin in ms
var diff = 1e-6 * (endAllocation - start); // getting the error margin in ms
assertTrue(sim.hasEnded());
assertEquals(0, sim.getEventsProcessed());
@@ -410,7 +421,7 @@ public class TestSimulation {
assertEquals(0, sim.getNodeState(node0.name).numServerUnavailable);
assertEquals(0, sim.getNodeState(node1.name).numServerBusy);
assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable);
var fel = sim.getFutureEventList();
fel = sim.getFutureEventList();
assertEquals(0, fel.size());
sim.addToFel(Event.newArrival(0, sim.getTime()));
@@ -489,6 +500,8 @@ public class TestSimulation {
assertEquals(0, sim.getNodeState(node1.name).numServerUnavailable);
fel = sim.getFutureEventList();
assertEquals(0, fel.size());
final var s = sim;
assertThrows(NullPointerException.class, () -> s.processNextEvent());
var elapsed = (double) (System.nanoTime() - time);
var result = sim.endSimulation();
@@ -529,7 +542,7 @@ public class TestSimulation {
@Test
public void simulationStats() {
var net = new Net();
net.addNode(ServerNode.Builder.sourceLimited("Source", 50, const1));
net.addNode(ServerNode.Builder.terminal("Source", 50, const1));
var sim = new Simulation(net, rigged);
var result = sim.run();
@@ -581,7 +594,7 @@ public class TestSimulation {
@Test
public void simulationDrop() {
var net = new Net();
net.addNode(ServerNode.Builder.sourceLimited("Source", 50, const1));
net.addNode(ServerNode.Builder.terminal("Source", 50, const1));
net.addNode(new ServerNode.Builder("Queue", _ -> 2.0).queue(20).build());
net.addConnection(0, 1, 1.0);

View File

Can't render this file because it is too large.