简体   繁体   中英

PuLP doesn't work with one list but works with another. What is the difference between these two?

I'm new to python, picked it up because of Optimization and I've wanted to learn something new. I've made an lp solver program using PyQt5 and PuLP. The concept is simple: The user types in the Lp problem to a QTextEdit widget clicks the solve button then gets the result in a QTextBrowser.

The example exercise I'm using and trying to replicate:

prob = LpProblem("LP problem", LpMaximize)
x1 = LpVariable("x1", lowBound=0, cat='Integer') # Integer variable x1 >= 0
x2 = LpVariable("x2", lowBound=0, cat='Integer') # Integer variable x2 >= 0

prob += x2<=4
prob += 4*x1 + 2*x2 <= 20
prob += 1*x1 + 4*x2 <= 12
prob += 4*x1 + 4*x2

prob.solve()

It works like a charm this way. The function for the button:

def textToVar(self):
    prob = LpProblem("LP problem", LpMaximize)
    x1 = LpVariable("x1", lowBound=0, cat='Integer') # Integer variable x1 >= 0
    x2 = LpVariable("x2", lowBound=0, cat='Integer') # Integer variable x2 >= 0
    mytext = self.lpInput.toPlainText()
    split = mytext.splitlines()

    for ele in range(0, len(split)):
        prob += split[ele]

    prob.solve()

    for v in prob.variables():
        self.lpOutput.append(str(v.name) + ' = ' + str(v.varValue))


    vmax = (value(prob.objective))
    self.lpOutput.append('max = ' + str(vmax))

It does not work and I've figured it is because split = mytext.splitlines() generates ['x2<=4', '4*x1+2*x2<=20', '1*x1+4*x2<=12', '4*x1+4*x2'] instead of [x2<=4, 4*x1+2*x2<=20, 1*x1+4*x2<=12, 4*x1+4*x2] . How can I convert my list from the first to the second one? Maybe I could use another method to store the input in a list or variable instead of splitlines() ?

Thank you in advance!

You could use exec() , like @AirSquid pointed out in their comment, but that does raise security issues. Another way would be to parse the strings, since you know what they will contain. Then, if something unexpected comes along, you can easily throw an error.

import re
import pulp as pl

x1 = pl.LpVariable("x1", lowBound=0, cat='Integer') # Integer variable x1 >= 0
x2 = pl.LpVariable("x2", lowBound=0, cat='Integer') # Integer variable x2 >= 0

def parse_equation(string):
    string_parts = re.split("(<=|=|>=)", string)
    if len(string_parts) == 1:
        # Objective function
        return parse_equation_part(string_parts[0])
    if len(string_parts) != 3:
        raise Exception(f"Unexpected number of parts in {string_parts}")
    lhs, comparator, rhs = (
        parse_equation_part(string_parts[0]),
        string_parts[1],
        parse_equation_part(string_parts[2])
    )

    if comparator == "<=":
        return lhs <= rhs
    if comparator == ">=":
        return lhs >= rhs
    return lhs == rhs

def parse_equation_part(string):
    addition_parts = re.split("(\+|-)", string)
    result = parse_addition_part(addition_parts.pop(0))

    while addition_parts:
        symbol, addition_part, addition_parts =\
            addition_parts[0], addition_parts[1], addition_parts[2:]
        part_result = parse_addition_part(addition_part)

        if symbol not in ('+', '-'):
            raise Exception(f"Unexpected value {symbol}")
        if symbol == '-':
            result -= part_result
        else:
            result += part_result
    return result

def parse_addition_part(string):
    parts = string.split("*")
    result = 1

    for part in parts:
        if part == 'x1':
            result *= x1
        elif part == 'x2':
            result *= x2
        elif part.isnumeric():
            result *= float(part)
        else:
            raise Exception(f"Unexpected part {part}, expected number or x1/x2")

    return result

for s in ['x2>=4', '4*x1+2*x2=20', '1*x1-4*x2<=12', '4*x1+4*x2']:
    print(s.ljust(20, ' '), '->', parse_equation(s))

yields

x2>=4                -> x2 >= 4.0
4*x1+2*x2=20         -> 4.0*x1 + 2.0*x2 = 20.0
1*x1-4*x2<=12        -> x1 - 4.0*x2 <= 12.0
4*x1+4*x2            -> 4.0*x1 + 4.0*x2

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