I have defined a generator which generates Poisson arrival rates to the system. I want each generated arrival (customer) has a random (x,y) which shows the location of the arrival customer to the system. i.e I want to generate Poisson arrival rate to the system where each arrival is coming from a random location. Let's assume x is in range 50 and y in range 60.
How can I add this to the following code?
class Arrival(object):
def __init__(self, stream_defin, referrer):
self.service = stream_defin["service"]
self.arrival_rate = stream_defin["rate"]
self.referrer = referrer
def sim_init(self, env,sim_stats):
self.sim_stats = sim_stats
self.env = env
self.env.process(self.sim_arrival_generator())
def sim_arrival_generator(self):
i = 0
while True:
interarrival = spstats.expon(scale=1/self.arrival_rate).rvs()
yield self.env.timeout(interarrival)
i+=1
Your code refers to a number of objects and methods that you don't provide the definitions for. This makes it hard to know what you're looking for exactly. Plus, I'm not sure I even understand what you want conceptually. But if I take the simplest interpretation of what you're asking for, here's what I'd suggest:
I assume that this line is currently creating an "arrival", which is referenced by the interarrival
variable:
interarrival = spstats.expon(scale=1/self.arrival_rate).rvs()
This value seems to currently be a delay value such that the pattern of successive delays covers a Poisson distribution pattern. Rather than just a time value, you want at this point in your code to be creating a delay along with a random position given by x
and y
coordinates, and have these together represent an "arrival".
What I would suggest is to create a Python dictionary object to represent each arrival. Here's how you could do that:
interarrival = {
'delay': spstats.expon(scale=1 / self.arrival_rate).rvs(),
'position': {
'x': random.randint(self.min_x, self.max_x),
'y': random.randint(self.min_y, self.max_y)
}
}
Doing a bunch of coding work in an answer isn't what S.O. is really about, but you caught me at a moment of boredom, and I hate providing code I haven't actually run, so...
I took a lot of liberties and filled out your code so that it would actually run and "do something", although all it does is delay between arrivals and print the value of each arrival as it comes through. I assumed you wanted to see an actual delay because of your call to self.env.timeout
and because your generator never stops generating arrivals. Without the delay or some time consuming processing, this code would quickly spew thousands of arrivals that you couldn't read.
I renamed your class from Arrival
to Arrivals
because the code within deals with a stream of arrivals, not a single arrival, and I couldn't think of a good way to change that without making many more changes. I tried to mostly add code, and change as little of your provided code as possible. With all this in mind, here's what I came up with:
import scipy.stats as spstats
import random
import json
import time
class Arrivals(object):
def __init__(self, stream_defin, referrer):
self.service = stream_defin["service"]
self.arrival_rate = stream_defin["rate"]
self.min_x, self.max_x = stream_defin["min_x"], stream_defin["max_x"]
self.min_y, self.max_y = stream_defin["min_y"], stream_defin["max_y"]
self.referrer = referrer
def sim_init(self, env, sim_stats):
self.sim_stats = sim_stats
self.env = env
self.env.process(self.sim_arrival_generator())
return self
def sim_arrival_generator(self):
i = 0
while True:
interarrival = {
'index': i,
'delay': spstats.expon(scale=1 / self.arrival_rate).rvs(),
'position': {
'x': random.randint(self.min_x, self.max_x),
'y': random.randint(self.min_y, self.max_y)
}
}
yield self.env.timeout(interarrival)
i += 1
class Env():
def process(self, arrivals):
for arrival in arrivals:
# Do whatever needs to be done with each arrival
print('Processing arrival: ')
print(json.dumps(arrival, indent=4))
def timeout(self, arrival):
# Delay the arrival by its delay time before delivering for processing
print("Delaying %2.2f seconds..." % (arrival['delay']))
time.sleep(arrival['delay'])
return arrival
def main():
stream_defin = {
'service': 'service',
'rate': 0.5,
'min_x': 5,
'max_x': 50,
'min_y': 10,
'max_y': 60
}
stats = [] # a place to collect results, I assume
Arrivals(stream_defin, 'referrer').sim_init(Env(), stats)
main()
This thing runs forever, so you have to CTRL-C out of it when you want to stop it. It would be easy to add an iterations
config value to limit the number of iterations. You could either add this to the generator itself, or just break out of the process()
method when the specified iteration count is reached.
Sample results (with actual delays in output as noted):
Delaying 5.39 seconds...
Processing arrival:
{
"index": 0,
"delay": 5.394974068076859,
"position": {
"x": 34,
"y": 29
}
}
Delaying 1.51 seconds...
Processing arrival:
{
"index": 1,
"delay": 1.5095025601339542,
"position": {
"x": 24,
"y": 24
}
}
Delaying 1.48 seconds...
Processing arrival:
{
"index": 2,
"delay": 1.4840036046166114,
"position": {
"x": 28,
"y": 57
}
}
Delaying 4.09 seconds...
Processing arrival:
{
"index": 3,
"delay": 4.08649062133332,
"position": {
"x": 37,
"y": 14
}
}
...