prolog generate list of numbers from a list[x,y] - prolog

Hello I want to generate a list as following. Given a list like [x,y] I want to generate a list that is x,x,...,x : y times eg [2,3]=[2,2,2] but I cannot figure out how.
This is my implementation so far:
generate([T,1],[T]).
generate([X,S],[X|T]):-S1 is S-1,generate([X,S1],[T]).
but for some reason it fails. Can you help me?

generate([E,R], Es) :-
length(Es, R),
maplist(=(E), Es).
You said that your version fails. But in fact it does not:
?- generate([a,0], Xs).
false.
?- generate([a,1], Xs).
Xs = [a]
; false.
?- generate([a,2], Xs).
Xs = [a|a]
; false.
?- generate([a,3], Xs).
false.
It doesn't work for 0, seems to work for length 1, then, produces an incorrect solution Xs = [a|a] for length 2, and finally fails from length 3 on. [a|a] is a good hint that at someplace in your definition, lists and their elements are confused. To better distinguish them, use a variable in plural for a list, like Es which is the plural of E.

The problem is in your second clause. When you have [X|T], it means that T is a list. In the body you write generate([X,S1],[T]): by writing [T] you're now saying the second argument to generate is a list of which the only element is this list T. What you want to say is that it is simply this list T:
generate([T,1], [T]).
generate([X,S], [X|T]) :- S1 is S-1, generate([X,S1], T).

Related

Prolog, understanding append/3

?- append([], [X1], [a,b]).
Why does this return no and not
X1 = a,b
Since
? - append([], [a,b], [a,b])
returns yes?
To understand a Prolog program you have two choices:
Think about the program as you do this in other programming languages by simulating the moves of the processor. This will lead to your mental exasperation very soon unless your name is Ryzen or in other words:
You are a processor
Let Prolog do the thinking and use Prolog to understand programs.
Whenever you see a failing goal, narrow down the reason why the goal fails by generalizing that goal (by replacing some term by a variable). You do not need to understand the precise definition at all. It suffices to try things out. In the case of your query
?- append([], [X1], [a,b]).
false.
We have three arguments. Maybe the first is the culprit? So I will replace it by a new variable:
?- append(Xs, [X1], [a,b]).
Xs = [a], X1 = b
; false.
Nailed it! Changing the first argument will lead to success. But what about the second argument?
?- append([], Ys, [a,b]).
Ys = [a, b].
Again, culprit, too. And now for the third:
?- append([], [X1], Zs).
Zs = [X1].
Verdict: All three kind-of guilty. That is, it suffices to blame one of them. Which one is up to you to choose.
Do this whenever you encounter a failing goal. It will help you gain the relational view that makes Prolog such a special language.
And if we are at it. It often helps to consider maximal failing generalizations. That is, generalizations that still fail but where each further step leads to success. In your example this is:
?- append([], [X1], [a,b]). % original query
false.
?- append([], [_], [_,_|_]). % maximal failing generalization
false.
From this you can already draw some conclusions:
The lists' elements are irrelevant.
Only the length of the three lists is of relevance
The third list needs to be two elements or longer.
See: append/3
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is the concatenation of List1 and List2
So for
?- append([], [X1], [a,b]).
[] is the empty list and [X1] is a list with a variable X1
If you run the query like this
?- append([],[X1],A).
you get
A = [X1].
which means that A is the concatenation of [] and [X1].
In your query it is asking if the concatenation of [] and [X1] is [a,b] which is false, or no.
For your second query
? - append([], [a,b], [a,b])
it is asking if the concatenation of [] and [a,b] is [a,b] which is true, or yes.

Using repeat to sort a collection of facts in prolog

I have a set of facts set/2 where the first variable is the identifier for the set and the second is the value associated with the identifier.
For example:
set(a,2).
set(a,c).
set(a,1).
set(a,a).
set(a,3).
set(a,b).
I need to construct a predicate ordering/2 (using the repeat operator) which will output the values of a specific set in their lexicographic order.
For example
?- ordering(a,Output).
Would result in
[1,2,3,a,b,c].
What I have made thus far is this code:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
doSort(List)
sort(List, OrderedList),
Output = OrderedList.
The idea here is that the predicate will find all values of the set associated with the specific Input and unify the List variable with them. Now we have the unsorted List. Here comes the part I'm not completely sure on. The predicate is supposed to keep using some sort of specific doSort on the List, then check the List with sort/2 and if it's lexicographically ordered, unify it with the Output.
Can anyone clarify if I'm on the correct path and if yes then how should the doSort be implemented?
Alright, I tried a sort of answer for this using #Daniel lyon's help:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
permutation(List,PermutationList),
sort(PermutationList, SortedList),
Output= SortedList , !.
The general idea is the same, for the repeat cycle, the predicate will unify the List with PermutationList, try all variants of it and check for their correctness with sort/2 until it achieves the correct permutation, unifying it with SortedList, after that it will unify the Output with SortedList. The cut is there so I will only get the Output once.
?- % init test DB
| maplist([X]>>assert(set(a,X)), [c,b,a,1,2,3]).
true.
?- % find first
| set(a,X), \+ (set(a,Y), Y #< X).
X = 1 ;
false.
?- % find next, given - hardcoded here as 1 - previous
| set(a,X), X #> 1, \+ (set(a,Y), Y #> 1, Y #< X).
X = 2 ;
false.
now we can try to make these queries reusable:
ordering(S,[H|T]) :- first(S,H), ordering(S,H,T).
first(S,X) :- set(S,X), \+ (set(S,Y), Y #< X).
next(S,P,X) :- set(S,X), X #> P, \+ (set(S,Y), Y #> P, Y #< X).
ordering(S,P,[X|T]) :- next(S,P,X), ordering(S,X,T).
ordering(_,_,[]).
To be correct, we need a cut somewhere. Can you spot the place ?

How to improve this code that looks for a specific number in a list?

I'm writing prolog code that finds a certain number; a number is the right number if it's between 0 and 9 and not present in a given list. To do this I wrote a predicate number/3 that has the possible numbers as the first argument, the list in which the Rightnumber cannot be present and the mystery RightNumber as third argument:
number([XH|XT], [H|T], RightNumber):-
member(XH, [H|T]), !,
number(XT, [H|T], RightNumber).
number([XH|_], [H|T], XH):-
\+ member(XH, [H|T]).
so this code basically says that if the Head of the possible numbers list is already a member of the second list, to cut of the head and continue in recursion with the tail.
If the element is not present in the second list, the second clause triggers and tells prolog that that number is the RightNumber. It's okay that it only gives the first number that is possible, that's how I want to use it.
This code works in theory, but I was wondering if there's a better way to write it down? I'm using this predicate in another predicate later on in my code and it doesn't work as part of that. I think it's only reading the first clause, not the second and fails as a result.
Does anybody have an idea that might improve my code?
sample queries:
?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X).
X = 3
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X).
X = 9
First, the code does not work. Consider:
?- number(Xs, Ys, N).
nontermination
This is obviously bad: For this so-called most general query, we expect to obtain answers, but Prolog does not give us any answer with this program!
So, I first suggest you eliminate all impurities from your program, and focus on a clean declarative description of what you want.
I give you a start:
good_number(N, Ls) :-
N in 0..9,
maplist(#\=(N), Ls).
This states that the relation is true if N is between 0 and 9, and N is different from any integer in Ls. See clpfd for more information about CLP(FD) constraints.
Importantly, this works in all directions. For example:
?- good_number(4, [1,2,3]).
true.
?- good_number(11, [1,2,3]).
false.
?- good_number(N, [1,2,3]).
N in 0\/4..9.
And also in the most general case:
?- good_number(N, Ls).
Ls = [],
N in 0..9 ;
Ls = [_2540],
N in 0..9,
N#\=_2540 ;
Ls = [_2750, _2756],
N in 0..9,
N#\=_2756,
N#\=_2750 .
This, with only two lines of code, we have implemented a very general relation.
Also see logical-purity for more information.
First of all, your predicate does not work, nor does it check all the required constraints (between 0 and 9 for instance).
Several things:
you unpack the second list [H|T], but you re-pack it when you call member(XH, [H|T]); instead you can use a list L (this however slightly alters the semantics of the predicate, but is more accurate towards the description);
you check twice member/2ship;
you do not check whether the value is a number between 0 and 9 (and an integer anyway).
A better approach is to construct a simple clause:
number(Ns, L, Number) :-
member(Number, Ns),
integer(Number),
0 =< Number,
Number =< 9,
\+ member(Number, L).
A problem that remains is that Number can be a variable. In that case integer(Number) will fail. In logic we would however expect that Prolog unifies it with a number. We can achieve this by using the between/3 predicate:
number(Ns, L, Number) :-
member(Number, Ns),
between(0, 9, Number),
\+ member(Number, L).
We can also use the Constraint Logic Programming over Finite Domains library and use the in/2 predicate:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
\+ member(Number, L).
There are still other things that can go wrong. For instance we check non-membership with \+ member(Number, L). but in case L is not grounded, this will fail, instead of suggesting lists where none of the elements is equal to Number, we can use the meta-predicate maplist to construct lists and then call a predicate over every element. The predicate we want to call over every element is that that element is not equal to Number, so we can use:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
maplist(#\=(Number), L).

Prolog: How to create a list of predicates?

d_edge(a, b, 5).
e_edge(a, c, 6).
f_edge(b, c, 8).
% I will have a list of rules for the graph point
% from source to destination with weight.
list2pair([T], [A,B], [(T,A,B)]).
list2pair([T1|Tt], [A1,A2|T], Result) :-
list2pair(Tt, [A1|T], R1),
append([(T1,A1,A2)], R1, Result).
I want to come up with the result like
[d_edge(a,b), f_edge(b,c)]
my 1st arg will be the list of names [d_edge,f_edge]
my 2nd arg will be the list of vertexes [a,b,c].
My current code generates [(d_edge,a,b),(f_edge,b,c)].
Whenever I try to update the predicate from (T1,A1,A2) to T1(,A1,A2)
I get an error saying that it is not valid predicate.
I understand why I am getting the error. But I couldn't find a way around it.
First things first: T1(,A1,A2) is syntactically incorrect.
Here's how you could proceed using the built-in predicate (=..)/2 (a.k.a. "univ"):
list2pair([T], [A1,A2], [X]) :-
X =.. [T,A1,A2].
list2pair([T1|Tt], [A1,A2|T], [X|Xs]) :-
X =.. [T1,A1,A2],
list2pair(Tt, [A2|T], Xs).
Sample query using SICStus Prolog 4.3.2:
| ?- list2pair([d_edge,f_edge], [a,b,c], Xs).
Xs = [d_edge(a,b),f_edge(b,c)] ? ; % expected result
no
Note that the above only "constructs" these compound terms—it does not ensure that suitable facts d_edge/3, f_edge/3 etc really do exist.

Prolog List Squaring, Modifying element in List

I am trying to write a short Prolog program which takes a list of numbers and returns a list where all numbers have been squared.
Ie: [2,4,5] => [4,16,25]
My code so far:
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :-
list_of_squares(XS, M).
For some reason though Prolog doesn't like me squaring X while adding it to a list... Any thoughts on how I could do this?
You're not that far off, but you make two small mistakes:
Firstly, you mix element X with list L. Your first clause should be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
Secondly, you cannot perform an arithmetic function in list notation.
Your second clauses should be as follows:
list_of_squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
list_of_squares(Xs, Ys).
Thirdly, there is a more fundamental problem. With the first two fixes, your code works, but the base case, i.e. the first clause, is not that well chosen. (A) the code cannot process the empty list. (B) For a singleton list the code is needlessly nondeterministic, because both clauses apply. This is solved by choosing the base case wisely:
squares([], []).
squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
squares(Xs, Ys).
Here is a general method how you can localize such an error. First, let's start with your exemple:
?- list_of_squares([2,4,5],[4,16,25]).
false.
Oh no! It fails! There is a very general method what to do in such a situation:
Generalize the query
So we replace [4,16,25] by a new, fresh (ah, true freshness!) variable:
?- list_of_squares([2,4,5],L).
L = [2^2,4^2|25]
; false.
That's way better: Now you know that there is a "result", but that result it not what you expected.
Next,
Minimize the query
The list is way too long, so I will chop off some elements. Say, the first two:
?- list_of_squares([5],L).
L = 25
; false.
Again, wrong, but smaller. Now, where is the error for that? To get it
Specialize your program
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :- false,
list_of_squares(XS, M).
That program, again gives the same wrong answer! So in there is a bug in the visible part. What we expect is
?- list_of_squares([5],[25]).
false.
this to succeed. But where is the error? Again:
Generalize the query
?- list_of_squares([5],[X]).
false.
HET!
Now, you should realize that that rule might be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
And the same (is)/2 should be used in the recursive rule. And, why not accept [].
I, personally, would rather write using library(lambda):
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX is X^2), Xs, Ys).
Or, even better, using library(clpfd)
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX #= X^2), Xs, Ys).
Prolog doesn't have a 'functional' mindset, but some standard builtin predicate can help working with lists. In this case
list_of_squares(L,S) :- findall(Sq,(member(E,L),Sq is E*E),S).
?- list_of_squares([2,4,5], R).
R = [4, 16, 25].
in this case, member/2 play a role similar to lambda expressions, giving a 'name' to each element E available in L. findall/3 compute all solutions of its goal ,(member(E,L),Sq is E*E),, and collects results (the 'template' expression, that is, Sq).

Resources