这是一个蛮力算法。
from __future__ import division
import itertools as IT
import operator
opmap = {operator.add: '+',
operator.mul: '*',
operator.truediv: '/'}
operators = opmap.keys()
def deduction_int(inputs, output):
iternums = IT.permutations(inputs, len(inputs))
iterops = IT.product(operators, repeat=len(inputs)-1)
for nums, ops in IT.product(iternums, iterops):
for result, rstr in combine(nums, ops):
if near(result, output, atol=1e-3):
return rstr
def combine(nums, ops, astr=''):
a = nums[0]
astr = astr if astr else str(a)
try:
op = ops[0]
except IndexError:
return [(a, astr)]
# combine a op (...)
result = []
for partial_val, partial_str in combine(nums[1:], ops[1:]):
r = op(a, partial_val)
if len(nums[1:]) > 1:
rstr = '{}{}({})'.format(astr, opmap[op], partial_str)
else:
rstr = '{}{}{}'.format(astr, opmap[op], partial_str)
assert near(eval(rstr), r)
result.append((r, rstr))
# combine (a op ...)
b = nums[1]
astr = '({}{}{})'.format(astr,opmap[op], b)
for partial_val, partial_str in combine((op(a, b),)+nums[2:], ops[1:],
astr):
assert near(eval(partial_str), partial_val)
result.append((partial_val, partial_str))
return result
def near(a, b, rtol=1e-5, atol=1e-8):
return abs(a - b) < (atol + rtol * abs(b))
def report(inputs, output):
rstr = deduction_int(inputs, output)
return '{} = {}'.format(rstr, output)
print(report([10,5,7], (10+5)/7))
print(report([1,2,3,4], 3/7.))
print(report([1,2,3,4,5], (1+(2/3)*(4-5))))
产量
(10+5)/7 = 2.14285714286
(1+2)/(3+4) = 0.428571428571
(1+5)/((2+4)*3) = 0.333333333333
主要思想是简单地枚举输入值的所有排序以及运算符的所有排序。例如,
In [19]: list(IT.permutations([10,5,7], 3))
Out[19]: [(10, 5, 7), (10, 7, 5), (5, 10, 7), (5, 7, 10), (7, 10, 5), (7, 5, 10)]
然后将输入值的每个排序与运算符的每个排序配对:
In [38]: list(IT.product(iternums, iterops))
Out[38]:
[((10, 5, 7), (<built-in function add>, <built-in function mul>)),
((10, 5, 7), (<built-in function add>, <built-in function truediv>)),
((10, 5, 7), (<built-in function mul>, <built-in function add>)),
((10, 5, 7), (<built-in function mul>, <built-in function truediv>)),
...
该combine
函数对 nums 和 ops 进行排序,并枚举所有可能的 nums 和 ops 分组:在 [65] 中:combine((10, 5, 7), (operator.add, operator.mul) )
Out[65]: [(45, '10+(5*7)'), (45, '10+((5*7))'), (105, '(10+5)*7'), (105, '((10+5)*7)')]
它返回一个元组列表。每个元组是一个 2 元组,由一个数值和rstr
计算为该值的分组操作的字符串表示形式 组成。
因此,您只需遍历所有可能性并返回rstr
which,当评估时,会产生一个接近output
.
for nums, ops in IT.product(iternums, iterops):
for result, rstr in combine(nums, ops):
if near(result, output, atol=1e-3):
return rstr
一些有用的参考: