- 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

@@ -4,16 +4,21 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* TODO * Class that helps with parsing the parameters passed as input in the console.
*/ */
public class Parameters { public class Parameters {
private final Map<String, Boolean> arguments; private final Map<String, Boolean> arguments;
private final String prefix; private final String prefix;
/** /**
* TODO * Constructs a new Parameters object with the specified prefix and arguments.
* * The arguments can be with value, in that case in the map the boolean should
* @param arguments * be true, otherwise it is only an argument that is a flag
*
* @param prefix the prefix to be used
* @param arguments a map of arguments where the key is a string and if the
* boolean is true then the argument expect a value
* @throws IllegalArgumentException if the arguments map is null or empty
*/ */
public Parameters(String prefix, Map<String, Boolean> arguments) { public Parameters(String prefix, Map<String, Boolean> arguments) {
if (arguments == null || arguments.size() == 0) if (arguments == null || arguments.size() == 0)
@@ -23,10 +28,11 @@ public class Parameters {
} }
/** /**
* TODO * Return a string with the standard <arggument> <description> spaced enough
* *
* @param eventualDescription * @param eventualDescription the description for the argument, if not present
* @return * the argument will be shown anyway/
* @return a string of arguments
*/ */
public String helper(Map<String, String> eventualDescription) { public String helper(Map<String, String> eventualDescription) {
var size = 0; var size = 0;
@@ -62,10 +68,14 @@ public class Parameters {
} }
/** /**
* TODO * Parse the arguments passed and returns a map of Argument --> Value that can
* be used to retrieve the information. In the case that the arguments are not
* in the correct format then an exception is thrown.
* *
* @param args * @param args the arguments in input
* @return * @throws IllegalArgumentException if the arguments are not formatted correctly
* or if there is an unknown argument
* @return a map of the values
*/ */
public Map<String, String> parse(String[] args) { public Map<String, String> parse(String[] args) {
var result = new HashMap<String, String>(); var result = new HashMap<String, String>();
@@ -85,12 +95,14 @@ public class Parameters {
} }
/** /**
* TODO * Parse one single argument and put it into the map.
* *
* @param current * @param current the current argument
* @param next * @param next the next argument if present
* @param result * @param result the map where to insert the value
* @return * @throws IllegalArgumentException if the arguments are not formatted correctly
* or if there is an unknown argument
* @return true if the next argument is used
*/ */
private boolean parseSingle(String current, String next, Map<String, String> result) { private boolean parseSingle(String current, String next, Map<String, String> result) {
if (!current.startsWith(this.prefix)) if (!current.startsWith(this.prefix))

View File

@@ -200,17 +200,20 @@ public interface Distribution {
} }
/** /**
* TODO * Distribution of the UnavailableTime that has a probability of happening.
* In case the node is unavailable then a value of the second distribution is
* returned.
*/ */
public static class UnavailableTime implements Distribution { public static class UnavailableTime implements Distribution {
public final double probability; public final double probability;
public final Distribution distribution; public final Distribution distribution;
/** /**
* TODO * Create a new distribution with a probability of happening.
* In case it happens then a value of the second distribution is returned.
* *
* @param probability * @param probability the probability of returning a value > 0.0
* @param distribution * @param distribution the distribution where to get the samples
*/ */
public UnavailableTime(double probability, Distribution distribution) { public UnavailableTime(double probability, Distribution distribution) {
this.probability = probability; this.probability = probability;

View File

@@ -1,23 +1,31 @@
package net.berack.upo.valpre.sim.stats; 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 { public class ConsoleTable {
private StringBuilder builder = new StringBuilder(); private StringBuilder builder = new StringBuilder();
private final int maxLen; private final int maxLen;
private final int columns;
private final String border; 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) { public ConsoleTable(String... header) {
var max = 0; var max = 0;
for (var name : header) for (var name : header)
max = Math.max(max, name.length()); max = Math.max(max, name.length());
this.columns = header.length;
this.maxLen = max + 2; this.maxLen = max + 2;
this.border = ("+" + "".repeat(maxLen)).repeat(header.length) + "+\n"; this.border = ("+" + "".repeat(maxLen)).repeat(header.length) + "+\n";
this.builder.append(border); 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) { public void addRow(String... values) {
if (this.columns != values.length)
throw new IllegalArgumentException("Length must be " + this.columns);
for (var val : values) { for (var val : values) {
var diff = maxLen - val.length(); var diff = maxLen - val.length();
var first = (int) Math.ceil(diff / 2.0); var first = (int) Math.ceil(diff / 2.0);

View File

@@ -5,7 +5,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
/** /**
* TODO * This class represent the result of multiple runs of simulation.
*/ */
public class ResultMultiple { public class ResultMultiple {
public final Result[] runs; public final Result[] runs;
@@ -14,9 +14,13 @@ public class ResultMultiple {
public final Result error95; 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) { public ResultMultiple(Result... runs) {
if (runs == null || runs.length <= 1) if (runs == null || runs.length <= 1)
@@ -24,17 +28,20 @@ public class ResultMultiple {
this.runs = runs; this.runs = runs;
this.average = ResultMultiple.calcAvg(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); this.error95 = calcError(this.average, this.variance, runs.length, 0.95);
} }
/** /**
* TODO * Save all the runs to a csv file.
* *
* @param filename * @param filename the name of the file
* @throws IOException * @throws IOException if anything happens wile wriiting to the file
*/ */
public void saveCSV(String filename) throws IOException { public void saveCSV(String filename) throws IOException {
if (!filename.endsWith(".csv"))
filename = filename + ".csv";
try (var file = new FileWriter(filename)) { try (var file = new FileWriter(filename)) {
var first = true; var first = true;
var builder = new StringBuilder(); 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 * @param runs the run to calculate
* @return * @return the average of the runs
*/ */
public static Result calcAvg(Result... runs) { public static Result calcAvg(Result... runs) {
var avgTime = 0.0d; 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 avg the average of the runs. {@link #calcAvg(Result...)}
* @param runs * @param runs the run to calculate
* @return * @return the standard deviation of the runs
*/ */
public static Result calcVar(Result avg, Result... runs) { public static Result calcStdDev(Result avg, Result... runs) {
var varTime = 0.0d; var time = 0.0d;
var varElapsed = 0L; var elapsed = 0.0d;
var nodes = new HashMap<String, Statistics>(); var nodes = new HashMap<String, Statistics>();
for (var run : runs) { for (var run : runs) {
varTime += Math.pow(run.simulationTime - avg.simulationTime, 2); time += Math.pow(run.simulationTime - avg.simulationTime, 2);
varElapsed += Math.pow(run.timeElapsedMS - avg.simulationTime, 2); elapsed += Math.pow(run.timeElapsedMS - avg.simulationTime, 2);
for (var entry : run.nodes.entrySet()) { for (var entry : run.nodes.entrySet()) {
var stat = nodes.computeIfAbsent(entry.getKey(), _ -> new Statistics()); var stat = nodes.computeIfAbsent(entry.getKey(), _ -> new Statistics());
@@ -100,22 +109,30 @@ public class ResultMultiple {
} }
} }
varTime /= runs.length - 1; time = Math.sqrt(time / runs.length - 1);
varElapsed /= runs.length - 1; elapsed = Math.sqrt(elapsed / runs.length - 1);
for (var stat : nodes.values()) 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 * Calculates the error at the selected alpha level.
* * This method computes the error margin for the provided average and standard
* @param avg * deviation values,
* @param stdDev * considering the sample size and the confidence level (alpha).
* @param sampleSize * The result is adjusted using a t-distribution to account for the variability
* @param alpha * in smaller sample sizes.
* @return *
* @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) { public static Result calcError(Result avg, Result stdDev, int sampleSize, double alpha) {
// Getting the correct values for the percentile // Getting the correct values for the percentile

View File

@@ -4,7 +4,11 @@ import java.util.function.BiFunction;
import java.util.function.Function; 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 class Statistics {
public double numArrivals = 0.0d; public double numArrivals = 0.0d;
@@ -25,11 +29,11 @@ public class Statistics {
public double unavailable = 0.0d; public double unavailable = 0.0d;
/** /**
* TODO * Updates statistics when a new arrival occurs. It updates the number of
* * arrivals, the average queue length, and the maximum queue length.
* @param time *
* @param newQueueSize * @param time The current time of the arrival event.
* @param updateBusy * @param newQueueSize The size of the queue after the arrival.
*/ */
public void updateArrival(double time, double newQueueSize) { public void updateArrival(double time, double newQueueSize) {
var total = this.avgQueueLength * this.numArrivals; var total = this.avgQueueLength * this.numArrivals;
@@ -40,10 +44,12 @@ public class Statistics {
} }
/** /**
* TODO * Updates statistics when a departure occurs. It increments the number of
* * departures and calculates the total response time.
* @param time *
* @param response * @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) { public void updateDeparture(double time, double response) {
this.numDepartures++; this.numDepartures++;
@@ -51,11 +57,14 @@ public class Statistics {
} }
/** /**
* TODO * Updates statistics related to server busy time, unavailable time, and derived
* * stats. It also calculates the average wait time, response time, throughput,
* @param time * utilization, and unavailability.
* @param serverBusy *
* @param serverUnavailable * @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) { public void updateTimes(double time, int serverBusy, int serverUnavailable, int maxServers) {
if (serverBusy > 0) 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 save The `Statistics` object where the merged results will be stored.
* @param val1 * @param val1 The first `Statistics` object to merge.
* @param val2 * @param val2 The second `Statistics` object to merge.
* @param func * @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, public static void apply(Statistics save, Statistics val1, Statistics val2,
BiFunction<Double, Double, Double> func) { BiFunction<Double, Double, Double> func) {