A curiosity journal of math, physics, programming, astronomy, and more.

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)))))

When we only allow into the line what the bottleneck produced, we avoid accumulating work in progress:

Work in progressStep 10Step 20Step 30Step 40Step 50Step 60Step 70Step 80Step 90Step 1000510152025
Inputing only as many pennies as the bottleneck produces avoids accumulating more and more pennies in the system.

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

Work in progressStep 10Step 20Step 30Step 40Step 50Step 60Step 70Step 80Step 90Step 10002468101214
Often, though, the bottleneck does not have enough pennies to work on.
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.