exupero's blog

Constraining input based on the current state

In the previous post we explored some different ways of constraining input to our simulated manufacturing line, but none of them had any information about the current state of the line. To calculate how many pennies to add based on what the line produced in the previous iteration, we can update our `simulate` function to pass the current state to the `generate-capacities`:

``````(defn simulate [initial-state update-state iterations generate-capacities]
(let [rng (java.util.Random. 10)
roll #(.nextInt rng 1 7)]
(take (inc iterations)
(iterate #(update-state % (generate-capacities roll %))
initial-state))))``````

Then we can write a capacities generating function that sets the number of incoming pennies based on, say, what the bottle actually produced (rather than what it had the capacity to produce):

``````(defn constrain-input-to-bottleneck-production
[[incoming & capacities] processed]
(cons (nth processed 3 incoming)
capacities))``````
``````(def constrained-to-bottleneck-production-steps
(simulate initial-state update-state 100
(fn [roll {:keys [processed]}]
(-> (repeatedly 7 roll)
more-efficient
(constrain-input-to-bottleneck-production processed)))))``````

If we only allow into the line what the bottleneck produced, we should avoid accumulating work in progress, which it appears to do quite well:

Unfortunately, having too little work in progress also starves the bottleneck fairly often:

Output
Original290
Improved336
Capacity-constrained331
Production-constrained312

It looks like we're better off constraining input based on the bottleneck's capacity rather than its actual production. When we do, we sometimes input too much, but that extra work keeps the bottleneck busy and improves output.