简体   繁体   中英

PULP: minimizing the maximum values of a set of vectors

I have a linear programming problem that I want to solve, with all its data originating in a table.

The table is of size (m * n) and looks something like this:

    |    c0      c1       c2       c3      ...       cn        sum
--- + ------ + ------ + ------ + ------ + ------ + ------ +++ ----- +
r0  |                                                     |||  Σ r0 
r1  |                                                     |||  Σ r1
r2  |                                                     |||  Σ r2
r3  |                                                     |||  Σ r3
r4  |                                                     |||
 .  |                                                     |||
 .  |                                                     |||
 .  |                                                     |||
rm  |                                                     |||  Σ rm
------------------------------------------------------------------- +
max |max(c0)  max(c1)  max(c2)  max(c3)           max(cn) |||  Σ max(c0...n)

All bins in this table will hold a float value when the problem has been optimized.

I'm trying to minimize the sum of the maximums of each column (Σ max(c0...n)) .

I have created an LpProblem :

problem = pulp.LpProblem("problem",pulp.LpMinimize)

I have created LpVariables representing each bin in the table:

variables = pulp.LpVariable.dicts("bin",
                                  ((r,c) for r in rows for c in columns),
                                  lowBound=0,
                                  cat='Continuous')

I know the sums of each row beforehand ( Σ rx ), and a constraint is that a row x 's values must sum to Σ rx . As a feature of these data, only a subset of indices in a row can contribute to this Σ rx value. For example, only bins (0,1) and (0,3) in row 0 will potentially have non-zero values. The index of these contributing bins differs from row to row; some rows may only have 1 contributing bin, while other rows have multiple (or all) contributing bins. I've accounted for this by creating constraints for each row.

for row in rows:
    column_set # a list of bin indexes for this row that make up the sum.
    variable_set = [ variables[(row,c)] for c in column_set ]
    problem += pulp.lpSum(variable_set) == row_sum # the sum of the row.

My issue lies in how to define my objective function. Since python's max() doesn't work on LpVariable objects, I trying to think of how to get the max value of any column and assign that to its own LpVariable object.

One way of doing that may be to loop through each LpVariable representing bins in a given column, do something like v = variable.value() and add all v s to a list, then do max() on this list and set an LpVariable equal to that, but this only gets the initial value of the LpVariable s, and as the solver changes data around during the solve() process, these max values will not be updated dynamically.

I've also tried making separate LpVariable s representing each column's max, setting them up like this:

pulp.LpVariable("Max___{}".format(s),
                lowBound=max([v.value() for v in column]),
                upBound=max([v.value() for v in column]),
                cat=pulp.LpContinuous
               )

but again this seems like just taking the values from the initial conditions of each LpVariable , and running solve() on this returns an 'infeasible' solution.

Any suggestions?

A high-level description :

  • m rows, n cols
  • introduce n new continuous variables m_0, m_1, ..., m_(n-1)
  • add m*n new constraints of the form:
    • m_0 >= entry(r_0,c_0)
    • m_0 >= entry(r_1,c_0)
    • ...
    • m_0 >= entry(r_(m-1),c_0)
    • ...
    • ...
    • m_1 >= entry(r_0,c_1)
    • m_1 >= entry(r_1,c_1)
    • ...
    • m_1 >= entry(r_(m-1),c_1)
    • ...
  • objective :
    • minimize(m_0 + m_1 + ... + m_(n-1))

Remarks :

  • this only works if each m is somehow pushed down by the solver!
    • here: minimize the sum -> ok!
  • it's independent on the type of the entries (binary, integer, continuous)

You could handle the sparsity of this problem in an easier way, by defining a set of 2-member tuples that are the row-column indexes of possible non-zero entries in the table.

To handle the max entry in each column, introduce new decision variables and constraints as @sascha had mentioned.

For example:

"""
Example where the table is 2x2, and any entries can be non-zero except the (2,1) entry
"""

import pulp

# Define the sparse set of row-column indexes for entries that can be non-zero
rowCols = set([(1, 1),
               (1, 2),
               (2, 2)])

# Define row sums
rowSums = {1: 1.1,
           2: 3.4}

# Detect the rows and columns of the table
rows = set([row for (row, _) in rowCols])
cols = set([col for (_, col) in rowCols])

# Define the PuLP model
problem = pulp.LpProblem("problem", pulp.LpMinimize)

# Define the variables
variables = pulp.LpVariable.dicts("bin", rowCols, lowBound=0,
                                  cat=pulp.LpContinuous)
colMaxes = pulp.LpVariable.dicts("maximum entry in the column", cols,
                                 lowBound=0, cat=pulp.LpContinuous)

# Define the constraints
#  row sum
for row in rows:
    problem += (
        pulp.lpSum([variables[row, col]
                    for col in cols
                    if (row, col) in rowCols])
        ==
        rowSums[row]
    )
#  max in column
for (row, col) in rowCols:
    problem += (
        pulp.lpSum([variables[row1, col1]
                    for (row1, col1) in rowCols
                    if col1 == col])
        <=
        colMaxes[col]
    )

# Define objective function
problem += pulp.lpSum([colMaxes[col] for col in cols])

# Solve the problem
problem.solve()

# Print the solution
print('row col value')
for (row, col) in rowCols:
    print(row, col, variables[row, col].varValue)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM