From 7eea127e0377f705a628afa9defa8de9016a03a9 Mon Sep 17 00:00:00 2001 From: Berack96 Date: Tue, 21 Jan 2025 20:44:49 +0100 Subject: [PATCH] Start of average - added average of the runs - added variance of the runs --- src/main/java/net/berack/upo/valpre/Main.java | 13 +- .../net/berack/upo/valpre/NetStatistics.java | 202 ++++++++++++++++-- 2 files changed, 192 insertions(+), 23 deletions(-) diff --git a/src/main/java/net/berack/upo/valpre/Main.java b/src/main/java/net/berack/upo/valpre/Main.java index e86fc21..3e766a8 100644 --- a/src/main/java/net/berack/upo/valpre/Main.java +++ b/src/main/java/net/berack/upo/valpre/Main.java @@ -5,8 +5,8 @@ import net.berack.upo.valpre.rand.Distribution; public class Main { public static void main(String[] args) throws Exception { // Parameters for the simulation - var seed = System.nanoTime(); - var total = 100000; + var seed = 2007539552; + var total = 10000; var lambda = 1.0 / 4.5; var mu = 3.2; var sigma = 0.6; @@ -23,7 +23,12 @@ public class Main { // var maxDepartures = new EndSimulationCriteria.MaxDepartures("Queue", total); // var maxTime = new EndSimulationCriteria.MaxTime(1000.0); - var results = sim.runParallel(seed, 100); - results.runs[80].printSummary(); + var nano = System.nanoTime(); + var results = sim.runParallel(seed, 1000); + nano = System.nanoTime() - nano; + + System.out.print(results.average.getHeader()); + System.out.print(results.average.getSummaryAsTable()); + System.out.println("Final time " + nano / 1e6 + "ms"); } } \ No newline at end of file diff --git a/src/main/java/net/berack/upo/valpre/NetStatistics.java b/src/main/java/net/berack/upo/valpre/NetStatistics.java index 5d473a4..0a81189 100644 --- a/src/main/java/net/berack/upo/valpre/NetStatistics.java +++ b/src/main/java/net/berack/upo/valpre/NetStatistics.java @@ -8,15 +8,102 @@ import java.util.Map; */ public class NetStatistics { public final RunResult[] runs; - // public final Run average; - // public final Run variance; + public final RunResult average; + public final RunResult variance; /** * TODO + * * @param runs */ public NetStatistics(RunResult... runs) { this.runs = runs; + this.average = calcAvg(runs); + this.variance = calcVar(this.average, runs); + } + + /** + * TODO + * + * @param runs + * @return + */ + public static RunResult calcAvg(RunResult... runs) { + var avgTime = 0.0d; + var avgElapsed = 0L; + var nodes = new HashMap(); + + for (var run : runs) { + avgTime += run.simulationTime; + avgElapsed += run.timeElapsedNano; + + for (var entry : run.nodes.entrySet()) { + var stat = nodes.computeIfAbsent(entry.getKey(), _ -> new Statistics()); + var other = entry.getValue(); + stat.numDepartures += other.numDepartures; + stat.numArrivals += other.numArrivals; + stat.busyTime += other.busyTime; + stat.responseTime += other.responseTime; + stat.lastEventTime += other.lastEventTime; + stat.averageQueueLength += other.averageQueueLength; + stat.maxQueueLength = Math.max(stat.maxQueueLength, other.maxQueueLength); + } + } + + avgTime /= runs.length; + avgElapsed /= runs.length; + for (var stat : nodes.values()) { + stat.numDepartures /= runs.length; + stat.numArrivals /= runs.length; + stat.busyTime /= runs.length; + stat.responseTime /= runs.length; + stat.lastEventTime /= runs.length; + stat.averageQueueLength /= runs.length; + } + return new RunResult(runs[0].seed, avgTime, avgElapsed, nodes); + } + + /** + * TODO + * + * @param avg + * @param runs + * @return + */ + public static RunResult calcVar(RunResult avg, RunResult... runs) { + var varTime = 0.0d; + var varElapsed = 0L; + var nodes = new HashMap(); + + for (var run : runs) { + varTime += Math.pow(run.simulationTime - avg.simulationTime, 2); + varElapsed += Math.pow(run.timeElapsedNano - avg.simulationTime, 2); + + for (var entry : run.nodes.entrySet()) { + var stat = nodes.computeIfAbsent(entry.getKey(), _ -> new Statistics()); + var average = avg.nodes.get(entry.getKey()); + var other = entry.getValue(); + stat.numDepartures += Math.pow(other.numDepartures - average.numDepartures, 2); + stat.numArrivals += Math.pow(other.numArrivals - average.numArrivals, 2); + stat.busyTime += Math.pow(other.busyTime - average.busyTime, 2); + stat.responseTime += Math.pow(other.responseTime - average.responseTime, 2); + stat.lastEventTime += Math.pow(other.lastEventTime - average.lastEventTime, 2); + stat.averageQueueLength += Math.pow(other.averageQueueLength - average.averageQueueLength, 2); + } + } + + varTime /= runs.length - 1; + varElapsed /= runs.length - 1; + for (var stat : nodes.values()) { + stat.numDepartures /= runs.length - 1; + stat.numArrivals /= runs.length - 1; + stat.busyTime /= runs.length - 1; + stat.responseTime /= runs.length - 1; + stat.lastEventTime /= runs.length - 1; + stat.averageQueueLength /= runs.length - 1; + } + + return new RunResult(runs[0].seed, varTime, varElapsed, nodes); } /** @@ -50,29 +137,68 @@ public class NetStatistics { * The summary includes the seed, the simulation time, the elapsed time, and * the statistics for each node in the network. */ - public void printSummary() { + public String getSummary() { var size = (int) Math.ceil(Math.log10(this.simulationTime)); - var format = "%" + (size + 4) + ".3f"; - - System.out.println("===== Net Stats ====="); - System.out.println("Seed: \t" + this.seed); - System.out.printf("Simulation: \t" + format + "\n", this.simulationTime); - System.out.printf("Elapsed: \t" + format + "ms\n", this.timeElapsedNano / 1e6); + var iFormat = "%" + size + ".0f"; + var fFormat = "%" + (size + 4) + ".3f"; + var builder = new StringBuilder(); for (var entry : this.nodes.entrySet()) { var stats = entry.getValue(); - var entrySize = (int) Math.max(size, (int) Math.ceil((Math.log10(stats.numArrivals)))); - var iFormat = "%" + entrySize + ".0f"; - var fFormat = "%" + (entrySize + 4) + ".3f"; + var busy = stats.busyTime * 100 / stats.lastEventTime; + var avgResp = stats.responseTime / stats.numDepartures; - System.out.println("===== " + entry.getKey() + " ====="); - System.out.printf(" Arrivals: \t" + iFormat + "\n", stats.numArrivals); - System.out.printf(" Departures:\t" + iFormat + "\n", stats.numDepartures); - System.out.printf(" Max Queue: \t" + iFormat + "\n", stats.maxQueueLength); - System.out.printf(" Response: \t" + fFormat + "\n", stats.responseTime / stats.numDepartures); - System.out.printf(" Busy %%: \t" + fFormat + "\n", stats.busyTime * 100 / stats.lastEventTime); - System.out.printf(" Last Event:\t" + fFormat + "\n", stats.lastEventTime); + builder.append("===== " + entry.getKey() + " =====\n"); + builder.append(String.format(" Arrivals: \t" + iFormat + "\n", stats.numArrivals)); + builder.append(String.format(" Departures:\t" + iFormat + "\n", stats.numDepartures)); + builder.append(String.format(" Max Queue: \t" + iFormat + "\n", stats.maxQueueLength)); + builder.append(String.format(" Avg Queue: \t" + fFormat + "\n", stats.averageQueueLength)); + builder.append(String.format(" Response: \t" + fFormat + "\n", avgResp)); + builder.append(String.format(" Busy %%: \t" + fFormat + "\n", busy)); + builder.append(String.format(" Last Event:\t" + fFormat + "\n", stats.lastEventTime)); } + return builder.toString(); + } + + /** + * TODO + */ + public String getSummaryAsTable() { + var size = (int) Math.ceil(Math.log10(this.simulationTime)); + var iFormat = "%" + size + ".0f"; + var fFormat = "%" + (size + 4) + ".3f"; + + String[] h = { "Node", "Arrivals", "Departures", "Max Queue", "Avg Queue", "Response", "Busy %", + "Last Event" }; + var table = new ConsoleTable(h); + + for (var entry : this.nodes.entrySet()) { + var stats = entry.getValue(); + table.addRow( + entry.getKey(), + String.format(iFormat, stats.numArrivals), + String.format(iFormat, stats.numDepartures), + String.format(iFormat, stats.maxQueueLength), + String.format(fFormat, stats.averageQueueLength), + String.format(fFormat, stats.responseTime / stats.numDepartures), + String.format(fFormat, stats.busyTime * 100 / stats.lastEventTime), + String.format(fFormat, stats.lastEventTime)); + } + return table.toString(); + } + + /** + * TODO + */ + public String getHeader() { + var size = (int) Math.ceil(Math.log10(this.simulationTime)); + var format = "%" + (size + 4) + ".3f"; + var builder = new StringBuilder(); + builder.append("===== Net Stats =====\n"); + builder.append(String.format("Seed: \t%d\n", this.seed)); + builder.append(String.format("Simulation: \t" + format + "\n", this.simulationTime)); + builder.append(String.format("Elapsed: \t" + format + "ms\n", this.timeElapsedNano / 1e6)); + return builder.toString(); } } @@ -101,4 +227,42 @@ public class NetStatistics { this.lastEventTime = 0.0d; } } + + /** + * TODO + */ + private static class ConsoleTable { + private StringBuilder builder = new StringBuilder(); + private final int maxLen; + private final String border; + + public ConsoleTable(String... header) { + var max = 0; + for (var name : header) + max = Math.max(max, name.length()); + this.maxLen = max + 2; + this.border = ("+" + "═".repeat(maxLen)).repeat(header.length) + "+\n"; + this.builder.append(border); + this.addRow(header); + } + + public void addRow(String... values) { + for (var val : values) { + var diff = maxLen - val.length(); + var first = (int) Math.ceil(diff / 2.0); + builder.append('║'); + builder.append(" ".repeat(first)); + builder.append(val); + builder.append(" ".repeat(diff - first)); + } + + builder.append("║\n"); + builder.append(border); + } + + @Override + public String toString() { + return builder.toString(); + } + } } \ No newline at end of file