Sut i Ddiffinio Dosraniadau Amser Dibynnol a Cyflwr Dibynnol¶
Trwy diffinio gwrthrychau dosraniad gwstwm, gallwn diffinio doraniadau amser-dibynnol a cyflwr-dibynnol. Mae'n hawdd wedyn creu dosraniadau amser-a-cyflwr-dibynnol hefy.
Rhaid i'r gwrthrych dosraniad gwstwm hyn etifeddu o'r dosbarth cyffredinol ciw.dists.Distribution
, ac mae angen diffinio dull .sample
sy'n allbynnu yr amser a samplwyd.
Rhaid i'r dull cymryd fel mewnbwn y newidyn amser t
, ac hefyd yr unigolyn ind
.
Dosraniadau Amser Dibynnol¶
Yn Ciw gallwn ddiffinio dosraniadau amser dibynnol, hynny yw dosraniadau amser gwasanaeth neu rhwng-dyfodiad sy'n newid wrth i amser yr efelychiad symud ymlaen.
I wneud hwn mae angen diffinio gwrthrych amser dibynnol, sydd a dull sample
, sy'n rhoi'r amser a samplwyd.
Er enghraifft, os ydyn ni eisiau dyfodiadau pob 30 munud yn y bore, pob 15 munud amser cinio, pob 45 munud yn y prynhawn, a pob 90 munud trwy'r nos:
>>> import ciw
>>> class TimeDependentDist(ciw.dists.Distribution):
... def sample(self, t, ind=None):
... if t % 24 < 12.0:
... return 0.5
... if t % 24 < 14.0:
... return 0.25
... if t % 24 < 20.0:
... return 0.75
... return 1.5
Mae'r dull yma yn rhoi amseroedd rhwng dyfodi o 0.5 awr rhwng canol nos (0) a 13, 0.25 awr rhwng 12 a 14, 0.75 awr rhwng 14 a 20, a 1.5 awr rhwng 20 a chanol nos (24). Yna mae'n ailadrodd. I brofi'r ffwythiant:
>>> D = TimeDependentDist()
>>> D.sample(9.5)
0.5
>>> D.sample(11.0)
0.5
>>> D.sample(13.25)
0.25
>>> D.sample(17.0)
0.75
>>> D.sample(22.0)
1.5
>>> D.sample(33.2) # hanner awr wedi 9 y diwrnod nesaf
0.5
Gadewch i ni weithredu hwn mewn ciw un nod gyda nifer anfeidraidd o weinyddion:
>>> import ciw
>>> N = ciw.create_network(
... arrival_distributions=[TimeDependentDist()],
... service_distributions=[ciw.dists.Deterministic(0.0)],
... number_of_servers=['Inf']
... )
Yna efelychwn am un diwrnod. Rydym yn disgwyl 24 dyfodiad yn y bore (12 awr, un pob hanner awr); 8 dyfodiad amser cinio (2 awr, un pob 15 munud); 8 dyfodiad yn y prynhawn (6 awr, un pob 45 munud); a 2 dyfodiad yn y nos (4 awr, un pob awr a hanner). Felly, disgwylir cyfanswm o 42 cwsmer pasio trwy'r system:
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(24.0)
>>> len(Q.nodes[-1].all_individuals)
42
Dosraniadau Cyflwr Dibynnol¶
Yn ogystal a'r paramedr amser t
, mae'r dull samplu yn cymryd mewn yr unigolyn ind
.
Felly gallwn defnyddio priodweddau'r unigolyn hyn er mwyn samplu amser gwasanaeth (noder nad yw'n gwneud synnwyr i defnyddio hwn i samplu amseroedd rhwng-dyfodiad oherwydd nad oes unigolyn wedi'i creu eto!).
Mae gan yr unigolyn hyn priodwedd :code:ind.simulation`, sy'n pwyntio at y gwrthrych Simulation
, sy'n golygu fod ganddo mynediad i cyflwr y system cyfan.
Nawr gallwn cymryd mantais o hwn i diffinio dosraniadau cyflwr dibynnol.
- Fel enghraifft, diffiniwn dosraniad ar gyfer system un nod sy'n rhoi:
0.20
os oes 0 person wrth y nod,0.15
os oes is 1 person wrth y nod,0.10
os oes 2 person wrth y nod,0.05
os oes 3 person wrth y nod,0.00
otherwise.
Mae hwn yn cyfateb i'r ffwythiant:
$$max(-0.05n + 0.2, 0)$$
lle \(n\) yw nifer y cwsmeriaid yn y nod. Ysgrifennwn dosbarth dosraniad i'w ddefnyddio:
>>> class StateDependentDist(ciw.dists.Distribution):
... def sample(self, t=None, ind=None):
... n = ind.simulation.statetracker.state
... return max((-0.05*n) + 0.2, 0)
Nawr i wirio os yw hyn yn gweithio, bydd yr amser gwasanaeth cymedrig tua'n hafal i'r gwerth a chafwyd os cymhwyswn y ffwythiant hyn i'r maint ciw cymedrig:
>>> N = ciw.create_network(
... arrival_distributions=[ciw.dists.Exponential(4)],
... service_distributions=[StateDependentDist()],
... number_of_servers=[1]
... )
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(500)
>>> recs = Q.get_all_records()
>>> services = [r.service_time for r in recs if r.arrival_date > 100]
>>> sum(services) / len(services)
0.1549304...
>>> average_queue_size = sum(s*p for s, p in Q.statetracker.state_probabilities().items())
>>> (-0.05 * average_queue_size) + 0.2
0.1552347...
Ar gyfer dosraniadau dyfodi - wrth creu'r gwrthrych Simulation
, rhoddir i'r gwrthrychau dosraniad y briodwedd .simulation
, felly gall rhywbeth tebyg digwydd. Er enghraifft, mae'r dosraniad canlynol yn samplu o ddosraniad Esbonyddol nes i nifer limit
o unigolion cael eu samplu:
>>> class LimitedExponential(ciw.dists.Exponential):
... def __init__(self, rate, limit):
... super().__init__(rate)
... self.limit = limit
...
... def sample(self, t=None, ind=None):
... if self.simulation.nodes[0].number_of_individuals < self.limit:
... return super().sample()
... else:
... return float('Inf')
Ac i weld os yw'n gweithio, gyda terfan o 44 unigolyn:
>>> N = ciw.create_network(
... arrival_distributions=[LimitedExponential(1, 44)],
... service_distributions=[ciw.dists.Exponential(3)],
... number_of_servers=[2]
... )
>>> ciw.seed(0)
>>> Q = ciw.Simulation(N)
>>> Q.simulate_until_max_time(3000)
>>> recs = Q.get_all_records()
>>> len(recs)
44