Reputation: 93
I would like to check if the elements of an array are less than 0, except for 1 element that is parameterized by (X, Y). I tried to use maplist, but could not maintain equality. Another alternative I tried is this:
verifyMatrix(X,Y,M) :-
verifyMatrix(X,Y,0,M).
verifyMatrix(,,_,[]) :-
!.
verifyMatrix(X,Y,I,[M|Ms]):-
rowVerify(0,M),
Ni is I,
verifyMatrix(X,Y,Ni,Ms).
verifyMatrix(X,Y,X,[M|Ms]):-
rowVerify(Y,M),
I is X,
verifyMatrix(-1,-1,I,Ms).
rowVerify(,,[]) :- !.
rowVerify(Ec,I,[R|Rs]):-
((R < 0) ; (Ec is I)),
Ni is I,
rowVerify(Ec,Ni,Rs).
rowVerify(Ec,R):-
rowVerify(Ec,0,R).
Upvotes: 2
Views: 450
Reputation: 5509
Use nth1/3
(or nth0/3
, if you prefer to index from 0) to enumerate elements of the matrix that are greater than ou equal to zero:
?- Matrix =[[-1,-2,-3],[-4,-5,+6],[-7,-8,-9]], nth1(R,Matrix,Row), nth1(C,Row,Element), Element>=0.
Matrix = [[-1, -2, -3], [-4, -5, 6], [-7, -8, -9]],
R = 2,
Row = [-4, -5, 6],
C = 3,
Element = 6 ;
false.
Then, use findall/3
to verify if such element is unique and is in the given position:
?- Matrix =[[-1,-2,-3],[-4,-5,+6],[-7,-8,-9]],
findall(R-C, (nth1(R,Matrix,Row),
nth1(C,Row,Element), Element>=0),[I-J]).
Matrix = [[-1, -2, -3], [-4, -5, 6], [-7, -8, -9]],
I = 2,
J = 3.
Thus, we can define the predicate less_than_zero_except/3
as:
less_than_zero_except(I, J, Matrix) :-
findall(R-C, (nth1(R,Matrix,Row), nth1(C,Row,Element), Element>=0), [I-J]).
This predicate can be used to verify a specific position or to find such position:
?- less_than_zero_except(2,3,[[-1,-2,-3],[-4,-5,+6],[-7,-8,-9]]).
true.
?- less_than_zero_except(I,J,[[-1,-2,-3],[-4,-5,+6],[-7,-8,-9]]).
I = 2,
J = 3.
?- less_than_zero_except(I,J,[[-1,-2,-3],[-4,-5,+6],[-7,-8,+9]]).
false.
?- less_than_zero_except(I,J,[[-1,-2,-3],[-4,-5,-6],[-7,-8,-9]]).
false.
Upvotes: 2
Reputation: 476557
You are making things too hard here, by trying to solve everything concurrently. Let us first write a predicate that verifies that all elements in a list ("row"), are less than zero, we will worry about that special element later. We can verify that with:
less_zero(L) :-
maplist(>(0), L).
We can also check if a condition holds for all elements, except for a given index, by using forall/2
[swi-doc]:
less_zero_except(L, J) :-
forall((nth0(I, L, V), dif(I, J)), V < 0).
For example:
?- less_zero_except([-1, -2, 3, -5], 2).
true.
?- less_zero_except([-1, -2, 3, -5], 1).
false.
We can generate a predicate that checks if the row index is the same as a given one, and routes it accordingly to less_zero/1
or less_zero_except/2
, like:
verify_row(Row, I, I, ColJ) :-
less_zero_except(Row, ColJ).
verify_row(Row, I, J, _) :-
dif(I, J),
less_zero(Row).
Now we can use forall/2
on the matrix level as well:
verifyMatrix(RowI, ColJ, Matrix) :-
forall(nth0(I, Matrix, Row), verify_row(Row, I, RowI, ColJ)).
The above is not bi-directional: we can not pass a matrix here, and then let Prolog determine the coordinates of the non-negative value (given that value exists). We can however implement that, for example by using the clpfd
library [swi-doc]:
:- use_module(library(clpfd)).
validate_cell(V, I, J, I, J) :-
V #>= 0.
validate_cell(V, _, _, _, _) :-
V #< 0.
Now we can iterate over these values like:
validate_row([], _, _, _, _).
validate_row([C|T], RowI, ColJ, I, J) :-
validate_cell(C, RowI, ColJ, I, J),
J1 is J+1,
validate_row(T, RowI, ColJ, I, J1).
and then we can validate the matrix:
validate_matrix([], _, _, _).
validate_matrix([Row|T], RowI, ColJ, I) :-
validate_row(Row, RowI, ColJ, I, 0),
I1 is I+1,
validate_matrix(T, RowI, ColJ, I1).
and then we can define the validate_matrix/3
in terms of validate_matrix/4
:
validate_matrix(ColI, RowJ, Matrix) :-
validate_matrix(Matrix, ColI, RowJ, 0).
We can now generate matrices that satisfy the given constraint, as well as finding out the coordinates of the non-negative element, and validate the matrix for a given coordinate pair:
?- validate_matrix(I, J, M).
M = [] ;
M = [[]] ;
M = [[], []] ;
M = [[], [], []] ;
M = [[], [], [], []] ;
M = [[], [], [], [], []] ;
M = [[], [], [], [], [], []] ;
M = [[], [], [], [], [], [], []] ;
M = [[], [], [], [], [], [], [], []] .
?- validate_matrix(I, J, [R1, R2, R3]).
R1 = R2, R2 = R3, R3 = [] ;
I = 2,
J = 0,
R1 = R2, R2 = [],
R3 = [_5416],
_5416 in 0..sup ;
I = 2,
J = 0,
R1 = R2, R2 = [],
R3 = [_5672, _5678],
_5672 in 0..sup,
_5678 in inf.. -1 ;
I = 2,
J = 0,
R1 = R2, R2 = [],
R3 = [_5916, _5922, _5928],
_5916 in 0..sup,
_5922 in inf.. -1,
_5928 in inf.. -1.
?- validate_matrix(I, J, [[1, -1], [-2, -3]]).
I = J, J = 0 ;
false.
?- validate_matrix(I, J, [[-1, -1], [-2, 3]]).
I = J, J = 1 ;
false.
?- validate_matrix(I, J, [[-1, 1], [-2, 3]]).
false.
?- validate_matrix(0, 1, [[-1, -1], [-2, 3]]).
false.
?- validate_matrix(1, 1, [[-1, -1], [-2, 3]]).
true ;
false.
Upvotes: 1