0

I am using pulp in an attempt to minimize the deviation from a target. In the MRE below, assume that items 1-50 have features A, B, C, D. The optimizer should apportion a "budget" equal to 100%, while attempting to get the average value of feature "A" equal to tgt_a. It would be fairly easy to just tell pulp to force a to be equal to the target, but in real life, it may not be possible to get exactly to the target. In addition, I ultimately want to have the system balance all the various features using a sum of squared deviation method, which makes it even less likely that a perfect solution even exists.

The code below runs fine, but simply minimizes the difference between the actual "A" feature value and the target. I need to square the difference in order to make it useful. However if you add a **2 to the appropriate line of code, you get:

TypeError: unsupported operand type(s) for ** or pow(): 'LpAffineExpression' and 'int'

What I'm looking for is a way to square a_dev and then set the solver to optimize the variables to minimize that squared difference.

import pandas as pd
import numpy as np
import pulp

def contrib(p, col):
    c = df.loc[p, col]
    return c

df_data = {'A':np.random.randint(20, 50, 50),
            'B':np.random.randint(0, 50, 50),
            'C':np.random.randint(20, 50, 50),
            'D':np.random.randint(20, 100, 50)}

df = pd.DataFrame(data=df_data)
picks = df.index

#Set up variable
pct = pulp.LpVariable.dicts('Pct', (p for p in picks), 0, 0.05)

#Create problem
ideal = pulp.LpProblem('Sq_dev', pulp.LpMinimize)

tgt_a = 35

a = [pct[p] * contrib(p, 'A') for p in picks]
a_tgt = [pct[p] * tgt_a for p in picks]
a_dev = (pulp.lpSum(a) - pulp.lpSum(a_tgt))
#I need a_dev to be squared in order to be useful!
ideal += a_dev

ideal += pulp.lpSum([pct[p] for p in picks]) == 1
ideal.solve()

for p in picks:
    if pct[p].value() > 0:
        print(p, pct[p].value())
Tom
  • 1,003
  • 2
  • 13
  • 25
  • What about `a_dev * a_dev`? – Mad Physicist Nov 27 '20 at 18:57
  • >TypeError: Non-constant expressions cannot be multiplied – Tom Nov 27 '20 at 19:00
  • That doesn't work; same basic reason. – Prune Nov 27 '20 at 19:03
  • So if you want to minimise deviation then minimising the absolute value of the deviation is not difficult - see for example - https://stackoverflow.com/a/64671123/4988601. Squared difference is not linear so you'll either need to use a different package or come up with a linear approximation. – kabdulla Nov 27 '20 at 19:45

1 Answers1

0

The problem is just what the error message tells you: pulp does not define these operations on affine expressions. This is somewhat like multiplying polynomials, or functions: you have to define the operation and write the implementation.

Very simply, you have to look up the basic definition of an affine function, research the operations that are supported, and write a function to perform the desired operation given those building blocks.

Prune
  • 76,765
  • 14
  • 60
  • 81