- added net test
- added more docs
This commit is contained in:
2025-01-29 10:54:42 +01:00
parent be3d95b86e
commit 2a4b494843
6 changed files with 246 additions and 45 deletions

View File

@@ -14,10 +14,6 @@ public class Main {
String csv = null;
var runs = 100;
var seed = 2007539552L;
var total = 10000;
var lambda = 1.0 / 4.5;
var mu = 3.2;
var sigma = 0.6;
// Evantually change the parameters
var arguments = parseParameters(args);
@@ -29,26 +25,11 @@ public class Main {
csv = arguments.get("csv");
var parallel = arguments.containsKey("p");
// varius distributions
var distrExp = new Distribution.Exponential(lambda);
var distrNorm = new Distribution.NormalBoxMuller(mu, sigma);
var distrUnav = new Distribution.UnavailableTime(0.2, distrNorm);
// Build the network
var net = new Net();
var node1 = ServerNode.createLimitedSource("Source", distrExp, total);
var node2 = ServerNode.createQueue("Queue", 1, distrNorm);
var node3 = ServerNode.createQueue("Queue Wait", 1, distrNorm, distrUnav);
net.addNode(node1);
net.addNode(node2);
net.addNode(node3);
net.addConnection(node1, node2, 1.0);
net.addConnection(node2, node3, 1.0);
net.normalizeWeights();
/// Run multiple simulations
var net = moreComplexNet();
// var maxDepartures = new EndSimulationCriteria.MaxDepartures("Queue", total);
// var maxTime = new EndSimulationCriteria.MaxTime(1000.0);
/// Run multiple simulations
var nano = System.nanoTime();
var sim = new SimulationMultiple(net);
var results = parallel ? sim.runParallel(seed, runs) : sim.run(seed, runs);
@@ -64,6 +45,39 @@ public class Main {
}
}
public static Net simpleNet() {
var lambda = 1.0 / 4.5;
var mu = 3.2;
var sigma = 0.6;
var total = 10000;
var distrExp = new Distribution.Exponential(lambda);
var distrNorm = new Distribution.NormalBoxMuller(mu, sigma);
// Build the network
var net = new Net();
net.addNode(ServerNode.createLimitedSource("Source", distrExp, total));
net.addNode(ServerNode.createQueue("Queue", 1, distrNorm));
net.addConnection(0, 1, 1.0);
net.normalizeWeights();
return net;
}
public static Net moreComplexNet() {
var net = simpleNet();
var distrNorm = new Distribution.NormalBoxMuller(3.2, 0.6);
var distrNorm2 = new Distribution.NormalBoxMuller(4.2, 0.6);
var distrUnav = new Distribution.UnavailableTime(0.2, distrNorm2);
// Build the network
net.addNode(ServerNode.createQueue("Queue Wait", 1, distrNorm, distrUnav));
net.addConnection(1, 2, 1.0);
net.normalizeWeights();
return net;
}
public static Map<String, String> parseParameters(String[] args) {
var arguments = new HashMap<String, Boolean>();
arguments.put("p", false);

View File

@@ -25,14 +25,17 @@ public final class Net {
*
* @param node The server node to add.
* @throws IllegalArgumentException if the node already exist
* @return the index of the created node
*/
public void addNode(ServerNode node) {
public int addNode(ServerNode node) {
if (this.indices.containsKey(node))
throw new IllegalArgumentException("Node already exist");
var index = this.servers.size();
this.servers.add(node);
this.indices.put(node, this.servers.size() - 1);
this.indices.put(node, index);
this.connections.add(new ArrayList<>());
return index;
}
/**
@@ -49,20 +52,36 @@ public final class Net {
public void addConnection(ServerNode parent, ServerNode child, double weight) {
var nodeP = this.indices.get(parent);
var nodeC = this.indices.get(child);
this.addConnection(nodeP, nodeC, weight);
}
/**
* Adds a connection between the nodes with the given weight to select it.
* The weight must be > 0 and the nodes must be already added to the net.
* If the connection is already present then the new weight is used.
*
* @param parent The parent node index.
* @param child The child node index to add.
* @param weight The probability of the child node.
* @throws IndexOutOfBoundsException if one of the two nodes are not in the net
* @throws IllegalArgumentException if the weight is negative or zero
*/
public void addConnection(int parent, int child, double weight) {
if (weight <= 0)
throw new IllegalArgumentException("Weight must be > 0");
if (nodeP == nodeC && nodeP == null)
throw new NullPointerException("One of the nodes does not exist");
var list = this.connections.get(nodeP);
var max = this.servers.size() - 1;
if (parent < 0 || child < 0 || parent > max || child > max)
throw new IndexOutOfBoundsException("One of the nodes does not exist");
var list = this.connections.get(parent);
for (var conn : list) {
if (conn.index == nodeC) {
if (conn.index == child) {
conn.weight = weight;
return;
}
}
list.add(new Connection(nodeC, weight));
list.add(new Connection(child, weight));
}
/**
@@ -75,9 +94,43 @@ public final class Net {
}
/**
* Get one of the child nodes from the parent specified. If the index is out of
* bounds then an
* exception is thrown. If the node has no child then null is returned;
* Return the index of the node based on the name passed as input.
* Note that this will iterate over all the nodes.
*
* @param name the name of the node
* @return the node
*/
public int getNodeIndex(String name) {
for (var entry : this.indices.entrySet()) {
if (entry.getKey().name.equals(name))
return entry.getValue();
}
return -1;
}
/**
* Return a node based on the hash of the string name passed as input
*
* @param name the name of the node
* @return the node
*/
public ServerNode getNode(String name) {
return this.servers.get(this.getNodeIndex(name));
}
/**
* Return a node based on the index, faster than recovering it by the name
*
* @param index the index of the node
* @return the node
*/
public ServerNode getNode(int index) {
return this.servers.get(index);
}
/**
* Get one of the child nodes from the parent specified.
* If the node has no child then null is returned.
*
* @param parent the parent node
* @param rng the random number generator used for getting one of the child
@@ -85,8 +138,22 @@ public final class Net {
*/
public ServerNode getChildOf(ServerNode parent, Rng rng) {
var index = this.indices.get(parent);
return this.getChildOf(index, rng);
}
/**
* Get one of the child nodes from the parent specified. If the index is out of
* bounds then an exception is thrown. If the node has no child then null is
* returned;
*
* @param parent the parent node
* @param rng the random number generator used for getting one of the child
* @throws IndexOutOfBoundsException If the index is not in the range
* @return the resultig node
*/
public ServerNode getChildOf(int parent, Rng rng) {
var random = rng.random();
for (var conn : this.connections.get(index)) {
for (var conn : this.connections.get(parent)) {
random -= conn.weight;
if (random <= 0) {
return this.servers.get(conn.index);
@@ -95,6 +162,37 @@ public final class Net {
return null;
}
/**
* Get a list of all the children of the parent.
* In the list there is the node and the weight associated with.
*
* @param parent the parent node
* @return the list of children
*/
public List<NetChild> getChildren(ServerNode parent) {
var index = this.indices.get(parent);
return this.getChildren(index);
}
/**
* Get a list of all the children of the parent.
* In the list there is the node and the weight associated with.
*
* @param parent the parent node
* @throws IndexOutOfBoundsException If the index is not in the range
* @return the resultig node
*/
public List<NetChild> getChildren(int parent) {
var children = new ArrayList<NetChild>();
for (var conn : this.connections.get(parent)) {
var child = this.servers.get(conn.index);
var listEntry = new NetChild(child, conn.weight);
children.add(listEntry);
}
return children;
}
/**
* Normalizes the weights in each connections so that their sum equals 1.
* This method should be called by the user if they have inserted weights that
@@ -132,4 +230,17 @@ public final class Net {
this.weight = weight;
}
}
/**
* A Static inner class used to represent the connection of a node
*/
public static class NetChild {
public final ServerNode child;
public final double weight;
private NetChild(ServerNode child, double weight) {
this.child = child;
this.weight = weight;
}
}
}

View File

@@ -153,6 +153,7 @@ public final class Simulation {
* distribution.
*
* @param node The node to create the event for.
* @param state The current state of the node
*/
public void addDepartureIfPossible(ServerNode node, NodeState state) {
var canServe = node.maxServers > state.numServerBusy + state.numServerUnavailable;
@@ -167,10 +168,10 @@ public final class Simulation {
}
/**
* TODO
* Add an AVAILABLE event in the case that the node has an unavailability time.
*
* @param node
* @param state
* @param node The node to create the event for
* @param state The current state of the node
*/
public void addUnavailableIfPossible(ServerNode node, NodeState state) {
var delay = node.getUnavailableTime(rng);

View File

@@ -16,8 +16,9 @@ public class SimulationMultiple {
private final Net net;
/**
* TODO
* @param net
* Create a new object that can simulate the net in input multiple times
*
* @param net the net that sould be simulated
*/
public SimulationMultiple(Net net) {
this.net = net;

View File

@@ -40,6 +40,8 @@ public class Result {
* Get the global information of the simulation. In particular this method build
* a string that contains the seed and the time elapsed in the simulation and in
* real time
*
* @return a string with the info
*/
public String getHeader() {
var builder = new StringBuilder();
@@ -52,8 +54,11 @@ public class Result {
/**
* Print a summary of the statistics to the console.
* The summary includes the seed, the simulation time, the elapsed time, and
* the statistics for each node in the network.
* The summary includes all the statistics of nodes and for each it displays the
* departures, queue, wait, response, throughput, utilization, unavailability
* and the last event time.
*
* @return a string with all the stats
*/
public String getSummary() {
String[] h = { "Node", "Departures", "Avg Queue", "Avg Wait", "Avg Response", "Throughput", "Utilization %",
@@ -77,10 +82,14 @@ public class Result {
}
/**
* TODO
* Return a summary formatted for CSV.
* This meaning that all the stats will be separated by a comma (,) and each row
* is a single statistic of the node.
* Each row it will have all the statistic from the class {@link Statistics},
* the seed used for obtaining them.
*
* @param tableHeader
* @return
* @return a string with all the stats formatted
*/
public String getSummaryCSV(boolean tableHeader) {
var builder = new StringBuilder();

View File

@@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.HashSet;
import org.junit.jupiter.api.Test;
import net.berack.upo.valpre.rand.Distribution;
@@ -19,7 +21,7 @@ public class TestSimulation {
private final static class RiggedRng extends Rng {
@Override
public double random() {
return 0.5;
return 0.1;
}
}
@@ -106,9 +108,72 @@ public class TestSimulation {
@Test
public void net() {
// TODO
var net = new Net();
net.addNode(null);
assertEquals(0, net.size());
var node = ServerNode.createSource("First", const0);
var index = net.addNode(node);
assertEquals(1, net.size());
assertEquals(0, index);
assertEquals(node, net.getNode(0));
assertEquals(node, net.getNode("First"));
assertEquals(index, net.getNodeIndex("First"));
var node1 = ServerNode.createQueue("Second", 1, const0);
var index1 = net.addNode(node1);
assertEquals(2, net.size());
assertEquals(0, index);
assertEquals(node, net.getNode(0));
assertEquals(node, net.getNode("First"));
assertEquals(index, net.getNodeIndex("First"));
assertEquals(1, index1);
assertEquals(node1, net.getNode(1));
assertEquals(node1, net.getNode("Second"));
assertEquals(index1, net.getNodeIndex("Second"));
var nodes = new HashSet<ServerNode>();
nodes.add(node);
nodes.add(node1);
net.forEachNode(n -> assertTrue(nodes.contains(n)));
net.addConnection(0, 1, 1.0);
var conn = net.getChildren(0);
assertEquals(1, conn.size());
assertEquals(node1, conn.get(0).child);
assertEquals(1.0, conn.get(0).weight, DELTA);
conn = net.getChildren(1);
assertEquals(0, conn.size());
var node2 = ServerNode.createQueue("Third", 1, const0);
net.addNode(node2);
net.addConnection(0, 2, 1.0);
conn = net.getChildren(0);
assertEquals(2, conn.size());
assertEquals(node1, conn.get(0).child);
assertEquals(node2, conn.get(1).child);
assertEquals(1.0, conn.get(0).weight, DELTA);
assertEquals(1.0, conn.get(1).weight, DELTA);
conn = net.getChildren(1);
assertEquals(0, conn.size());
conn = net.getChildren(2);
assertEquals(0, conn.size());
net.normalizeWeights();
conn = net.getChildren(0);
assertEquals(2, conn.size());
assertEquals(node1, conn.get(0).child);
assertEquals(node2, conn.get(1).child);
assertEquals(0.5, conn.get(0).weight, DELTA);
assertEquals(0.5, conn.get(1).weight, DELTA);
conn = net.getChildren(1);
assertEquals(0, conn.size());
conn = net.getChildren(2);
assertEquals(0, conn.size());
var sample = net.getChildOf(0, rigged);
assertEquals(node1, sample);
sample = net.getChildOf(node, rigged);
assertEquals(node1, sample);
}
@Test