pyschedule
pyschedule copied to clipboard
Variable length task?
Hi,
First of all, thanks for this wonderful piece of code! I've managed to modelize almost all my needs except one case. Is there a way to either:
- have a variable task that can be dynamically extended to the beginning of its following?
- block a resource until the next task is scheduled?
To understand my scenario, here's the use case:
- we brew (1 day)
- we ferment (~15 days)
- and we bottle condition as soon as we're available
[Brew/R=brewhouse] <= [Ferment/R=Tank1] <..[variable length task/R=Tank1]..< [Bottle condition/R=Tank1+Capper]
The problem is that sometimes, we are busy or it's sunday and we want to wait a few days before bottle conditioning. How would you achieve that? Thank you!
Hi, nice to hear that pyschedule is used to brew beer!
Regarding your problem, you could use some capacity constraint like setting:
Ferment.block = 1 Bottle.block = -1 For t in range(horizon): Tank1['block'][:t] <= 1
This would ensure that some bottle operation needs to take place before a new ferment is started.
You probably also want to ensure that the fermenting and bottleling are happening at the same tank for one beer. This works like Bottle >= Ferment*Tank1
If you have a concrete example, i could try to fix it, i am always looking for real-life examples to showcast.
Thank you for you quick answer!
I've tried using the block strategy but I still experience 2 fermentations being scheduled one after the other then two bottling jobs. Weird!
I already had added a "same tank" constraint, that works quite well! But I did that using:
bottling += fermentation * fermenters_all
do you think that's correct?
Give me a few days to clean up my mess and I'll send you a link to the code. I'll be quite happy if you can help me fix the latest "bugs" and of course, you can use it as a showcast :)
Cheers!
Maybe you should also constrain the number of bottle operations in a row by using Tank1['block'][:t] >= -1 ? But this should more be a problem the other way round, happy to take a look
I've created a gist for you to read my (very dirty) code. Sorry for the quality, it's really a poc: https://gist.github.com/glibersat/c5a487178a7e6b82102aaa1a6066dd09
I hope it's clear enough, feel free to ask for informations where it's not understandable.
Thank you very much!
Unfortunately, the constraint is still not working. See attached picture: multiple fermentations take place in tanks before bottling/transfer order (example: Tank "funky" and fermentations of "Fut Papayou" and "Yoga").

Had a quick look on my phone and spotted the following syntactic problem. You need to write
S += fermenter['block'][:t] <= 1
Otherwise, the constraint is created but not added to the scenario. Please check if that gives some progress. I will be able to run your code next sunday.
My bad, I didn't know I had to add it. Now it works, in the expected order, thank you! Took about 50minutes but the result is good :) I'll now start cleaning a little bit and try to implement extra things after that.
Excellent. If you have performance problems, check the option a “group“ interchangeable tasks, if you have any. I will have a look.
Had a look at the gist above, some comments:
- you can define
chambre_garde = S.Resource('chambre_garde', size=7)to group these resources, this drops the computation time. - your can set e.g.
plot_color = ColorHash(name).hex
brewday = S.Task('{0}_brewday'.format(name),plot_color=plot_color)
to color all tasks in one batch with the same color. You can then plot without text using plotters.matplotlib.plot(S,show_task_labels=False,fig_size=(10,5)) to get better visuals right away.
- for testing, it is quite handy to use a
ratio_gaplikesolvers.mip.solve(S, kind="CBC", time_limit=3000, ratio_gap=1.2, msg=1). This will e.g. stop the computation as soon as a solution is found, which is provably only 20% off an optimal one
Looks like an awesome project, happy to see some newer version if available