Prolog program won't compute variable answer? - list

This should be an easy fix, but I can't seem to tackle this, and it's getting frustrating. I've coded a program which computes or verifies that two lists are related because the elements of the second list are all incremented by one from the elements of the first list. This works when two lists are given, but not when it needs to compute a list.
Code is as follows:
inc([], []).
inc([X|XS],[Y|YS]) :-
Y =:= X+1,
inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated
Any help would be greatly appreciated!

Your problem is essentially that =:=/2 is for testing rather than establishing bindings, though is/2 still doesn't really do what you want. For instance, while 2 is 1 + 1 is true, 2 is X+1 will not result in X being bound to 1, because is/2 expects there to be just one variable or value on the left and one expression on the right, and it does not behave "relationally" like the rest of Prolog. If you want arithmetic that behaves this way, you should check out clpfd; looking at the complexity it adds is a good explanation for why things are the way they are.
Fortunately, you don't need all of arithmetic to solve your problem. The succ/2 builtin will do exactly what you need, and bonus, you get a one line solution:
inc(X, Y) :- maplist(succ, X, Y).
In use:
?- inc([1,2,3], [2,3,4]).
true.
?- inc([1,2,3], X).
X = [2, 3, 4].
?- inc(X, [1,2,3]).
X = [0, 1, 2].
Your code also works fine if you use succ/2 instead of =:=/2:
inc([], []).
inc([X|XS],[Y|YS]) :-
succ(X, Y),
inc(XS,YS).
This must be the "easy fix" you suspected. :)
I'm not sure what #mbratch is referring to about there being "too many variables" for one predicate. I suspect this is a misunderstanding of Prolog on their part, perhaps a holdover from other languages where a function can return one value or something. There is no technical limitation here; predicates can take as many ground or nonground arguments and bind as many of them as you want; the limiting factor is your creativity.
Similarly, I don't think "asymmetry" is a meaningful concept here. It's quite normal to define predicates that have just a single instantiation pattern, but it's also normal and preferable to make predicates that are flexible about instantiation—you can't know ahead of time what uses may be needed in the future. You might think to yourself that an instantiation pattern that destroys information might preclude the inverse instantiation pattern, but in practice, frequently you can turn it into a generator instead.
To give a trite example, append/3's name seems to imply this pattern:
?- append([1,2], [3,4], X).
X = [1,2,3,4]
That's a perfectly good use, but so is:
?- append(X, Y, [1,2,3,4]).
This is a non-deterministic instantiation pattern and will produce five solutions:
X = [], Y = [1,2,3,4]
X = [1], Y = [2,3,4]
X = [1,2], Y = [3,4]
X = [1,2,3], Y = [4]
X = [1,2,3,4], Y = []
This seems to stand in contradiction to some of #mbratch's ideas, but there's no explicit testing for ground/nonground in the usual definition of append/3, because it isn't necessary, and likewise with the second calling pattern you get two "return values" from one input. SWI source:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
Edit: Negative numbers. I forgot that succ/2 is defined only on positive integers. We can apply #mbratch's technique and still get a tidy solution with the desired properties:
isucc(X, Y) :- var(X), X is Y-1.
isucc(X, Y) :- Y is X+1.
inc(X, Y) :- maplist(isucc, X, Y).
In action:
?- inc(X, [-1,2]).
X = [-2, 1] ;
false.
Edit: Using clp(fd) (via #mat):
fdsucc(X,Y) :- Y #= X + 1.
inc(X, Y) :- maplist(fdsucc, X, Y).
This generates even for the most general query:
?- inc(X, Y).
X = Y, Y = [] ;
X = [_G467],
Y = [_G476],
_G467+1#=_G476 ;
X = [_G610, _G613],
Y = [_G622, _G625],
_G610+1#=_G622,
_G613+1#=_G625 ;
X = [_G753, _G756, _G759],
Y = [_G768, _G771, _G774],
_G753+1#=_G768,
_G756+1#=_G771,
_G759+1#=_G774
...
The utility of this is questionable, but presumably since you're using clp(fd) you'll eventually impose other constraints and get something useful.

inc([],[]).
inc([X|XS],[Y|YS]) :-
nonvar(X),
Z is X + 1,
Y = Z,
inc(XS,YS), !.
inc([X|XS],[Y|YS]) :-
nonvar(Y),
Z is Y - 1,
X = Z,
inc(XS,YS), !.
Here we need to get a real computation for the addition, then attempt instantiation with =. The predicate had to be split to deal with the case where X was not instantiated, versus when Y wasn't. The ! at the end of each is to prevent it from trying for more solutions after it has found one through one of the two similar paths.

Related

How to simplify algebra equations represented as list of list

With Prolog I want to simplify algebra expression represented as as list of list:
algebra equation
f = 3x+2
list of list
[[3,1],[2,0]]
3 and 2 are coefficients
1 and 0 are exponents
That should be obvious.
I am looking for some tips or suggestions on how to code the simplifications for this example:
f = 3x+2x+1+2
[[3,1],[2,1],[1,0],[2,0]]
simplified:
f = 5x+3
[[5,1],[3,0]]
I have tried some built in functions but did not get the proper idea about how to use them.
One liner, similar to what's proposed by joel76:
simplify(I,O) :-
bagof([S,E],L^(bagof(C,member([C,E],I),L),sum_list(L,S)),O).
The inner bagof collects C (coefficients) given E (exponents), the resulting list L is summed into S, and paired with E becomes [S,E], an element (monomial) of O.
If you omit the universal quantification specifier (that is L^) you get single monomials on backtracking.
You can solve your problem in this way:
simplify(_,_,S,S,[]):- !.
simplify(L,I,Sum,NTot,[[I,S]|T]):-
Sum =< NTot,
findall(X,member([X,I],L),LO),
length(LO,N),
S1 is Sum + N,
sum_list(LO,S),
I1 is I+1,
simplify(L,I1,S1,NTot,T).
write_function([]).
write_function([[D,V]|T]):-
write(' + '),write(V),write('x^'),write(D),
write_function(T).
test:-
L = [[3,1],[2,1],[1,0],[2,0]],
length(L,N),
simplify(L,0,0,N,LO),
LO = [[D,V]|T],
write('f='),write(V),write('x^'),write(D),
write_function(T).
The main predicate is simplify/5 which uses findall/3 to find all the coefficients with the same degree and then sums them using sum_list/2. Then you can write the result in a fancy way using write_function/1.
In SWI-Prolog You can use aggregate :
pred(>, [_,X], [_,Y]) :- X > Y.
pred(<, [_,X], [_,Y]) :- X < Y.
pred(=, [_,X], [_,X]).
simplify(In, Out) :-
aggregate(set([S,X]), aggregate(sum(P), member([P,X], In), S), Temp),
predsort(pred, Temp, Out).
For example :
?- simplify([[3,1],[2,1],[1,0],[2,0]], Out).
Out = [[5, 1], [3, 0]] ;
false.

Output seems to only test the very last in the list for difference function

Link to old question: Checking if the difference between consecutive elements is the same
I have posted my progress in another question post, but here is my code my the problem I am trying to solve in Prolog. I would like my function to return the result of sameSeqDiffs([3,5,7],2) depending on whether the difference between each number is the same as my last argument. Here is what I cam up with so far:
sameSeqDiffs([X,Y], Result):-
A is Y - X,
A = Result.
sameSeqDiffs([X,Y,Z|T], Result):-
sameSeqDiffs([Y,Z|T], Result).
When I test this code, it seems to work for some input, but clearly fails for others:
Your solution has some issues:
sameSeqDiffs([X,Y,Z|T], Result):-
sameSeqDiffs([Y,Z|T], Result).
Here you ignore completely variable X and the difference X-Y.
sameSeqDiffs([X,Y], Result):-
Result is Y - X.
sameSeqDiffs([X,Y,Z|T], Result):-
Result is Y - X,
sameSeqDiffs([Y,Z|T], Result).
In essence you forgot one thing: to calculate the difference in the recursive case:
sameSeqDiffs([X,Y], Result):-
A is Y - X,
A = Result.
sameSeqDiffs([X,Y,Z|T], Result):-
Result is Y - X,
sameSeqDiffs([Y,Z|T], Result).
So here we unify Result with the difference between Y and X. We make a recurive call with this difference, such that a "deeper" recursive call will unify against the already grounded difference. If the differences do not match, then the predicate will fail.
You can also make the first clause a bit more elegant, by immediately using Result in the is/2 predicate call, instead of first using a variable (A), and then unifying it, so:
sameSeqDiffs([X,Y], Result):-
Result is Y - X.
sameSeqDiffs([X,Y,Z|T], Result):-
Result is Y - X,
sameSeqDiffs([Y,Z|T], Result).
We then obtain the following results:
?- sameSeqDiffs([3, 5, 7], D).
D = 2 ;
false.
?- sameSeqDiffs([3, 5, 7], 2).
true ;
false.
?- sameSeqDiffs([3, 5, 7], 4).
false.
?- sameSeqDiffs([2, 3, 4], 1).
true ;
false.
?- sameSeqDiffs([2, 3, 4, 6], 2).
false.
?- sameSeqDiffs([2, 3, 4, 6], 1).
false.
The fact that it returns false after a true is due to Prolog backtracing and aiming to find another solution. So if it prints true; false. we know that an attempt was successful, and hence the predicate succeeded.
For problems like this it's a good time to learn about CLP(FD) which is the part of Prolog used to reason over integers:
same_seq_dif([X,Y], R) :- Y - X #= R.
same_seq_dif([X,Y,Z|T], R) :-
Y - X #= R,
same_seq_dif([Y,Z|T], R).
In addition to yielding correct results when you provide a fully instantiated list, it knows how to handle more general cases as well:
| ?- same_seq_dif([X,5,7], R).
R = 2
X = 3 ? ;
no
| ?- length(L,3), same_seq_dif(L, 3), fd_labeling(L).
L = [0,3,6] ? ;
L = [1,4,7] ? ;
L = [2,5,8] ? ;
L = [3,6,9] ? ;
L = [4,7,10] ?
...
I'm using GNU Prolog, thus the fd_labeling/1 predicate. SWI has a similar predicate, label/1.

Give as a solution every different number in a list of lists

I need to do a predicate, select(ListOfLists, X) that returns as a solution every different number in a list of lists, starting with the numbers that are alone in a list, for example:
select([[1,2,3],[1,2],[4],[3]],X).
Would return:
X = 4 ;
X = 3 ;
X = 2 ;
X = 1
Order doesn't matter as long as the numbers that are alone in the list are shown first.
To do this, first I coded 2 other predicates, which are:
%OrderedList is Lists ordered by size.
orderListsBySize(Lists, OrderedLists).
Example: orderListsBySize([[1,2],[6],[3,4,5]], L). ->L = [[6], [1,2], [3,4,5]]
And
%ListsWithoutX is Lists without the X elements
removeFromLists(X, Lists, ListsWithoutX).
Example: removeFromLists(1,[[1,2],[3],[4,1,5]],L). -> L = [[2],[3],[4,5]]
Both predicates work.
Then, to do the select(ListOfLists, X) predicate, I tried the following:
select([[X|[]]|_], X). select(L1,S) :-
orderListsBySize(L1, [[X|XS]|LS]),
length(XS, A),
A == 0,
select([[X|[]]|M], S),
removeFromLists(X, [XS|LS], M).
select([[X|_]|_], X).
But it doesn't work.
It's not a hard exercise to do in other languages, the problem is that it's still hard for me to understand how prolog works. I appreaciate any help, thanks!
You could start with:
select2(ListOfLists,Element):-
length(List,_Len),
member(List,ListOfLists),
member(Element,List).
Which will return all the answers, but then get stuck in a loop looking for ever bigger lists.
This can be averted using the :-use_module(library(clpfd)). and defining a fd_length/2 which wont keep looking for bigger lists then exist in the list of lists.
fd_length(L, N) :-
N #>= 0,
fd_length(L, N, 0).
fd_length([], N, N0) :-
N #= N0.
fd_length([_|L], N, N0) :-
N1 is N0+1,
N #>= N1,
fd_length(L, N, N1).
select(ListOfLists,Element):-
maplist(length,ListOfLists,Lengths),
sort(Lengths,SortedLength),
last(SortedLength,Biggest),
Biggest #>= Len,
fd_length(List,Len),
member(List,ListOfLists),
member(Element,List).
Example Query:
?-select([[1,2,3],[1,2],[4],[3]],X).
X = 4
X = 3
X = 1
X = 2
X = 1
X = 2
X = 3
false
If you want unique solutions, you could enclose in a setof/3 and then call member/2 again.

Masking in Prolog

I have recently been trying to figure out Prolog and been messing with lists of lists in Prolog. I am trying to create a sort of mask I suppose in p
Prolog. I have a predicate that determines the difference between two lists of lists (L1 and L2 lets say) in Prolog and saves them as a list of a list(Lets say R). I have another predicate that simply states if the difference is equal to zero(noDifference). I would like to have two resulting lists of lists (M1 and M2) based off of L1 and L2 compared to the R. For example I would like to compare all values of L1 and L2 to R, if a negative value is at a location of R then the value in the same location of L1 is saved into M1. And if a positive value is at a location of R then the value in the same location of L2 is saved into M2 if that makes sense. Before all of this I check with my noDifference function to see if the difference is 0 and if so all values of M1 and M2's lists of lists will be 0.
This is what I have so far(I'm not sure if I started it right)
masker(L1,L2,R,M1,M2):- noDifference(R1), M1=R, M2=R1;
and for the rest of it here are what some example values should look like under the hood
L1=[[1,5,3,8],[1,5,3,8]]
L2=[[5,4,7,4],[5,4,7,4]]
R=[[4,-1,4,-4],[4,-1,4,-4]]
M1=[[0,5,0,8],[0,5,0,8]]Neg values of L1 at R are stored rest are 0)
M2=[[5,0,7,0],[5,0,7,0]](Pos values of L2 at R are stored rest are 0)
Any insight if what I am doing so far is right and how to properly formulate the subgoals/where I should go next would be awesome!
edit with ex predicate
?- masker([[1,5,3,8],[1,5,3,8]],
[[5,4,7,4],[5,4,7,4]],
[[4,-1,4,-4],[4,-1,4,-4]], M1, M2).
M1=[[0,5,0,8],[0,5,0,8]].
M2=[[5,0,7,0],[5,0,7,0]].
Think what your predicate should describe. It is a relation between five lists of lists which, according to the example you provided, are of same length. This suggests the base case with five empty lists. Otherwise the heads of all five lists are lists themselves, that are in a specific relation to each other, let's call it lists_mask_mlists/5. And of course the same should be true for the tails, which can be realized by a recursive goal. So your predicate masker/5 could look something like that:
masker([],[],[],[],[]).
masker([X|Xs],[Y|Ys],[M|Ms],[R1|R1s],[R2|R2s]) :-
lists_mask_mlists(X,Y,M,R1,R2),
masker(Xs,Ys,Ms,R1s,R2s).
The actual masking relation also has a base case with five empty lists. Otherwise there are two further cases:
1) The current masking element (head of the third list) is negative: The head of the first list is the head of the fourth list and the head of the fifth list is 0
2) The current masking element is positive: The head of the second list is the head of the fifth list and the head of the fourth list is 0
You can express that like so:
lists_mask_mlists([],[],[],[],[]).
lists_mask_mlists([X|Xs],[_Y|Ys],[M|Ms],[X|R1s],[0|R2s]) :- % 1)
M < 0,
lists_mask_mlists(Xs,Ys,Ms,R1s,R2s).
lists_mask_mlists([_X|Xs],[Y|Ys],[M|Ms],[0|R1s],[Y|R2s]) :- % 2)
M >= 0,
lists_mask_mlists(Xs,Ys,Ms,R1s,R2s).
With this predicate your example query yields the desired result:
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2).
M1 = [[0,5,0,8],[0,5,0,8]],
M2 = [[5,0,7,0],[5,0,7,0]] ? ;
no
Note however, that due to < and >= this only works, if the third list is variable free. Replacing the first 4 in the third argument by a variable yields an instantiation error:
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[X,-1,4,-4],[4,-1,4,-4]],M1,M2).
ERROR at clause 2 of user:masked/5 !!
INSTANTIATION ERROR- =:=/2: expected bound value
If you intend to use the predicate with a third argument that is not variable free, you might like to consider using clpfd. Include the line
:-use_module(library(clpfd)).
in your source file and alter lists_mask_mlists/5 like so:
lists_mask_mlists([],[],[],[],[]).
lists_mask_mlists([X|Xs],[_Y|Ys],[M|Ms],[X|R1s],[0|R2s]) :-
M #< 0, % <- here
lists_mask_mlists(Xs,Ys,Ms,R1s,R2s).
lists_mask_mlists([_X|Xs],[Y|Ys],[M|Ms],[0|R1s],[Y|R2s]) :-
M #>= 0, % <- here
lists_mask_mlists(Xs,Ys,Ms,R1s,R2s).
Now the second query works too:
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[X,-1,4,-4],[4,-1,4,-4]],M1,M2).
M1 = [[1,5,0,8],[0,5,0,8]],
M2 = [[0,0,7,0],[5,0,7,0]],
X in inf.. -1 ? ;
M1 = [[0,5,0,8],[0,5,0,8]],
M2 = [[5,0,7,0],[5,0,7,0]],
X in 0..sup ? ;
no
#tas has presented a good solution and explanation (+1).
Building on this code, I would like to improve the space efficiency of the program. Consider again the example query with the CLP(FD) based solution:
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2).
M1 = [[0, 5, 0, 8], [0, 5, 0, 8]],
M2 = [[5, 0, 7, 0], [5, 0, 7, 0]] ;
false.
We see from the ; false that choice points were accumulated during the execution of this program, because it was not apparent to the Prolog engine that the clauses were in fact mutually exclusive.
Obviously, such programs use more memory than necessary to keep track of remaining choices.
Resist the temptation to impurely cut away branches of the computation, because that will only lead to even more problems.
Instead, consider using if_/3.
All it takes to apply if_/3 in this case is a very easy reification of the CLP(FD) constraint (#<)/2, which is easy to do with zcompare/3:
#<(X, Y, T) :-
zcompare(C, X, Y),
less_true(C, T).
less_true(<, true).
less_true(>, false).
less_true(=, false).
With this definition, the whole program becomes:
:- use_module(library(clpfd)).
masker([], [], [], [], []).
masker([X|Xs], [Y|Ys], [M|Ms], [R1|R1s], [R2|R2s]) :-
lists_mask_mlists(X, Y, M, R1, R2),
masker(Xs, Ys, Ms, R1s, R2s).
lists_mask_mlists([], [], [], [], []).
lists_mask_mlists([X|Xs], [Y|Ys], [M|Ms], R1s0, R2s0) :-
if_(M #< 0,
(R1s0 = [X|R1s], R2s0 = [0|R2s]),
(R1s0 = [0|R1s], R2s0 = [Y|R2s])),
lists_mask_mlists(Xs, Ys, Ms, R1s, R2s).
And now the point:
?- masker([[1,5,3,8],[1,5,3,8]],[[5,4,7,4],[5,4,7,4]],[[4,-1,4,-4],[4,-1,4,-4]],M1,M2).
M1 = [[0, 5, 0, 8], [0, 5, 0, 8]],
M2 = [[5, 0, 7, 0], [5, 0, 7, 0]].
This example query is now deterministic!
And the program is still general enough to also handle the second example query!

Prolog list elements editing

I need to write a predicate that will take a list of numbers and a number X, and then from X elements from this list (staring from the first one) it will subtract 1.
It may seem easy but I am new to this language and I cannot write it properly.
Here is what I got for now:
sub([H|T], X):-NEWH is H-1, NEWX is X-1, sub(T, NEWX).
but how can I end this reccursion? Like this?
sub([H|T], 0).
And how to avoid errors when X is larger than the number of elements in list?
You need to do four things:
Add a parameter for the result - your rule manufactures a new list, there needs to be an extra parameter there.
Add a base case for when X is zero - your sub([H|T], 0). could be further simplified as sub(_, 0). To make sure that you accept negative X, you could even make it sub(_,X) :- X =< 0.
Add another base case for when the list is empty - this would let you handle situations when X is too large: sub([], _).
Make sure that the recursive clause does not apply when X is zero - all you need to do is to add a check X > 0 to your recursive clause.
Here is how the resultant rules would look:
sub(L,X,L) :- X =< 0.
sub([], _,[]).
sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWX is X-1, sub(T, NEWX, NEWT).
Demo.
I want to remove zeros from the list
You need to add another clause for that:
sub(L,X,L) :- X =< 0.
sub([], _,[]).
sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWH > 0, NEWX is X-1, sub(T, NEWX, NEWT).
sub([H|T], X, NEWT) :- X > 0, NEWH is H-1, NEWH =< 0, NEWX is X-1, sub(T, NEWX, NEWT).
Demo.
Prolog is declarative. That means that once an object is created, it can't be modified (this is not strictly true for most Prolog systems, but it is in many cases unwise to perform such hacking).
What you thus need is a predicate, that takes as input the first list, and generates a new list. For your example this is for instance:
sub([],_,[]). %base case: you reached the end of the list, return an empty list as well
sub(L,0,L). %base case: you reached zero, no more editing, return the list.
sub([H|T],X,[NewH|newT]) :- %recursive case, subtract one from the head and from X and perform recursion.
NewH is H-1,
NewX is X-1,
sub(T,NewX,newT).
Note there are two base cases:
sub([],_,[]): you reached the end of the list, an possibly X has not reached zero yet. Then return an empty list as well.
sub(L,0,L): X reached zero, then you stop editing and return the list L untoched.
1) Your code doesn't do anything, since your NEWH is not returned anywhere.
2) Your code should return the full list, with modified elements, so your recursion should stop either by:
a) Comparing X to zero and appending the rest of the list
or
b) Recurring until the end of the list and compare X to 0 everytime.
The first approach is simple:
sub(L, 0, L).
sub([H|T], X, [H1 | Res]) :-
H1 is H-1,
X1 is X-1,
sub(T, X1, Res).
Then calling:
>>> sub([1,2,3,4,5,6,7], 4, L).
L = [0, 1, 2, 3, 5, 6, 7]