Implementing toy model as linear programming problem

5 hours ago 1
ARTICLE AD BOX

I am trying to implement the following toy model as linear programming problem, and look forward to hearing whether I missed anything.

Consider the following toy model, with three factories A, B, and C, producing products foo and bar.

foo bar
A 80 20
B 20 40
C 10 5

We want to increase the total output of foo and bar system by 50 and 25.

Factories cannot reduce their output.

The ratio of foo and bar per factory is fixed (e.g. factory A produces 80 units of foo per 20 units of bar).

We want to minimize the relative change in output per factory.

If I understand correctly, I can solve this question with linear programming.

The objective function is : minimize z = sum(x_i^*/w_i), where x_i^* is the new output per factory, and w_i is the baseline output per factory. Note that x_i^* is a variable, and w_i is fixed.

Next, to implement this objective function in linprog, we need to rewrite the objective function in the form of c^t @ x:

minimize z = sum(1/w_i * x_i^*) ,such that c^t = [1/w_a, 1/w_b, 1/w_c], and x = [x_a^*, x_b^*, x_c^*].

Furthermore, we need to add the constraint that the new output is foo = 50 and bar = 25. For this, we transpose the initial table, to obtain the form:

array([[80, 20, 10],[20, 40, 5]]) @ [x_a^*, x_b^*, x_c^*] = [50, 25]

Note that since we need to match this new output exactly, we use A_eq and b_eq (instead of A_ub and b_ub.

Moreover, note that we do not have to define a constraint that the ratio of foo and bar is fixed, since the decision variables concern the total output per factory, and not output per factory per product individually.

Finally, by formulating the constraint as the change in output (instead of the new output of foo = 110 + 50 = 160 and bar = 65+ 25 = 90 , we can leverage the default bounds used by linprog where decision variables are non-negative. In other words, we do not have to explicitly add a constraint that factories cannot decrease their output.

I believe this gives us everything we need:

import numpy as np import pandas as pd from scipy.optimize import linprog # Toy model. df_base = pd.DataFrame([[80, 20], [20, 40], [10, 5]]) # Additional output of foo and bar. df_scen_s = pd.DataFrame(np.array([50, 25])) # Get total output per factory: w1, w2, w3. df_base_s = df_base.sum(axis=1) # Get coefficients: 1/w1, 1/w2, 1/w3. df_base_s_inv = 1 / df_base_s # Linear objective function. ar_c = df_base_s_inv.values # Constraint to match new output exactly. ar_base = df_base.T.values ar_scen_s = df_scen_s.values result = linprog(ar_c, A_eq=ar_base, b_eq=ar_scen_s) print(result.x) >>> [0.53571429 0.35714286 0. ]

Here we see that factory A increased the output by 54%, and factory B increased by 36%, while factory C is unaffected (output stays at 100%).

If my interpretation of this toy model into a linear programming problem is correct, I observe the following:

It seems that the change in output is not distributed over factories (i.e. factory C is unaffected). If I would want to do so, I believe I need to revise the objective function, however I don't immediately see how.

I wonder whether this can be actually done with linear programming, or whether I need to use e.g. quadratic programming, where the objective function would look something like minimize z = sum(((x_i^*-w_i)/w_i)^2)), i.e. sum of least squares.

EDIT 1:

My intuition of the objective function was as follows: factory A is least affected by absolute change, followed by factory B, then C. In other words, if I were to increase output by 10 total units, A would increase output by 10%, B by 17%, and C by 67%. This would thus favor increasing first the output of factory A, then B, then C.

To test my intuition, I changed the objective function to c^t @ x = [1, 1, 1] @ x. In other words, now changing the output of each factory is equally bad. This did not change the outcome.

Next, I heavily penalized the output of factory A: c^t @ x = [10, 1, 1] @ x. This changed the output to [0, 0, 5], i.e. factory A and B stay at 100%, while factory C increases output by 500%.

This new objective function could be interpreted as follows. Say that instead of aiming to minimize the relative change per factory, we aim to minimize the total cost, where factory A is really expensive to run, and factory B and C are equally cheap. Now, we would favor allocating all increased output to factory C.

Furthermore, if I understand correctly, this highlights that linear programming finds solutions at vertices in the solution space, and by heavily penalizing factory A, I force the solver to jump to another vertex.

Moreover, it seems that the objective function in this case is quite robust, in that changes to the coefficients of the objective function don't seem to really affect the outcome, only in extreme cases.

Read Entire Article