Related
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.
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.
I have a range of numbers R = (1..n). I also have another character 'a'. I want to generate strings of length L (L > n + 2) that have all the numbers in the same order, but go through every repeated permutation of 'a' to fill the length L. For example, if n = 3, and L = 7, then some valid strings would be :
"123aaaa",
"1a23aaa",
"1aa2a3a",
"aaaa123"
while the following strings would be invalid:
"213aaaa", # invalid, because 1,2,3 are not in order
"123a", #invalid, because length < L
"1123aaa", # invalid because a number is repeated
I am currently doing this, which is way too inefficient:
n = 3
L = 7
all_terms = (1..n).to_a + Array.new(L - n, 'a')
all_terms.permutation.each do |permut|
if(valid_permut? permut) # checks if numbers are in their natural order
puts permut.join
end
end
How do I directly generate valid strings more efficiently?
The problem is equivalent to: select n elements from index 0 to L - 1, fill these with 1 to n accordingly, and fill the rest with some constant character.
In your example, it's taking 3 elements from 0..6:
(0..6).to_a.combination(3).to_a
=> [[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 2, 3], [0, 2, 4],
[0, 2, 5], [0, 2, 6], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [0, 5, 6],
[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5],
[1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6],
[3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6]]
Every subarray here represents a possible result. For example, [0, 2, 3] corresponds to '0a12aaa', [3, 5, 6] corresponds to 'aaa0a12', etc. The code for this conversion is straight-forward.
You can model this as all possible interleavings of two strings, where relative order of the input elements is preserved. Here's a recursive solution. It works by choosing an element from one list, and prepending it to all possible subproblems, then doing it again where an element is chosen from the second list instead, and combining the two solution sets at the end.
# Returns an array of all possible interleaving of two strings
# Maintains relative order of each character of the input strings
def interleave_strings_all(a1, a2)
# Handle base case where at least one input string is empty
return [a1 + a2] if a1.empty? || a2.empty?
# Place element of first string, and prepend to all subproblems
set1 = interleave_strings_all(a1[1..-1], a2).map{|x| a1[0] + x}
# Place element of second string and prepend to all subproblems
set2 = interleave_strings_all(a1, a2[1..-1]).map{|x| a2[0] + x}
# Combine solutions of subproblems into overall problem
return set1.concat(set2)
end
if __FILE__ == $0 then
l = 5
n = 3
a1 = (1..n).to_a.map{|x| x.to_s}.join()
a2 = 'a' * (l - n)
puts interleave_strings_all(a1, a2)
end
The output is:
123aa
12a3a
12aa3
1a23a
1a2a3
1aa23
a123a
a12a3
a1a23
aa123
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, [...|...]|...]]
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...