Related
I need to read the contents of a fixed-format text file into a list of lists (LL) in Prolog but I want to exclude the first and last element on each line from the list for that line. The very first line of the input file includes the number of rows (number of lists in LL) and columns (number of elements per list in LL).
An example input file with 3 rows and 4 columns is
3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
and I would like
LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]
How can I exclude the first and last element on each line from LL?
I have tried reading the SWI-Prolog documentation and searching for relevant threads here, but I have been unsuccessful.
readAll( InStream, [W|L] ) :-
readWordNumber( InStream, W ), !,
readAll( InStream, L ).
readAll( InStream, [] ) :-
\+readWordNumber(InStream,_).
lst_2_lst_of_lst([], _N, []).
lst_2_lst_of_lst(L, N, LL) :-
lst_2_lst_of_lst_helper(L, 1, N, LL).
lst_2_lst_of_lst_helper([H|T], N, N, [[H]|LL]):-
lst_2_lst_of_lst(T, N, LL).
lst_2_lst_of_lst_helper([H|T], N1 , N, [[H|TMP]|LL]):-
N2 is N1 + 1,
lst_2_lst_of_lst_helper(T, N2 , N, [TMP| LL]).
After calls to
...readAll(F,Input), ...
lst_2_lst_of_lst(Input, C, LL)
(C is 4, read in from first line of F, the text file)
My current result looks like this
LL = [[1,9 3 7 4 7,2,6 8 4 0 32],[3,2 4 3 8 42,Ab,140 21 331 41]]
and I would like it to look like this
LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]
I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:
cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).
Capturing lines of tokens could be
readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).
read_a_line(F,L) :-
read_line_to_string(F,S),
S\=end_of_file,
tokenize_atom(S,L).
To illustrate some of the IO facilities of SWI-Prolog, a quick test:
?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4\nA B C D Cd\n1 9 3 7 4 7\n2 6 8 4 0 32\n3 2 4 3 8 42\nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]
where data(F) actually binds F to the string you have in your example file.
Without lambda, we need an 'use once' predicate: for instance
cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).
Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.
Here is how I will interpret your problem:
The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.
The second row is not relevant (?).
Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:
skip the first column;
take the next ncol columns and put them in a list of integers.
skip the rest of input.
Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).
Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):
$ cat ignore.pl
:- use_module(library(dcg/basics)).
read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).
stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("\n", _Skip_this_line), "\n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).
rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> { succ(Nrow0, Nrow) },
skip_column,
cols(Ncol, R),
string_without("\n", _Skip_rest_of_line), "\n", !,
rows(Nrow0, Ncol, Rows).
skip_column --> nonblanks(_Skip_this_column), white, whites.
cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> { succ(Ncol0, Ncol) },
integer(C), white, whites, !,
cols(Ncol0, Cols).
It isn't "clean" code but it is a starting point. It works for the example you gave it.
3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.
?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].
There is room for improvement in like 10 different directions. If you don't understand something, ask.
Complete code using DCG.
:- use_module(library(dcg/basics), except([eos/2])).
:- set_prolog_flag(double_quotes, codes).
parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.
size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"\n".
header -->
string_without("\n",_),
"\n".
rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
{ Rows is Rows0 - 1 },
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].
row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"\n".
values(Columns0,[Item|Items]) -->
value(Item),
{ Columns is Columns0 - 1 },
values(Columns,Items).
values(0,[]) --> [].
value(Item) -->
integer(Item),
whites.
footer -->
rest_of_line, !.
rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].
readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').
Test cases
:- begin_tests(data).
test(1) :-
Input = "\c
3 4\n\c
A B C D Cd\n\c
1 9 3 7 4 7\n\c
2 6 8 4 0 32\n\c
3 2 4 3 8 42\n\c
Ab 140 21 331 41 55\n\c
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).
test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).
:- end_tests(data).
Example run of test cases
?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.
Example run
?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].
When ever you process list you should consider using DCG (Primer).
The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.
:- set_prolog_flag(double_quotes, codes).
Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.
SWI Prolog has unit test.
To make it easier to format the input data for reading with unit test \c is used.
The predicate that drives DCGs is phrase but it comes it two very common variations.
phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)
phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.
View unit test in SWI-Prolog debugger.
If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with
?- gtrace.
true.
Then run a specific test
[trace] ?- run_tests(data:1).
I am trying to understand N-queens problem's solution as given below:
:- use_module(library(clpfd)).
n_queens(N, Qs) :-
length(Qs, N),
Qs ins 1..N,
safe_queens(Qs).
safe_queens([]).
safe_queens([Q|Qs]) :-
safe_queens(Qs, Q, 1),
safe_queens(Qs).
safe_queens([], _, _).
safe_queens([Q|Qs], Q0, D0) :-
Q0 #\= Q,
abs(Q0 - Q) #\= D0,
D1 #= D0 + 1,
safe_queens(Qs, Q0, D1).
I am not able to understand the below snippet:
safe_queens([]).
safe_queens([Q|Qs]) :-
safe_queens(Qs, Q, 1),
safe_queens(Qs).
safe_queens([], _, _).
safe_queens([Q|Qs], Q0, D0) :-
Q0 #\= Q,
abs(Q0 - Q) #\= D0,
D1 #= D0 + 1,
safe_queens(Qs, Q0, D1).
Please help me to understand. Any help would be greatly appreciated.
Since you did not give any example queries, start with some example queries to determine the parameters and output format.
Normally to determine the parameters and output format for unknown code requires looking at the code for the structure of the arguments and then trying sample queries. Additionally note that this code uses the Constraint Logic Programming library clpfd; when I read that I literally stop thinking syntactic unification and start thinking constraints. I think of it as a separate system embedded within Prolog and not additional predicates. You will notice that in this answer that constraint is used very often and predicate or rule is quite absent even though this is Prolog.
Since the N-Queens problem is so well known as a logic problem a quick Google search (clpfd n queens) turns up SWI-Prolog Example: Eight queens puzzle. Note the addition of the keyword clpfd it is crucial for understanding this variation of the code; there are many solutions in other programming langues.
This gives an example query n_queens(8, Qs), label(Qs) for which label/1 returns values for the system generated variables.
This also tells us that the first argument is a positive integer and the second argument is a list of length of the first argument.
Also by having worked with this problem before, the first argument is the dimensional size of the board, so 1 is 1x1 board, 8 is an 8x8 board, etc., and the number of queens that will be on the board.
The next thing that helps is to know what the valid solutions are or at least a count of them for a set of parameters.
The Wikipedia article for Eight queens puzzle provides that in the counting solutions section.
This shows that for a board of 1x1 there is one solution, no solutions for a board of 2x2, or 3x3, two solutions for 4x4 and so on.
For a 1x1 board there is one solution.
?- n_queens(1,Qs),label(Qs).
Qs = [1].
For a 2x2 board there is no solution.
?- n_queens(2,Qs),label(Qs).
false.
For a 4x4 board there are two solutions.
?- n_queens(4,Qs),label(Qs).
Qs = [2, 4, 1, 3] ;
Qs = [3, 1, 4, 2] ;
false.
Qs = [2, 4, 1, 3]
To interpret the results the positions in the list correspond with the columns on the board and the values with a row on the board, so for the first value in the list (2) it reads a queen in row 2, column 1, for the second value in the list (4) it reads a queen in row 4, column 2
Qs = [3, 1, 4, 2]
Note: Images generated using Chess Diagram Setup
If we run the query with the values as a variables the result is an endless parade of the valid answers.
?- n_queens(N,Qs),label(Qs).
N = 0,
Qs = [] ;
N = 1,
Qs = [1] ;
N = 4,
Qs = [2, 4, 1, 3] ;
N = 4,
Qs = [3, 1, 4, 2] ;
N = 5,
Qs = [1, 3, 5, 2, 4] ;
N = 5,
Qs = [1, 4, 2, 5, 3] ;
N = 5,
Qs = [2, 4, 1, 3, 5] ;
N = 5,
Qs = [2, 5, 3, 1, 4] ;
N = 5,
Qs = [3, 1, 4, 2, 5] ;
N = 5,
Qs = [3, 5, 2, 4, 1] ;
N = 5,
Qs = [4, 1, 3, 5, 2]
...
Now that we know the code runs and gives valid solutions we can start to dissect it.
Normally SWI-Prolog trace/0 or SWI-PRolog GUI-tracer started with gtrace/0 would be a tool of choice but having used that on clpfd before I know that is not a tool of first choice with Constraint Logic Programming. Try it and and you will see why.
On with the dissection.
?- n_queens(1,Qs).
Qs = [1].
?- n_queens(2,Qs).
Qs = [_1942, _1948],
_1942 in 1..2,
abs(_1942-_1948)#\=1,
_1942#\=_1948,
_1948 in 1..2.
This is something of interest.
To make this easier to understand, swap out the system generated variables with user friendly variables and give a human reading to the meaning of the statement.
?- n_queens(2,Qs).
Qs = [A, B],
A in 1..2,
abs(A-B)#\=1,
A#\=B,
B in 1..2.
Note that with CLP(FD) operators with # in them are typically constraints, e.g. #\= and #= are read like the normal operators less the #
`A in 1..2` reads the value for `A` must be in the range `1..2`
`abs(A-B)#\=1` reads the difference of the values between `A` and `B` must not equal 1
`A#\=B` reads the value of `A` must not equal the value of `B`
`B in 1..2` reads the value of `B` must be in `1..2`
So these are just a set of constraints. If you try to solve the constraints by hand you will find that there is no solution, e.g.
0,_ invalid by `A in 1..2`
_,0 invalid by `B in 1..2`
3,_ invalid by `A in 1..2`
_,3 invalid by `B in 1..2`
1,1 invalid by `A#\=B`
1,2 invalid by `abs(A-B)#\=1`
2,1 invalid by `abs(A-B)#\=1`
2,2 invalid by `A#\=B`
Doing the same for a 4x4 board
?- n_queens(4,Qs).
Qs = [_5398, _5404, _5410, _5416],
_5398 in 1..4,
abs(_5398-_5416)#\=3,
_5398#\=_5416,
abs(_5398-_5410)#\=2,
_5398#\=_5410,
abs(_5398-_5404)#\=1,
_5398#\=_5404,
_5416 in 1..4,
abs(_5410-_5416)#\=1,
_5410#\=_5416,
abs(_5404-_5416)#\=2,
_5404#\=_5416,
_5410 in 1..4,
abs(_5404-_5410)#\=1,
_5404#\=_5410,
_5404 in 1..4.
?- n_queens(4,Qs).
Qs = [A, B, C, D],
A in 1..4, reads the value for `A` must be in the range `1..4`
abs(A-D)#\=3, reads the difference of the values between `A` and `D` must not equal 3
A#\=D, reads the value of `A` must not equal the value of `D`
abs(A-C)#\=2, reads the difference of the values between `A` and `C` must not equal 2
A#\=C, reads the value of `A` must not equal the value of `C`
abs(A-B)#\=1, reads the difference of the values between `A` and `B` must not equal 1
A#\=B, reads the value of `A` must not equal the value of `B`
D in 1..4, reads the value for `D` must be in the range `1..4`
abs(C-D)#\=1, reads the difference of the values between `C` and `D` must not equal 1
C#\=D, reads the value of `C` must not equal the value of `D`
abs(B-D)#\=2, reads the difference of the values between `B` and `D` must not equal 2
B#\=D, reads the value of `B` must not equal the value of `D`
C in 1..4, reads the value for `C` must be in the range `1..4`
abs(B-C)#\=1, reads the difference of the values between `B` and `C` must not equal 1
B#\=C, reads the value of `B` must not equal the value of `C`
B in 1..4. reads the value for `B` must be in the range `1..4`
That is a bit to take in but this being logic we can rearrange the statements and the meaning will be the same.
So grouping like statements, sorting by variable, then ordering groups by simplicity gives
`A in 1..4` reads the value for `A` must be in the range `1..4`
`B in 1..4` reads the value for `B` must be in the range `1..4`
`D in 1..4` reads the value for `D` must be in the range `1..4`
`C in 1..4` reads the value for `C` must be in the range `1..4`
`A#\=B` reads the value of `A` must not equal the value of `B`
`A#\=C` reads the value of `A` must not equal the value of `C`
`A#\=D` reads the value of `A` must not equal the value of `D`
`B#\=C` reads the value of `B` must not equal the value of `C`
`B#\=D` reads the value of `B` must not equal the value of `D`
`C#\=D` reads the value of `C` must not equal the value of `D`
`abs(A-B)#\=1` reads the difference of the values between `A` and `B` must not equal 1
`abs(A-C)#\=2` reads the difference of the values between `A` and `C` must not equal 2
`abs(A-D)#\=3` reads the difference of the values between `A` and `D` must not equal 3
`abs(B-C)#\=1` reads the difference of the values between `B` and `C` must not equal 1
`abs(B-D)#\=2` reads the difference of the values between `B` and `D` must not equal 2
`abs(C-D)#\=1` reads the difference of the values between `C` and `D` must not equal 1
Now to explain the constraints and show how they relate to queens on a square board; note I say square board and not chess board because a chess board is 8x8 and this code works with different dimensional square boards.
A in 1..4
Means that the A queen has to be placed in a position on the 4x4 board. When working with constraint problems you often find that what we as humans take for granted or think of a common sense need to be given as specific constraints, this is a point in case. Also learning that adding rules for common sense is sometimes one of the hardest task when creating AI solutions. While I can not find a reference, when the creators of Cyc were adding rules, the concept of time took a lot of time to get right (no pun intended). The remainder of the constraints like A in 1..4 just ensure that no queen is placed in a position off the board.
A#\=B
To better understand this constraint lets do a picture with a 4x4 board and white queens as a valid position and the black queen as an invalid position as defined by the constraint.
So A is the white queen in row 1 and B is the black queen in row 1. Since A can not equal B this says that if queen A is in row 1 then queen B can not be in row 1. As the rule is used with variables it means that for any row the A queen is in the B queen can not be in that row. The remainder of the constraints like A#\=B just ensure that no two queens can be in the same row.
Think of this constraint as the horizontal attack for a queen.
abs(A-B)#\=1
To better understand this constraint lets do a picture with a 4x4 board and white queens as a valid position and the black queen as an invalid position as defined by the constraint.
There are four positions for A 1,2,3,4 but since the rule is symmetric horizontally (1 is the same a 4, and 2 is the same as 3) I will only do two of them.
When A is 1.
Since A is 1, B can not be 2.
1-2 = -1
ABS(-1) = 1
1 can not equal 1.
When A is 2.
Since A is 2, B can not be 1.
2 - 1 = 1
ABS(1) = 1
1 can not equal 1.
Since A is 2, B can not be 3.
2 - 3 = -1
ABS(-1) = 1
1 can not equal 1.
If the constraint using queen A and queen D is examined
abs(A-D)#\=3
When A is 1.
Since A is 1, D can not be 4.
1-4 = -3
ABS(-3) = 3
3 can not equal 1.
When A is 2.
Since A is 2, D can be 1.
2-1 = 1
ABS(1) = 1
1 can not equal 3.
Since A is 2, D can be 2.
2-2 = 0
ABS(0) = 0
0 can not equal 3.
Since A is 2, D can be 3.
2-3 = -1
ABS(-1) = 1
1 can not equal 3.
Since A is 2, D can be 4.
2-4 = -2
ABS(-2) = 2
2 can not equal 3.
Think of this constraint as the diagonal attack for a queen.
But wait a minute, a queen can move horizontally, vertically and diagonally, where is the constraint for moving vertically?
While this does not appear as a constraint in the output from the example query, there is a constraint. So far we have constraints that limit the positions of the queens to being on the board, the horizontal attack, and the diagonal attack as distinct constraints, however the structure of the data, the list of length N is also a constraint, ([A,B,C,D]) and constrains the A queen to the first column, the B queen to the second column and so on. Again this is one of points of learning to code in AI is that how we think as humans does not always directly translate into how to solve a problem with a computer. So while this code uses constraints to solve a problem, it also uses a data structure.
Think of the list as the column attack for a queen.
No two queens can be in the same column and that is limited by the fact that no two values can be in a scalar variable.
At this point many of you will recognize the remainder of the code as a helper and recursive predicate safe_queens/1 and as a recursive predicate safe_queens/3.
safe_queens([], _, _).
safe_queens([Q|Qs], Q0, D0) :-
Q0 #\= Q,
abs(Q0 - Q) #\= D0,
D1 #= D0 + 1,
safe_queens(Qs, Q0, D1).
This is a standard recursive call to process a list, e.g.
safe_queens([], _, _).
safe_queens([H|T], _, _) :-
% Process head of list (H)
safe_queens(T, _, _). % Process tail of list (T)
These two statements
Q0 #\= Q
abs(Q0 - Q) #\= D0
are explained above
and
D1 #= D0 + 1
sets D1 to D0 + 1
If we modify the predicate as such
permutations([], _, _).
permutations([Q|Qs], Q0, D0) :-
write(Q0),write('#\\='),writeln(Q),
write('abs('),write(Q0),write('-'),write(Q),write(')#\\='),writeln(D0),
D1 is D0 + 1,
permutations(Qs, Q0, D1).
and run these queries we see that it generates some of the constraints
?- permutations(['B','C','D'],'A',1).
A#\=B
abs(A-B)#\=1
A#\=C
abs(A-C)#\=2
A#\=D
abs(A-D)#\=3
true.
?- permutations(['C','D'],'B',1).
B#\=C
abs(B-C)#\=1
B#\=D
abs(B-D)#\=2
true.
?- permutations(['D'],'C',1).
C#\=D
abs(C-D)#\=1
true.
safe_queens([]).
safe_queens([Q|Qs]) :-
safe_queens(Qs, Q, 1),
safe_queens(Qs).
This is a standard recursive call to process a list, e.g.
safe_queens([]).
safe_queens([H|T]) :-
% Process head of list (H)
safe_queens(T). % Process tail of list (T)
and also a helper for safe_queens/3 because this statement
safe_queens(Qs, Q, 1)
initializes the third argument for safe_queens/3 to 1
If we modify the predicate as such
generate_args([]).
generate_args([Q|Qs]) :-
write('Qs: '),write(Qs),write(', Q: '),write(Q),writeln(', 1'),
generate_args(Qs).
and run this query we see that it generates the arguments needed for safe_queens/3
?- generate_args(['A','B','C','D']).
Qs: [B,C,D], Q: A, 1
Qs: [C,D], Q: B, 1
Qs: [D], Q: C, 1
Qs: [], Q: D, 1
true.
However in your question you did not ask about the first predicate
n_queens(N, Qs) :-
length(Qs, N),
Qs ins 1..N,
safe_queens(Qs).
which has
length(Qs,N)
that generates the list of length N with unbound variables
[A,B,C,D]
and has the crucial constraint statement
Qs ins 1..N
that generates the constraints like
A in 1..4
Now the crucial difference appended to the query
labels(Qs)
If you use the SWI-Prolog GUI-tracer and run the code up to the end of n_queens/2 you will see in the debugger a list of constraints but not a solution
that is because those predicates generate constraints that are maintained internally, it is not until labels/1 is called that the constraints are solved to generate a result.
I want to compare 2 values X and C1 as you can see in code, X is reversed value of C if both values are equal then it should print the compared value please tell me how to do this. It is to print Palindrome Numbers like... 1,11,22,33,44,55,66,77,88,99,101....
go(N):-
write(0),nl,
go(0,N).
go(_,0):- !.
go(A,C):-
A1 is A,
C1 is A1 + 1,
/* write(C1),nl,*/
rev(C1,X),
/* write(X),nl,*/
/* To compare the Value of X and C1 and print if compared value is true*/
NewC is C-1,
go(C1,NewC).
rev(Q,E):-
name(Q, Q1),
reverse(Q1,E1),
name(E,E1).
Describing palindrome numbers is actually a nice task for CLP(FD) and DCGs. First let's describe what the digits of a palindrome number look like:
:- use_module(library(clpfd)).
palindromedigits(Digits) :- % Digits are palindrome digits if
Digits ins 0..9, % they are between 0 and 9
Digits = [H|_], % and the first digit...
H #\= 0, % ... is different from 0
phrase(palindrome, Digits). % and they form a palindrome
palindrome --> % a palindrome is
[]. % an empty list
palindrome --> % or
[_]. % a list with a single element
palindrome --> % or
[A], % an element A
palindrome, % followed by a palindrome
[A]. % followed by an element A
To test if a number is a palindrome, you could turn it into a list of digits and palindromedigits/1 has to hold for that list. To generate such numbers, you could use length/2 to describe lists of all possible lengths, palindromedigits/1 again has to hold for those lists and the digits have to be multiplied by their respective powers of ten and summed up. Since leading zeros are excluded by palindromedigits/1, you'd have to add a fact for 0, if you want to include it in the palindrome numbers. That might look something like this:
palindromenumber(0). % 0 is a palindromenumber
palindromenumber(PN) :- % rule for testing numbers
number(PN), % succeeds if PN is a number
number_codes(PN,C), % C is a list of codes corresponding to the digits
maplist(plus(48),Digits,C), % codes and digits are off by 48
palindromedigits(Digits). % Digits is a palindrome
palindromenumber(PN) :- % rule for generating numbers
var(PN), % succeeds if PN is a variable
length(Digits,_), % Digits is a list of length 0,1,2,...
palindromedigits(Digits), % Digits is a palindrome
digits_number_(Digits,PN,1,0), % Digits correspond to the number PN
label(Digits). % labels the list Digits with actual numbers
Note that the codes corresponding to the digits are off by 48, hence the goal with maplist/3, e.g.:
?- number_codes(123,C), maplist(plus(48),Digits,C).
C = [49, 50, 51], % <- the codes
Digits = [1, 2, 3]. % <- the actual digits
The predicate digits_number_/4 is fairly straight forward. It is called with 1 as the initial power of ten and 0 as the initial accumulator for the number. The digits are multiplied with the power of ten corresponding to their position in the number and subsequently added to the accumulator. If the list of digits is empty, the accumulator holds the number corresponding to the list of digits.
digits_number_([],PN,_,PN).
digits_number_([D|Ds],PN,P,Acc) :-
Acc1 #= Acc + D*B,
P10 #= P*10,
digits_number_(Ds,PN,P10,Acc1).
Note that it doesn't matter that the digits are multiplied with the powers in reverse order, because it's a palindrome number.
Now you can query for palindrome numbers:
?- palindromenumber(PN).
PN = 0 ;
PN = 1 ;
PN = 2 ;
.
.
.
PN = 33 ;
PN = 44 ;
PN = 55 ;
.
.
.
PN = 666 ;
PN = 676 ;
PN = 686 ;
.
.
.
PN = 7667 ;
PN = 7777 ;
PN = 7887
.
.
.
Or you can test if a number is a palindrome:
?- palindromenumber(121).
true ;
false.
?- palindromenumber(123).
false.
?- palindromenumber(12321).
true ;
false.
EDIT
To address the question in your comment, you can do that by describing a relation between such a sequence and it's length. So you'll have a predicate with arity two instead of arity one. Let's give it a nice descriptive name, say firstN_palindromicnumbers/2. The actual realation is described by a predicate with an additional argument that holds the current candidate to be examined. Since you want to start the sequence with 1, that will be the argument firstN_palindromicnumbers_/3 will be called with:
firstN_palindromicnumbers(N,PNs) :-
firstN_palindromicnumbers_(N,PNs,1). % sequence starts with 1
The argument that holds the candidates will be increased by 1 through the recursions, while the first argument, N, will be decreased every time a candidate turns out to be an actual palindromic number. So the predicate eventually ends up with N being 0, an empty list and a candidate we don't care for. That will be the base case. Otherwise the head of the list is the smallest palindromic number in the (remainder of the) sequence. You can reuse the goals number_codes/2 and maplist/3 from above to describe a list of digits corresponding to the current candidate and the DCG palindrome//0 to state that the digits have to be a palindrome. The other goals from the predicate palindromedigits/1 won't be needed, since the candidates will be 1,2,3,..., thus consisting of (at least one) digit(s) from 0 to 9 without leading zeros. You can express this in Prolog like so:
firstN_palindromicnumbers_(0,[],_C). % base case
firstN_palindromicnumbers_(N1,[C0|PNs],C0) :- % case: C0 is a palindrome
N1 #> 0, % sequence is not of desired length yet
number_codes(C0,Codes),
maplist(plus(48),Digits,Codes),
phrase(palindrome, Digits), % digits form a palindrome
N0 #= N1-1, % sequence of length N1-1 has to be described yet
C1 #= C0+1, % C1 is the next candidate
firstN_palindromicnumbers_(N0,PNs,C1). % PNs is the rest of the sequence
firstN_palindromicnumbers_(N1,PNs,C0) :- % case: C0 ain't a palindrome
N1 #> 0, % sequence is not of desired length yet
number_codes(C0,Codes),
maplist(plus(48),Digits,Codes),
\+ phrase(palindrome, Digits), % digits don't form a palindrome
C1 #= C0+1, % C1 is the next candidate
firstN_palindromicnumbers_(N1,PNs,C1). % PNs is the rest of the sequence
Now you can query the predicate for a sequence of palindromic numbers of given length (Note that with SWI-Prolog you might have to hit w to see the entire list):
?- firstN_palindromicnumbers(15,PNs).
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] [write] % <- hit the w key
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66] ;
false.
?- firstN_palindromicnumbers(25,PNs).
PNs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161] ;
false.
You can also use the predicate to check if a given list is the sequence of the first N palindrommic numbers:
?- firstN_palindromicnumbers(N,[1,2,3,4,5]).
N = 5 ;
false.
?- firstN_palindromicnumbers(N,[0|_]).
false.
?- firstN_palindromicnumbers(N,[1,2,3,4,11]).
false.
And the most general query yields the expected answers as well:
?- firstN_palindromicnumbers(N,PNs).
N = 0,
PNs = [] ;
N = 1,
PNs = [1] ;
N = 2,
PNs = [1, 2] ;
N = 3,
PNs = [1, 2, 3] ;
.
.
.
how to replace any of the element in the list with prolog?
example:
replace(2,[1,2,3,2,1],5,X)
should have both the solutions:
X = [1,5,3,2,1]
X = [1,2,3,5,1]
You can do it by iterating over the input list:
%replace(_, [], _, []).
replace(Element, [Element|Tail], NElement, [NElement|Tail]).
replace(Element, [CurElement|Tail], NElement, [CurElement|NTail]):-
replace(Element, Tail, NElement, NTail).
Sample input:
?- replace(2,[1,2,3,2,1],5,X).
X = [1, 5, 3, 2, 1] ;
X = [1, 2, 3, 5, 1] ;
If you uncomment the first clause it would also output the solution where the output list remains unchanged.
The first clause (commented) is a base case for iterating over a list. It states that the replaced list of an empty list is the empty itself.
The second clause states that if the head of the list unifies with the Element then the replace list would contain the replaced element and the rest of the list (Tail).
The third clause is the recursive step, it takes the first element and calls recursively with the tail of the list, and the output is the element taken concatenated with the result of the recursive call.
I have to solve the following problem in Prolog. Alex, Fred and Jane are 3 children that have made a seesaw out of a plank that is 10 meters long. They mark 11 seating positions along the plank, each one meter apart. The number the seating positions as -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 where 0 is the center position. Alex, Fred and Jane weight respective 4, 3, and 2 units of weight. They are interested to know how they can get the seesaw to balance when all three of them are seated somewhere along the plank, and each child has to sit on a different position.
One seating position is when Alex, Fred, and Jane are at positions -4, 2, and 5 since (-4 * 4) + (2 * 3) + (5 * 2) = -16 + 6 + 10 = 0. Another seating position for Alex, Fred and Jane is -4, 4 and 2, and yet another is -3, 2, and 3.
I have tried the following to solve this but get error: ERROR: Type error: integer' expected, found[_G11889,_G11892,_G11895]'
Can anyone please help explain where I have gone wrong/how to go about this?
Many thanks in advance
:-use_module(library(clpfd)).
find(Seats):-
Seats=[Alex, Fred, Jane],
Seats in -5..5,
all_different(Seats),
(Alex*4+Fred*3+Jane*2)#=0, % I am not sure about this line
labeling([],Seats).
I would use symmetry breaking to reduce the number of solutions.
A simple symmetry is when (A,F,J) is a solution, so is also (-A,-F,-J).
So we could possibly restrict to J #>= 0, and keep in mind if J #\= 0,
then there is a flipped solution.
So we first begin by importing the CLP(FD) library:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.1.16)
Copyright (c) 1990-2014 University of Amsterdam, VU Amsterdam
?- use_module(library(clpfd)).
And then we formulate our query, instead of the (in)/2 one should
use (ins)/2, as larsman has already noted. The use of (in)/2 causes
also the error messsage. The parenthesis are not needed around
the linear form. So we get:
?- Seats=[Alex, Fred, Jane],
Seats ins -5..5,
Jane #> 0,
all_different(Seats),
Alex*4+Fred*3+Jane*2 #= 0,
label(Seats),
write(Seats), nl, fail; true.
[-4,2,5]
[-4,4,2]
[-3,2,3]
[-2,0,4]
[-2,2,1]
[-1,-2,5]
[-1,0,2]
[0,-2,3]
[1,-4,4]
true.
You get unique solutions for different weights, and if
you require that nobody is sitting in the middle of the
seesaw. The weights 15, 10 and 6 do the job. Here is
an example run, note the modified (ins)/2 statement:
?- Seats=[Alex, Fred, Jane],
Seats ins -5.. -1\/1..5,
Jane #> 0,
all_different(Seats),
Alex*15+Fred*10+Jane*6 #= 0,
label(Seats),
write(Seats), nl, fail; true.
[-4,3,5]
true.
Bye