Get dimension in quadratic matrix - prolog

I have problem with computing dimension of Quadratic Matrix for instance [3x3].
when I run dim([[1,2],[3,4]], D). should return D=[1,4].
But I got an error that RowIndex is singleton... but it is defined in first line of dim function... there-> dim(M,D):-dim(M,0,[],D). and RowIndex at the beginning is equal to 0, this is second parameter of function with accumulator.
Could sb look at it and give me some advice? Thanks in advance.
:- use_module(library(lists)).
getElement(L,Index,Element):-
length(L,D),
( D>Index -> getElement(L,Index,Element,0)
; !,fail
).
getElement([H|L],Index,Element,Current):-
( Index =:=Current -> Element is H
; Current1 is Current + 1,
getElement(L,Index,Element,Current1)
).
dim(M,D):-
dim(M,0,[],D).
dim([],_,Acc,Acc).
dim([H|M],RowIndex,Acc,D):-
getElement(H,RowIndex,Element),
append(Acc,[Element],Acc1),
RowIndex1 is RowIndex + 1,
dim(M,RowIndex1,Acc1,D).

Related

Why is my function returning a negative value?

So I drew a simple function in prolog that counts how many of a variable are in a matrix.
And it goes like this :
:-use_module(library(lists)).
:-use_module(library(clpfd)).
countOccurrences([],Y,0).
countOccurrences([X|T], Y, Z):-
countOccur(X, Y, N),
Acc #=N + Z,
countOccurrences(T, Y, Acc).
countOccur([],X,0).
countOccur([X|T],X,Y):- countOccur(T,X,Z), Y is 1+Z.
countOccur([X1|T],X,Z):- X1\=X,countOccur(T,X,Z).
countOccur seems to be working fine and returns the right value. The problem is countOccurences is returning the right absolute value but negative. I Just dont seem to understand why that is happening.
Can someone enlighten me ?
An input of [[a,a,a,a]] looking for a does countOccurrences of a in [] and sets Acc = 0 and then countOccur of a in [a,a,a,a] sets N=4 then Acc #= N + Z becomes 0 #= 4 + Z and so the result must be Z = -4.

Recursivity | Natural numbers in list swish prolog

i have the next problem,
"return the numbers of natural numbers of an array"
ex. naturales(R,[6,-7,-4,3,2,8]).
R = 4
when a negative numbers appears return false and break my recursivity
naturales(R,[Head|Tail]):-naturales(R1,Tail), Head >= 0, R is R1+1.
naturales(0,[]).
Here is a very short solution :
naturales(In, Out) :-
aggregate(count,X^(member(X, In), X >= 0), Out).
If your predicate really needs to have only 2 arguments, one being the result, R, and the other one the given list, [H|T], you can do something like this. Note that the first predicate calls the second "naturales" with 3 arguments and then, that one starts the recursive process. The C is only a counter where you can add the number of positive elements and then copy that value to the result, in the last line of code. The first line just its just to make sure the empty list returns 0 positive elements. There is probably better ways to do this, this one is probably the most intuitive.
naturales(X, []):- X = 0.
naturales(R, [H|T]):- naturales(R, [H|T], 0).
naturales(R, [H|T], C):- (H > 0, C1 is C + 1, naturales(R1, T, C1), R = R1) ; naturales(R1, T, C), R = R1.
naturales(X, [], X).
A common prolog idiom is the use of a helper predicate with an accumulator (extra) variable. Try something like this:
natural_numbers( Xs, N ) :- natural_numbers( Xs, 0, N ).
natural_numbers( [] , N , N ) .
natural_numbers( [X|Xs] , T , N ) :-
( X > 0 -> T1 is T+1 ; T1 = T ) ,
natural_numbers( Xs, T1, N ).
As others pointed out, the recursive call cannot complete when there are negative numbers. So, you can just patch your program in this way
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0, R is R1+1 ; R=R1).
naturales(0,[]).
Now, nearly every Prolog out there (except mine :) implements (->)/2, also know as 'if-then-else'. So, the patch could also be written like
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0 -> R is R1+1 ; R=R1).
naturales(0,[]).
Given that naturales/2 is anyway not tail recursive (see #NicholasCarey answer for that), I think it has no practical relevance for you.

Count sum of spaces between first element and a specific element prolog

Basically trying to figure out how you would make a predicate where given two parameters, a list and a number, you would sum up the amount of spaces from the first element to the specific letter.
Example, say 'w' is the letter, given the statement
h1([e,w,b,a,w,w,c], 10)
would return true since 10 = 1+4+5 where 1,4,5 are the distances from element 0 and would return false if not 10.
Heres what I have so far
h2(List, H) :- sum(List,0,H).
sum([],TotalCount,TotalCount):- !.
sum([w|T],CurrentCount, TotalCount) :-
NewCount is CurrentCount + CountSince,
sum(T, NewCount, 0)
sum([_|T], NewCount, 0) :-
CountSince is CountSince + 1,
sum(T, NewCount, CountSince).
As said in the comment, you can solve this problem with three lines of code, using findall/3 and sum_list/2. Here the code:
h2(L,E,V):-
findall(P,nth0(P,L,E),LP),
( LP = [] -> false;
sum_list(LP,V)).
I wrote h2/3 and not h2/2 to make it more modular (i.e. you can pass the element you want to find to the predcate). Since you want false as answer if the element is not in the list, i've added an if statement to check if the list from findall/3 is empty. If it's not, simply sum the elements with sum_list/2.
?- h2([e, w, b, a, w, w, c],f,V).
false
?- h2([e, w, b, a, w, w, c],w,V).
V = 10

How can I get this simple Prolog predicate to "return" the right way?

So I am learning Prolog. I need to write a predicate that finds the min/max value of an integer list. For example, the query minmaxArray([4,-1,5,4,1,2,3,-2],X,Y) would return X = -2 Y = 5. Here is what I have so far:
%min/max element of a 1 item list is that item.
minmaxArray([X], X, X).
%when there is only 2 items, put the smaller element in A and the
%larger element in B
minmaxArray([X,Y], A, B) :- mymin(X,Y,Min),
A is Min, mymax(X,Y,Max), B is Max.
%when there is more than two items make a recursive call to find the min/max
%of the rest of the list.
minmaxArray([X,Y|T], A, B) :- minmaxArray([Y|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
Assume mymin and mymax predicates work properly. They return the min and max of 2 numbers.
The issue here is that for example when I query minmaxArray([4,-1,5],X,Y) it returns X = -1 Y = 5 and then again X = -1 Y = 5. I know this must be because it hits the 2nd condition on the recursive call. I only want it to return X = -1 Y = 5 one time. I tried replacing condition 3 with this:
minmaxArray([X,Y,_|T], A, B) :- minmaxArray([Y,_|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
but that crashes the program. What can I do to fix this?
Note: I know that I may not be using the terminology correctly by saying returning and saying predicate when it should be rule, etc so I apologize in advance.
Seems that your code could be simpler. This predicate does all what's needed, and attempt to show how to use some standard construct (if/then/else)
minmaxArray([X], X, X).
minmaxArray([X|R], Min, Max) :-
minmaxArray(R, Tmin, Tmax),
( X < Tmin -> Min = X ; Min = Tmin ), % or mymin(X,Tmin,Min)
( X > Tmax -> Max = X ; Max = Tmax ).
You have provided 2 ways of solving the case where there are 2 items: one explicitly for 2 items, and your general case, which then employs the 1 element case.
Solution: remove the unneeded 2-element case.
Or, tail-recursive:
minmax([X|Xs],Min,Max) :- % we can only find the min/max of a non-empty list.
minmax(Xs,(X,X),Min,Max) % invoke the helper with the min/max accumulators seeded with the first item
.
minmax([],(Min,Max),Min,Max). % when the source list is exhausted, we're done: unify the accumulators with the result
minmax([X|Xs],(M,N),Min,Max) :- % when the source list is non-empty
min(X,M,M1) , % - get a new min value for the accumulator
max(X,N,N1) , % - get a new max value for the accumulator
minmax(Xs,(M1,N1),Min,Max) % - recurse down on the tail.
.
min(X,Y,X) :- X =< Y . % X is the min if it's less than or equal to Y.
min(X,Y,Y) :- X > Y . % Y is the min if it's greater than X.
max(X,Y,X) :- X >= Y . % X is the max if it's greater than or equal to Y.
max(X,Y,Y) :- X < Y . % Y is the max if it's greater than X.

Generalizing Fibonacci sequence with SICStus Prolog

I'm trying to find a solution for a query on a generalized Fibonacci sequence (GFS). The query is: are there any GFS that have 885 as their 12th number? The initial 2 numbers may be restricted between 1 and 10.
I already found the solution to find the Nth number in a sequence that starts at (1, 1) in which I explicitly define the initial numbers. Here is what I have for this:
fib(1, 1).
fib(2, 1).
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
For the query mentioned I thought the following would do the trick, in which I reuse the fib method without defining the initial numbers explicitly since this now needs to be done dynamically:
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
fib2 :-
X1 in 1..10,
X2 in 1..10,
fib(1, X1),
fib(2, X2),
fib(12, 885).
... but this does not seem to work.
Is it not possible this way to define the initial numbers, or am I doing something terribly wrong? I'm not asking for the solution, but any advice that could help me solve this would be greatly appreciated.
Under SWI-Prolog:
:- use_module(library(clpfd)).
fib(A,B,N,X):-
N #> 0,
N0 #= N-1,
C #= A+B,
fib(B,C,N0,X).
fib(A,B,0,A).
task(A,B):-
A in 1..10,
B in 1..10,
fib(A,B,11,885).
Define a predicate gfs(X0, X1, N, F) where X0 and X1 are the values for the base cases 0 and 1.
I'd say you're doing something terribly wrong...
When you call fib(1, X1), the variable X1 is the number that the function fib will return, in this case, it will be 1, because of the base case fib(1, 1)..
Without the base cases, fib/2 has no solution; no matter how you call it in fib2.
Note: if you use recursion, you need at least one base case.
Consider fib(N,F1,F2) so you'll be able to replace fib(Nmin1, Xmin1) and fib(Nmin2, Xmin2) with simple fib(Nmin2, Xmin2, Xmin1).
Maybe not a solution in the strict sense but I will share it never the less. Probably the only gain is to show, that this does neither need a computer nor a calculator to be solved. If you know the trick it can be done on a bearmat.
If F_n ist the n-th Term of the ordinary Fibo-sequence, starting with F_1=F_2=1, then the n-th Term of the generalized sequence will be G_n = F_{n-2}*a+F_{n-1}*b.
Define F_{-1}=1, F_0 = 0
(Indeed, by induction
G_1 = F_{-1}*a+F_0*b = 1*a+0*b=a
G_2 = F_0 * a + F_1 * b = 0*a + 1*b = b
G_{n+1} = F_{n-1}a + F_nb = (F_{n-3} + F_{n-2} )a + (F_{n-2} + F_{n-1})*b = G_n + G_{n-1}
)
Thus G_12 = F_10 * a + F_11 * b = 55a + 89b.
Now you can either search for solutions to the equation 55a + 89b = 885 with your computer
OR
do the math:
Residues mod 11 (explanation):
55a + 89b = 0 + 88b + b = b; 885 = 880 + 5 = 80*11 + 5 = 5
So b = 5 mod 11, but since 1 <= b <= 10, b really is 5. 89 * 5 = 445 and 885-445 = 440. Now, divide by 55 and get a=8.

Resources