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

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.

Related

How can I calculate the length of a list containing lists in OCAML

i am a beginner in ocaml and I am stuck in my project.
I would like to count the number of elements of a list contained in a list.
Then test if the list contains odd or even lists.
let listoflists = [[1;2] ; [3;4;5;6] ; [7;8;9]]
output
l1 = even
l2 = even
l3 = odd
The problem is that :
List.tl listoflists
Gives the length of the rest of the list
so 2
-> how can I calculate the length of the lists one by one ?
-> Or how could I get the lists and put them one by one in a variable ?
for the odd/even function, I have already done it !
Tell me if I'm not clear
and thank you for your help .
Unfortunately it's not really possible to help you very much because your question is unclear. Since this is obviously a homework problem I'll just make a few comments.
Since you talk about putting values in variables you seem to have some programming experience. But you should know that OCaml code tends to work with immutable variables and values, which means you have to look at things differently. You can have variables, but they will usually be represented as function parameters (which indeed take different values at different times).
If you have no experience at all with OCaml it is probably worth working through a tutorial. The OCaml.org website recommends the first 6 chapters of the OCaml manual here. In the long run this will probably get you up to speed faster than asking questions here.
You ask how to do a calculation on each list in a list of lists. But you don't say what the answer is supposed to look like. If you want separate answers, one for each sublist, the function to use is List.map. If instead you want one cumulative answer calculated from all the sublists, you want a fold function (like List.fold_left).
You say that List.tl calculates the length of a list, or at least that's what you seem to be saying. But of course that's not the case, List.tl returns all but the first element of a list. The length of a list is calculated by List.length.
If you give a clearer definition of your problem and particularly the desired output you will get better help here.
Use List.iter f xs to apply function f to each element of the list xs.
Use List.length to compute the length of each list.
Even numbers are integrally divisible by two, so if you divide an even number by two the remainder will be zero. Use the mod operator to get the remainder of the division. Alternatively, you can rely on the fact that in the binary representation the odd numbers always end with 1 so you can use land (logical and) to test the least significant bit.
If you need to refer to the position of the list element, use List.iteri f xs. The List.iteri function will apply f to two arguments, the first will be the position of the element (starting from 0) and the second will be the element itself.

Prolog - How to generate a number with certain prerequisites?

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).

What is a "Test succeeded with choicepoint" warning in PL-Unit, and how do I fix it?

I'm writing a prolog program to check if a variable is an integer.
The way I'm "returning" the result is strange, but I don't think it's important for answering my question.
The Tests
I've written passing unit tests for this behaviour; here they are...
foo_test.pl
:- begin_tests('foo').
:- consult('foo').
test('that_1_is_recognised_as_int') :-
count_ints(1, 1).
test('that_atom_is_not_recognised_as_int') :-
count_ints(arbitrary, 0).
:- end_tests('foo').
:- run_tests.
The Code
And here's the code that passes those tests...
foo.pl
count_ints(X, Answer) :-
integer(X),
Answer is 1.
count_ints(X, Answer) :-
\+ integer(X),
Answer is 0.
The Output
The tests are passing, which is good, but I'm receiving a warning when I run them. Here is the output when running the tests...
?- ['foo_test'].
% foo compiled into plunit_foo 0.00 sec, 3 clauses
% PL-Unit: foo
Warning: /home/brandon/projects/sillybin/prolog/foo_test.pl:11:
/home/brandon/projects/sillybin/prolog/foo_test.pl:4:
PL-Unit: Test that_1_is_recognised_as_int: Test succeeded with choicepoint
. done
% All 2 tests passed
% foo_test compiled 0.03 sec, 1,848 clauses
true.
I'm using SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.6)
I have tried combining the two count_ints predicates into one, using ;, but it still produces the same warning.
I'm on Debian 8 (I doubt it makes a difference).
The Question(s)
What does this warning mean? And...
How do I prevent it?
First, let us forget the whole testing framework and simply consider the query on the toplevel:
?- count_ints(1, 1).
true ;
false.
This interaction tells you that after the first solution, a choice point is left. This means that alternatives are left to be tried, and they are tried on backtracking. In this case, there are no further solutions, but the system was not able to tell this before actually trying them.
Using all/1 option for test cases
There are several ways to fix the warning. A straight-forward one is to state the test case like this:
test('that_1_is_recognised_as_int', all(Count = [1])) :-
count_ints(1, Count).
This implicitly collects all solutions, and then makes a statement about all of them at once.
Using if-then-else
A somewhat more intelligent solution is to make count_ints/2 itself deterministic!
One way to do this is using if-then-else, like this:
count_ints(X, Answer) :-
( integer(X) -> Answer = 1
; Answer = 0
).
We now have:
?- count_ints(1, 1).
true.
i.e., the query now succeeds deterministically.
Pure solution: Clean data structures
However, the most elegant solution is to use a clean representation, so that you and the Prolog engine can distinguish all cases by pattern matching.
For example, we could represent integers as i(N), and everything else as other(T).
In this case, I am using the wrappers i/1 and other/1 to distinguish the cases.
Now we have:
count_ints(i(_), 1).
count_ints(other(_), 0).
And the test cases could look like:
test('that_1_is_recognised_as_int') :-
count_ints(i(1), 1).
test('that_atom_is_not_recognised_as_int') :-
count_ints(other(arbitrary), 0).
This also runs without warnings, and has the significant advantage that the code can actually be used for generating answers:
?- count_ints(Term, Count).
Term = i(_1900),
Count = 1 ;
Term = other(_1900),
Count = 0.
In comparison, we have with the other versions:
?- count_ints(Term, Count).
Count = 0.
Which, unfortunately, can at best be considered covering only 50% of the possible cases...
Tighter constraints
As Boris correctly points out in the comments, we can make the code even stricter by constraining the argument of i/1 terms to integers. For example, we can write:
count_ints(i(I), 1) :- I in inf..sup.
count_ints(other(_), 0).
Now, the argument must be an integer, which becomes clear by queries like:
?- count_ints(X, 1).
X = i(_1820),
_1820 in inf..sup.
?- count_ints(i(any), 1).
ERROR: Type error: `integer' expected, found `any' (an atom)
Note that the example Boris mentioned fails also without such stricter constraints:
?- count_ints(X, 1), X = anything.
false.
Still, it is often useful to add further constraints on arguments, and if you need to reason over integers, CLP(FD) constraints are often a good and general solution to explicitly state type constraints that are otherwise only implicit in your program.
Note that integer/1 did not get the memo:
?- X in inf..sup, integer(X).
false.
This shows that, although X is without a shadow of a doubt constrained to integers in this example, integer(X) still does not succeed. Thus, you cannot use predicates like integer/1 etc. as a reliable detector of types. It is much better to rely on pattern matching and using constraints to increase the generality of your program.
First things first: the documentation of the SWI-Prolog Prolog Unit Tests package is quite good. The different modes are explained in Section 2.2. Writing the test body. The relevant sentence in 2.2.1 is:
Deterministic predicates are predicates that must succeed exactly once and, for well behaved predicates, leave no choicepoints. [emphasis mine]
What is a choice point?
In procedural programming, when you call a function, it can return a value, or a set of values; it can modify state (local or global); whatever it does, it will do it exactly once.
In Prolog, when you evaluate a predicate, a proof tree is searched for solutions. It is possible that there is more than one solution! Say you use between/3 like this:
For x = 1, is x in [0, 1, 2]?
?- between(0, 2, 1).
true.
But you can also ask:
Enumerate all x such that x is in [0, 1, 2].
?- between(0, 2, X).
X = 0 ;
X = 1 ;
X = 2.
After you get the first solution, X = 0, Prolog stops and waits; this means:
The query between(0, 2, X) has at least one solution, X = 0. It might have further solutions; press ; and Prolog will search the proof tree for the next solution.
The choice point is the mark that Prolog puts in the search tree after finding a solution. It will resume the search for the next solution from that mark.
The warning "Test succeeded with choicepoint" means:
The solution Prolog found was the solution the test expected; however, there it leaves behind a choice point, so it is not "well-behaved".
Are choice points a problem?
Choice points you didn't put there on purpose could be a problem. Without going into detail, they can prevent certain optimizations and create inefficiencies. That's kind of OK, but sometimes only the first solution is the solution you (the programmer) intended, and a next solution can be misleading or wrong. Or, famously, after giving you one useful answer, Prolog can go into an infinite loop.
Again, this is fine if you know it: you just never ask for more than one solution when you evaluate this predicate. You can wrap it in once/1, like this:
?- once( between(0, 2, X) ).
or
?- once( count_ints(X, Answer) ).
If someone else uses your code though all bets are off. Succeeding with a choice point can mean anything from "there are other useful solutions" to "no more solutions, this will now fail" to "other solutions, but not the kind you wanted" to "going into an infinite loop now!"
Getting rid of choice points
To the particular example: You have a built-in, integer/1, which will succeed or fail without leaving choice points. So, these two clauses from your original definition of count_ints/2 are mutually exclusive for any value of X:
count_ints(X, Answer) :-
integer(X), ...
count_ints(X, Answer) :-
\+ integer(X), ...
However, Prolog doesn't know that. It only looks at the clause heads and those two are identical:
count_ints(X, Answer) :- ...
count_ints(X, Answer) :- ...
The two heads are identical, Prolog doesn't look any further that the clause head to decide whether the other clause is worth trying, so it tries the second clause even if the first argument is indeed an integer (this is the "choice point" in the warning you get), and invariably fails.
Since you know that the two clauses are mutually exclusive, it is safe to tell Prolog to forget about the other clause. You can use once/1, as show above. You can also cut the remainder of the proof tree when the first argument is indeed an integer:
count_ints(X, 1) :- integer(X), !.
count_ints(_, 0).
The exactly same operational semantics, but maybe easier for the Prolog compiler to optimize:
count_ints(X, Answer) :-
( integer(X)
-> Answer = 1
; Answer = 0
).
... as in the answer by mat. As for using pattern matching, it's all good, but if the X comes from somewhere else, and not from the code you have written yourself, you will still have to make this check at some point. You end up with something like:
variable_tagged(X, T) :-
( integer(X) -> T = i(X)
; float(X) -> T = f(X)
; atom(X) -> T = a(X)
; var(X) -> T = v(X)
% and so on
; T = other(X)
).
At that point you can write your count_ints/2 as suggested by mat, and Prolog will know by looking at the clause heads that your two clauses are mutually exclusive.
I once asked a question that boils down to the same Prolog behaviour and how to deal with it. The answer by mat recommends the same approach. The comment by mat to my comment below the answer is just as important as the answer itself (if you are writing real programs at least).

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).

Prolog - Check number of occurences doesn't work as expected

In Prolog:
I have the following function that counts the occurences of a certain element in a list:
%count(L:list,E:int,N:int) (i,i,o)
count([],_,0).
count([H|T],E,C):-H == E,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).
I tested it and it works well. But here comes the problem, I have another function that has to check if "1" occurs less than 2 times in a list.
check(L):-count(L,1,C),C<2.
Whenever I try to check the list [1,1,1,1] for example, the result I get is "true", which is wrong, and I have no idea why. I tried to make some changes, but the function just won't work.
Improve your testing habits!
When testing Prolog code don't only look at the first answer to some query and conclude "it works".
Non-determinism is central to Prolog.
Quite often, some code appears to be working correctly at first sight (when looking at the first answer) but exhibits problems (mainly wrong answers and/or non-termination) upon backtracking.
Coming back to your original question... If you want / need to preserve logical-purity, consider using the following minimal variation of the code #Ruben presented in his answer:
count([],_,0).
count([E|T],E,C) :-
count(T,E,C1),
C is C1+1.
count([H|T],E,C) :-
dif(H,E),
count(T,E,C).
dif/2 expresses syntactic term inequality in a logical sound way. For info on it look at prolog-dif!
It happens because count([1,1,1,1],1,1) is also true! In your last count it can also be matched when H does equal E. To illustrate this, use ; to make prolog look for more answers to count([1,1,1,1],1,R). You'll see what happens.
count([],_,0).
count([E|T],E,C):-
count(T,E,C1),
C is C1+1.
count([H|T],E,C):-
H \= E,
count(T,E,C).
check(L) :-
count(L,1,C),
C < 2.
?- check([1,1,1,1,1]).
false
?- check([1]).
true
second and third clauses heads match both the same sequence. As a minimal correction, I would commit the test
count([],_,0).
count([H|T],E,C):-H == E,!,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).