JavaDoc added
This commit is contained in:
@@ -1,16 +1,26 @@
|
|||||||
package net.berack.upo.valpre;
|
package net.berack.upo.valpre;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an event in the simulation.
|
||||||
|
*/
|
||||||
public class Event implements Comparable<Event> {
|
public class Event implements Comparable<Event> {
|
||||||
public final double time;
|
public final double time;
|
||||||
public final Type type;
|
public final Type type;
|
||||||
public final ServerNode node;
|
public final ServerNode node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event.
|
||||||
|
* @param type The type of event.
|
||||||
|
* @param node The node that the event is associated with.
|
||||||
|
* @param time The time at which the event occurs.
|
||||||
|
*/
|
||||||
private Event(Type type, ServerNode node, double time) {
|
private Event(Type type, ServerNode node, double time) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.time = time;
|
this.time = time;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int compareTo(Event other) {
|
public int compareTo(Event other) {
|
||||||
if (this.time < other.time)
|
if (this.time < other.time)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -19,14 +29,29 @@ public class Event implements Comparable<Event> {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new arrival event.
|
||||||
|
* @param node The node that the event is associated with.
|
||||||
|
* @param time The time at which the event occurs.
|
||||||
|
* @return The new event.
|
||||||
|
*/
|
||||||
public static Event newArrival(ServerNode node, double time) {
|
public static Event newArrival(ServerNode node, double time) {
|
||||||
return new Event(Type.ARRIVAL, node, time);
|
return new Event(Type.ARRIVAL, node, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new departure event.
|
||||||
|
* @param node The node that the event is associated with.
|
||||||
|
* @param time The time at which the event occurs.
|
||||||
|
* @return The new event.
|
||||||
|
*/
|
||||||
public static Event newDeparture(ServerNode node, double time) {
|
public static Event newDeparture(ServerNode node, double time) {
|
||||||
return new Event(Type.DEPARTURE, node, time);
|
return new Event(Type.DEPARTURE, node, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of event.
|
||||||
|
*/
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
ARRIVAL,
|
ARRIVAL,
|
||||||
DEPARTURE,
|
DEPARTURE,
|
||||||
|
|||||||
@@ -6,20 +6,43 @@ import java.util.Map;
|
|||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
import net.berack.upo.valpre.rand.Rng;
|
import net.berack.upo.valpre.rand.Rng;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A network simulation that uses a discrete event simulation to model the
|
||||||
|
* behavior of a network of servers.
|
||||||
|
*/
|
||||||
public class NetSimulation {
|
public class NetSimulation {
|
||||||
public final long seed;
|
public final long seed;
|
||||||
private final Rng rng;
|
private final Rng rng;
|
||||||
private final Map<String, ServerNode> servers = new HashMap<>();
|
private final Map<String, ServerNode> servers = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new network simulation with the given seed.
|
||||||
|
*
|
||||||
|
* @param seed The seed to use for the random number generator.
|
||||||
|
*/
|
||||||
public NetSimulation(long seed) {
|
public NetSimulation(long seed) {
|
||||||
this.seed = seed;
|
this.seed = seed;
|
||||||
this.rng = new Rng(seed);
|
this.rng = new Rng(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new server node to the network.
|
||||||
|
*
|
||||||
|
* @param node The server node to add.
|
||||||
|
*/
|
||||||
public void addNode(ServerNode node) {
|
public void addNode(ServerNode node) {
|
||||||
this.servers.put(node.name, node);
|
this.servers.put(node.name, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the simulation for the given number of total arrivals, stopping when the
|
||||||
|
* given node has reached the
|
||||||
|
* specified number of departures.
|
||||||
|
*
|
||||||
|
* @param total The total number of arrivals to simulate.
|
||||||
|
* @param untilDepartureNode The name of the node to stop at.
|
||||||
|
* @return A map of statistics for each server node in the network.
|
||||||
|
*/
|
||||||
public Map<String, Statistics> run(long total, String untilDepartureNode) {
|
public Map<String, Statistics> run(long total, String untilDepartureNode) {
|
||||||
// Initialization
|
// Initialization
|
||||||
var timeNow = 0.0d;
|
var timeNow = 0.0d;
|
||||||
@@ -49,6 +72,12 @@ public class NetSimulation {
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a statistical summary of the behavior of a server node in the
|
||||||
|
* network.
|
||||||
|
* It is used by the simulation to track the number of arrivals and departures,
|
||||||
|
* the maximum queue length, the busy time, and the response time.
|
||||||
|
*/
|
||||||
public static class Statistics {
|
public static class Statistics {
|
||||||
public int numArrivals = 0;
|
public int numArrivals = 0;
|
||||||
public int numDepartures = 0;
|
public int numDepartures = 0;
|
||||||
@@ -61,10 +90,18 @@ public class NetSimulation {
|
|||||||
private ArrayDeque<Double> queue = new ArrayDeque<>();
|
private ArrayDeque<Double> queue = new ArrayDeque<>();
|
||||||
private final Rng rng;
|
private final Rng rng;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new statistics object with the given random number generator.
|
||||||
|
*
|
||||||
|
* @param rng The random number generator to use.
|
||||||
|
*/
|
||||||
public Statistics(Rng rng) {
|
public Statistics(Rng rng) {
|
||||||
this.rng = rng;
|
this.rng = rng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the statistics to their initial values.
|
||||||
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
this.numArrivals = 0;
|
this.numArrivals = 0;
|
||||||
this.numDepartures = 0;
|
this.numDepartures = 0;
|
||||||
@@ -74,6 +111,17 @@ public class NetSimulation {
|
|||||||
this.queue.clear();
|
this.queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes an arrival event for the given node at the given time.
|
||||||
|
* The event is processed by adding the arrival time to the queue, updating the
|
||||||
|
* maximum queue length, and checking if a server is available to process the
|
||||||
|
* arrival. If a server is available, a departure event is created and added to
|
||||||
|
* the future event list.
|
||||||
|
*
|
||||||
|
* @param event The arrival event to process.
|
||||||
|
* @param timeNow The current time of the simulation.
|
||||||
|
* @param fel The future event list to add new events to.
|
||||||
|
*/
|
||||||
private void processArrival(Event event, double timeNow, PriorityQueue<Event> fel) {
|
private void processArrival(Event event, double timeNow, PriorityQueue<Event> fel) {
|
||||||
this.numArrivals++;
|
this.numArrivals++;
|
||||||
this.queue.add(event.time);
|
this.queue.add(event.time);
|
||||||
@@ -92,6 +140,18 @@ public class NetSimulation {
|
|||||||
this.addArrivalIf(event.node.isSource, event.node, timeNow, fel);
|
this.addArrivalIf(event.node.isSource, event.node, timeNow, fel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a departure event for the given node at the given time.
|
||||||
|
* The event is processed by removing the departure time from the queue,
|
||||||
|
* updating the busy time, and checking if there are any arrivals in the queue.
|
||||||
|
* If there are, a new departure event is created and added to the fel.
|
||||||
|
* At the end it will add an arrival to the next node if the current node has a
|
||||||
|
* child.
|
||||||
|
*
|
||||||
|
* @param event The departure event to process.
|
||||||
|
* @param timeNow The current time of the simulation.
|
||||||
|
* @param fel The future event list to add new events to.
|
||||||
|
*/
|
||||||
private void processDeparture(Event event, double timeNow, PriorityQueue<Event> fel) {
|
private void processDeparture(Event event, double timeNow, PriorityQueue<Event> fel) {
|
||||||
var startService = this.queue.poll();
|
var startService = this.queue.poll();
|
||||||
var response = timeNow - startService;
|
var response = timeNow - startService;
|
||||||
@@ -113,6 +173,15 @@ public class NetSimulation {
|
|||||||
this.addArrivalIf(!event.node.isSink, next, timeNow, fel);
|
this.addArrivalIf(!event.node.isSink, next, timeNow, fel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an arrival event to the future event list if the given condition is
|
||||||
|
* true.
|
||||||
|
*
|
||||||
|
* @param condition The condition to check.
|
||||||
|
* @param node The node to add the arrival event for.
|
||||||
|
* @param timeNow The current time of the simulation.
|
||||||
|
* @param fel The future event list to add the event to.
|
||||||
|
*/
|
||||||
private void addArrivalIf(boolean condition, ServerNode node, double timeNow, PriorityQueue<Event> fel) {
|
private void addArrivalIf(boolean condition, ServerNode node, double timeNow, PriorityQueue<Event> fel) {
|
||||||
if (condition && node != null) {
|
if (condition && node != null) {
|
||||||
var delay = node.distribution.sample(this.rng);
|
var delay = node.distribution.sample(this.rng);
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import java.util.List;
|
|||||||
import net.berack.upo.valpre.rand.Distribution;
|
import net.berack.upo.valpre.rand.Distribution;
|
||||||
import net.berack.upo.valpre.rand.Rng;
|
import net.berack.upo.valpre.rand.Rng;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a node in the network. It can be a source, a queue, or a sink
|
||||||
|
* based on the configuration passed as parameters.
|
||||||
|
*/
|
||||||
public class ServerNode {
|
public class ServerNode {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final int maxServers;
|
public final int maxServers;
|
||||||
@@ -14,14 +18,35 @@ public class ServerNode {
|
|||||||
private final List<NodeChild> children = new ArrayList<>();
|
private final List<NodeChild> children = new ArrayList<>();
|
||||||
private double sumProbabilities = 0.0;
|
private double sumProbabilities = 0.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a source node with the given name and distribution.
|
||||||
|
* @param name The name of the node.
|
||||||
|
* @param distribution The distribution of the inter-arrival times.
|
||||||
|
* @return The created source node.
|
||||||
|
*/
|
||||||
public static ServerNode createSource(String name, Distribution distribution) {
|
public static ServerNode createSource(String name, Distribution distribution) {
|
||||||
return new ServerNode(name, Integer.MAX_VALUE, distribution, false, true);
|
return new ServerNode(name, Integer.MAX_VALUE, distribution, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a queue node with the given name, maximum number of servers, and distribution.
|
||||||
|
* @param name The name of the node.
|
||||||
|
* @param maxServers The maximum number of servers in the queue.
|
||||||
|
* @param distribution The distribution of the service times.
|
||||||
|
* @return The created queue node.
|
||||||
|
*/
|
||||||
public static ServerNode createQueue(String name, int maxServers, Distribution distribution) {
|
public static ServerNode createQueue(String name, int maxServers, Distribution distribution) {
|
||||||
return new ServerNode(name, maxServers, distribution, false, false);
|
return new ServerNode(name, maxServers, distribution, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a generic node with the given name and distribution.
|
||||||
|
* @param name The name of the node.
|
||||||
|
* @param maxServers The maximum number of servers in the queue.
|
||||||
|
* @param distribution The distribution of the service times.
|
||||||
|
* @param isSink Whether the node is a sink.
|
||||||
|
* @param isSource Whether the node is a source.
|
||||||
|
*/
|
||||||
public ServerNode(String name, int maxServers, Distribution distribution, boolean isSink, boolean isSource) {
|
public ServerNode(String name, int maxServers, Distribution distribution, boolean isSink, boolean isSource) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.maxServers = maxServers;
|
this.maxServers = maxServers;
|
||||||
@@ -30,11 +55,21 @@ public class ServerNode {
|
|||||||
this.isSource = isSource;
|
this.isSource = isSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a child node with the given probability to select it.
|
||||||
|
* @param node The child node to add.
|
||||||
|
* @param probability The probability of the child node.
|
||||||
|
*/
|
||||||
public void addChild(ServerNode node, double probability) {
|
public void addChild(ServerNode node, double probability) {
|
||||||
this.children.add(new NodeChild(node, probability));
|
this.children.add(new NodeChild(node, probability));
|
||||||
this.sumProbabilities += probability;
|
this.sumProbabilities += probability;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a child node based on the given random number generator.
|
||||||
|
* @param rng The random number generator to use.
|
||||||
|
* @return The child node selected based on the probabilities.
|
||||||
|
*/
|
||||||
public ServerNode getChild(Rng rng) {
|
public ServerNode getChild(Rng rng) {
|
||||||
var random = rng.random();
|
var random = rng.random();
|
||||||
for (var child : this.children) {
|
for (var child : this.children) {
|
||||||
@@ -46,6 +81,9 @@ public class ServerNode {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a child node with a probability to select it.
|
||||||
|
*/
|
||||||
public static class NodeChild {
|
public static class NodeChild {
|
||||||
public final ServerNode node;
|
public final ServerNode node;
|
||||||
public final double probability;
|
public final double probability;
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
package net.berack.upo.valpre.rand;
|
package net.berack.upo.valpre.rand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a probability distribution.
|
||||||
|
*/
|
||||||
public interface Distribution {
|
public interface Distribution {
|
||||||
public double sample(Rng rng);
|
public double sample(Rng rng);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an exponential distribution.
|
||||||
|
*/
|
||||||
public static class Exponential implements Distribution {
|
public static class Exponential implements Distribution {
|
||||||
private final double lambda;
|
private final double lambda;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new exponential distribution with the given rate.
|
||||||
|
* @param lambda The rate of the distribution.
|
||||||
|
*/
|
||||||
public Exponential(double lambda) {
|
public Exponential(double lambda) {
|
||||||
this.lambda = lambda;
|
this.lambda = lambda;
|
||||||
}
|
}
|
||||||
@@ -16,10 +26,18 @@ public interface Distribution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a normal distribution.
|
||||||
|
*/
|
||||||
public static class Normal implements Distribution {
|
public static class Normal implements Distribution {
|
||||||
private final double mean;
|
private final double mean;
|
||||||
private final double sigma;
|
private final double sigma;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new normal distribution with the given mean and standard deviation.
|
||||||
|
* @param mean The mean of the distribution.
|
||||||
|
* @param sigma The standard deviation of the distribution.
|
||||||
|
*/
|
||||||
public Normal(double mean, double sigma) {
|
public Normal(double mean, double sigma) {
|
||||||
this.mean = mean;
|
this.mean = mean;
|
||||||
this.sigma = sigma;
|
this.sigma = sigma;
|
||||||
@@ -32,11 +50,19 @@ public interface Distribution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a normal distribution using the Box-Muller transform.
|
||||||
|
*/
|
||||||
public static class NormalBoxMuller implements Distribution {
|
public static class NormalBoxMuller implements Distribution {
|
||||||
private final double mean;
|
private final double mean;
|
||||||
private final double sigma;
|
private final double sigma;
|
||||||
private double next = Double.NaN;
|
private double next = Double.NaN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new normal distribution with the given mean and standard deviation.
|
||||||
|
* @param mean The mean of the distribution.
|
||||||
|
* @param sigma The standard deviation of the distribution.
|
||||||
|
*/
|
||||||
public NormalBoxMuller(double mean, double sigma) {
|
public NormalBoxMuller(double mean, double sigma) {
|
||||||
this.mean = mean;
|
this.mean = mean;
|
||||||
this.sigma = sigma;
|
this.sigma = sigma;
|
||||||
|
|||||||
Reference in New Issue
Block a user