Merge branch 'unavailable_logic'

This commit is contained in:
2025-01-28 19:27:21 +01:00
8 changed files with 220 additions and 87 deletions

View File

@@ -29,13 +29,21 @@ public class Main {
csv = arguments.get("csv"); csv = arguments.get("csv");
var parallel = arguments.containsKey("p"); 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 // Build the network
var net = new Net(); var net = new Net();
var node1 = ServerNode.createLimitedSource("Source", new Distribution.Exponential(lambda), total); var node1 = ServerNode.createLimitedSource("Source", distrExp, total);
var node2 = ServerNode.createQueue("Queue", 1, new Distribution.NormalBoxMuller(mu, sigma)); var node2 = ServerNode.createQueue("Queue", 1, distrNorm);
var node3 = ServerNode.createQueue("Queue Wait", 1, distrNorm, distrUnav);
net.addNode(node1); net.addNode(node1);
net.addNode(node2); net.addNode(node2);
net.addNode(node3);
net.addConnection(node1, node2, 1.0); net.addConnection(node1, node2, 1.0);
net.addConnection(node2, node3, 1.0);
net.normalizeWeights(); net.normalizeWeights();
/// Run multiple simulations /// Run multiple simulations

View File

@@ -4,8 +4,34 @@ package net.berack.upo.valpre.rand;
* Represents a probability distribution. * Represents a probability distribution.
*/ */
public interface Distribution { public interface Distribution {
/**
* Return a sample from the distribution.
*
* @param rng The random number generator to use.
* @return A number given from the distribution.
*/
public double sample(Rng rng); public double sample(Rng rng);
/**
* Gets a positive sample from the distribution.
* This is useful if you need to generate a positive value from a distribution
* that can generate negative values. For example, the normal distribution.
*
* @param distribution The distribution to sample
* @param rng The random number generator to use.
* @return A positive or 0 value from the distribution.
*/
public static double getPositiveSample(Distribution distribution, Rng rng) {
if (distribution == null)
return 0;
double sample;
do {
sample = distribution.sample(rng);
} while (sample < 0);
return sample;
}
/** /**
* Represents an exponential distribution. * Represents an exponential distribution.
*/ */
@@ -172,4 +198,30 @@ public interface Distribution {
return -Math.log(rng.random()) / lambdas[i]; return -Math.log(rng.random()) / lambdas[i];
} }
} }
/**
* TODO
*/
public static class UnavailableTime implements Distribution {
public final double probability;
public final Distribution distribution;
/**
* TODO
*
* @param probability
* @param distribution
*/
public UnavailableTime(double probability, Distribution distribution) {
this.probability = probability;
this.distribution = distribution;
}
@Override
public double sample(Rng rng) {
if (rng.random() < this.probability)
return Distribution.getPositiveSample(this.distribution, rng);
return 0.0;
}
}
} }

View File

@@ -30,19 +30,6 @@ public class Event implements Comparable<Event> {
return 1; return 1;
} }
/**
* Create a new event.
*
* @param node The node that the event is associated with.
* @param time The time at which the event occurs.
* @param type The type of event.
*
* @return The new event.
*/
public static Event newType(ServerNode node, double time, Type type) {
return new Event(type, node, time);
}
/** /**
* Create a new arrival event. * Create a new arrival event.
* *
@@ -65,11 +52,23 @@ public class Event implements Comparable<Event> {
return new Event(Type.DEPARTURE, node, time); return new Event(Type.DEPARTURE, node, time);
} }
/**
* Create a new available 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 newAvailable(ServerNode node, double time) {
return new Event(Type.AVAILABLE, node, time);
}
/** /**
* The type of event. * The type of event.
*/ */
public static enum Type { public static enum Type {
ARRIVAL, ARRIVAL,
DEPARTURE, DEPARTURE,
AVAILABLE,
} }
} }

View File

@@ -11,7 +11,8 @@ public class ServerNode {
public final String name; public final String name;
public final int maxServers; public final int maxServers;
public final int spawnArrivals; public final int spawnArrivals;
public final Distribution distribution; public final Distribution service;
public final Distribution unavailable;
/** /**
* Creates a source node with the given name and distribution. * Creates a source node with the given name and distribution.
@@ -23,7 +24,7 @@ public class ServerNode {
* @return The created source node. * @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, Integer.MAX_VALUE); return new ServerNode(name, Integer.MAX_VALUE, distribution, null, Integer.MAX_VALUE);
} }
/** /**
@@ -31,25 +32,39 @@ public class ServerNode {
* arrivals to spawn that are served by infinite servers (Integer.MAX_VALUE). * arrivals to spawn that are served by infinite servers (Integer.MAX_VALUE).
* *
* @param name The name of the node. * @param name The name of the node.
* @param distribution The distribution of the inter-arrival times. * @param service The distribution of the inter-arrival times.
* @param spawnArrivals The number of arrivals to spawn. * @param spawnArrivals The number of arrivals to spawn.
* @return The created source node. * @return The created source node.
*/ */
public static ServerNode createLimitedSource(String name, Distribution distribution, int spawnArrivals) { public static ServerNode createLimitedSource(String name, Distribution service, int spawnArrivals) {
return new ServerNode(name, Integer.MAX_VALUE, distribution, spawnArrivals); return new ServerNode(name, Integer.MAX_VALUE, service, null, spawnArrivals);
} }
/** /**
* Creates a queue node with the given name, maximum number of servers, and * Creates a queue node with the given name, maximum number of servers, and
* distribution. * distribution.
* *
* @param name The name of the node. * @param name The name of the node.
* @param maxServers The maximum number of servers in the queue. * @param maxServers The maximum number of servers in the queue.
* @param distribution The distribution of the service times. * @param service The distribution of the service times.
* @return The created queue node. * @return The created queue node.
*/ */
public static ServerNode createQueue(String name, int maxServers, Distribution distribution) { public static ServerNode createQueue(String name, int maxServers, Distribution service) {
return new ServerNode(name, maxServers, distribution, 0); return new ServerNode(name, maxServers, service, null, 0);
}
/**
* 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 service The distribution of the service times.
* @param unavailable The distribution of the unavailable times after service.
* @return The created queue node.
*/
public static ServerNode createQueue(String name, int maxServers, Distribution service, Distribution unavailable) {
return new ServerNode(name, maxServers, service, unavailable, 0);
} }
/** /**
@@ -60,13 +75,14 @@ public class ServerNode {
* *
* @param name The name of the node. * @param name The name of the node.
* @param maxServers The maximum number of servers in the queue. * @param maxServers The maximum number of servers in the queue.
* @param distribution The distribution of the service times. * @param service The distribution of the service times.
* @param unavailable The distribution of the unavailable times after service.
* @param spawnArrivals The number of arrivals to spawn. * @param spawnArrivals The number of arrivals to spawn.
* @throws NullPointerException if the distribution is null * @throws NullPointerException if the distribution is null
*/ */
public ServerNode(String name, int maxServers, Distribution distribution, int spawnArrivals) { private ServerNode(String name, int maxServers, Distribution service, Distribution unavailable, int spawnArrivals) {
if (distribution == null) if (service == null)
throw new NullPointerException("Distribution can't be null"); throw new NullPointerException("Service distribution can't be null");
if (maxServers <= 0) if (maxServers <= 0)
maxServers = 1; maxServers = 1;
if (spawnArrivals < 0) if (spawnArrivals < 0)
@@ -74,8 +90,9 @@ public class ServerNode {
this.name = name; this.name = name;
this.maxServers = maxServers; this.maxServers = maxServers;
this.distribution = distribution;
this.spawnArrivals = spawnArrivals; this.spawnArrivals = spawnArrivals;
this.service = service;
this.unavailable = unavailable;
} }
/** /**
@@ -86,12 +103,18 @@ public class ServerNode {
* @param rng The random number generator to use. * @param rng The random number generator to use.
* @return A positive sample from the distribution. * @return A positive sample from the distribution.
*/ */
public double getPositiveSample(Rng rng) { public double getServiceTime(Rng rng) {
double sample; return Distribution.getPositiveSample(this.service, rng);
do { }
sample = this.distribution.sample(rng);
} while (sample < 0); /**
return sample; * Return the unavailable time after a service
*
* @param rng The random number generator to use.
* @return A positive or 0 value from the distribution.
*/
public double getUnavailableTime(Rng rng) {
return Distribution.getPositiveSample(this.unavailable, rng);
} }
/** /**
@@ -105,6 +128,14 @@ public class ServerNode {
return this.spawnArrivals > Math.max(0, numArrivals); return this.spawnArrivals > Math.max(0, numArrivals);
} }
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ServerNode))
return false;
var other = (ServerNode) obj;
return obj.hashCode() == other.hashCode();
}
@Override @Override
public int hashCode() { public int hashCode() {
return this.name.hashCode(); return this.name.hashCode();

View File

@@ -26,7 +26,7 @@ public final class Simulation {
* Creates a new run of the simulation with the given nodes and random number * Creates a new run of the simulation with the given nodes and random number
* generator. * generator.
* *
* @param states The nodes in the network. * @param states The nodes in the network.
* @param rng The random number generator to use. * @param rng The random number generator to use.
* @param criterias when the simulation has to end. * @param criterias when the simulation has to end.
*/ */
@@ -73,32 +73,32 @@ public final class Simulation {
this.time = event.time; this.time = event.time;
switch (event.type) { switch (event.type) {
case AVAILABLE -> {
state.stats.updateTimes(this.time, state.numServerBusy, state.numServerUnavailable, node.maxServers);
state.numServerUnavailable--;
this.addDepartureIfPossible(node, state);
}
case ARRIVAL -> { case ARRIVAL -> {
state.queue.add(this.time); state.queue.add(this.time);
state.stats.updateArrival(this.time, state.queue.size(), state.numServerBusy != 0); state.stats.updateArrival(this.time, state.queue.size());
state.stats.updateTimes(this.time, state.numServerBusy, state.numServerUnavailable, node.maxServers);
if (state.numServerBusy < node.maxServers) { this.addDepartureIfPossible(node, state);
state.numServerBusy++;
this.addDeparture(node);
}
} }
case DEPARTURE -> { case DEPARTURE -> {
var startService = state.queue.poll(); var arrivalTime = state.queue.poll();
state.stats.updateDeparture(this.time, this.time - startService); state.stats.updateDeparture(this.time, arrivalTime);
state.stats.updateTimes(this.time, state.numServerBusy, state.numServerUnavailable, node.maxServers);
state.numServerBusy--;
if (state.numServerBusy > state.queue.size()) { this.addUnavailableIfPossible(node, state);
state.numServerBusy--; this.addDepartureIfPossible(node, state);
} else {
this.addDeparture(node);
}
var next = this.net.getChildOf(node, this.rng); var next = this.net.getChildOf(node, this.rng);
if (next != null) { if (next != null)
this.addArrival(next); this.addArrival(next);
}
if (node.shouldSpawnArrival(state.stats.numArrivals)) { if (node.shouldSpawnArrival(state.stats.numArrivals))
this.addArrival(node); this.addArrival(node);
}
} }
} }
} }
@@ -149,14 +149,36 @@ public final class Simulation {
/** /**
* Adds a departure event to the future event list. The event is created based * Adds a departure event to the future event list. The event is created based
* on the given node, and the delay is determined by the node's distribution. * on the given node, and the delay is determined by the node's service
* distribution.
* *
* @param node The node to create the event for. * @param node The node to create the event for.
*/ */
public void addDeparture(ServerNode node) { public void addDepartureIfPossible(ServerNode node, NodeState state) {
var delay = node.getPositiveSample(this.rng); var canServe = node.maxServers > state.numServerBusy + state.numServerUnavailable;
var event = Event.newDeparture(node, this.time + delay); var hasRequests = state.queue.size() > state.numServerBusy;
fel.add(event);
if (canServe && hasRequests) {
state.numServerBusy++;
var delay = node.getServiceTime(this.rng);
var event = Event.newDeparture(node, this.time + delay);
fel.add(event);
}
}
/**
* TODO
*
* @param node
* @param state
*/
public void addUnavailableIfPossible(ServerNode node, NodeState state) {
var delay = node.getUnavailableTime(rng);
if (delay > 0) {
state.numServerUnavailable++;
var event = Event.newAvailable(node, time + delay);
this.fel.add(event);
}
} }
/** /**
@@ -183,7 +205,8 @@ public final class Simulation {
*/ */
public static class NodeState { public static class NodeState {
public int numServerBusy = 0; public int numServerBusy = 0;
public int numServerUnavailable = 0;
public final Statistics stats = new Statistics(); public final Statistics stats = new Statistics();
private final ArrayDeque<Double> queue = new ArrayDeque<>(); public final ArrayDeque<Double> queue = new ArrayDeque<>();
} }
} }

View File

@@ -31,7 +31,7 @@ public class Result {
this.simulationTime = time; this.simulationTime = time;
this.timeElapsedMS = elapsed; this.timeElapsedMS = elapsed;
this.nodes = nodes; this.nodes = nodes;
this.size = (int) Math.ceil(Math.log10(this.simulationTime)); this.size = (int) Math.ceil(Math.max(Math.log10(this.simulationTime), 1));
this.iFormat = "%" + this.size + ".0f"; this.iFormat = "%" + this.size + ".0f";
this.fFormat = "%" + (this.size + 4) + ".3f"; this.fFormat = "%" + (this.size + 4) + ".3f";
} }
@@ -57,7 +57,7 @@ public class Result {
*/ */
public String getSummary() { public String getSummary() {
String[] h = { "Node", "Departures", "Avg Queue", "Avg Wait", "Avg Response", "Throughput", "Utilization %", String[] h = { "Node", "Departures", "Avg Queue", "Avg Wait", "Avg Response", "Throughput", "Utilization %",
"Last Event" }; "Unavailable %", "Last Event" };
var table = new ConsoleTable(h); var table = new ConsoleTable(h);
for (var entry : this.nodes.entrySet()) { for (var entry : this.nodes.entrySet()) {
@@ -70,6 +70,7 @@ public class Result {
fFormat.formatted(stats.avgResponse), fFormat.formatted(stats.avgResponse),
fFormat.formatted(stats.troughput), fFormat.formatted(stats.troughput),
fFormat.formatted(stats.utilization * 100), fFormat.formatted(stats.utilization * 100),
fFormat.formatted(stats.unavailable * 100),
fFormat.formatted(stats.lastEventTime)); fFormat.formatted(stats.lastEventTime));
} }
return table.toString(); return table.toString();
@@ -86,7 +87,7 @@ public class Result {
if (tableHeader) if (tableHeader)
builder.append( builder.append(
"Seed,Node,Arrivals,Departures,MaxQueue,AvgQueue,AvgWait,AvgResponse,BusyTime,WaitTime,ResponseTime,LastEventTime,Throughput,Utilization\n"); "Seed,Node,Arrivals,Departures,MaxQueue,AvgQueue,AvgWait,AvgResponse,BusyTime,WaitTime,UnavailableTime,ResponseTime,LastEventTime,Throughput,Utilization,Unavailable\n");
for (var entry : this.nodes.entrySet()) { for (var entry : this.nodes.entrySet()) {
var stats = entry.getValue(); var stats = entry.getValue();
builder.append(this.seed); builder.append(this.seed);
@@ -109,6 +110,8 @@ public class Result {
builder.append(','); builder.append(',');
builder.append(stats.waitTime); builder.append(stats.waitTime);
builder.append(','); builder.append(',');
builder.append(stats.unavailableTime);
builder.append(',');
builder.append(stats.responseTime); builder.append(stats.responseTime);
builder.append(','); builder.append(',');
builder.append(stats.lastEventTime); builder.append(stats.lastEventTime);
@@ -116,6 +119,8 @@ public class Result {
builder.append(stats.troughput); builder.append(stats.troughput);
builder.append(','); builder.append(',');
builder.append(stats.utilization); builder.append(stats.utilization);
builder.append(',');
builder.append(stats.unavailable);
builder.append('\n'); builder.append('\n');
} }
return builder.toString(); return builder.toString();

View File

@@ -11,6 +11,7 @@ public class Statistics {
public double numDepartures = 0.0d; public double numDepartures = 0.0d;
public double maxQueueLength = 0.0d; public double maxQueueLength = 0.0d;
public double avgQueueLength = 0.0d; public double avgQueueLength = 0.0d;
public double unavailableTime = 0.0d;
public double busyTime = 0.0d; public double busyTime = 0.0d;
public double waitTime = 0.0d; public double waitTime = 0.0d;
public double responseTime = 0.0d; public double responseTime = 0.0d;
@@ -21,6 +22,7 @@ public class Statistics {
public double avgResponse = 0.0d; public double avgResponse = 0.0d;
public double troughput = 0.0d; public double troughput = 0.0d;
public double utilization = 0.0d; public double utilization = 0.0d;
public double unavailable = 0.0d;
/** /**
* TODO * TODO
@@ -29,16 +31,12 @@ public class Statistics {
* @param newQueueSize * @param newQueueSize
* @param updateBusy * @param updateBusy
*/ */
public void updateArrival(double time, double newQueueSize, boolean updateBusy) { public void updateArrival(double time, double newQueueSize) {
var total = this.avgQueueLength * this.numArrivals; var total = this.avgQueueLength * this.numArrivals;
this.numArrivals++; this.numArrivals++;
this.avgQueueLength = (total + newQueueSize) / this.numArrivals; this.avgQueueLength = (total + newQueueSize) / this.numArrivals;
this.maxQueueLength = Math.max(this.maxQueueLength, newQueueSize); this.maxQueueLength = Math.max(this.maxQueueLength, newQueueSize);
if (updateBusy)
this.busyTime += time - this.lastEventTime;
this.lastEventTime = time;
} }
/** /**
@@ -49,15 +47,30 @@ public class Statistics {
*/ */
public void updateDeparture(double time, double response) { public void updateDeparture(double time, double response) {
this.numDepartures++; this.numDepartures++;
this.responseTime += response; this.responseTime += time - response;
this.busyTime += time - this.lastEventTime; }
this.lastEventTime = time;
this.waitTime = this.responseTime - this.busyTime;
/**
* TODO
*
* @param time
* @param serverBusy
* @param serverUnavailable
*/
public void updateTimes(double time, int serverBusy, int serverUnavailable, int maxServers) {
if (serverBusy > 0)
this.busyTime += time - this.lastEventTime;
else if (serverUnavailable == maxServers)
this.unavailableTime += time - this.lastEventTime;
this.waitTime = this.responseTime - this.busyTime;
this.avgWaitTime = this.waitTime / this.numDepartures; this.avgWaitTime = this.waitTime / this.numDepartures;
this.avgResponse = this.responseTime / this.numDepartures; this.avgResponse = this.responseTime / this.numDepartures;
this.troughput = this.numDepartures / this.lastEventTime; this.troughput = this.numDepartures / time;
this.utilization = this.busyTime / this.lastEventTime; this.utilization = this.busyTime / time;
this.unavailable = this.unavailableTime / time;
this.lastEventTime = time;
} }
/** /**
@@ -106,11 +119,13 @@ public class Statistics {
save.avgQueueLength = func.apply(val1.avgQueueLength, val2.avgQueueLength); save.avgQueueLength = func.apply(val1.avgQueueLength, val2.avgQueueLength);
save.busyTime = func.apply(val1.busyTime, val2.busyTime); save.busyTime = func.apply(val1.busyTime, val2.busyTime);
save.responseTime = func.apply(val1.responseTime, val2.responseTime); save.responseTime = func.apply(val1.responseTime, val2.responseTime);
save.unavailableTime = func.apply(val1.unavailableTime, val2.unavailableTime);
save.waitTime = func.apply(val1.waitTime, val2.waitTime); save.waitTime = func.apply(val1.waitTime, val2.waitTime);
save.lastEventTime = func.apply(val1.lastEventTime, val2.lastEventTime); save.lastEventTime = func.apply(val1.lastEventTime, val2.lastEventTime);
// derived stats // derived stats
save.avgWaitTime = func.apply(val1.avgWaitTime, val2.avgWaitTime); save.avgWaitTime = func.apply(val1.avgWaitTime, val2.avgWaitTime);
save.avgResponse = func.apply(val1.avgResponse, val2.avgResponse); save.avgResponse = func.apply(val1.avgResponse, val2.avgResponse);
save.unavailable = func.apply(val1.unavailable, val2.unavailable);
save.troughput = func.apply(val1.troughput, val2.troughput); save.troughput = func.apply(val1.troughput, val2.troughput);
save.utilization = func.apply(val1.utilization, val2.utilization); save.utilization = func.apply(val1.utilization, val2.utilization);
} }

View File

@@ -14,7 +14,7 @@ public class TestSimulation {
private static double DELTA = 0.0000001; private static double DELTA = 0.0000001;
private static Rng rigged = new RiggedRng(); private static Rng rigged = new RiggedRng();
private static Distribution const0 = new Constant(0.0); private static Distribution const0 = new Constant(0.0);
private static Distribution const1 = new Constant(0.0); private static Distribution const1 = new Constant(1.0);
private final static class RiggedRng extends Rng { private final static class RiggedRng extends Rng {
@Override @Override
@@ -38,7 +38,7 @@ public class TestSimulation {
@Test @Test
public void serverNode() { public void serverNode() {
var node = new ServerNode("Nodo", 0, const1, 0); var node = ServerNode.createQueue("Nodo", 0, const1);
assertEquals("Nodo", node.name); assertEquals("Nodo", node.name);
assertEquals(1, node.maxServers); assertEquals(1, node.maxServers);
assertFalse(node.shouldSpawnArrival(0)); assertFalse(node.shouldSpawnArrival(0));
@@ -46,7 +46,7 @@ public class TestSimulation {
assertFalse(node.shouldSpawnArrival(1000)); assertFalse(node.shouldSpawnArrival(1000));
assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE)); assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE));
assertFalse(node.shouldSpawnArrival(-1)); assertFalse(node.shouldSpawnArrival(-1));
assertEquals(1.0, node.getPositiveSample(null), DELTA); assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createQueue("Queue", 50, const1); node = ServerNode.createQueue("Queue", 50, const1);
assertEquals("Queue", node.name); assertEquals("Queue", node.name);
@@ -56,7 +56,7 @@ public class TestSimulation {
assertFalse(node.shouldSpawnArrival(1000)); assertFalse(node.shouldSpawnArrival(1000));
assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE)); assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE));
assertFalse(node.shouldSpawnArrival(-1)); assertFalse(node.shouldSpawnArrival(-1));
assertEquals(1.0, node.getPositiveSample(null), DELTA); assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createSource("Source", const1); node = ServerNode.createSource("Source", const1);
assertEquals("Source", node.name); assertEquals("Source", node.name);
@@ -67,7 +67,7 @@ public class TestSimulation {
assertTrue(node.shouldSpawnArrival(Integer.MAX_VALUE - 1)); assertTrue(node.shouldSpawnArrival(Integer.MAX_VALUE - 1));
assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE)); assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE));
assertTrue(node.shouldSpawnArrival(-1)); assertTrue(node.shouldSpawnArrival(-1));
assertEquals(1.0, node.getPositiveSample(null), DELTA); assertEquals(1.0, node.getServiceTime(null), DELTA);
node = ServerNode.createLimitedSource("Source", const1, 50); node = ServerNode.createLimitedSource("Source", const1, 50);
assertEquals("Source", node.name); assertEquals("Source", node.name);
@@ -78,25 +78,25 @@ public class TestSimulation {
assertFalse(node.shouldSpawnArrival(1000)); assertFalse(node.shouldSpawnArrival(1000));
assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE)); assertFalse(node.shouldSpawnArrival(Integer.MAX_VALUE));
assertTrue(node.shouldSpawnArrival(-1)); assertTrue(node.shouldSpawnArrival(-1));
assertEquals(1.0, node.getPositiveSample(null), DELTA); assertEquals(1.0, node.getServiceTime(null), DELTA);
} }
@Test @Test
public void event() { public void event() {
var node = ServerNode.createSource("Source", const0); var node = ServerNode.createSource("Source", const0);
var event = Event.newType(node, 0, Event.Type.ARRIVAL); var event = Event.newAvailable(node, 1.0);
assertEquals(node, event.node); assertEquals(node, event.node);
assertEquals(0.0, event.time, 0.000000000001); assertEquals(1.0, event.time, 0.000000000001);
assertEquals(Event.Type.ARRIVAL, event.type); assertEquals(Event.Type.AVAILABLE, event.type);
var event2 = Event.newArrival(node, 1.0); var event2 = Event.newArrival(node, 5.0);
assertEquals(node, event2.node); assertEquals(node, event2.node);
assertEquals(1.0, event2.time, 0.000000000001); assertEquals(5.0, event2.time, 0.000000000001);
assertEquals(Event.Type.ARRIVAL, event2.type); assertEquals(Event.Type.ARRIVAL, event2.type);
var event3 = Event.newDeparture(node, 5.0); var event3 = Event.newDeparture(node, 8.0);
assertEquals(node, event3.node); assertEquals(node, event3.node);
assertEquals(5.0, event3.time, 0.000000000001); assertEquals(8.0, event3.time, 0.000000000001);
assertEquals(Event.Type.DEPARTURE, event3.type); assertEquals(Event.Type.DEPARTURE, event3.type);
assertEquals(0, event2.compareTo(event2)); assertEquals(0, event2.compareTo(event2));