- added docs for all the classes and methods
- fixed variance --> stdDev
This commit is contained in:
2025-01-29 12:07:36 +01:00
parent 2a4b494843
commit 0c82dc7dff
5 changed files with 136 additions and 74 deletions

View File

@@ -1,23 +1,31 @@
package net.berack.upo.valpre.sim.stats;
/**
* TODO
* Class used to build a nice table from the header and row passed.
* The result can be retrieved by {@link #toString()}
*/
public class ConsoleTable {
private StringBuilder builder = new StringBuilder();
private final int maxLen;
private final int columns;
private final String border;
/**
* TODO
* Create a new table with the header passed as input.
* The table will have as many columns as the length of the header array.
* Each column will have the same size and will be the max length of all the
* headers string.
*
* @param header
* @param header an array of strings
* @throws NullPointerException if the array is null
*/
public ConsoleTable(String... header) {
var max = 0;
for (var name : header)
max = Math.max(max, name.length());
this.columns = header.length;
this.maxLen = max + 2;
this.border = ("+" + "".repeat(maxLen)).repeat(header.length) + "+\n";
this.builder.append(border);
@@ -25,11 +33,16 @@ public class ConsoleTable {
}
/**
* TODO
* Add to the table the values of the array. If the array null or the length is
* different than the header.len then an exception i thrown.
*
* @param values
* @param values an array of values to print
* @throw IllegalArgumentException if the values.len is != than the headers.len
*/
public void addRow(String... values) {
if (this.columns != values.length)
throw new IllegalArgumentException("Length must be " + this.columns);
for (var val : values) {
var diff = maxLen - val.length();
var first = (int) Math.ceil(diff / 2.0);

View File

@@ -5,7 +5,7 @@ import java.io.IOException;
import java.util.HashMap;
/**
* TODO
* This class represent the result of multiple runs of simulation.
*/
public class ResultMultiple {
public final Result[] runs;
@@ -14,9 +14,13 @@ public class ResultMultiple {
public final Result error95;
/**
* TODO
* This has all the result and give some statistics about the runs.
* The object created has the average, the variance, and the error95.
* The runs must be an array of at least 2 run result otherwise an exception is
* thrown.
*
* @param runs
* @param runs an array of run result
* @throws IllegalArgumentException if the runs is null or if has a len <= 1
*/
public ResultMultiple(Result... runs) {
if (runs == null || runs.length <= 1)
@@ -24,17 +28,20 @@ public class ResultMultiple {
this.runs = runs;
this.average = ResultMultiple.calcAvg(runs);
this.variance = ResultMultiple.calcVar(this.average, runs);
this.variance = ResultMultiple.calcStdDev(this.average, runs);
this.error95 = calcError(this.average, this.variance, runs.length, 0.95);
}
/**
* TODO
* Save all the runs to a csv file.
*
* @param filename
* @throws IOException
* @param filename the name of the file
* @throws IOException if anything happens wile wriiting to the file
*/
public void saveCSV(String filename) throws IOException {
if (!filename.endsWith(".csv"))
filename = filename + ".csv";
try (var file = new FileWriter(filename)) {
var first = true;
var builder = new StringBuilder();
@@ -47,10 +54,11 @@ public class ResultMultiple {
}
/**
* TODO
* This method calculate the average of the runs result.
* The average is calculated for each node.
*
* @param runs
* @return
* @param runs the run to calculate
* @return the average of the runs
*/
public static Result calcAvg(Result... runs) {
var avgTime = 0.0d;
@@ -75,20 +83,21 @@ public class ResultMultiple {
}
/**
* TODO
* This method calculate the standard deviation of the runs result.
* The standard deviation is calculated for each node.
*
* @param avg
* @param runs
* @return
* @param avg the average of the runs. {@link #calcAvg(Result...)}
* @param runs the run to calculate
* @return the standard deviation of the runs
*/
public static Result calcVar(Result avg, Result... runs) {
var varTime = 0.0d;
var varElapsed = 0L;
public static Result calcStdDev(Result avg, Result... runs) {
var time = 0.0d;
var elapsed = 0.0d;
var nodes = new HashMap<String, Statistics>();
for (var run : runs) {
varTime += Math.pow(run.simulationTime - avg.simulationTime, 2);
varElapsed += Math.pow(run.timeElapsedMS - avg.simulationTime, 2);
time += Math.pow(run.simulationTime - avg.simulationTime, 2);
elapsed += Math.pow(run.timeElapsedMS - avg.simulationTime, 2);
for (var entry : run.nodes.entrySet()) {
var stat = nodes.computeIfAbsent(entry.getKey(), _ -> new Statistics());
@@ -100,22 +109,30 @@ public class ResultMultiple {
}
}
varTime /= runs.length - 1;
varElapsed /= runs.length - 1;
time = Math.sqrt(time / runs.length - 1);
elapsed = Math.sqrt(elapsed / runs.length - 1);
for (var stat : nodes.values())
stat.apply(val -> val / (runs.length - 1));
stat.apply(val -> Math.sqrt(val / (runs.length - 1)));
return new Result(runs[0].seed, varTime, varElapsed, nodes);
return new Result(runs[0].seed, time, elapsed, nodes);
}
/**
* TODO
*
* @param avg
* @param stdDev
* @param sampleSize
* @param alpha
* @return
* Calculates the error at the selected alpha level.
* This method computes the error margin for the provided average and standard
* deviation values,
* considering the sample size and the confidence level (alpha).
* The result is adjusted using a t-distribution to account for the variability
* in smaller sample sizes.
*
* @param avg The average of the results, typically computed using
* {@link #calcAvg(Result...)}.
* @param stdDev The standard deviation of the results, typically computed
* using {@link #calcVar(Result, Result...)}.
* @param sampleSize The number of runs or samples used.
* @param alpha The significance level (probability) used for the
* t-distribution. A value of 0.95 for a 95% confidence level.
* @return The calculated error.
*/
public static Result calcError(Result avg, Result stdDev, int sampleSize, double alpha) {
// Getting the correct values for the percentile

View File

@@ -4,7 +4,11 @@ import java.util.function.BiFunction;
import java.util.function.Function;
/**
* TODO
* This class keeps track of various statistical metrics related to the net
* performance, such as the number of arrivals and departures, queue lengths,
* wait times, response times, server utilization, and unavailability. These
* statistics are updated during simulation events, such as arrivals and
* departures, and can be used to analyze the net's behavior and performance.
*/
public class Statistics {
public double numArrivals = 0.0d;
@@ -25,11 +29,11 @@ public class Statistics {
public double unavailable = 0.0d;
/**
* TODO
*
* @param time
* @param newQueueSize
* @param updateBusy
* Updates statistics when a new arrival occurs. It updates the number of
* arrivals, the average queue length, and the maximum queue length.
*
* @param time The current time of the arrival event.
* @param newQueueSize The size of the queue after the arrival.
*/
public void updateArrival(double time, double newQueueSize) {
var total = this.avgQueueLength * this.numArrivals;
@@ -40,10 +44,12 @@ public class Statistics {
}
/**
* TODO
*
* @param time
* @param response
* Updates statistics when a departure occurs. It increments the number of
* departures and calculates the total response time.
*
* @param time The current time of the departure event.
* @param response The time at which the response was generated for this
* departure.
*/
public void updateDeparture(double time, double response) {
this.numDepartures++;
@@ -51,11 +57,14 @@ public class Statistics {
}
/**
* TODO
*
* @param time
* @param serverBusy
* @param serverUnavailable
* Updates statistics related to server busy time, unavailable time, and derived
* stats. It also calculates the average wait time, response time, throughput,
* utilization, and unavailability.
*
* @param time The current time when the event occurs.
* @param serverBusy The number of servers currently busy.
* @param serverUnavailable The number of servers currently unavailable.
* @param maxServers The total number of servers available.
*/
public void updateTimes(double time, int serverBusy, int serverUnavailable, int maxServers) {
if (serverBusy > 0)
@@ -105,12 +114,20 @@ public class Statistics {
}
/**
* TODO
* Applies a binary function to merge two sets of statistics into a third one.
* This method combines the statistics from two `Statistics` objects (`val1` and
* `val2`) and stores the result in the `save` object. The provided function is
* applied to each pair of corresponding statistics from `val1` and `val2` to
* compute the merged value. This is useful for merging or combining statistics
* from different sources (e.g., different simulation runs), allowing the
* creation of aggregated statistics.
*
* @param save
* @param val1
* @param val2
* @param func
* @param save The `Statistics` object where the merged results will be stored.
* @param val1 The first `Statistics` object to merge.
* @param val2 The second `Statistics` object to merge.
* @param func The binary function that defines how to merge each pair of values
* from `val1` and `val2`. It takes two `Double` values (from `val1`
* and `val2`) and returns a new `Double` value.
*/
public static void apply(Statistics save, Statistics val1, Statistics val2,
BiFunction<Double, Double, Double> func) {