Source code for tryalgo.arithm_expr_target
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""\
Create arithmetic expression approaching target value
jill-jênn vie, christoph dürr et jean-christophe filliâtre - 2014-2019
"""
# snip{
# pylint: disable=too-many-locals, too-many-nested-blocks, unnecessary-pass
# pylint: disable=inconsistent-return-statements, too-many-branches
[docs]
def arithm_expr_target(x, target):
""" Create arithmetic expression approaching target value
:param x: allowed constants
:param target: target value
:returns: string in form 'expression=value'
:complexity: huge
"""
n = len(x)
expr = [{} for _ in range(1 << n)]
# expr[S][val]
# = string solely composed of values in set S that evaluates to val
for i in range(n):
expr[1 << i] = {x[i]: str(x[i])} # store singletons
all_ = (1 << n) - 1
for S in range(3, all_ + 1): # 3: first num that isn't a power of 2
if expr[S] != {}:
continue # in that case S is a power of 2
for L in range(1, S): # decompose set S into non-empty sets L, R
if L & S == L:
R = S ^ L
for vL in expr[L]: # combine expressions from L
for vR in expr[R]: # with expressions from R
eL = expr[L][vL]
eR = expr[R][vR]
expr[S][vL] = eL
if vL > vR: # difference cannot become negative
expr[S][vL - vR] = "(%s-%s)" % (eL, eR)
if L < R: # break symmetry
expr[S][vL + vR] = "(%s+%s)" % (eL, eR)
expr[S][vL * vR] = "(%s*%s)" % (eL, eR)
if vR != 0 and vL % vR == 0: # only integer div
expr[S][vL // vR] = "(%s/%s)" % (eL, eR)
# look for the closest expression from the target
for dist in range(target + 1):
for sign in [-1, +1]:
val = target + sign * dist
if val in expr[all_]:
return "%s=%i" % (expr[all_][val], val)
# never reaches here if x contains integers between 0 and target
pass
# snip}