将比较公式的字符串表示形式转换回公式



Python新手。

我有一个库函数,它期待一个公式对象;solver.Add(x + y < 5)

然而,我的公式是动态的,由另一个系统作为字符串"x + y < 5"

提供库函数不接受字符串,我的问题是有一种方法来创建一个函数,可以评估我的字符串,并返回公式作为对象?如solver.Add(evaluateFormula("x + y < 5"))solver.Add(evaluateFormula("x + y") < 5)

使用内置的eval()不适合这种类型的公式,因为它试图执行公式,这不是我想做的。

下面是一些完整的示例代码;

from ortools.linear_solver import pywraplp
def main():
# Create the MIP solver BOP/SAT/CBC
solver = pywraplp.Solver.CreateSolver('BOP')
# Sample Input Data
req_json = {
"Variables": [
{
"Name": "x",
"Max": 10
},
{
"Name": "y",
"Max": 5
}
],
"Constraints": [
{
"Name": "c",
"Formula": "x + y < 5"
}
]
}
# Create the variables
v = {}
for i in range(len(req_json['Variables'])):
v[i] = solver.IntVar(0, req_json['Variables'][i]['Max'], req_json['Variables'][i]['Name'])
# Create the constraints
solver.Add(v[0] + v[1] < 5)
# solver.Add(evaluateFormula(req_json['Constraints'][0]['Formula']))
# Maximize
solver.Maximize(v[0] + v[1])
# Solve
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
print('Solution:')
print('Objective value =', solver.Objective().Value())
print('x =', v[0].solution_value())
print('y =', v[1].solution_value())

这个想法是xy是变量,例如,

x = solver.IntVar(0, xmax, 'x')
y = solver.IntVar(0, ymax, 'y')

以便在调用solver.Add(x + y < 5)时,python将查找名称xy,并将它们替换为它们所对应的对象。即IntVar + IntVar < 5,它将是一个约束对象。

当你执行eval('x + y < 5')时,就好像你在执行x + y < 5,所以你只需要确保名称xy存在于当前作用域中。有两种方法可以实现,即

var = req_json['Variables'][0]
exec('{0} = IntVar(0, {1}, "{0}")'.format(var['Name'], var['Max']))   # first
locals()[var['Name']] = IntVar(0, var['Max'], var['Name'])            # second

第一个创建字符串'x = IntVar(0, 10, "x")',并将其作为字面python语句执行。而第二个则以编程方式创建IntVar,然后将其存储在名称x中。locals()['x'] = 1相当于x = 1

总而言之,解决方案可能是

# You don't need to manually store the variables, as they're added in `solver.variables()`
for var in req_json['Variables']:
name = var['Name']
locals()[name] = solver.IntVar(0, var['Max'], name)
for constraint in req_json['Constraints']:
solver.Add(eval(constraint['Formula']), constraint['Name'])
# However you decide what the expression is to maximise. Whether it's another key
# in your `req_json` dict, or the LHS of the constraint formula. I'll just hardcode this.
solver.Maximize(x + y)
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
print('Solution:')
print('Objective value =', solver.Objective().Value())
for v in solver.variables():
print('{} = {}'.format(v.name(), v.solution_value()))

这假设eval(constraint['Formula'])永远不会做任何恶意的事情,你说是你的案子。如果你不能保证这一点,你的另一个选择是手动解析字符串的变量名、操作和关系,并建立一个安全的字符串,然后可以求值。

最后,如果你按原样运行,你会得到一个错误,说

ValueError: Operators "<" and ">" not supported with the linear solver

但是如果你将约束公式更改为'x + y <= 5',它将正常工作。

最新更新