Coverage for /usr/lib/python3/dist-packages/sympy/strategies/tree.py: 53%
17 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from functools import partial
2from sympy.strategies import chain, minimize
3from sympy.strategies.core import identity
4import sympy.strategies.branch as branch
5from sympy.strategies.branch import yieldify
8def treeapply(tree, join, leaf=identity):
9 """ Apply functions onto recursive containers (tree).
11 Explanation
12 ===========
14 join - a dictionary mapping container types to functions
15 e.g. ``{list: minimize, tuple: chain}``
17 Keys are containers/iterables. Values are functions [a] -> a.
19 Examples
20 ========
22 >>> from sympy.strategies.tree import treeapply
23 >>> tree = [(3, 2), (4, 1)]
24 >>> treeapply(tree, {list: max, tuple: min})
25 2
27 >>> add = lambda *args: sum(args)
28 >>> def mul(*args):
29 ... total = 1
30 ... for arg in args:
31 ... total *= arg
32 ... return total
33 >>> treeapply(tree, {list: mul, tuple: add})
34 25
35 """
36 for typ in join:
37 if isinstance(tree, typ):
38 return join[typ](*map(partial(treeapply, join=join, leaf=leaf),
39 tree))
40 return leaf(tree)
43def greedy(tree, objective=identity, **kwargs):
44 """ Execute a strategic tree. Select alternatives greedily
46 Trees
47 -----
49 Nodes in a tree can be either
51 function - a leaf
52 list - a selection among operations
53 tuple - a sequence of chained operations
55 Textual examples
56 ----------------
58 Text: Run f, then run g, e.g. ``lambda x: g(f(x))``
59 Code: ``(f, g)``
61 Text: Run either f or g, whichever minimizes the objective
62 Code: ``[f, g]``
64 Textx: Run either f or g, whichever is better, then run h
65 Code: ``([f, g], h)``
67 Text: Either expand then simplify or try factor then foosimp. Finally print
68 Code: ``([(expand, simplify), (factor, foosimp)], print)``
70 Objective
71 ---------
73 "Better" is determined by the objective keyword. This function makes
74 choices to minimize the objective. It defaults to the identity.
76 Examples
77 ========
79 >>> from sympy.strategies.tree import greedy
80 >>> inc = lambda x: x + 1
81 >>> dec = lambda x: x - 1
82 >>> double = lambda x: 2*x
84 >>> tree = [inc, (dec, double)] # either inc or dec-then-double
85 >>> fn = greedy(tree)
86 >>> fn(4) # lowest value comes from the inc
87 5
88 >>> fn(1) # lowest value comes from dec then double
89 0
91 This function selects between options in a tuple. The result is chosen
92 that minimizes the objective function.
94 >>> fn = greedy(tree, objective=lambda x: -x) # maximize
95 >>> fn(4) # highest value comes from the dec then double
96 6
97 >>> fn(1) # highest value comes from the inc
98 2
100 Greediness
101 ----------
103 This is a greedy algorithm. In the example:
105 ([a, b], c) # do either a or b, then do c
107 the choice between running ``a`` or ``b`` is made without foresight to c
108 """
109 optimize = partial(minimize, objective=objective)
110 return treeapply(tree, {list: optimize, tuple: chain}, **kwargs)
113def allresults(tree, leaf=yieldify):
114 """ Execute a strategic tree. Return all possibilities.
116 Returns a lazy iterator of all possible results
118 Exhaustiveness
119 --------------
121 This is an exhaustive algorithm. In the example
123 ([a, b], [c, d])
125 All of the results from
127 (a, c), (b, c), (a, d), (b, d)
129 are returned. This can lead to combinatorial blowup.
131 See sympy.strategies.greedy for details on input
132 """
133 return treeapply(tree, {list: branch.multiplex, tuple: branch.chain},
134 leaf=leaf)
137def brute(tree, objective=identity, **kwargs):
138 return lambda expr: min(tuple(allresults(tree, **kwargs)(expr)),
139 key=objective)