Create expression trees from given sets of numbers and operations and find those that evaluate the target number in Mathematica 8 or higher

Given a set of numbers and a set of binary operations, what is the fastest way to create random expression trees or exhaustively check every possible combination in Mathematica?

What I am trying to solve is given:

numbers={25,50,75,100,3,6}              (* each can ONLY be used ONCE  *)
operators={Plus,Subtract,Times,Divide}  (* each can be used repeatedly *)
target=99

Find expression trees to evaluate for goals.

I have two solutions whose characteristics I give for the case when the expression trees contain exactly 4 numbers and 3 operators:

  • random selection and selection: ~ 25 thousand trees per second
  • exhaustive scan: 806400 trees in ~ 2.15 seconds

(dedicated to a laptop with: Intel (R) Core (TM) 2 Duo CPU T9300 @ 2.50 GHz, 3 GB RAM, parallelization is not used yet, but will be most desired in answers)

. , .

- , (6) " [] -1" (5).

:

  • : ~ 21K /
  • : 23224320 ~ 100

Mathematica 8.0.1, , , - OpenCL Target → "C" ..

+5
2

, , , (). monte carlo, , () , , . - ; , , , , .

( , ):

ClearAll[swap];
swap[lst_, {p1_, p2_}] := 
 ReplacePart[
  lst, {p1 \[Rule] lst\[LeftDoubleBracket]p2\[RightDoubleBracket], 
   p2 \[Rule] lst\[LeftDoubleBracket]p1\[RightDoubleBracket]}]

ClearAll[evalops];
(*first element of opslst is Identity*)

evalops[opslst_, ord_, nums_] := 
 Module[{curval}, curval = First@nums;
  Do[curval = 
    opslst\[LeftDoubleBracket]p\[RightDoubleBracket][curval, 
     nums\[LeftDoubleBracket]ord\[LeftDoubleBracket]p\
\[RightDoubleBracket]\[RightDoubleBracket]], {p, 2, Length@nums}];
  curval]

ClearAll[randomizeOrder];
randomizeOrder[ordlst_] := 
 swap[ordlst, RandomInteger[{1, Length@ordlst}, 2]]

ClearAll[randomizeOps];
(*never touch the first element*)

randomizeOps[oplst_, allowedOps_] := 
 ReplacePart[
  oplst, {RandomInteger[{2, Length@oplst}] \[Rule] RandomChoice[ops]}]

ClearAll[takeMCstep];
takeMCstep[goal_, opslst_, ord_, nums_, allowedops_] := 
 Module[{curres, newres, newops, neword, p}, 
  curres = evalops[opslst, ord, nums];
  newops = randomizeOps[opslst, allowedops];
  neword = randomizeOrder[ord];
  newres = evalops[newops, neword, nums];
  Switch[Abs[newres - goal], 
   0, {newops, 
    neword}, _, (p = Abs[curres - goal]/Abs[newres - goal];
    If[RandomReal[] < p, {newops, neword}, {opslst, ord}])]]

, ,

ops = {Times, Plus, Subtract, Divide}
nums = {25, 50, 75, 100, 3, 6}
ord = Range[Length@nums]
(*the first element is identity to simplify the logic later*)
oplist = {Identity}~Join~RandomChoice[ops, Length@nums - 1]
out = NestList[
  takeMCstep[
    99, #\[LeftDoubleBracket]1\[RightDoubleBracket], #\
\[LeftDoubleBracket]2\[RightDoubleBracket], nums, ops] &, {oplist, 
   ord}, 10000]

, , ,

ev = Map[evalops[#\[LeftDoubleBracket]1\[RightDoubleBracket], #\
\[LeftDoubleBracket]2\[RightDoubleBracket], nums] &, out];
ev // Last // N
ev // ListPlot[#, PlotMarkers \[Rule] None] &

enter image description here

, 2000 .

, , , . , .

+4

. :

ExprEval[nums_, ops_] := Fold[
  #2[[1]][#1, #2[[2]]] &,
  First@nums,
  Transpose[{ops, Rest@nums}]]

SymbolicEval[nums_, ops_] := ExprEval[nums, ToString /@ ops]

GetExpression[nums_, ops_, target_] := Select[
  Tuples[ops, Length@nums - 1],
  (target == ExprEval[nums, #]) &]

:

nums = {-1, 1, 2, 3};
ops = {Plus, Subtract, Times, Divide};
solutions = GetExpression[nums, ops, 3]

ExprEval[nums, #] & /@ solutions
SymbolicEval[nums, #] & /@ solutions

:

{{Plus, Times, Plus}, {Plus, Divide, Plus}, {Subtract, Plus, 
  Plus}, {Times, Plus, Times}, {Divide, Plus, Times}}

{3, 3, 3, 3, 3}

{"Plus"["Times"["Plus"[-1, 1], 2], 3], 
 "Plus"["Divide"["Plus"[-1, 1], 2], 3], 
 "Plus"["Plus"["Subtract"[-1, 1], 2], 3], 
 "Times"["Plus"["Times"[-1, 1], 2], 3], 
 "Times"["Plus"["Divide"[-1, 1], 2], 3]}

ExprEval , ( ) RPN:

ExprEval[{1, 2, 3}, {Plus, Times}] == (1 + 2) * 3

, , .

, , . Tuples, , .

, Select, , .


. . k n , O (k ^ n).

n = 10 6 , Win 7 x64, Core i7 860, 12 . :

Timings

- , - . x - nums, y - .

, . , , .

, , , .


. , . , {a, b, c, d, e, ... }, . . , O(k^n * n!), k - , n - .

:

(* generates a lists of the form 
{
 {number permutation, {{op order 1}, {op order 2}, ... }
 }, ...
}*)

GetAllExpressions[nums_, ops_, target_] :=
 ParallelMap[{#, GetExpression[#, ops, target]} &, 
  Tuples[nums, Length@nums]]
+5

All Articles