Prolog - How to generate a number with certain prerequisites? - list

So I want to create a simple number generator that generates a number between 1 and 9, but it is not allowed to be part of three lists provided (lists of numbers). An example:
findnumber(Number, [1,2,3], [3,4,5], [6,7,8]).
Number = 9.
or:
findnumber(Number, [1,2], [3,4], [5,6]).
Number = 7;
Number = 8;
Number = 9.
How would I go about this, I tried this:
findnumber(Number, List1, List2, List3) :-
random_between(1, 9, Number),
not(member(Number, List1)),
not(member(Number, List2)),
not(member(Number, List3)).
I thought this would work but apparently not, I think it is because the Number is generated beforehand so it can't really find the prerequisites. It merely checks if they aren't members and if they are, then the predicate fails.
Hopefully someone can help me out.
Thanks in advance.

Recently, there have been several exercises under this general theme. The tasks force you to hack together programs that run counter to elementary properties of logical relations: In particular, we expect logical relations to not depend on implicit global states, such as the state of a random number generator. These are examples of logic hacking, not of logic programming.
In any case, your solution and also analysis are perfectly valid.
One easy way out is to simply repeatedly try to generate such integers until you at last succeed. Prolog makes it easy to repeatedly try, via its built-in backtracking mechanism.
You can use the predicate repeat/0, which succeeds an arbitrary number of times. So, your query works exactly as expected if you simply prepend a call of repeat/0:
?- repeat, findnumber(Number, [1,2], [3,4], [5,6]).
Number = 9 ;
Number = 9 ;
Number = 8 ;
Number = 8 ;
Number = 7 .
You can commit to the first solution by wrapping the whole query in once/1, i.e.:
?- once((repeat, findnumber(Number, [1,2], [3,4], [5,6]))).
Number = 7.
As I said, the whole relation violates elementary properties we expect from a logic program. For example, when posting the exact same query again, I get a different answer:
?- once((repeat, findnumber(Number, [1,2], [3,4], [5,6]))).
Number = 8.
This explains why it "worked" (by coincidence) for one of the commenters.
Such impurities make declarative debugging and many other benefits of logic programming inapplicable. I recommend you choose a different instructor. See logical-purity to learn more about properties we expect from logical relations, and how you can benefit from them in your work.

You can use constraint logic programming (CLP) to easily solve tasks of this kind. For example, with Swi-Prolog you can use following code to define findnumber:
:- use_module(library(clpfd)).
findnumber(Number, List1, List2, List3) :-
append([List1, List2, List3], NotIn),
Number in 1..9,
maplist(#\=(Number), NotIn),
indomain(Number).

Related

Extracting list of items between two values in a list - prolog

Say I have a unique list of length 9 of the values between 1 and 9 inclusive in a random order (think sudoku), and I want to extract a the sub-list of the items that occur between the values 1 and 9 (exclusive). IE: between1and9([1,3,5,4,2,9,7,8,6],[3,5,4,2]) should be true.
At the moment I'm trying to use flatten/2, but not having much luck. Here's my current tactic (assuming I enforce List ins 1..9, maplist(all_distinct, List), length(List, 9) elsewhere to keep it tidy here/seperation of concerns):
between1and9(List,Between) :-
flatten([_,[1],Between,[9],_], List);
flatten([_,[9],Between,[1],_], List).
This version fails though when 1 or 9 are at the first or last position in List, or if they're adjacent within List. between1and9([_,1,9,_,_,_,_,_,_],[]) is true, but between1and9([_,1,9,_,_,_,_,_,_],_) is false (and fails when I try to use it as a constraint to solve a bigger problem.)
It seems to be the same problem casuing both failures, flatten doesn't seem to like treating unknowns as empty lists unless they're made explicit somewhere.
I can see why that would potentially be, if flatten could "invent" empty lists in the first argument it would mean an infinite set of solutions for anything in the first argument. Although my full program has other constraints to prevent this, I can understand why flatten might not want to accomodate it.
I can account for the edge cases (pun intended) by matching every permutation with disjunctions (ie: flatten([_,1,B,9,_],L);flatten([_,9,B,1,_],L);flatten([_,1,B,9]);flatten..., And account for the Between as an empty list with: \*above permutations on flatten*\; ( Between = [], (\*permutations for either edge and 1/9*\) )
But that seems to be making an already longwinded solution (10 permutations of flatten in total) even worse (18) so I have two (strongly related) questions:
If I could do the following:
between1and9(L,B) :-
( ( X = 1, Y = 9 ); ( X = 9, Y = 1 ) ),
( ( Z1 = _; Z1 = [] ), ( Z2 = _ ; Z2 = [] ) ),
( B = _; B = [] ),
flatten([Z1,X,B,Y,Z2],L).
I wouldn't have to manually type out each permutation of match for flatten. Unfortunately this and a few variations on it all unilaterally fail. Am I missing somethign obvious here? (I suspect opperator precedence but I've tried a few different versions.)
Or am I doing this completely wrong? The flatten/2 documentation suggests that in most cases it's an anti-pattern, is there a more prolog-ish* way to go about solving this problem? Given all the pitfalls I'm realising as I go through this I'm almost certain there is.
(Sorry, I'm painfully aware that a lot of the terminology I'm using to describe things in this is probably very wrong, I'm only kind of familiar with predicate/formal logic and much more used-to describing control flow type programming. Even though I understand logic programming in practice reasonably well I'm struggling to find the language to talk about it robustly yet, I will amend this question with any corrections I get.)
Some background: I'm new to prolog and testing out my understanding by trying to extend one of the many sudoku solvers to solve a strange variety of sudoku I found in some puzzles I printed out years ago where you're shown the sum of all the numbers that appear between the 1 and the 9 in any given row or column as an extra hint, it's kind of like a mix of sudoku and picross. The solver as it stands now is on swish: SumSudoku(swish). Although it may be a mess when you get to it.
*Corollary quesiton: is there a prolog version of the word "pythonic?"
You could use good old append/3 for this. Is it possible that you wanted append/3 all along but somehow thought it is called flatten?
For the "1 comes before 9" case, you'd write:
between_1_and_9(List, Sublist) :-
append(_, [1|Rest], List),
append(Sublist, [9|_], Rest).
You need to swap 1 and 9 for the "9 comes before 1" case.
This also leaves a "spurious choice point" (Thank you #PauloMoura for the comment). Make sure to get rid of it somehow.
As for "Pythonic" (and this comes from a recovering Pythonista), I can only say, rest assured:
There is always more than one obvious way to do it in Prolog.
You don't even have to be Dutch.

Why does my prolog predicate only work with an even number of elements in its list?

My predicate eo is supposed to function as so,
?- eo([a,b,c,d,e,f],L).
L = [b,d,f]
My code right now is,
eo([], []).
eo([_,X|L], [X | R]) :-
eo(L, R).
But it only works when the given list as an even number of elements. When given a list with an odd number of elements, it just outputs false. Any advice?
EDIT:
?- eo([a,b,c,d,e,f,g],L).
L = [b,d,f]
is the expected results for an odd number of elements in the list.
This solution is working
eo([],[]).
eo([_],[]).
eo([_,X|L],[X|R]) :- eo(L,R).
You need to have the second line that handle the list of one element ,
QuickCheck can help no only in finding failing queries for buggy predicates but also narrow down those failing queries to the most simple one. In this case, using Logtalk's lgtunit tool QuickCheck support:
?- lgtunit::quick_check(eo(+list(character), -list(character))).
* quick check test failure:
* eo([d],[])
false.
Comparing the failing query to your code, makes it clear the bug pointed out in the (other) answers and the comments: no clause for handling an input list with a single element.
But do remember that QuickCheck generates random test queries and thus is only able to show a failing query, not proving correctness.

Prolog union fails

I'm trying to understand the use of union (the built in predicate) in Prolog. In many cases it seems to fail when it should succeed. It seems it has something to do with the order of the elements of the lists. All of the below cases fail (they come back with "false.").
?- union([1,2,3],[],[2,3,1]).
?- union([1,5,3], [1,2], [1,5,3,2]).
?- union([4,6,2,1], [2], [1,2,4,6]).
?- union([1,2], [], [2,1]).
Shouldn't all of these be true? Any explanation as to why these cases keep failing would be very helpful.
Also: Why does the below not succeed and find the correct list for A?
?- union([1,5,3], A, [4,1,5,3,2]). /** comes back with "fail." */
There are a couple of issues here. Declarative and procedural ones. Let's start with the declarative ones, they are really sitting a bit deeper. The procedural aspects can be handled easily with appropriate programming techniques, as in this answer.
When we consider declarative properties of a predicate, we consider its set of solutions. So we pretend that all we care about is what solutions the predicate will describe. We will completely ignore how all of this is implemented. For very simple predicates, that's a simple enumeration of facts - just like a database table. It is all obvious in such situations. It becomes much more unintuitive if the set of solutions is infinite. And this happens so easily. Think of the query
?- length(Xs,1).
This harmless looking query asks for all lists of length one. All of them! Let me count - that's infinitely many!
Before we look at the actual answer Prolog produces, think what you would do in such a situation. How would you answer that query? Some of my feeble attempts
?- length(Xs,1).
Xs = [1]
; Xs = [42]
; Xs = [ben+jerry]
; Xs = [feel([b,u,r,n])]
; Xs = [cromu-lence]
; Xs = [[[]]]
; ... . % I am running out of imagination
Should Prolog produce all those infinitely many values? How much time would this take? How much time do you have to stare at walls of text? Your lifetime is clearly not enough.
Taming the number of solutions, from solutions to answers
There is a way out: The logic variable!
?- length(Xs, 1).
Xs = [_A].
% ^^
This little _A permits us to collapse all strange solutions into a single answer!
So here we really had a lot of luck: we tamed the infinity with this nice variable.
Now back to your relation. There, we want to represent sets as lists. Lists are clearly not sets per se. Consider the list [a,a] and the list [a]. While they are different, they are meant to represent the same set. Think of it: How many alternate representations are there for [a]? Yep, infinitely many. But now, the logic variable cannot help us to represent all of them compactly1. Thus we have to enumerate them one-by-one. But if we have to enumerate all those answers, practically all queries will not terminate due to infinitely many solutions to enumerate explicitly. OK, some still will:
?- union([], [], Xs).
Xs = [].
And all ground queries. And all failing queries. But once we have a variable like
?- union([a], [], Xs).
Xs = [a]
; Xs = [a,a]
; Xs = [a,a,a]
; ... .
we already are deep into non-termination.
So given that, we have to make some decisions. We somehow need to tame that infinity. One idea is to consider a subset of the actual relation that leans somehow to a side. If we want to ask questions like union([1,2],[3,4], A3) then it is quite natural to impose a subset where we have this functional dependency
A1, A2 → A3
With this functional dependency we now determine exactly one value for A3 for each pair of A1, A2. Here are some examples:
?- union([1,5,3], [1,2], A3).
A3 = [5,3,1,2].
?- union([1,2,3], [], A3).
A3 = [1,2,3].
Note that Prolog always puts a . a the end. That means Prolog says:
Dixi! I have spoken. There are no more solutions.
(Other Prologs will moan "No" at the end.) As a consequence, the queries (from your comments) now fail:
?- union([1,5,3], [1,2], [1,5,3,2]).
false.
?- union([1,2,3],[],[2,3,1]).
false.
So imposing that functional dependency now restricts the set of solutions drastically. And that restriction was an arbitrary decision of the implementer. It could have been different! Sometimes, duplicates are removed, sometimes not. If A1 and A2 both are duplicate free lists, the result A3 will be duplicate free, too.
After looking into its implementation, the following seems to hold (you do not need to do this, the documentation should be good enough - well it isn't): The elements in the last argument are structured as follows and in that order:
The elements of A1 that do not occur in A2, too. In the relative order of A1.
All elements of A2 in their original order.
So with this functional dependency further properties have been sneaked in. Such as that A2 is always a suffix of A3! Consequently the following cannot be true, because there is no suffix of A3 that would make this query true:
?- union([1,5,3], A2, [4,1,5,3,2]).
false.
And there are even more irregularities that can be described on a declarative level. Often, for the sake of efficiency, relations are too general. Like:
?- union([],non_list,non_list).
Such concerns are often swiped away by noting that we are only interested in goals with arguments that are either lists (like [a,b]) or partial lists (like [a,b|Xs]).
Anyway. We finally have now described all the declarative properties we expect. Now comes the next part: That relation should be implemented adequately! There again a new bunch of problems awaits us!
With library(lists) of SWI, I get:
?- union([1,2], [X], [1,2,3]).
false.
?- X = 3, union([1,2], [X], [1,2,3]).
X = 3.
Which is really incorrect: This can only be understood procedurally, looking at the actual implementation. This no longer is a clean relation. But this problem can be fixed!
You can avoid the correctness issues altogether by sticking to the pure, monotonic subset of Prolog. See above for more.
1) To tell the truth, it would be possible to represent that infinite set with some form of constraints. But the mere fact that there is not a single library for sets provided by current Prolog systems should make it clear that this is not an obvious choice.

Prolog Predicate Solution

I am going through some past exam questions for my prolog exam that is coming up.
Here is the question:
(a) Write a predicate insert(Xs, Y, Zs) that holds when Zs is the list obtained
by inserting Y into the list Xs. A query such as:
? - insert([1,2,3], 4, Zs).
should succeed four times and give the following answers:
Zs = [4, 1, 2, 3]
Zs = [1, 4, 2, 3]
Zs = [1, 2, 4, 3]
Zs = [1, 2, 3, 4].
I'm a bit concerned because I have no idea where to start. Would anyone be able to help out as I need example solutions to practice for my exam.
Would really appreciate any help with this.
We start by changing the terrible name of this predicate: The predicate should describe what holds, not what to do. The name should reflect that. I suggest list_with_element/3, and encourage you to try finding even better names, ideally making clear what each argument stands for.
Then, we do what we set out to do: Describe the cases that make this relation hold.
For example:
list_with_element([], E, [E]).
list_with_element([L|Ls], E, [E,L|Ls]).
list_with_element([L|Ls0], E, [L|Ls]) :-
...
I leave filling in the ... as an easy exercise. State the condition that is necessary for the clause head to be true!
EDIT: I would like to say a bit more about the pattern above. In my experience, a good way—and definitely in the beginning—to reason about predicates that describe lists is to consider two basic cases:
the atom [], denoting the empty list
terms of the form '.'(E, Es), also written as [E|Es], where E is the first element of the list and Es is again a list.
This follows the inductive definition of lists.
The drawback in this specific case is that this approach leads to a situation where case (2) again needs to be divided into two subcases, and somehow unexpectedly necessitates three clauses to handle the two basic cases. This obviously runs counter to our intuitive expectation that two clauses should suffice. Indeed they do, but we need to be careful not to accidentally lose solutions. In this case, the first two clauses above are both subsumed by the fact:
list_with_element(Ls, E, [E|Ls]).
Every experienced Prolog coder will write such predicates in this way, or just, as in this case, use select/3 directly. This is what #lurker sensed and hinted at, and #tas correctly shows that a different clause (which is easy to come up with accidentally) does not fully subsume all cases we want to express.
Thus, I still find it a lot easier to think first about the empty list explicitly, make sure to get that case correct, then continue with more complex cases, and then see if you can write the existing program more compactly. This is the way I also used for this sample code, but I did not make it as short as possible. Note that with monotonic code, it is completely OK to have redundant facts!
Note that is is specifically not OK to just replace the first two clauses by:
list_with_element([L|Ls], E, [E|Ls]).
because this clause does not subsume case (1) above.
I guess that one answer that the question might be looking for goes along these lines:
insert(List, Element, NewList) :-
append(Front, Back, List), % split list in two
append(Front, [Element|Back], NewList). % reassemble list
If you would like a declarative reading:
NewList has Element between the front and the back of List.
Check carefully if append/3 or a predicate with the same semantics appears in the earlier questions or the study material.
And note that this is in essence the exact same solution as the suggestion by #mat, if I understand it correctly. Consult the textbook definition of append/3 for details. Or even better, look at the textbook definition of append/3 and adapt it to use if for "inserting".
There is a built-in predicate select/3 that does the same thing, although with the arguments in a different order.
Remember that (if defined correctly) a predicate can work in different directions. For instance, it can tell you what a list would look like after removing an element, it can (although it's fairly trivial) tell you what element to remove from one list to get another, or it can tell you what lists, after having a given element removed, would resemble a given list.
(Hint: you may want to look into that last one).

Is an infinite list of ones sane?

In Prolog, is the unification X = [1|X] a sane way to get an infinite list of ones? SWI-Prolog does not have any problem with it, but GNU Prolog simply hangs.
I know that in most cases I could replace the list with
one(1).
one(X) :- one(X).
but my question is explicitly if one may use the expression X = [1|X], member(Y, X), Y = 1 in a "sane" Prolog implementation.
In Prolog, is the unification X = [1|X] a sane way to get an infinite list of ones?
It depends on whether or not you consider it sane to produce an infinite list at all. In ISO-Prolog a unification like X = [1|X] is subject to occurs check (STO) and thus is undefined. That is, a standard-conforming program must not execute such a goal. To avoid this from happening, there is unify_with_occurs_check/2, subsumes_term/2. And to guard interfaces against receiving infinite terms, there is acyclic_term/1.
All current implementations terminate for X = [1|X]. Also GNU Prolog terminates:
| ?- X = [1|X], acyclic_term(X).
no
But for more complex cases, rational tree unification is needed. Compare this to Haskell where
repeat 1 == repeat 1 causes ghci to freeze.
As for using rational trees in regular Prolog programs, this is quite interesting in the beginning but does not extend very well. As an example, it was believed for some time in the beginning 1980s that grammars will be implemented using rational trees. Alas, people are happy enough with DCGs alone.
One reason why this isn't leaving research, is, because many notions Prolog programmers assume to exist, do not exist for rational trees. Take as an example the lexicographic term ordering which has no extension for rational trees. That is, there are rational trees that cannot be compared using standard term order. (Practically this means that you get quasi random results.) Which means that you cannot produce a sorted list containing such terms. Which again means that many built-ins like bagof/3 no longer work reliably with infinite terms.
For your example query, consider the following definition:
memberd(X, [X|_Xs]).
memberd(E, [X|Xs]) :-
dif(E,X),
memberd(E, Xs).
?- X = 1, Xs=[1|Xs], memberd(X,Xs).
X = 1, Xs = [1|Xs]
; false.
So sometimes there are simple ways to escape non-termination. But more often than not there are none.
You don't get an infinite number of ones, of course, but what's called a rational or cyclic term. Not all Prolog systems support cyclic terms, however. Systems that provide some support for rational terms include CxProlog, ECLiPSe, SICStus, SWI-Prolog, and YAP. But be aware that there are differences between them regarding the computations that you can perform with rational terms.
A query such as:
X = [1|X], member(Y, X), Y = 1.
requires support for coinduction. You have a portable implementation of coinduction in Logtalk, which you can use with all the systems mentioned above. Coinduction requires that the Prolog system can create rational terms (using a query such as X = [1|X]), that can unify rational terms, and that can print bindings with rational terms in a non-ambigouos way.
For an example about enumerating (or testing) the elements of a rational list, see:
https://github.com/LogtalkDotOrg/logtalk3/blob/master/examples/coinduction/lists.lgt
Two sample queries for this example:
?- {coinduction(loader)}.
...
% (0 warnings)
true.
?- X = [1|X], lists::comember(Y, X), Y = 1.
X = [1|X],
Y = 1 ;
false.
?- X = [1, 2, 3| X], lists::comember(Y, X).
X = [1, 2, 3|X],
Y = 1 ;
X = [1, 2, 3|X],
Y = 2 ;
X = [1, 2, 3|X],
Y = 3 ;
false.
If you're interested in rational terms and coinduction, Logtalk's coinduction example includes several individual examples and bibliographic references.
If you want to work with infinite lists, you can alternatively also revert to lazy lists. They have also a coinductive reading. Here is a simple Haskell like take predicate in Prolog that will evaluate an initial segment of a lazy list [Head|TailClosure]:
take(0, _, R) :- !, R = [].
take(N, C, [H|R]) :-
call(C, [H|T]),
M is N-1,
take(M, T, R).
And here is a definition of the list of ones in this framework:
one([1|one]).
As you can see you can expand the coinductive definition:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- take(5,one,L).
L = [1, 1, 1, 1, 1].
The requirements to make this work are much lower than in the case of rational terms. You only need a Prolog system that supports call/n which is required by ISO core standard, in its corrigendum 2. On the other hand rational terms are not required.
Its possible to define irrational lists this way and also to code stream processors that combine different streams. There is a growing literature about certain applications as for example exact reals and theorem provers like Coq, HOL/Isabelle, .. can reason about such streams.
Further reading:
Markus Triska - Prolog Streams
https://www.metalevel.at/various/prost
Dexter Kozen & Alexandra Silva - Practical Coinduction
https://www.cs.cornell.edu/~kozen/Papers/Structural.pdf
Edit 14.08.2018:
It must be said that neither prost from Markus Triska nor my post here did invent lazy lists via higher order calls. We find a 1983 Richard O'Keefe snippet here lazy.pl, where apply/2, the precursor of call/n is used. So I guess it pretty much belongs to Prolog folklore.