Related
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)
I am new to prolog and I was wondering if anyone could help me with this problem. The problem: given the integers 1,2,3,4, and the predicates mult/2, div/2, div/2, minus/2, and minus/2, and eval/2, I need to write a predicate solutions/1 that, when called like this:
?- solutions(L).
it should terminate with the variable L unified to a list of expressions with value 6. Expressions are of the form:
X, Y, exp/2
But my code is not working. I have two versions. The first freezes up SWI-Prolog, not returning any answer after I type a period, and not letting me evaluate anything else afterward:
eval(1,1.0).
eval(2,2.0).
eval(3,3.0).
eval(4,4.0).
eval(mult(X,Y),Z) :-
eval(X,A),
eval(Y,B),
Z is A*B.
eval(div(X,Y),Z) :-
eval(X,A),
eval(Y,B),
Z is A/B.
eval(minus(X,Y),Z) :-
eval(X,A),
eval(Y,B),
Z is A-B.
solutions(L) :-
setof(X,eval(X,6),L),
print(L).
The second version just returns false when I type ?- solutions(L).:
solutions(L) :-
setof([exp,X,Y],eval(exp(X,Y),6),L),
print(L).
Thank you so much for taking the time to help!
Maybe you're looking for something like
solutions(L) :-
Ns = [1,2,3,4],
Ex = [*,/,-],
findall((X,Y,E),
(member(X,Ns),member(Y,Ns),member(E,Ex),F=..[E,X,Y],6=:=F),
L).
that yields
?- solutions(L).
L = [(2, 3, (*)), (3, 2, (*))].
Expressions are usually recursive, that is, arguments could be expressions instead of plain numbers. But then, in my opinion your problem is underspecified, as we need criteria to stop the infinite flow of solutions resulting - for instance - by repeated application of operations that don't change the value. Like multiply or divide by 1.
The problem is that your code is going in infinite recursion with eval/2 predicate.
You can try this solution:
num(1).
num(2).
num(3).
num(4).
eval(mult(A,B),Z) :-
num(A),
num(B),
Z is A*B.
eval(div(A,B),Z) :-
num(A),
num(B),
Z is A/B.
eval(minus(A,B),Z) :-
num(A),
num(B),
Z is A-B.
test(L) :-
setof(X,eval(X,6),L),
print(L).
Which yields:
?- test(L).
[mult(2,3),mult(3,2)]
L = [mult(2, 3), mult(3, 2)].
I'm trying to understand how this program works.
Code from Daniel Lyons' solution(from the link above)
takeout(X,[X|R],R).
takeout(X,[F |R],[F|S]) :- takeout(X,R,S).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
I'm trying ti understand how it works with this list [1,2,3]
So, I have perm([1,2,3],X).
It's easy to understand at first, Y = [2,3] then Y = [3] and then Y = []
After that perm([],[]). is called and it gives us W = []
Now, takeout is called for the first time - takeout(3, Z, []).
It returns Z = [3]
Now, we are going back, where perm([],[]). gives us W = [3], (because Y was [3] at this point)
Same as above, takeout(2, Z, [3]) and Z = [2, 3].
Again perm([], []). and W = [2, 3].
And takeout(1, Z, [2, 3]), which gives us first answer Z = [1, 2, 3]
Here I don't know why program don't end , recursion is done, so why takeout and perm are working again ?
After that takeout is called takeout(1, [2,3]).
Which now works with takeout(X,[F |R],[F|S]) and not with takeout(X,[X|R],R). and that's my second question, why?
In Prolog, a predicate's behavior is quite unlike that of a function in procedural languages. A function is called to perform a task, it executes, and then comes back returning some values or having performed some side effects, or both.
A predicate defines a relation and/or set of facts that establish a logical connection between it's arguments. When a query is made to a predicate in Prolog, Prolog will attempt to find every instantiation of the argument variables that will make that predicate succeed (be true).
In a very simple case, I might have the following facts:
likes(tom, mary). % Tom likes Mary
likes(fred, mary). % Fred likes Mary
Here I have one predicate or fact, likes, which defines a relation between two people. We call the above facts because they each specify a precise, concrete relation with fully instantiated arguments. I can make a query to determine Who likes Mary? as follows:
| ?- likes(Person, mary).
Person = tom ? ;
Person = fred
yes
The query first comes back with Person = tom but indicates it has more options to check once it has found that Person = tom satisfies the query. Entering ; tells Prolog to continue with the next solution (if there is one), and it finds it: Person = fred.
Now let's consider takeout/3. This is a predicate which defines a relation between a set of variables.
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
The takeout/3 predicate has two predicate clauses or rules for the relation. It's helpful to try to read them:
R is what you get if you take X out of [X|R].
[F|S] is what you get if you take X out of [F|R] if S is what you get when you take X out of R.
Prolog looks at multiple clauses in a disjunctive way. That is, a query or call to the predicate will succeed if any one of the rules can hold true. When a query on takeout/3 is made, Prolog will look for instantiations of the given variables in the query which will make it true, and it will attempt to find every such instantiation that does so. In other words, if there's more than one way to satisfy the condition, it will backtrack and attempt to find those variables instantiations that do so.
Consider the query:
?- takeout(X, [1,2,3], R).
Prolog is able to match this to the first predicate clause: takeout(X, [X|R], R) as takeout(1, [1,2,3], [2,3]) by instantiating X = 1 and R = [2,3]. So this query will succeed with the following result:
R = [2,3]
X = 1 ?
But we see that Prolog is indicating there are more options to explore. That's because there's another clause: takeout(X,[F|R],[F|S]) which matches the query, takeout(X, [1,2,3], R). Prolog therefore backtracks and attempts the second clause, which matches:
takeout(X, [1|[2,3]], [1|S]) :- % F = 1, R = [2,3]
takeout(X, [2,3], S).
Prolog will then follow the recursive call takeout(X, [2,3], S) and start from the first clause again and attemp to match takeout(X, [2,3], S) with takeout(X, [X|R], R), which succeeds with X = 2 and S = [3] (takeout(2, [2|[3]], [3]).. The recursion unwinds or returns (as it would in any language), and the previous call head, takeout(X, [1|[2,3]], [1|S]) then ends up instantiating as: takeout(1, [1|[2,3]], [1|[3]]). So we get:
R = [2,3]
X = 1 ? ;
R = [1,3] % that is, [1|[3]]
X = 2 ?
And so on. Similar behavior applies to perm. In the context of the query perm, the calls to takeout backtrack to produce additional results, so perm produces additional results (since its calls to takeout backtrack, just like they do when you query takeout by hand).
As noted by #false, the predicate takeout/3 is implemented as a standard predicate in Prolog as select/3.
copyList([], []). % base case
copyList([H|T], [H|R]) :-
copyList(T, R).
I "sort of" understand how recursion works, but when I analysed this function, I got really confused. Can someone please explain, step-by-step what happens in this function and how it reaches the end using the example below:
?- copyList([1,2,3],L).
To understand what happens, you must see Prolog as a theorem solver: when you give Prolog the query ?- copyList([1, 2, 3], L)., you're essentially asking Prolog to prove that copyList([1, 2, 3], L) is true.
Prolog will therefore try to prove it. At its disposal, it has two clauses:
copyList([], []).
copyList([H|T], [H|R]):-
copyList(T, R).
As it is the first that it encounters, Prolog wil try to prove that copyList([1, 2, 3], L) is true by using the clause copyList([], []).
To do so, and since the clause has no body (nothing after :-), it would just have to unify the arguments of your query with the arguments of the clause (unify [1, 2, 3] with [] and L with []). While it is easy to unify L5 with [] (with the unification L5 = []), it is impossible to unify [1, 2, 3] with []. Therefore Prolog has failed to prove your query by using the first clause at its disposal. It must then try to use the second.
Once again it will unify the query arguments with the clause arguments to see if the clause is applicable: here it can do so, with the unifications H = 1, T = [2, 3], L = [H|R]. Now it has to see if the conditions listed after :- are respected, so it has to prove copyList(T, R). The exact same thing goes on twice, until it finds itself trying to prove copyList([], R). There, the first clause is applicable, and its job is over.
You can sum up the execution with a drawing as follows:
copyList([1, 2, 3], L).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and L = [1|R]
|
` copyList([2, 3], R).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R = [2|R2]
|
` copyList([3], R2).
|
| try to use clause number 1, doesn't unify with arguments.
| use clause number 2 and R2 = [3|R3]
|
` copyList([], R3).
|
| use clause number 1 and R3 = []. One solution found
| try to use clause number 2, doesn't unify with arguments.
| No more possibilities to explore, execution over.
Now that the execution is over, we can see what the original L is by following the chain of unifications:
L = [1|R]
R = [2|R2]
R2 = [3|R3]
R3 = []
R2 = [3]
R = [2, 3]
L = [1, 2, 3]
Thanks to Will Ness for his original idea on how to explain the final value of a variable.
While your specific question was already answered, few remarks.
First, you could just as well call ?- copyList(L,[1,2,3]). or ?- copyList([1,2,3],[1,2|Z]). etc. What's important is that both lists can be of equal length, and their elements at the corresponding positions can be equal (be unified), because the meaning of the predicate is that its two argument lists are the same - i.e. of the same length, and having the same elements.
For example, the first condition can be violated with the call
?- copyList(X, [A|X]).
because it says that the 2nd argument is one element longer than the first. Of course such solution can not be, but the query will never terminate, because the first clause won't ever match and the second always will.
list_sum([], 0).
list_sum([Head | Tail], TotalSum) :-
list_sum(Tail, Sum1),
Total = Head + Sum1.
This code returns true. If I replace Total = Head + Sum1 with Total is Head + Sum1, then it will return the value. But what I should replace it with to get the result like this:
?- list_sum([1,2,0,3], Sum).
Sum = 1+2+0+3 ; % not to return value 6!!!
The answer is simple:
sum_list([], 0).
sum_list([H|T], Sum) :-
sum_list(T, Rest),
Sum is H + Rest.
This code works in only one direction - this means - it does not allow you to generate lists with that specific sum. But since the set of such lists is infinite, that would not be practical anyways.
Note that in the second clause of your procedure TotalSum is never instantiated. You should have received a warning by the interpreter when consulting your code.
Here's my suggestion:
list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
list_sum([Item1+Item2|Tail], Total).
The first clause deals with the base case, when there is only one element left in the list, that is your result.
The second clause deals with the recursion step. It grabs the first two items of the list and performs a recursive call replacing those two items with a new term Item1+Item2.
The program is
list_sum([],0).
list_sum([Head|Tail], TotalSum):-
list_sum(Tail, Sum1),
TotalSum is Head+Sum1.
now if the query is
?- list_sum([1,2,3,4], Sum).
answer is
Sum = 10
In Prolog (+)/2 is a binary infix operator. This allows us to write A+B instead of +(A,B).
?- current_op(_,yfx,+). % left-associative binary infix operator
true.
(+)/2 associates to the left, so 1+2+3 is a short for (1+2)+3.
(.)/2 associates to the right, so [1,2,3] is short for .(1,.(2,.(3,[]))).
To get parenthesization right, we use an auxiliary predicate with an extra "accumulator" argument:
list_sum([X|Xs],S) :-
list_sum0_sum(Xs,X,S).
list_sum0_sum([], S ,S).
list_sum0_sum([X|Xs],S0,S) :-
list_sum0_sum(Xs,S0+X,S).
Sample query:
?- list_sum([1,2,0,3],S).
S = 1+2+0+3.
If you want to transform a list of numbers into an additive expression, from
[1,2,3]
to
1 + 2 + 3
you could do something like this, using something like a difference list:
list_to_additive_expr( [] , 0 ).
list_to_additive_expr( [X|Xs] , X + RHS ) :-
sum_of( Xs , RHS ).
Alternatively, you could use an accumulator:
list_to_additive_expr( Xs , Expr ) :-
list_to_additive_expr( Xs , 0 , Expr )
.
list_to_additive_expr( [] , Expr , Expr ) .
list_to_additive_expr( [X|Xs] , RHS , Expr ) :-
sum_of( Xs , X + RHS , Expr )
.
I believe you'll find the first style is not properly tail recursive and so won't get optimized into a loop via tail recursion optimization (TRO) — and so, if the list is sufficiently long, will get a stack overflow. The second approach should have TRO applied and should work for lists of any length.
What is TRO, you might ask? Here's Wikipedia with an answer for you:
In computer science, a tail call is a subroutine call that happens inside another
procedure and that produces a return value, which is then immediately returned by the
calling procedure. The call site is then said to be in tail position, i.e. at the end of
the calling procedure. If a subroutine performs a tail call to itself, it is called
tail-recursive. This is a special case of recursion.
Tail calls are significant because they can be implemented without adding a new stack
frame to the call stack. Most of the frame of the current procedure is not needed any
more, and it can be replaced by the frame of the tail call, modified as appropriate
(similar to overlay for processes, but for function calls). The program can then jump to
the called subroutine. Producing such code instead of a standard call sequence is called
tail call elimination, or tail call optimization.