Add new images and update README with network modifications; improve ConsoleTable formatting

This commit is contained in:
2025-03-22 09:39:23 +01:00
parent e48bddf94d
commit 3844a46379
9 changed files with 1132 additions and 1044 deletions

View File

@@ -67,10 +67,6 @@ Queue Response Time = 7.3022 con un range [7.1456, 7.4589]\
Queue Throughput = 0.2226 con un range [0.2182, 0.2271]\
Queue Utilization = 0.7111 con un range [0.6959, 0.7262]
Ho successivamente modificato la rete cambiando solamente la distribuzione di servizio usata dal nodo "Queue". Le distribuzioni usate sono Normale, Esponenziale, Erlang, Uniforme.\
Come si può notare l'utilizzo e il throughput rimangono pressochè invariati, mentre cambia il **numero medio della coda**, il **tempo medio di attesa** e, di conseguenza, anche il **tempo medio di risposta**.\
![1742150755381](image/README/1742150755381.png)
### Secondo esempio
![1741863043733](image/README/1741863043733.png)\
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)\
@@ -85,3 +81,27 @@ Service1 Utilization ~ 0.7488\
Calibration Number of Customers ~ 0.0150\
Busy2 Number of Customers ~ 0.4279\
Throughput ~ 1.5000
### Modifiche alle reti
Di seguito sono state modificate le due reti descritte precedentemente in modo da mostrare cosa succede con l'aumento del numero di clienti nel sistema e cambiando la distribuzione di servizio di un nodo. Ogni valore ottenuto ha un sample di 1000 simulazioni. I risultati possono essere presi dal seguente [link](https://docs.google.com/spreadsheets/d/1yM1fvlpc2mIIpRe8M7_ry8m3DC3ZxNA204mM60O2hoQ/edit?usp=sharing)\
Le distribuzioni usate hanno tutte la stessa media μ:
- Normale(μ, 0.6)
- Uniforme(μ - (μ\*0.1), μ + (μ\*0.1))
- Esponenziale(1/μ)
- Erlang(5, 5/μ)
- Iperesponenziale(p=\[0.5, 0.5\], e=\[1/(μ\*0.5), 1/(μ\*1.5)\])
##### Prima rete
Per la prima rete ho cambiato la distribuzione di servizio usata dal nodo "Queue".\
Come si può notare l'utilizzo e il throughput rimangono pressochè invariati tra le varie distribuzioni, ma convergono con l'aumentare dei clienti.\
I valori che cambiano sono il **numero medio della coda**, il **tempo medio di attesa** e, di conseguenza, anche il **tempo medio di risposta**.\
![1742150755381](image/README/1742150755381.png)\
Di seguito si può vedere il cambiamento del tempo medio di attesa, il numero medio della coda e l'utilizzazione al variare del numero di clienti nel sistema.\
![1742556358341](image/README/1742556358341.png)
##### Secoda rete
Per la seconda rete ho cambiato la distribuzione di servizio usata dal nodo "Service2".\
Anche in questo caso l'utilizzo e il throughput rimangono pressochè invariati e convergono con l'aumentare dei clienti nel sistema, ma cambiano il **numero medio della coda** e il **tempo medio di attesa**.\
Una particolarità di questa rete è il basso valore atteso per il tempo di servizio. Questo, in concomitanza con il resample in caso di valori negativi, fa si di aumentare la media della Distribuzione Normale. Nei grafici seguenti è stata inclusa la Normale solo nell'ultimo per mostrare la differenza rispetto le altre distribuzioni.\
![1742632017987](image/README/1742632017987.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -1,11 +1,13 @@
package net.berack.upo.valpre;
import java.util.concurrent.ExecutionException;
import java.util.List;
import java.util.function.BiFunction;
import net.berack.upo.valpre.rand.Distribution;
import net.berack.upo.valpre.sim.Net;
import net.berack.upo.valpre.sim.ServerNode;
import net.berack.upo.valpre.sim.SimulationMultiple;
import net.berack.upo.valpre.sim.stats.CsvResult;
import net.berack.upo.valpre.sim.stats.Result;
/**
@@ -16,30 +18,79 @@ import net.berack.upo.valpre.sim.stats.Result;
public final class NetExamples {
/**
* Main method to test the example networks.
* It runs the fist network and prints the results.
* The network will have the distribution changed but the mean will be the same.
* Main method to test the networks.
* The first network will have the distribution changed but the mean will be the
* same. The second network will have the distribution changed but the mean will
* be the same. The results will be saved to a csv file.
*
* @param args not needed
* @throws ExecutionException if the execution fails
* @throws InterruptedException if the execution is interrupted
* @throws Exception if the simulation fails or the file is not saved
*/
public static void main(String[] args) throws InterruptedException, ExecutionException {
var avg1 = 3.2;
var seed = 0l;
public static void main(String[] args) throws Exception {
var seed = 123456789L;
runNet(seed, 3.2, 1, "net1.csv", (spawn, dist) -> {
var name = dist.getClass().getSimpleName() + "_" + spawn;
return NetExamples.getNet1(spawn, name, dist);
});
runNet(seed, 1 / 3.5, 2, "net2.csv", (spawn, dist) -> {
var name = dist.getClass().getSimpleName() + "_" + spawn;
return NetExamples.getNet2(spawn, name, dist);
});
}
var nets = new Net[] {
getNet1("Normal", new Distribution.NormalBoxMuller(avg1, 0.6)),
getNet1("Exponential", new Distribution.Exponential(1 / avg1)),
getNet1("Erlang", new Distribution.Erlang(5, 5 / avg1)),
getNet1("Uniform", new Distribution.Uniform(avg1 - 1, avg1 + 1))
};
/**
* Method to test whatever network you input.
* The network will have the distribution changed but the mean will be the same.
* The bifunction requested is to get the network you want to test passing the
* spawn and the distribution with the same mean.
* The network will be tested with spawn totals of 1, 2, 5, 7, 10, 25, 50, 75,
* 100, 250, 500, 750, 1000, 1500, 2000.
* The results will be saved to a csv passed as argument.
*
* @param seed the seed for the simulation
* @param avg the mean of the distribution
* @param nodeToWatch the node to watch
* @param csv the file to save the results
* @param getNet the bifunction to get the network
* @throws Exception if the simulation fails or the file is not saved
*/
public static void runNet(long seed, double avg, int nodeToWatch, String csv,
BiFunction<Integer, Distribution, Net> getNet) throws Exception {
var build = new Result.Builder().seed(seed);
var spawnTotals = new int[] { 1, 2, 5, 7, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 1500, 2000 };
for (var net : nets) {
var summary = new SimulationMultiple(net).runParallel(seed, 1000);
var table = Result.getResultString(summary.getNodes(), summary.getStats());
System.out.println(table);
var normal = new Distribution.NormalBoxMuller(avg, 0.6);
var exponential = new Distribution.Exponential(1 / avg);
var erlang = new Distribution.Erlang(5, 5 / avg);
var uniform = new Distribution.Uniform(avg - (avg * 0.1), avg + (avg * 0.1));
var hyper = new Distribution.HyperExponential(
new double[] { 1 / (avg * 0.5), 1 / (avg * 1.5) },
new double[] { 0.5f, 0.5f });
System.out.println("Normal: " + normal.mean);
System.out.println("Uniform: " + uniform.min + " - " + uniform.max);
for (var spawn : spawnTotals) {
System.out.println("Spawn: " + spawn);
var nets = new Net[] {
getNet.apply(spawn, normal),
getNet.apply(spawn, exponential),
getNet.apply(spawn, erlang),
getNet.apply(spawn, uniform),
getNet.apply(spawn, hyper),
};
for (var net : nets) {
var summary = new SimulationMultiple(net).runParallel(build.seed, 1000);
var name = net.getNode(nodeToWatch).name;
var stat = summary.getSummaryOf(name).average;
build.addNode(name, stat);
}
}
var result = build.build();
new CsvResult(csv).saveResults(List.of(result));
System.out.println("Results saved to " + csv);
}
/**
@@ -53,20 +104,21 @@ public final class NetExamples {
*/
public static Net getNet1() {
var norm3_2 = new Distribution.NormalBoxMuller(3.2, 0.6);
return getNet1("Queue", norm3_2);
return getNet1(10000, "Queue", 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.
* The terminal node generates 10000 jobs with an exponential distribution 4.5.
* The terminal node generates N jobs with an exponential distribution 4.5.
*
* @param spawn the number of jobs to generate
* @param name the name of the queue node
* @param queue the distribution of the queue node
* @return the first example network
*/
public static Net getNet1(String name, Distribution queue) {
var spawn = 10000;
public static Net getNet1(int spawn, String name, Distribution queue) {
var source = new Distribution.Exponential(1.0 / 4.5);
var net1 = new Net();
@@ -90,13 +142,8 @@ public final class NetExamples {
* @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 getNet2(10000, "Service2", exp3_5);
}
/**
@@ -106,18 +153,20 @@ public final class NetExamples {
* 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 name the name of the second 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) {
public static Net getNet2(int spawn, String name, Distribution service2) {
var exp1_5 = new Distribution.Exponential(1.5);
var exp2 = new Distribution.Exponential(2.0);
var exp10 = new Distribution.Exponential(10.0);
var unExp = new Distribution.UnavailableTime(0.1, exp10);
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.addNode(ServerNode.Builder.terminal("Source", spawn, exp1_5));
net3.addNode(ServerNode.Builder.queue("Service", 1, exp2));
net3.addNode(ServerNode.Builder.queue(name, 1, service2, unExp));
net3.addConnection(0, 1, 1.0);
net3.addConnection(1, 2, 1.0);
return net3;

View File

@@ -49,7 +49,7 @@ public class ConsoleTable {
builder.append('║');
builder.append(" ".repeat(first));
builder.append(val);
builder.append(" ".repeat(diff - first));
builder.append(" ".repeat(Math.max(diff - first, 0)));
}
builder.append("\n");

View File

@@ -55,4 +55,23 @@ public class TestRandom {
assertTrue("Standard Dev must be less than [" + expected + "] -> [" + stdDev + "]", stdDev < expected);
}
@Test
public void testMean() {
var rng = new Rng();
var normal = new Distribution.NormalBoxMuller(1 / 3.5, 0.6);
var mean = 0.0;
for (var i = 0; i < 100000; i++) {
var sample = Distribution.getPositiveSample(normal, rng);
mean = (mean * (i + 1) + sample) / (i + 2);
}
assertEquals(0.6, mean, 0.01);
for (var i = 0; i < 100000; i++) {
var sample = Math.max(0, normal.sample(rng));
mean = (mean * (i + 1) + sample) / (i + 2);
}
assertEquals(0.41, mean, 0.01);
}
}

View File

@@ -144,8 +144,8 @@ public class TestInteractions {
// 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"
assertEquals("Source[servers:1, queue:100, spawn:10000, Exponential(1.5)] -> Service(1.0)\n"
+ "Service[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());
}

File diff suppressed because it is too large Load Diff