Test Net
- added net test - added more docs
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user