I am scouring the web but I cannot find how to generate random math expressions with sympy. Is it even possible?
I would like to build an expression tree by randomly selecting functions (product, sum, cosine...) and symbols from a set of predefined functions and symbols.
For instance, given the set [+,.] of sum and product and the symbols [x,y] I'd like to generate expressions such as x+y, (x+y).x, y+(x.x+y)+x etc, controlling parameters as the tree depth, width and the number of nodes.
Any hints?
Something like the following might help you get started:
from random import choice, randint
from sympy import FunctionClass, Add, Mul, cos, sin, binomial, arity, S
def args(n, atoms, funcs):
a = funcs+atoms
g = []
for _ in range(n):
ai = choice(a)
if isinstance(ai, FunctionClass):
g.append(ai(*args(arity(ai), atoms, funcs)))
else:
g.append(ai)
return g
def expr(ops, atoms, funcs=()):
types = [Add, Mul]
atoms = tuple(atoms)
while 1:
e = S.Zero
while e.count_ops() < ops:
_ = choice(types)(*args(randint(1,3), atoms, funcs))
e = choice(types)(e, _)
if e is S.NaN: break
else:
return e
>>> [expr(5, (-1,0,1,x,y)) for do in range(2)]
[(x - 1)*(2*x + y + 2), x + y*(x + 4*y - 2) + y]
>>> expr(5, (-1,0,1,x,y), (cos, binomial))
x*y**2 + x + cos(1)
>>> expr(5, (-1,0,1,x,y), (cos, binomial))
(y + zoo*binomial(y, x) - 2)*(y + cos(1) + 1)
To generate rational expressions you could change make the 2nd _ arg be _**choice((1,-1)).
I am given a list of numbers, for example [22,45,2,6,7,...].
Now I have to insert binary operators: +, -, /, * and parentheses (, ) between numbers so that expression is equal to given number k.
List all possible expressions created by insertions of operators and parentheses that will give sum of k.
Position of numbers in resulting expression have to be fixed, i.e. only insertion of operators and parentheses between or around numbers
For example: given number k=9 and list [1,2,3], one solution would be [(,(,1,+,2,),*,3,)].
How would I do that?
[ my current wrong solution ]:
Right now I know how to evaluate expression like [1,+,3,*,5] by going from left to right and eating Operand1,Operator,Operand2 until there is nothing to eat.
But I have to insert parentheses too..
Can anybody sketch a solution or give a hint?
This was an old exam question, and I'm preparing for exam which will be in 3 months, so I'm trying to solve these, but I'm stuck.
EDIT: This is prolog question.
I think trying to directly build the result list with parentheses while traversing the input is a bad idea. It's easier to build up the syntax tree of an expression whose leaves are labeled with the elements of the given list, then process that in a separate step.
For example:
?- leaves_expr([A,B,C,D], Expr).
Expr = leaf(A)+ (leaf(B)+ (leaf(C)+leaf(D))) ;
Expr = leaf(A)+ (leaf(B)+leaf(C)*leaf(D)) ;
Expr = leaf(A)+ (leaf(B)+leaf(C)+leaf(D)) ;
Expr = leaf(A)+ (leaf(B)*leaf(C)+leaf(D)) ;
Expr = leaf(A)+leaf(B)* (leaf(C)+leaf(D)) ;
Expr = leaf(A)+leaf(B)* (leaf(C)*leaf(D)) ;
This can be implemented as follows:
leaves_expr([X], leaf(X)).
leaves_expr(Leaves, X + Y) :-
append([L|Left], [R|Right], Leaves),
leaves_expr([L|Left], X),
leaves_expr([R|Right], Y).
leaves_expr(Leaves, X * Y) :-
append([L|Left], [R|Right], Leaves),
leaves_expr([L|Left], X),
leaves_expr([R|Right], Y).
The append/3 calls are used to decompose the list of leaves into non-empty parts to avoid nontermination problems. I would be interested in an elegant way of doing this with DCGs.
Then, given an expression tree like this, we can "output" it again in a fully parenthesized form:
expr_parenthesized(leaf(X)) -->
[X].
expr_parenthesized(X + Y) -->
['('],
expr_parenthesized(X),
[+],
expr_parenthesized(Y),
[')'].
expr_parenthesized(X * Y) -->
['('],
expr_parenthesized(X),
[*],
expr_parenthesized(Y),
[')'].
Composing these two parts, we get:
?- leaves_expr([A,B,C], Expr), expr_parenthesized(Expr, Parenthesized).
Expr = leaf(A)+ (leaf(B)+leaf(C)),
Parenthesized = ['(', A, +, '(', B, +, C, ')', ')'] ;
Expr = leaf(A)+leaf(B)*leaf(C),
Parenthesized = ['(', A, +, '(', B, *, C, ')', ')'] ;
Expr = leaf(A)+leaf(B)+leaf(C),
Parenthesized = ['(', '(', A, +, B, ')', +, C, ')'] ;
Expr = leaf(A)*leaf(B)+leaf(C),
Parenthesized = ['(', '(', A, *, B, ')', +, C, ')'] ;
Expr = leaf(A)* (leaf(B)+leaf(C)),
Parenthesized = ['(', A, *, '(', B, +, C, ')', ')'] ;
Expr = leaf(A)* (leaf(B)*leaf(C)),
Parenthesized = ['(', A, *, '(', B, *, C, ')', ')'] ;
and so on. If you write the easy predicate expr_value/2 to evaluate such expressions (constructed from numbers at the leaves), you're done.
One way to think about the parenthesis problem without actually putting any parentheses is to use postfix notation. In other words:
(a + b) * c
turns into:
a b + c *
which is the following tree in canonical Prolog notation:
*(+(a, b), c)
Similarly:
a + (b * c) ---> a b c * + ---> +(a, *(b, c))
For a complete example, with three operands, 1, 2, and 3, and only + and * as operators, to keep it short, you get:
1 2 + 3 + ---> (1 + 2) + 3 = 6
1 2 + 3 * ---> (1 + 2) * 3 = 9
1 2 * 3 + ---> (1 * 2) + 3 = 6
1 2 * 3 * ---> (1 * 2) * 3 = 6
1 2 3 + + ---> 1 + (2 + 3) = 6
1 2 3 + * ---> 1 * (2 + 3) = 5
1 2 3 * + ---> 1 + (2 * 3) = 7
1 2 3 * * ---> 1 * (2 * 3) = 6
Looking at the first column, I get the following general idea: you start with n operands and n-1 binary operators. You push the first two operands on the stack, and need to perform 2*n-3 more steps. At each step, you either push an operand or apply an operator. You can always push an operand if you still have any left. You can apply an operator only if you have two or more operands on the stack; you will have to reduce the stack at that point.
Backtracking will take care of enumerating all possibilities (so this is a typical brute-force exhaustive search of the solution space). You will have two sources of choicepoints: picking one of the operators; and either pushing or reducing.
With this in mind, I arrive at the following implementation of a predicate that takes a list of operands, a list of binary operators, and gives you a "parenthesized" expression:
expr(Operands, Operators, E) :-
Operands = [A, B|Rest],
length(Operands, N),
Steps is 2*N - 3,
expr(Steps, Rest, [B, A], Operators, E).
This pushed the first two operands to the stack and calculated the number of steps left.
expr(Steps, Operands, Stack, Operators, E) :-
( succ(Steps0, Steps) ->
next(Steps0, Operands, Stack, Operators, E)
; Stack = [E]
).
Here I used succ/2 to count down to 0 and then stop; at the end, the only element on the stack is your expression.
next(Steps, Operands, Stack, Operators, E) :-
push(Operands, Stack, Operands_next, Stack_next),
expr(Steps, Operands_next, Stack_next, Operators, E).
next(Steps, Operands, Stack, Operators, E) :-
member(Op, Operators),
reduce(Stack, Op, Stack_next),
expr(Steps, Operands, Stack_next, Operators, E).
This is where you either push or reduce. The two separate clauses is the first source of choice points; using member/2 to take one operator from the list is the other.
push([X|Xs], S0, Xs, [X|S0]).
reduce([A,B|Stack], Op, [X|Stack]) :-
X =.. [Op, B, A].
Implementing pushing and reducing is trivial. I used the "univ" operator =.. to make terms like +(1, 2) from a list like [+, 1, 2].
With this, you can already ask "how can I use +, *, and parenthesis to make 7 out of [1,2,3]":
?- expr([1,2,3], [+,*], E), E =:= 7.
E = 1+2*3 ;
false.
This is the most basic "generate and test": you generate arithmetic expressions, then test if they evaluate to a value. If you leave out the test, you can see all expressions:
?- expr([1,2,3], [+,*], E).
E = 1+(2+3) ;
E = 1*(2+3) ;
E = 1+2*3 ;
E = 1*(2*3) ;
E = 1+2+3 ;
E = (1+2)*3 ;
E = 1*2+3 ;
E = 1*2*3 ;
false.
One curious detail is that because + and * are already defined as infix operators, Prolog writes them and even parenthesizes them for you. I don't know if a solution like E = (1+2)*3 is good enough for you or do you really need ['(', 1, +, 2, ')', *, 3]. The other answer seems to have a working solution for this already. Since here the expression is already a valid arithmetic expression, you would have to adjust it slightly. I would probably write it like this:
infix(N) -->
{ number(N)
}, !,
[N].
infix(E) -->
{ compound(E),
E =.. [Op, A, B]
}, !,
['('], infix(A), [Op], infix(B), [')'].
I also don't know if 1+2+3 = 3+3 = 6 is the same as 1+(2+3) = 1+5 = 6: do you need to consider associativity?
Either way, you can wrap expr/3 in a predicate like this:
equals_k(Numbers, K, E) :-
expr(Numbers, [+,-,*,/], E0),
K =:= E0,
phrase(infix(E0), E).
PS: it is quite easy to get a division by zero exception, try for example:
?- expr([1,0], [/], E), R is E.
This my solution proposal which I find to be simple and straight forward,
copy and paste to notepad++ editor for best readability.
* ________________________________________________ *
*|find_expression(NumsList,TargetValue,Expression)| *
**------------------------------------------------* *
* Expression is an arithmetic expression of the numbers in Numslist with *
* possible operators '+','-','*','/' and '(' and ')' between the numbers *
* in such a way that the expression evaluates to the TargetValue argument *
*****************************************************************************/%
/* a single element number list can evaluate only to itself */
find_expression([SingleNumber],SingleNumber,SingleNumber).
/* expression of a multypile number list */
find_expression(NumberList,Target,Expression):-
/* non-deterministically divide the number list
into 2 separate lists which include at least one number each*/
append([X|Xs],[Y|Ys], NumberList),
/* recursively find an expression for east list,
where the expression evaluates to itself */
find_expression([X|Xs],Exp1,Exp1),
find_expression([Y|Ys],Exp2,Exp2),
/* non-deterministically choose an operand from [+,-,*,division]
and compose Expression to be (Exp1 Operand Exp2) */
( member(Expression,[Exp1+Exp2,Exp1-Exp2,Exp1*Exp2])
; /* prevent zero divison */
(Val2 is Exp2, Val2 =\= 0, Expression = (Exp1/Exp2))), %/*
/* assure that final expression evaluates(matches) the targe value
and convert value from integer to float if necessary */
( Target = Expression ; Target is Expression
; FloatTarget is Target*1.0, FloatTarget is Expression)