Closed galenseilis closed 6 months ago
Hi, I love this idea. In fact, the baulking function could just take in the simulation object itself, and then have access to any property of the system it needs, including the time?
e.g.
def probability_of_baulking(Q, node_id):
if len(Q.nodes[node_id].all_customers) < 3:
return 0.0
if len(Q.nodes[node_id].all_customers) < 7:
return 0.5
return 1.0
What do you think?
Hi, I love this idea. In fact, the baulking function could just take in the simulation object itself, and then have access to any property of the system it needs, including the time?
e.g.
def probability_of_baulking(Q, node_id): if len(Q.nodes[node_id].all_customers) < 3: return 0.0 if len(Q.nodes[node_id].all_customers) < 7: return 0.5 return 1.0
What do you think?
Thank you for considering my ideas! 😊
I can see how passing the simulation to probability_of_baulking
naturally gives access to the top-level. From there the time and state can be accessed. I'm wondering, how would probability_of_baulking
know which individual is being considered for baulking. That would be important for individual-dependent baulking behaviour. Would there be a natural way to access that information if the function signature was probability_of_baulking(Q, node_id)
?
Here is my thinking for the function signature I suggested. Using the probability_of_baulking(next_node, next_individual)
signature would communicate the pair of node and individual in consideration. In my opinion this is a natural default. However, if the time was needed, one could always use next_individual.simulation.current_time
since every individual has a reference of simulation as an instance attribute. Similarly, next_individual.simulation.nodes
should give access to arbitrary state information.
I suppose another option would be something like probability_of_baulking(Q, node_id, ind_id)
, but that means performing a search for the instance of the next node if we wanted it. It doesn't seem like a good option.
I know, I am slightly modifying the term type signature to a related note I am terming "function signature". I really am just talking about what parameters the function has.
Further discussion on this is welcome! I am still unfamiliar with most of the mechanisms in Ciw, so I may be missing something.
Implemented here: 9d00262de505e163405f135bd630f26278fee959
I noticed that
arrival_node.ArrivalNode.decide_baulk
is responsible for making a decision about whether to baulk an instance ofIndividual
.Here is the implementation:
Baulking is conventionally thought of as customers deciding not to join the queue if it is too long, which is may be why it was implemented this way. I first learn from the docs that the baulking function just takes the length of the queue and returns a probability of baulking.
Here is the example from the documentation:
That function actually uses
n
. We could of course make baulking functions that just ignoren
. Here is a frivolous example that we would not be interested in practice. In this case there is a probability of 1 that the individual will baulk if theint
of the unix time is prime, otherwise there is a 0.5 probability of baulking.But what is of practical interest to me is baulking that depends on time, or the individual's properties, or other properties of
next_node
, or even some entirely non-local properties. And I don't want to patch this unless I have to.How feasible is replacing
next_node.baulking_functions[self.next_class](next_node.number_of_individuals)
with
next_node.baulking_functions[self.next_class](next_node, next_individual)
?Having
next_node
available is a handy default behaviour and otherwise anything about time or state can be accessed vianext_individual.simulation
. It would allow for a form of "generalized baulking" where the reason for not joining the queue could be for reasons other than the length of the waitlist.