"SEND+MORE=MONEY" 任务的 pyomo 模型约束编程
pyomo model constraint programming for "SEND+MORE=MONEY" task
正在尝试建立一个 pyomo 模型来解决“SEND+MORE=MONEY”任务。
C4 C3 C2 C1
S E N D
+ M O R E
______________
M O N E Y
模型建筑:
from pyomo.environ import *
m = ConcreteModel()
m.letters = Set(initialize = ['S', 'E', 'N', 'D', 'M', 'O', 'R', 'Y'])
m.tens = Set(initialize = ['C1', 'C2', 'C3', 'C4'])
m.let_val = Var(m.letters, bounds=(0,9), initialize=9, within=Integers)
m.ten_val = Var(m.tens, within=Binary)
m.C1 = Constraint(expr = m.ten_val['C3'] + m.let_val['S'] + m.let_val['M'] == m.let_val['O'] + m.ten_val['C4']*10)
m.C2 = Constraint(expr = m.ten_val['C2'] + m.let_val['E'] + m.let_val['O'] == m.let_val['N'] + m.ten_val['C3']*10)
m.C3 = Constraint(expr = m.ten_val['C1'] + m.let_val['N'] + m.let_val['R'] == m.let_val['E'] + m.ten_val['C2']*10)
m.C4 = Constraint(expr = m.let_val['D'] + m.let_val['E'] == m.let_val['Y'] + m.ten_val['C1']*10)
m.C5 = Constraint(expr = m.let_val['M'] == m.ten_val['C4'])
m.C6 = Constraint(expr = m.let_val['M'] == 1)
m.f1 = Objective(expr = m.let_val['S']*1000 + m.let_val['E']*100 + m.let_val['N']*10 + m.let_val['D'] +
m.let_val['M']*1000 + m.let_val['O']*100 + m.let_val['R']*10 + m.let_val['E'], sense=minimize)
solver = SolverFactory('glpk')
results = solver.solve(m)
print(' ', int((value(m.let_val['S'])*1000 + value(m.let_val['E'])*100 + value(m.let_val['N'])*10 + value(m.let_val['D']))))
print('+ ', int((value(m.let_val['M'])*1000 + value(m.let_val['O'])*100 + value(m.let_val['R'])*10 + value(m.let_val['E']))))
print('=', int((value(m.let_val['M'])*10000 + value(m.let_val['O'])*1000 + value(m.let_val['N'])*100 + value(m.let_val['E'])*10 + value(m.let_val['Y']))))
'glpk'解法:
9000
+ 1000
= 10000
'ipopt'解法:
8942
+ 1057
= 10000
Ipopt 更接近但不够好。我必须帮助求解器并添加约束(C5 和 C6)。没有它答案是 0.
我找不到任何关于如何声明所有字母值应该互不相同的说明的信息。
怎么做到的?
如何用pyomo正确解决这样的任务?
这是一种解决方案:
from pyomo.environ import *
m = ConcreteModel()
m.letters = Set(initialize = ['S', 'E', 'N', 'D', 'M', 'O', 'R', 'Y'])
m.vals = RangeSet(0, 9)
m.tens = Set(initialize = ['C1', 'C2', 'C3', 'C4'])
m.ten_val = Var(m.tens, within=Binary, initialize=0)
m.x = Var(m.letters, m.vals, within=Binary, initialize=1)
def c_rule(m, i):
return sum(m.x[i, j] for j in m.vals) <= 1
m.col = Constraint(m.letters, rule=c_rule) # not more than one value for the letter
def r_rule(m, j):
return sum(m.x[i, j] for i in m.letters) <= 1
m.row = Constraint(m.vals, rule=r_rule) # not more than one value for the digit
m.C1 = Constraint(expr = m.ten_val['C4'] == m.x['M', 1])
m.C2 = Constraint(expr = m.x['M', 1] == 1)
m.C3 = Constraint(expr = m.ten_val['C3'] + sum(m.x['S', j]*j for j in m.vals) + m.x['M', 1] == sum(m.x['O', j]*j for j in m.vals) + m.ten_val['C4']*10)
m.C4 = Constraint(expr = m.ten_val['C2'] + sum(m.x['E', j]*j for j in m.vals) + sum(m.x['O', j]*j for j in m.vals) == sum(m.x['N', j]*j for j in m.vals) + m.ten_val['C3']*10)
m.C5 = Constraint(expr = m.ten_val['C1'] + sum(m.x['N', j]*j for j in m.vals) + sum(m.x['R', j]*j for j in m.vals) == sum(m.x['E', j]*j for j in m.vals) + m.ten_val['C2']*10)
m.C6 = Constraint(expr = sum(m.x['D', j]*j for j in m.vals) + sum(m.x['E', j]*j for j in m.vals) == sum(m.x['Y', j]*j for j in m.vals) + m.ten_val['C1']*10)
m.f1 = Objective(expr = sum(m.x['S', j]*j for j in m.vals), sense=minimize) # we are searching for working solution, no matter what to minimize
solver = SolverFactory('glpk')
results = solver.solve(m);
x_leters = [i for i, v in m.x.get_values().items() if v == 1]
digits = {}
for i in m.letters:
val = 0
for j in x_leters:
if i in j:
val = j[1]
digits[i] = val
print(' ',digits['S'],digits['E'],digits['N'],digits['D'])
print('+',digits['M'],digits['O'],digits['R'],digits['E'])
print(digits['M'],digits['O'],digits['N'],digits['E'],digits['Y'])
9 5 6 7
+ 1 0 8 5
1 0 6 5 2
干得好!
正在尝试建立一个 pyomo 模型来解决“SEND+MORE=MONEY”任务。
C4 C3 C2 C1
S E N D
+ M O R E
______________
M O N E Y
模型建筑:
from pyomo.environ import *
m = ConcreteModel()
m.letters = Set(initialize = ['S', 'E', 'N', 'D', 'M', 'O', 'R', 'Y'])
m.tens = Set(initialize = ['C1', 'C2', 'C3', 'C4'])
m.let_val = Var(m.letters, bounds=(0,9), initialize=9, within=Integers)
m.ten_val = Var(m.tens, within=Binary)
m.C1 = Constraint(expr = m.ten_val['C3'] + m.let_val['S'] + m.let_val['M'] == m.let_val['O'] + m.ten_val['C4']*10)
m.C2 = Constraint(expr = m.ten_val['C2'] + m.let_val['E'] + m.let_val['O'] == m.let_val['N'] + m.ten_val['C3']*10)
m.C3 = Constraint(expr = m.ten_val['C1'] + m.let_val['N'] + m.let_val['R'] == m.let_val['E'] + m.ten_val['C2']*10)
m.C4 = Constraint(expr = m.let_val['D'] + m.let_val['E'] == m.let_val['Y'] + m.ten_val['C1']*10)
m.C5 = Constraint(expr = m.let_val['M'] == m.ten_val['C4'])
m.C6 = Constraint(expr = m.let_val['M'] == 1)
m.f1 = Objective(expr = m.let_val['S']*1000 + m.let_val['E']*100 + m.let_val['N']*10 + m.let_val['D'] +
m.let_val['M']*1000 + m.let_val['O']*100 + m.let_val['R']*10 + m.let_val['E'], sense=minimize)
solver = SolverFactory('glpk')
results = solver.solve(m)
print(' ', int((value(m.let_val['S'])*1000 + value(m.let_val['E'])*100 + value(m.let_val['N'])*10 + value(m.let_val['D']))))
print('+ ', int((value(m.let_val['M'])*1000 + value(m.let_val['O'])*100 + value(m.let_val['R'])*10 + value(m.let_val['E']))))
print('=', int((value(m.let_val['M'])*10000 + value(m.let_val['O'])*1000 + value(m.let_val['N'])*100 + value(m.let_val['E'])*10 + value(m.let_val['Y']))))
'glpk'解法:
9000
+ 1000
= 10000
'ipopt'解法:
8942
+ 1057
= 10000
Ipopt 更接近但不够好。我必须帮助求解器并添加约束(C5 和 C6)。没有它答案是 0.
我找不到任何关于如何声明所有字母值应该互不相同的说明的信息。 怎么做到的?
如何用pyomo正确解决这样的任务?
这是一种解决方案:
from pyomo.environ import *
m = ConcreteModel()
m.letters = Set(initialize = ['S', 'E', 'N', 'D', 'M', 'O', 'R', 'Y'])
m.vals = RangeSet(0, 9)
m.tens = Set(initialize = ['C1', 'C2', 'C3', 'C4'])
m.ten_val = Var(m.tens, within=Binary, initialize=0)
m.x = Var(m.letters, m.vals, within=Binary, initialize=1)
def c_rule(m, i):
return sum(m.x[i, j] for j in m.vals) <= 1
m.col = Constraint(m.letters, rule=c_rule) # not more than one value for the letter
def r_rule(m, j):
return sum(m.x[i, j] for i in m.letters) <= 1
m.row = Constraint(m.vals, rule=r_rule) # not more than one value for the digit
m.C1 = Constraint(expr = m.ten_val['C4'] == m.x['M', 1])
m.C2 = Constraint(expr = m.x['M', 1] == 1)
m.C3 = Constraint(expr = m.ten_val['C3'] + sum(m.x['S', j]*j for j in m.vals) + m.x['M', 1] == sum(m.x['O', j]*j for j in m.vals) + m.ten_val['C4']*10)
m.C4 = Constraint(expr = m.ten_val['C2'] + sum(m.x['E', j]*j for j in m.vals) + sum(m.x['O', j]*j for j in m.vals) == sum(m.x['N', j]*j for j in m.vals) + m.ten_val['C3']*10)
m.C5 = Constraint(expr = m.ten_val['C1'] + sum(m.x['N', j]*j for j in m.vals) + sum(m.x['R', j]*j for j in m.vals) == sum(m.x['E', j]*j for j in m.vals) + m.ten_val['C2']*10)
m.C6 = Constraint(expr = sum(m.x['D', j]*j for j in m.vals) + sum(m.x['E', j]*j for j in m.vals) == sum(m.x['Y', j]*j for j in m.vals) + m.ten_val['C1']*10)
m.f1 = Objective(expr = sum(m.x['S', j]*j for j in m.vals), sense=minimize) # we are searching for working solution, no matter what to minimize
solver = SolverFactory('glpk')
results = solver.solve(m);
x_leters = [i for i, v in m.x.get_values().items() if v == 1]
digits = {}
for i in m.letters:
val = 0
for j in x_leters:
if i in j:
val = j[1]
digits[i] = val
print(' ',digits['S'],digits['E'],digits['N'],digits['D'])
print('+',digits['M'],digits['O'],digits['R'],digits['E'])
print(digits['M'],digits['O'],digits['N'],digits['E'],digits['Y'])
9 5 6 7
+ 1 0 8 5
1 0 6 5 2
干得好!