I have some code, looks like this:
main :-
open('input.txt', read, Input),
repeat,
read_line_to_codes(Input, Line),
maplist(my_representation, Line, FinalLine),
( Line \= end_of_file -> writeln(FinalLine), fail ; true ),
close(Input).
FinalLine is a list of integers, including some underscores (based on the input file). Since this loops, I am wondering how to dynamically, each iteration of the loop, add the FinalLine list to another list. Basically this will create a list of lists.
And since I know the specifications of my input file, I know it loops 16 times, therefore I want a list of 16 lists. So although I don't know how to do this, I am pretty sure the best way would be to make a predicate that I call, instead of the output I am doing now (writeln(FinalLine)), to dynamically create this list of lists.
Hope this makes sense. Would appreciate any help, thanks!
While historically I/O in Prolog was often presented in terms of repeat/fail loops, recursion is often (almost always?) the superior way to implement iteration. Especially if you need to remember data from one iteration to the next; failing causes backtracking, which unbinds your variables from the previously computed data. On backtracking you lose any data you had not saved away using yet more impure constructs. Recursion is simpler.
Recursion forces you to decompose the program into more than one predicate, but that is a good idea anyway. For example, separating opening the stream from reading it makes your program more reusable and more testable, because streams may be constructed from things other than files.
% dummy
my_representation(Codes, Result) :-
atom_codes(Result, Codes).
stream_representations(Input, Lines) :-
read_line_to_codes(Input, Line),
( Line == end_of_file
-> Lines = []
; my_representation(Line, FinalLine),
Lines = [FinalLine | FurtherLines],
stream_representations(Input, FurtherLines) ).
main :-
open('input.txt', read, Input),
stream_representations(Input, Lines),
close(Input),
writeln(Lines).
Test input file:
hello
world
hello, world!
this file ends here
Test run:
?- main.
[hello,world,hello, world!,this file ends here]
true.
A 2-dimensional list of lists is a matrix, and the easiest way to visualize it in your head is a table consisting of rows and columns. Here's a piece of example code to clarify the concept.
This code generates a matrix based on the maximum amounts of columns you want as MaxX, and the maximum amount of rows you want as MaxY. Each position in the matrix has a cell(point(X,Y)) coordinate to visualize the output more easily.
%If the MaxY has been reached for the Y axis, step back
generate_matrix([],_,_,MaxY,MaxY) :- !.
%If MaxX has been reached, new row
generate_matrix([Row|Tp],X,MaxX,Y,MaxY):-
generate_row(Row, X, MaxX, Y),
Y1 is Y+1,
generate_matrix(Tp,0,MaxX,Y1,MaxY).
%If the MaxX has been reached for the X axis, step back
generate_row([], MaxX,MaxX,_) :- !.
generate_row([cell(point(X,Y))|T], X, MaxX, Y) :-
XNew is X + 1,
generate_row(T, XNew, MaxX, Y).
You could easily replace cell(point(X,Y) with something you want to place there instead. I hope this clarifies the concept for you, be sure to ask for clarification if it doesn't.
Testquery to generate a 10 by 10 matrix/grid/table/2-dimensional list of lists:
%generate_matrix(Matrix, 0, MaxX, 0, MaxY)
generate_matrix(Matrix, 0, 10, 0, 10).
You can add dimensions to represent more complex structures. Adding a Z-axis gives you a 3D-cube.
Related
I need to find the max number in a list of lists in Prolog, and then 'print' (output in a new list) the lists that include this max number.
For example: lists_with_max([[1,2,3],[2,3,44],[44,5,6]],Lists).
Should output: Lists = [[2,3,44],[44,5,6]]
Code below is the closest I could think of that works and has no errors, but it's obviously wrong because everytime it finds a new max and then outputs wrong lists.
'max' finds the max number in a list.
'flat' "flattens" a list.
'maxl' finds the max number in a list of lists.
max([X], X).
max([H|T], H):-
max(T, MaxT),
H > MaxT.
max([H|T], MaxT):-
max(T, MaxT),
H =< MaxT.
flat([], []).
flat([H|T], [H|LT]):-
atomic(H),
flat(T, LT).
flat([H|T], L):-
flat(T, LT),
not(atomic(H)),
flat(H, LH),
append(LH, LT, L).
maxl(List,Max):-
flat(List,Newlist),
max(Newlist,Max).
lists_with_max([],[]).
lists_with_max([H|T],[H|L]):-
maxl([H|T],Max),
member(Max,H),
lists_with_max(T,L).
lists_with_max([_H|T],L):-
lists_with_max(T,L).
Here's another approach using builting predicates max_list/2, maplist/3, include/3 and memberchk/2:
lists_with_max(LL, LL1):-
maplist(max_list, LL, ML),
max_list(ML, M),
include(memberchk(M), LL, LL1).
I think you went off the rails a bit with maxl/2 and flat/2, you don't really need them to solve your problem. This isn't, IMO, a great example of something you can do by throwing a bunch of recursion at the problem, you really are going to have to look through all the lists, find the max element, and then look through them all again. Your max/2 is fine though.
So, let's find the max element:
setof(Max, L^(member(L, Lists), max(L, Max)), Maxes),
This is a meta-predicate, it's just going to look through all the lists for the max of that list, and make a new list of the maxes of each list. I think good Prolog should have a fluent quality; if you reworded your query into something more like logic, you would have something like "The Maxes of the Lists is a list containing the max of each List" and eventually you would arrive at something like what you see there. The L^ is saying, we do not want to group this by the list L it generates (there will come other times in your life as a Prolog programmer where you will want this grouping). Probably using findall/3 would have the same effect, but I like setof/3 more.
Next, let's find the max-of-maxes:
max(Maxes, Max),
Pretty straight-forward. Now let's find all the lists that have the maximum in them:
setof(L, (member(L, Lists), member(Max, L)), Result).
This is another one like the first, where we're saying "find me all the lists L such that L is in Lists and Max is in L". Putting it all together we have:
lists_with_max(Lists, Result) :-
setof(Max, L^(member(L, Lists), max(L, Max)), Maxes),
max(Maxes, Max),
setof(L, (member(L, Lists), member(Max, L)), Result).
Another way of doing max/2, which I include here mostly to show you another way to think about Prolog because it is way, way less efficient and sort of terrible is this:
max(List, Max) :-
member(Max, List),
\+ (member(Y, List), Y > Max).
This isn't great style, but it does demonstrate that you can sometimes tell Prolog what you want rather than how to find it. This says the Max of List is the member of Max of List such that there is no member Y of List which is greater than it. Food for thought, I hope.
I have a matrix of 6x6 numbers and I'm writing a prolog code that gives me the numbers in a certain row, column or square. For instance:
0n 1n 2n 3n 4n 5n
0n [[1,2,3,4,5,6]
1n [2,3,4,5,6,1]
2n [3,4,5,6,1,2]
3n [4,5,6,1,2,3]
4n [5,6,1,2,3,4]
5n [6,1,2,3,4,5]]
I already have code for rows and columns, which is something like:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y-1 is Y1,
row(Y1,B,X).
But now I'm stuck on how to generate a 3x3 square. I want to work with coordinates, so the first argument should be something like (1,3) and it will give the square of row 1n and column 3n, then the matrix as the second and the numbers in the square as third argument.
Does anyone have any tips? I was thinking I might have to work with a head tail pattern again; getting the first three numbers of the given row/column, then doing this three times, but I don't know how or if this is possible and effective.
Any comments are greatly appreciated!
First of all, your predicate to obtain the row, is not safe:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y-1 is Y1,
row(Y1,B,X).
In case I query for row(0,[1,4,2,5],X). it will get stuck into an infinite loop immediately, in case i work with row(2,[1,4,2,5]). it will first give me the correct result, but then get into an infinite loop when searching for more answers.
A better approach would be:
row(1,[A|_],A).
row(Y,[_|B],X) :-
Y > 1,
Y-1 is Y1,
row(Y1,B,X).
Since now the Y > 1 guards the fact that you will not perform recursion if Y is less than or equal to 1.
That being said, you do not need to construct this predicate yourself: most Prolog interpreters already have such a predicate: nth1/3:
nth1(?Index, ?List, ?Elem)
Is true when Elem is the Index'th element of List. Counting
starts at 1.
If you can assume that this predicate exists, you can use:
elem(I,J,Matrix,Cell) :-
nth1(I,Matrix,Row),
nth1(J,Row,Cell).
Where I is the number of the row, and J the number of the column we wish to fetch.
In case it does not exists, I suggest renaming your row/3 predicate to nth1/3 since it is equivalent.
In case you want to start counting at 0 (which the top of your question suggests), you can use nth0/3 instead of nth1/3.
I'm dragging along in python, learning so slow but making progress. Have hit a wall, and don't even know where to start on this.
I have other scripts that get me to where I am now: two output CSV files with multiple rows containing 4 numbers each. The first number is an identifier integer, the other three are X, Y, Z coordinates.
Now the OTHER file is the same thing, with the same set of identifier integers, but a different set of X, Y, Z coordinates.
For each identifier integer, I want to calculate the RMSD between the X,Y,Z. In other words, I think I need to do (X2-X1)^2 + (Y2-Y1)^2 + (Z2-Z1)^2 then take the square root of that. This will give me a float as an output answer, which I'd like to write into an output file of two columns: one with the the identifier integer, and the second is the output from this script.
I actually have no idea where to start on this one.. I've never had to work with two files at once. Gah!
thanks so much!!
sorry I have no script to even start here!
I am solving a fixed point problem through the following algorithm:
1. specify grids x1,x2,x3,... xn
2. initial guess f=0 on all grids x1, x2, x3, ..., xn
3. update f according to some mapping T. f'=Tf on all grids.
4. calculate distance ||f'-f||. If greater than tolerance, go back to 3; otherwise, end.
5. Write a .txt file to record the solution f.
If let'say, I'm interested in checking out f and f' before the tolerance is reached (i.e. before the program jumps from 4 to 5), is there a way to ask Fortran to write out f and f' once the program is forced to stop? Something like:
IF (stop message received) THEN
PRINT f and f' to files
END IF
I know a variation of doing that is to write f and f' each time the function is updated. But that's perhaps too costly as the algorithm takes 100 seconds for 1 iteration and about 200 iterations to finish, which is approx. 6~7 hours.
Any thoughts and suggestions? Thanks!
So replace
4. calculate distance ||f'-f||. If greater than tolerance, go back to 3; otherwise, end.
5. Write a .txt file to record the solution f.
with
4. calculate distance ||f'-f||. If greater than tolerance, go back to 3.
5. Write a .txt file to record the solution f. end
This seems so obvious I expect I've completely missed the point.
hill(+IntList) succeeds if IntList consists of monotonically increasing >integers followed by monotonically decreasing integers. For example, >[1,2,5,8,11,6,3,-1] is a hill, but [1,2,5,8,11,6,9,3,-1] and [1,2,3,4,5,6] are >not hills. You may assume that IntList contains only integers.
This is what I have done so far:
hill(List) :-
increasing(List), decreasing(List).
increasing([H|Tail]) :-
sm(H,Tail),
increasing(Tail).
increasing([]).
decreasing([H|Tail]) :-
gr(H,Tail),
decreasing(Tail).
decreasing([]).
hill([]).
gr(X,[H|Tail]) :- X>H.
gr(X,[]).
sm(X,[H|Tail]) :- X<H.
sm(X,[]).
But this doesn't work. The logic is: A list of numbers is hill IF it is increasing and then decreasing. How do I say that? This code does increasing and decreasing, but no list can be both increasing and decreasing.
Any ideas?
I don't want to give a complete, working solution to a homework problem, but I'll describe in words how I would proceed from the code you've got right now. Right now your increasing and decreasing predicates test the entire list. By your definition, though, a hill is neither entirely increasing nor entirely decreasing. I would modify these predicates to have two arguments instead of one. The additional argument would be bound to the tail of the list which is not does not satisfy the increasing/decreasing criteria. Then, I'd modify hill slightly to use the new argument of increasing to test decreasingness not of the entire list, but of the portion after the initial increasing subsequence. Finally, I would use the new argument of decreasing to verify that there are no non-decreasing elements after the decreasing subsequence.
If you need better hints, or if I seem to be talking nonsense (quite possible as I'm not that good with Prolog), just let me know and I'll try to clarify more.
Edit based on OP's comments: Alright, let's try something else. L is a hill if and only if L is a list of at least two monotone increasing elements ending with some element M, followed by a list of at least one monotone decreasing element starting with some element N, where N < M. Can you translate that description to Prolog clauses?
Edit take two (SPOILER WARNING):
In your revised code, drop these three predicates: increasing([])., hill([])., and hill(List) :- decreasing(List).. This will almost give you a solution, but it will still fail, e.g. on [3, 2, 1]. Fixing this should be fairly easy, though.
Use clpfd!
:- use_module(library(clpfd)).
We don't need to worry about getting recursion right if we use append/3 and chain/2 like this:
hill(Zs) :-
Ascending0 = [_|_],
Descending = [M,_|_],
append(Ascending0,Descending,Zs),
append(Ascending0,[M],Ascending),
chain(Ascending ,#<),
chain(Descending,#>).
Let's run the queries the OP gave!
?- hill([1,2,5,8,11,6,3,-1]).
true % as expected
; false.
?- hill([1,2,5,8,11,6,9,3,-1]).
false. % as expected
?- hill([1,2,3,4,5,6]).
false. % as expected
hill(L1) :- concatenate(L2,L3,L1), inc(L2), dec(L3).
dec([X|[Y|[]]]) :- X > Y.
dec([X|[Y|L]]) :- X > Y, dec([Y|L]).
inc([X|[Y|[]]]) :- Y > X.
inc([X|[Y|L]]) :- Y > X, inc([Y|L]).
concatenate([],L2,L2).
concatenate([X|L1],L2,[X|L3]) :- concatenate(L1,L2,L3).
This works :)