Prolog: Given a Matrix create the transpose - prolog

I'm trying to learn how to use Prolog.
I have a matrix and I should make the transpose of this matrix.
I have done in this way:
transpose_matrix([], []).
transpose_matrix(Matrix, New_Matrix):-
length(Matrix, Num_Rows),
nth0(0, Matrix, First_Row),
length(First_Row, Num_Cols),
Num_Rows == Num_Cols,
transpose_matrix(Matrix, Num_Rows, 0, 0, New_Matrix).
transpose_matrix(Matrix, Num_Rows, Row, Col, [[Element|Rest]|Rest1]):-
Row < Num_Rows,
nth0(Row,Matrix,Current_Row),
nth0(Col,Current_Row,Element),
Row1 is Row + 1,
transpose_matrix(Matrix, Num_Rows, Row1, Col, [Rest|Rest1]).
transpose_matrix(Matrix, Num_Rows, Row, Col, [[_Element|_Rest]|Rest1]):-
Row >= Num_Rows,
Col1 is Col + 1,
transpose_matrix(Matrix, Num_Rows, 0, Col1, Rest1).
transpose_matrix(_Matrix, Num_Rows, _Row, Col, _New_Matrix):-
Col == Num_Rows.
In this way when I sum 1 to the Row to choose the correct element, when the Row is equal to the Length so I update the Col and I set the row value equal to 0.
Now this method seems to work, my problem is how the values are printed:
transpose_matrix([[6, 3, 2], [8, 1, 4], [3, 5, 9]], New_Matrix).
New_Matrix = [[6, 8, 3, _17602|_17604], [3, 1, 5, _17650|_17652], [2, 4, 9, _17698|_17700]|_17658]
How Can I Delete :
_17602| _17604...._17650|_17652..._17698|_17700]|_17658 ?
Thank you.

This may help you out:
1- The transp predicate will take the matrix of any length and will give the Transposed list in MatrixOut.
2- The add_col predicate can save you from the hassle of -1708,... type of values.
% transp(MatrixIn,MatrixOut)
transp([],[]).
transp([Row|Rows],Transpose) :-
transp(Rows,RowsT),
add_col(Row,RowsT,Transpose).
% add_col(Col,MatrixIn,MatrixOut)
add_col([],_,[]) :- !.
add_col([X|Col],[],[[X]|Rows]) :- !,
add_col(Col,[],Rows).
add_col([X|Col],[Row|Rows],[NewRow|NewRows]) :-
NewRow = [X|Row],
add_col(Col,Rows,NewRows).
Example:
?-transp([[2,0,1],[3,4,5],[6,7,8]],Out)
Out = [[2, 3, 6], [0, 4, 7], [1, 5, 8]]
?-transp([[6, 3, 2], [8, 1, 4], [3, 5, 9]],Out)
Out = [[6, 8, 3], [3, 1, 5], [2, 4, 9]]
?-transp([[6, 3, 2, 5, 3, 2], [8, 1, 4, 7, 4, 2], [3, 5, 9, 8, 5, 4],[6, 4, 5, 7, 8, 9]],Out)
Out = [[6, 8, 3, 6], [3, 1, 5, 4], [2, 4, 9, 5], [5, 7, 8, 7], [3, 4, 5, 8], [2, 2, 4, 9]]
Note: Solution is from my teacher's Lecture.

A very concise solution is:
transpose(Matrix, NewMatrix) :-
nonvar(Matrix),
findall(Row, maplist(nth1(_), Matrix, Row), NewMatrix).
Here are some examples:
?- transpose([[1,2], [3,4]], M).
M = [[1, 3], [2, 4]].
?- transpose([[6,3,2], [8,1,4], [3,5,9]], Matrix).
Matrix = [[6, 8, 3], [3, 1, 5], [2, 4, 9]].
?- transpose([[1,2,3], [4,5,6], [7,8,9]], M), maplist(writeln,M).
[1,4,7]
[2,5,8]
[3,6,9]
M = [[1, 4, 7], [2, 5, 8], [3, 6, 9]].
How it works:
nth1/3 generate elements (through backtracking).
maplist/3 generate rows (through backtracking).
findall/3 collect all rows.

Related

Data structure for conditional probabilities with updating conditions

I have a list of lists of 4 integers. All integers in the same list are distinct, e.g.,
data = [[8, 9, 3, 0], [3, 8, 4, 9], [7, 9, 6, 4], [3, 6, 4, 8], [0, 5, 3, 7], [0, 9, 4, 2], [9, 0, 1, 5], [3, 2, 8, 6], [3, 5, 4, 0], [1, 2, 5, 9], [1, 3, 6, 5], [2, 4, 5, 7], [7, 8, 6, 3], [6, 2, 9, 8], [8, 7, 5, 4], [8, 5, 1, 3]]
Currently I have a function that receives the list above and a list of distinct integers certain. The function returns a list with the probabilities of each integer (from 0 to 9) being in a list knowing that it contains the integers in certain.
def probability(data, certain):
probs = [0] * 10
counter_total = 0
set_certain = set(certain)
for d in data:
if set_certain.issubset(d):
counter_total += 1
for i in range(10):
if i in d and i not in set_certain:
probs[i] += 1
probs = [x / counter_total for x in probs]
return probs
Initially, the list certain is empty and values are added later. Is there a data structure I can use in the start of the program so that I don't have to go through all the data again every time I append a new value to certain? The list data can be very big.

Why does this recursive Prolog predicate add some "_1508"-like numbers to lists?

My task is to split a given sorted list (LSorted) into several other ones, where the first one would contain values from the LSorted that are smaller than the first prime number (1 is not considered prime) (from Primes list), the second one would contain values from LSorted smaller than the second prime number but greater or equal to the first prime, etc.
ans(L, Res):-
max_list(L, X), /*determine the max value X of L*/
listPrimes(X, Primes), /*generate a list of primes up to X and the prime greater than X*/
msort(L, LSorted), /*sort L*/
ans_recur(LSorted, Primes, Res),!.
ans_recur([], _, [[]|[]]).
ans_recur([InH|Input], [PrimeH|Primes], [[InH|Res]|ResT]):-
InH < PrimeH,
ans_recur(Input, [PrimeH|Primes], [Res|ResT]).
ans_recur([InH|Input], [_|Primes], [_|ResT]):-
ans_recur([InH|Input], Primes, ResT).
When I run a query: ans([1,2,3,4], L)., I get this result:
L = [_1508, [1|_1522], [2|_1534], [3, 4]], while I expect [[1], [2], [3,4]]. The program does "put" the numbers into the "correct" lists, but adds some values like _1508.
As far as I understand, the reason for that is that Prolog is trying to assign some value to Res in ans_recur predicate, but why does it do that?
Tracing:
Call:ans([1, 1, 2, 2, 3, 4], _13636)
Call:lists:max_list([1, 1, 2, 2, 3, 4], _14050)
Exit:lists:max_list([1, 1, 2, 2, 3, 4], 4)
Call:listPrimes(4, _14080)
Exit:listPrimes(4, [1, 2, 3, 5])
Call:sort([1, 1, 2, 2, 3, 4], _14224)
Exit:sort([1, 1, 2, 2, 3, 4], [1, 2, 3, 4])
Call:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], _13636)
Call:1<1
Fail:1<1
Redo:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], _13636)
Call:ans_recur([1, 2, 3, 4], [2, 3, 5], _14156)
Call:1<2
Exit:1<2
Call:ans_recur([2, 3, 4], [2, 3, 5], [_14174|_14168])
Call:2<2
Fail:2<2
Redo:ans_recur([2, 3, 4], [2, 3, 5], [_14174|_14168])
Call:ans_recur([2, 3, 4], [3, 5], _14168)
Call:2<3
Exit:2<3
Call:ans_recur([3, 4], [3, 5], [_14204|_14198])
Call:3<3
Fail:3<3
Redo:ans_recur([3, 4], [3, 5], [_14204|_14198])
Call:ans_recur([3, 4], [5], _14198)
Call:3<5
Exit:3<5
Call:ans_recur([4], [5], [_14234|_14228])
Call:4<5
Exit:4<5
Call:ans_recur([], [5], [_14252|_14228])
Exit:ans_recur([], [5], [[]])
Exit:ans_recur([4], [5], [[4]])
Exit:ans_recur([3, 4], [5], [[3, 4]])
Exit:ans_recur([3, 4], [3, 5], [_14204, [3, 4]])
Exit:ans_recur([2, 3, 4], [3, 5], [[2|_14204], [3, 4]])
Exit:ans_recur([2, 3, 4], [2, 3, 5], [_14174, [2|_14204], [3, 4]])
Exit:ans_recur([1, 2, 3, 4], [2, 3, 5], [[1|_14174], [2|_14204], [3, 4]])
Exit:ans_recur([1, 2, 3, 4], [1, 2, 3, 5], [_14154, [1|_14174], [2|_14204], [3, 4]])
Exit:ans([1, 1, 2, 2, 3, 4], [_14154, [1|_14174], [2|_14204], [3, 4]])
L = [_1282, [1|_1296], [2|_1308], [3, 4]]
Thanks in advance.
ans_recur([InH|Input], [PrimeH|Primes], [[InH|Res]|ResT]):-
InH < PrimeH,
ans_recur(Input, [PrimeH|Primes], [Res|ResT]).
ans_recur([InH|Input], [_|Primes], [_|ResT]):-
ans_recur([InH|Input], Primes, ResT).
What you are trying to express in these clauses is something like this:
if InH is less than the next prime, it should be part of the current running result
otherwise, it should be part of some later running result
But in the last case, the "current running result" is finished, it has no more elements. So its tail, which is so far open, must be closed. You need to change the head of the last clause accordingly:
ans_recur([InH|Input], [_|Primes], [[]|ResT]):-
This now behaves like this:
?- ans_recur([1,2,3,4,5,6,7,8,9,10], [2,3,5,7,11], Result).
Result = [[1], [2], [3, 4], [5, 6], [7, 8, 9, 10]] ;
Result = [[1], [2], [3, 4], [5], [6, 7, 8, 9|...]] ;
Result = [[1], [2], [3, 4], [], [5, 6, 7, 8|...]] ;
Result = [[1], [2], [3], [4, 5, 6], [7, 8, 9, 10]] . % further incorrect answers
The problem is that you don't express the "otherwise" condition explicitly, and Prolog will not guess implicitly that it was what you meant. You can change the last clause to this:
ans_recur([InH|Input], [PrimeH|Primes], [[]|ResT]):-
InH >= PrimeH,
ans_recur([InH|Input], Primes, ResT).
And only get the expected answer:
?- ans_recur([1,2,3,4,5,6,7,8,9,10], [2,3,5,7,11], Result).
Result = [[1], [2], [3, 4], [5, 6], [7, 8, 9, 10]] ;
false.
As you can see, I only dealt with your implementation of ans_recur/3. There might be more bugs lingering in the rest of the code. We cannot tell because the code you posted is incomplete. In the future, please only post complete programs. Many contributors will not bother to try to complete your question for you, and you will get fewer answers.

Breaking a matrix into smaller sub-lists

I can't wrap my head around how to achieve this. To be more specific, I would like to break the following matrix
matrix = [[7, 9, 1, 8, 9, 1],
[4, 2, 1, 2, 1, 5],
[3, 2, 3, 1, 2, 3],
[7, 9, 11, 6, 4, 8],
[8, 9, 22, 3, 1, 9],
[1, 1, 1, 1, 1, 1]]
into:
[[7, 9,
4, 2],
[1, 8,
1, 2],
[9, 1,
1, 5],
[3, 2,
7, 9],
[3, 1,
11, 6],
[2, 3,
4, 8],
[8, 9,
1, 1],
[22, 3,
1, 1],
[1, 9,
1, 1]]
Or equivalently,
[[7, 9, 4, 2],
[1, 8, 1, 2],
[9, 1, 1, 5],
[3, 2, 7, 9],
[3, 1, 11, 6],
[2, 3, 4, 8],
[8, 9, 1, 1],
[22, 3, 1, 1],
[1, 9, 1, 1]]
Here is what I have tried doing:
def split([[]]) -> [[]]
split_matrix = []
temp_map = []
row_limit, col_limit = 2, 2
for row in range(len(elevation_map)):
for col in range(len(elevation_map)):
elevation = elevation_map[row][col]
if row < row_limit and col < col_limit:
temp_map.append(elevation)
split_matrix.append(temp_map)
return split_matrix
However, I had no luck in doing so.
Is there a way to do it without using libraries like numpy? Is it possible?
The solution is going to be neater if we write a helper function to extract one 2x2 sub-matrix into a list. After that, it's a simple list comprehension, iterating over the coordinates of the top-left of each submatrix.
def split_matrix(matrix, rows=2, cols=2):
def helper(i, j):
out = []
for row in matrix[i:i+rows]:
out.extend(row[j:j+cols])
return out
width, height = len(matrix[0]), len(matrix)
return [
helper(i, j)
for i in range(0, height, rows)
for j in range(0, width, cols)
]

Prolog merge sort a list that is inside a list

For an example I need to sort:
?- mergesort([8,1,[4,6,3],2],Sorted).
The outcome should be:
Sorted = [1, 2, 8, [3, 4, 6]]
Unfortunately I'm not sure what to do. I've tried to find an answer myself, but didn't find a solution. Currently the outcome is:
Sorted = [1, 2, 8, [4, 6, 3]]
My code:
mergesort([],[]).
mergesort([A],[A]).
mergesort([A,B|R],S) :-
split([A,B|R],L1,L2),
mergesort(L1,S1),
mergesort(L2,S2),
merge(S1,S2,S).
split([],[],[]).
split([A],[A],[]).
split([A,B|R],[A|Ra],[B|Rb]) :- split(R,Ra,Rb).
merge(A,[],A).
merge([],B,B).
merge([A|Ra],[B|Rb],[A|M]) :- A #=< B, merge(Ra,[B|Rb],M).
merge([A|Ra],[B|Rb],[B|M]) :- A #> B, merge([A|Ra],Rb,M).
Big thanks in advance!
I would write a simple preprocessing step:
sortl([H|T],[Hs|Ts]) :-
( is_list(H)
-> mergesort(H,Gs),
sortl(Gs,Hs)
; Hs = H
),
sortl(T,Ts).
sortl([],[]).
then you could use it this way
?- sortl([8,1,[4,6,[3,4],[1,8],3],2,[1,3,2]],T),mergesort(T,Sorted).
T = [8, 1, [3, 4, 6, [1, 8], [3|...]], 2, [1, 2, 3]],
Sorted = [1, 2, 8, [1, 2, 3], [3, 4, 6, [...|...]|...]]

Divide List to pieces of needed length

I was trying to write predicate divide(L,Len,Slist) which will be true when Slist can unify with a List of length Len allocated from List L. for example
divide([1,2,3,4,5,6,7],3,Slist).
Should give such answers
Slist=[1,2,3];
Slist=[2,3,4];
Slist=[3,4,5];
Slist=[4,5,6];
Slist=[5,6,7];
But i couldn't find a better way then length(X,Len), sublist(L,X). but it does work too slow.
How should look divide predicate?
Alternatively you could use DCG as mentionned by #false in this great answer:
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
divide(List, Length, Result) :-
length(Result, Length),
phrase((seq(_), seq(Result), seq(_)), List).
sublist/2 doesn't seems to work as expected:
?- [library(dialect/sicstus/lists)].
% library(dialect/sicstus/lists) compiled into sicstus_lists 0,00 sec, 14 clauses
true.
?- L=[1,2,3,4,5,6], length(T, 3),sublist(T,L).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 4] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 5] ;
....
You could use append/3 instead:
?- L=[1,2,3,4,5,6], length(T, 3), append(_, Q, L), append(T, _, Q).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3],
Q = [1, 2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [2, 3, 4],
Q = [2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [3, 4, 5],
Q = [3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = Q, Q = [4, 5, 6] ;
false.
I don't think it's very fast, just essential...

Resources