Comments (5)
Yes please, it would be very useful. If you have to model passengers arriving at a train station for example, it would be nice to have a fixed number of customers for each node too(corresponding in this example to a train)
Cause in the meantime I am using a "dummy solution", that is to say that when the last passenger of that train arrives, I put the next interarrival time equal to 100000hours, so that no one else comes to that node during the simulation.
from ciw.
Thank @KAI10
We'd be keen to see what you have done. I'm not sure I quite understand what you mean by "Fixed Number of Customers from each class" though, can you explain further please?
from ciw.
@geraintpalmer Sure.
Currently, there are features for multiple customer classes, and for simulating up to a certain number of customers. For example:
import ciw
N = ciw.create_network(
arrival_distributions={
'Class 0': [
ciw.dists.Exponential(1.0),
ciw.dists.NoArrivals(),
ciw.dists.NoArrivals()
],
'Class 1': [
ciw.dists.Exponential(2.0),
ciw.dists.NoArrivals(),
ciw.dists.NoArrivals()
]
},
service_distributions={
'Class 0': [
ciw.dists.Exponential(4.0),
ciw.dists.Exponential(1.0),
ciw.dists.Deterministic(0.0)
],
'Class 1': [
ciw.dists.Exponential(6.0),
ciw.dists.Deterministic(0.0),
ciw.dists.Exponential(1.0)
]
},
routing={
'Class 0': [
[0.0, 1.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]
],
'Class 1': [
[0.0, 0.0, 1.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]
]
},
number_of_servers=[1, 2, 3],
)
Q.simulate_until_max_customers(100)
However, in the example above, number of customers of Class 0 and Class 1 is not directly specified. It is only ensured that the total number of customers simulated is 100.
The feature that I am talking about lets a user specify the number of customers for each class. An example is shown below:
import ciw
N = ciw.create_network(
arrival_distributions={
'Class 0': [
ciw.dists.Exponential(1.0),
ciw.dists.NoArrivals(),
ciw.dists.NoArrivals()
],
'Class 1': [
ciw.dists.Exponential(2.0),
ciw.dists.NoArrivals(),
ciw.dists.NoArrivals()
]
},
service_distributions={
'Class 0': [
ciw.dists.Exponential(4.0),
ciw.dists.Exponential(1.0),
ciw.dists.Deterministic(0.0)
],
'Class 1': [
ciw.dists.Exponential(6.0),
ciw.dists.Deterministic(0.0),
ciw.dists.Exponential(1.0)
]
},
routing={
'Class 0': [
[0.0, 1.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]
],
'Class 1': [
[0.0, 0.0, 1.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]
]
},
number_of_servers=[1, 2, 3],
number_of_customers_per_class = [80, 20] # specifying how many customers to simulate for each class, i.e 80 for Class 0, 20 for Class 1
)
Q.simulate_until_max_customers(100)
from ciw.
Hi @KAI10 I think this can be done by defining custom distributions:
As an example consider the following system:
N = ciw.create_network(
arrival_distributions={
'Class 0': [ciw.dists.Exponential(1)],
'Class 1': [ciw.dists.Exponential(1)]},
service_distributions={
'Class 0': [ciw.dists.Exponential(3)],
'Class 1': [ciw.dists.Exponential(3)]},
number_of_servers=[2]
)
Running we get:
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(100)
>>> recs = Q.get_all_records()
>>> len([r for r in recs if r.customer_class==0])
88
>>> len([r for r in recs if r.customer_class==1])
105
88 customers in of Class 0 and 105 customers of Class 1.
Now say we only want 40 customers of Class 0. We can difine a new Exponential distribution:
class LimitedExponential(ciw.dists.Exponential):
def __init__(self, rate, limit):
super().__init__(rate)
self.limit = limit
self.number_of_customers_sampled = 0
def sample(self, t=None, ind=None):
if self.number_of_customers_sampled < self.limit:
self.number_of_customers_sampled += 1
return super().sample()
else:
return float('Inf')
And using it we get:
>>> N = ciw.create_network(
... arrival_distributions={
... 'Class 0': [LimitedExponential(1, 40)],
... 'Class 1': [ciw.dists.Exponential(1)]},
... service_distributions={
... 'Class 0': [ciw.dists.Exponential(3)],
... 'Class 1': [ciw.dists.Exponential(3)]},
... number_of_servers=[2]
... )
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(100)
>>> recs = Q.get_all_records()
>>> len([r for r in recs if r.customer_class==0])
40
>>> len([r for r in recs if r.customer_class==1])
105
After 40 observations were sampled, the next arrival happens at time infinity, so no more arivals.
The above only works if all customers of that class arrive at the same node (hence using the same Distribution object). If you want to track the total number of customers of that class, then you'll need to define a true state dependent distribution that looks at the number of customers of that class that have arrived altogether. This is possible in the latest version of Ciw, v2.1.1 (https://ciw.readthedocs.io/en/latest/Guides/time_dependent.html), where the Distributions objects have access to the Simulation object itself, and hence its state.
For example:
class LimitedExponential(ciw.dists.Exponential):
def __init__(self, rate, limit):
super().__init__(rate)
self.limit = limit
def __repr__(self):
return 'Limited Exponential ' + str(self.rate)
def sample(self, t=None, ind=None):
if self.simulation.nodes[0].number_of_individuals_per_class[0] < self.limit:
return super().sample()
else:
return float('Inf')
So we are checking against self.simulation.nodes[0].number_of_individuals_per_class[0]
, the number of individuals of class 0 created at the arrival node.
>>> N = ciw.create_network(
... arrival_distributions={
... 'Class 0': [LimitedExponential(1, 40), LimitedExponential(1, 40), LimitedExponential(1, 40)],
... 'Class 1': [ciw.dists.Exponential(1), ciw.dists.Exponential(1), ciw.dists.Exponential(1)]},
... service_distributions={
... 'Class 0': [ciw.dists.Exponential(3), ciw.dists.Exponential(3), ciw.dists.Exponential(3)],
... 'Class 1': [ciw.dists.Exponential(3), ciw.dists.Exponential(3), ciw.dists.Exponential(3)]},
... number_of_servers=[2, 2, 2],
... routing={
... 'Class 0': [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]],
... 'Class 1': [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]}
... )
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(100)
>>> recs = Q.get_all_records()
>>> len([r for r in recs if r.customer_class==0])
42
>>> len([r for r in recs if r.customer_class==1])
300
Notice here, even though we set the limit as 40, we sample 42 customers. Thats because we have 3 different nodes, all sampling a new customer when the number of customers is below 40. For example, when the number of customers is 39, all three will be allowed to sample a customer, because all three see that the simulation has not reached the limit of number of customers. I am not sure yet how to get around that.
I hope this helps, let me know what you think.
from ciw.
The solution you suggested is clean, at least cleaner than what I did, which was adding some conditions in arrival_node.py
. I definitely prefer your solution. Thanks. I am closing the issue.
from ciw.
Related Issues (20)
- can Ciw set a state-dependent system capacity allocation for simulation? HOT 3
- error rate HOT 4
- Wishlist for Ciw 3.0 HOT 9
- re-entrance customer with dynamic priority HOT 6
- Emulate Simpy's Machine Shop example HOT 5
- Type Annotations HOT 1
- Black Code Formatter HOT 1
- Recommended practices for model configuration storage HOT 1
- How to implement class-selective servers?
- [Question]: What happens when service discipline returns None? HOT 1
- Slotted undocumented HOT 2
- [Feature Request] Failure to start service HOT 2
- [FYI] Are there other types of blocking in queueing networks beyond Type I? HOT 1
- [Feature Request] Time/State-Dependent Baulking HOT 3
- [Media Request] Wikipedia Article HOT 3
- [FYI] Wikipedia Article Draft
- [FYI] Ciw examples of Wikipedia Articles HOT 1
- [Feature Request] Service linger time and batch serving HOT 3
- Consider getting open peer review of package by pyOpenSci HOT 2
- NumPy 2.0 Migration
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ciw.