Coverage for moptipyapps / prodsched / rop_simulation.py: 92%

38 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-11 04:40 +0000

1""" 

2A re-order-point-based simulation. 

3 

4Re-Order-Point (ROP) scenarios are such that for each product, a value `X` is 

5provided. Once there are no more than `X` elements of that product in the 

6warehouse, one new unit is ordered to be produced. 

7Therefore, we have `n_products` such `X` values. 

8 

9ROP-based simulations extend the basic behavior of the class 

10:class:`~moptipyapps.prodsched.simulation.Simulation` to re-order production 

11based on ROPs. 

12 

13>>> from moptipyapps.prodsched.simulation import PrintingListener 

14>>> instance = Instance( 

15... name="test1", n_products=2, n_customers=4, n_stations=2, n_demands=4, 

16... time_end_warmup=3000, time_end_measure=10000, 

17... routes=[[0, 1], [1, 0]], 

18... demands=[Demand(arrival=100, deadline=100, demand_id=0, 

19... customer_id=0, product_id=0, amount=1, measure=False), 

20... Demand(arrival=3100, deadline=3100, demand_id=1, 

21... customer_id=1, product_id=0, amount=1, measure=True), 

22... Demand(arrival=500, deadline=500, demand_id=2, 

23... customer_id=2, product_id=1, amount=1, measure=False), 

24... Demand(arrival=4000, deadline=5000, demand_id=3, 

25... customer_id=3, product_id=1, amount=1, measure=True)], 

26... warehous_at_t0=[0, 0], 

27... station_product_unit_times=[[[10.0, 50.0, 15.0, 100.0], 

28... [ 5.0, 20.0, 7.0, 35.0, 4.0, 50.0]], 

29... [[ 5.0, 24.0, 7.0, 80.0], 

30... [ 3.0, 21.0, 6.0, 50.0,]]]) 

31>>> rop_sim = ROPSimulation(instance, PrintingListener(print_time=False)) 

32>>> rop_sim.set_rop((10, 20)) 

33>>> rop_sim.ctrl_run() 

34start 

35T=0.0: product=0, amount=0, in_warehouse=0, in_production=0, 0 pending demands 

36T=0.0: station=0, 1 jobs queued 

37T=0.0: start j(id: 0, p: 0, am: 11, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

38 at station 0 

39T=0.0: product=1, amount=0, in_warehouse=0, in_production=0, 0 pending demands 

40T=0.0: station=1, 1 jobs queued 

41T=0.0: start j(id: 1, p: 1, am: 21, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

42 at station 1 

43T=84.0: finished j(id: 1, p: 1, am: 21, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

44 at station 1 

45T=100.0: product=0, amount=0, in_warehouse=0, in_production=11,\ 

46 1 pending demands 

47T=130.0: finished j(id: 0, p: 0, am: 11, ar: 0, me: F, c: F, st: 0,\ 

48 sp: 0) at station 0 

49T=130.0: station=0, 2 jobs queued 

50T=130.0: start j(id: 1, p: 1, am: 21, ar: 0, me: F, c: F, st: 84,\ 

51 sp: 1) at station 0 

52T=130.0: station=1, 1 jobs queued 

53T=130.0: start j(id: 0, p: 0, am: 11, ar: 0, me: F, c: F, st: 130,\ 

54 sp: 1) at station 1 

55T=197.0: finished j(id: 0, p: 0, am: 11, ar: 0, me: F, c: T, st: 130,\ 

56 sp: 1) at station 1 

57T=197.0: product=0, amount=11, in_warehouse=0, in_production=1,\ 

58 1 pending demands 

59T=197.0: d(id: 0, p: 0, c: 0, am: 1, ar: 100, dl: 100, me: F) statisfied 

60T=197.0: 10 units of product 0 in warehouse 

61T=240.0: finished j(id: 1, p: 1, am: 21, ar: 0, me: F, c: T, st: 84,\ 

62 sp: 1) at station 0 

63T=240.0: station=0, 1 jobs queued 

64T=240.0: start j(id: 2, p: 0, am: 1, ar: 100, me: F, c: F, st: 100,\ 

65 sp: 0) at station 0 

66T=240.0: product=1, amount=21, in_warehouse=0, in_production=0,\ 

67 0 pending demands 

68T=240.0: 21 units of product 1 in warehouse 

69T=250.0: finished j(id: 2, p: 0, am: 1, ar: 100, me: F, c: F, st: 100,\ 

70 sp: 0) at station 0 

71T=250.0: station=1, 1 jobs queued 

72T=250.0: start j(id: 2, p: 0, am: 1, ar: 100, me: F, c: F, st: 250, sp: 1)\ 

73 at station 1 

74T=255.0: finished j(id: 2, p: 0, am: 1, ar: 100, me: F, c: T, st: 250, sp: 1)\ 

75 at station 1 

76T=255.0: product=0, amount=1, in_warehouse=10, in_production=0,\ 

77 0 pending demands 

78T=255.0: 11 units of product 0 in warehouse 

79T=500.0: product=1, amount=0, in_warehouse=21, in_production=0,\ 

80 1 pending demands 

81T=500.0: d(id: 2, p: 1, c: 2, am: 1, ar: 500, dl: 500, me: F) statisfied 

82T=500.0: 20 units of product 1 in warehouse 

83T=500.0: station=1, 1 jobs queued 

84T=500.0: start j(id: 3, p: 1, am: 1, ar: 500, me: F, c: F, st: 500,\ 

85 sp: 0) at station 1 

86T=503.0: finished j(id: 3, p: 1, am: 1, ar: 500, me: F, c: F, st: 500,\ 

87 sp: 0) at station 1 

88T=503.0: station=0, 1 jobs queued 

89T=503.0: start j(id: 3, p: 1, am: 1, ar: 500, me: F, c: F, st: 503,\ 

90 sp: 1) at station 0 

91T=508.0: finished j(id: 3, p: 1, am: 1, ar: 500, me: F, c: T, st: 503,\ 

92 sp: 1) at station 0 

93T=508.0: product=1, amount=1, in_warehouse=20, in_production=0,\ 

94 0 pending demands 

95T=508.0: 21 units of product 1 in warehouse 

96T=3100.0! product=0, amount=0, in_warehouse=11, in_production=0,\ 

97 1 pending demands 

98T=3100.0! d(id: 1, p: 0, c: 1, am: 1, ar: 3100, dl: 3100, me: T) statisfied 

99T=3100.0! 10 units of product 0 in warehouse 

100T=3100.0! station=0, 1 jobs queued 

101T=3100.0! start j(id: 4, p: 0, am: 1, ar: 3100, me: T, c: F, st: 3100,\ 

102 sp: 0) at station 0 

103T=3110.0! finished j(id: 4, p: 0, am: 1, ar: 3100, me: T, c: F, st: 3100,\ 

104 sp: 0) at station 0 

105T=3110.0! station=1, 1 jobs queued 

106T=3110.0! start j(id: 4, p: 0, am: 1, ar: 3100, me: T, c: F, st: 3110,\ 

107 sp: 1) at station 1 

108T=3117.0! finished j(id: 4, p: 0, am: 1, ar: 3100, me: T, c: T, st: 3110,\ 

109 sp: 1) at station 1 

110T=3117.0! product=0, amount=1, in_warehouse=10, in_production=0,\ 

111 0 pending demands 

112T=3117.0! 11 units of product 0 in warehouse 

113T=4000.0! product=1, amount=0, in_warehouse=21, in_production=0,\ 

114 1 pending demands 

115T=4000.0! d(id: 3, p: 1, c: 3, am: 1, ar: 4000, dl: 5000, me: T) statisfied 

116T=4000.0! 20 units of product 1 in warehouse 

117T=4000.0! station=1, 1 jobs queued 

118T=4000.0! start j(id: 5, p: 1, am: 1, ar: 4000, me: T, c: F, st: 4000,\ 

119 sp: 0) at station 1 

120T=4003.0! finished j(id: 5, p: 1, am: 1, ar: 4000, me: T, c: F, st: 4000,\ 

121 sp: 0) at station 1 

122T=4003.0! station=0, 1 jobs queued 

123T=4003.0! start j(id: 5, p: 1, am: 1, ar: 4000, me: T, c: F, st: 4003,\ 

124 sp: 1) at station 0 

125T=4008.0! finished j(id: 5, p: 1, am: 1, ar: 4000, me: T, c: T, st: 4003,\ 

126 sp: 1) at station 0 

127T=4008.0! product=1, amount=1, in_warehouse=20, in_production=0,\ 

128 0 pending demands 

129T=4008.0! 21 units of product 1 in warehouse 

130T=4008.0 -- finished 

131 

132>>> instance = Instance( 

133... name="test2", n_products=2, n_customers=1, n_stations=2, n_demands=5, 

134... time_end_warmup=21, time_end_measure=10000, 

135... routes=[[0, 1], [1, 0]], 

136... demands=[[0, 0, 1, 4, 20, 90], [1, 0, 0, 5, 22, 200], 

137... [2, 0, 1, 4, 30, 200], [3, 0, 1, 6, 60, 200], 

138... [4, 0, 0, 3, 5, 2000]], 

139... warehous_at_t0=[2, 1], 

140... station_product_unit_times=[[[10.0, 50.0, 15.0, 100.0], 

141... [ 5.0, 20.0, 7.0, 35.0, 4.0, 50.0]], 

142... [[ 5.0, 24.0, 7.0, 80.0], 

143... [ 3.0, 21.0, 6.0, 50.0,]]]) 

144>>> rop_sim = ROPSimulation(instance, PrintingListener(print_time=False)) 

145>>> rop_sim.set_rop((10, 10)) 

146>>> rop_sim.ctrl_run() 

147start 

148T=0.0: product=0, amount=2, in_warehouse=0, in_production=0, 0 pending demands 

149T=0.0: 2 units of product 0 in warehouse 

150T=0.0: station=0, 1 jobs queued 

151T=0.0: start j(id: 0, p: 0, am: 9, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

152 at station 0 

153T=0.0: product=1, amount=1, in_warehouse=0, in_production=0, 0 pending demands 

154T=0.0: 1 units of product 1 in warehouse 

155T=0.0: station=1, 1 jobs queued 

156T=0.0: start j(id: 1, p: 1, am: 10, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

157 at station 1 

158T=5.0: product=0, amount=0, in_warehouse=2, in_production=9, 1 pending demands 

159T=20.0: product=1, amount=0, in_warehouse=1, in_production=10,\ 

160 1 pending demands 

161T=22.0! product=0, amount=0, in_warehouse=2, in_production=12,\ 

162 2 pending demands 

163T=30.0! product=1, amount=0, in_warehouse=1, in_production=14,\ 

164 2 pending demands 

165T=39.0: finished j(id: 1, p: 1, am: 10, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

166 at station 1 

167T=39.0! station=1, 2 jobs queued 

168T=39.0: start j(id: 3, p: 1, am: 4, ar: 20, me: F, c: F, st: 20, sp: 0)\ 

169 at station 1 

170T=57.0: finished j(id: 3, p: 1, am: 4, ar: 20, me: F, c: F, st: 20, sp: 0)\ 

171 at station 1 

172T=57.0! station=1, 1 jobs queued 

173T=57.0! start j(id: 5, p: 1, am: 4, ar: 30, me: T, c: F, st: 30, sp: 0)\ 

174 at station 1 

175T=60.0! product=1, amount=0, in_warehouse=1, in_production=18,\ 

176 3 pending demands 

177T=69.0! finished j(id: 5, p: 1, am: 4, ar: 30, me: T, c: F, st: 30, sp: 0)\ 

178 at station 1 

179T=69.0! station=1, 1 jobs queued 

180T=69.0! start j(id: 6, p: 1, am: 6, ar: 60, me: T, c: F, st: 60, sp: 0)\ 

181 at station 1 

182T=102.0! finished j(id: 6, p: 1, am: 6, ar: 60, me: T, c: F, st: 60, sp: 0)\ 

183 at station 1 

184T=110.0: finished j(id: 0, p: 0, am: 9, ar: 0, me: F, c: F, st: 0, sp: 0)\ 

185 at station 0 

186T=110.0! station=0, 6 jobs queued 

187T=110.0: start j(id: 2, p: 0, am: 3, ar: 5, me: F, c: F, st: 5, sp: 0)\ 

188 at station 0 

189T=110.0! station=1, 1 jobs queued 

190T=110.0: start j(id: 0, p: 0, am: 9, ar: 0, me: F, c: F, st: 110, sp: 1)\ 

191 at station 1 

192T=140.0: finished j(id: 2, p: 0, am: 3, ar: 5, me: F, c: F, st: 5, sp: 0)\ 

193 at station 0 

194T=140.0! station=0, 5 jobs queued 

195T=140.0! start j(id: 4, p: 0, am: 5, ar: 22, me: T, c: F, st: 22, sp: 0)\ 

196 at station 0 

197T=171.0: finished j(id: 0, p: 0, am: 9, ar: 0, me: F, c: T, st: 110, sp: 1)\ 

198 at station 1 

199T=171.0! station=1, 1 jobs queued 

200T=171.0: start j(id: 2, p: 0, am: 3, ar: 5, me: F, c: F, st: 140, sp: 1)\ 

201 at station 1 

202T=171.0! product=0, amount=9, in_warehouse=2, in_production=8,\ 

203 2 pending demands 

204T=171.0: d(id: 4, p: 0, c: 0, am: 3, ar: 5, dl: 2000, me: F) statisfied 

205T=171.0! d(id: 1, p: 0, c: 0, am: 5, ar: 22, dl: 200, me: T) statisfied 

206T=171.0! 3 units of product 0 in warehouse 

207T=186.0: finished j(id: 2, p: 0, am: 3, ar: 5, me: F, c: T, st: 140, sp: 1)\ 

208 at station 1 

209T=186.0! product=0, amount=3, in_warehouse=3, in_production=5,\ 

210 0 pending demands 

211T=186.0! 6 units of product 0 in warehouse 

212T=210.0! finished j(id: 4, p: 0, am: 5, ar: 22, me: T, c: F, st: 22, sp: 0)\ 

213 at station 0 

214T=210.0! station=0, 4 jobs queued 

215T=210.0: start j(id: 1, p: 1, am: 10, ar: 0, me: F, c: F, st: 39, sp: 1)\ 

216 at station 0 

217T=210.0! station=1, 1 jobs queued 

218T=210.0! start j(id: 4, p: 0, am: 5, ar: 22, me: T, c: F, st: 210, sp: 1)\ 

219 at station 1 

220T=245.0! finished j(id: 4, p: 0, am: 5, ar: 22, me: T, c: T, st: 210, sp: 1)\ 

221 at station 1 

222T=245.0! product=0, amount=5, in_warehouse=6, in_production=0,\ 

223 0 pending demands 

224T=245.0! 11 units of product 0 in warehouse 

225T=263.0: finished j(id: 1, p: 1, am: 10, ar: 0, me: F, c: T, st: 39, sp: 1)\ 

226 at station 0 

227T=263.0! station=0, 3 jobs queued 

228T=263.0: start j(id: 3, p: 1, am: 4, ar: 20, me: F, c: F, st: 57, sp: 1)\ 

229 at station 0 

230T=263.0! product=1, amount=10, in_warehouse=1, in_production=14,\ 

231 3 pending demands 

232T=263.0: d(id: 0, p: 1, c: 0, am: 4, ar: 20, dl: 90, me: F) statisfied 

233T=263.0! d(id: 2, p: 1, c: 0, am: 4, ar: 30, dl: 200, me: T) statisfied 

234T=263.0! 3 units of product 1 in warehouse 

235T=287.0: finished j(id: 3, p: 1, am: 4, ar: 20, me: F, c: T, st: 57, sp: 1)\ 

236 at station 0 

237T=287.0! station=0, 2 jobs queued 

238T=287.0! start j(id: 5, p: 1, am: 4, ar: 30, me: T, c: F, st: 69, sp: 1)\ 

239 at station 0 

240T=287.0! product=1, amount=4, in_warehouse=3, in_production=10,\ 

241 1 pending demands 

242T=287.0! d(id: 3, p: 1, c: 0, am: 6, ar: 60, dl: 200, me: T) statisfied 

243T=287.0! 1 units of product 1 in warehouse 

244T=303.0! finished j(id: 5, p: 1, am: 4, ar: 30, me: T, c: T, st: 69, sp: 1)\ 

245 at station 0 

246T=303.0! station=0, 1 jobs queued 

247T=303.0! start j(id: 6, p: 1, am: 6, ar: 60, me: T, c: F, st: 102, sp: 1)\ 

248 at station 0 

249T=303.0! product=1, amount=4, in_warehouse=1, in_production=6,\ 

250 0 pending demands 

251T=303.0! 5 units of product 1 in warehouse 

252T=337.0! finished j(id: 6, p: 1, am: 6, ar: 60, me: T, c: T, st: 102, sp: 1)\ 

253 at station 0 

254T=337.0! product=1, amount=6, in_warehouse=5, in_production=0,\ 

255 0 pending demands 

256T=337.0! 11 units of product 1 in warehouse 

257T=337.0 -- finished 

258""" 

259 

260from typing import Final, Iterable 

261 

262import numpy as np 

263from pycommons.types import check_int_range, type_error 

264 

265from moptipyapps.prodsched.instance import ( 

266 Demand, 

267 Instance, 

268) 

269from moptipyapps.prodsched.simulation import Listener, Simulation 

270 

271 

272class ROPSimulation(Simulation): 

273 """Create the re-order point-based simulation.""" 

274 

275 def __init__(self, instance: Instance, listener: Listener) -> None: 

276 """ 

277 Initialize this simulation. 

278 

279 :param instance: the instance 

280 :param listener: the listener 

281 """ 

282 super().__init__(instance, listener) 

283 #: the re-order point 

284 self.__rop: Final[list[int]] = [0] * instance.n_products 

285 

286 def set_rop(self, rop: Iterable[int] | np.ndarray) -> None: 

287 """ 

288 Set the re-order point. 

289 

290 :param rop: the re-order point 

291 """ 

292 if isinstance(rop, np.ndarray): 

293 rop = map(int, rop) # type: ignore 

294 if not isinstance(rop, Iterable): 

295 raise type_error(rop, "rop", Iterable) 

296 i: int = -1 

297 for i, rv in enumerate(rop): 

298 self.__rop[i] = check_int_range( 

299 rv, "rop-value", 0, 1_000_000_000) 

300 i += 1 

301 n_prod: Final[int] = list.__len__(self.__rop) 

302 if i != n_prod: 

303 raise ValueError(f"Invalid rop length {i}, must be {n_prod}!") 

304 

305 def event_product(self, time: float, # pylint: disable=W0613,R0913,R0917 

306 product_id: int, amount: int, 

307 in_warehouse: int, 

308 in_production: int, # pylint: disable=W0613 

309 pending_demands: tuple[Demand, ...]) -> None: 

310 """Perform a simulation step based on a product.""" 

311 # satisfy demands 

312 available: int = in_warehouse + amount 

313 unsatisfied: int = 0 

314 for demand in pending_demands: 

315 request: int = demand.amount 

316 if request <= available: 

317 self.act_demand_satisfied(demand) 

318 available -= request 

319 else: 

320 unsatisfied += request 

321 

322 # update warehouse 

323 if available < in_warehouse: 

324 self.act_take_from_warehouse(product_id, in_warehouse - available) 

325 elif available > in_warehouse: 

326 self.act_store_in_warehouse(product_id, available - in_warehouse) 

327 

328 # check if re-order point needs to be triggered 

329 rop: Final[int] = self.__rop[product_id] 

330 available = available - unsatisfied + in_production 

331 if available <= rop: 

332 self.act_produce(product_id, rop - available + 1)