I have a matrix, where every element should be unique. To be honest, every element can take an integer value in [1, 19], but I got confused on handling list with variables with length(List, 3), so for now I have this:
matrix([[a,b,c],[d,e,f],[g,h,i]]).
row(M, N, Row) :-
nth1(N, M, Row).
column(M, N, Col) :-
transpose(M, MT),
row(MT, N, Col).
get_row(N, Row) :-
matrix(M),
row(M, N, Row).
diff_matrix(M) :-
matrix(M),
foo(M).
foo([]).
foo([H|T]) :-
length(H, Len),
write(Len),
foo(T).
different_from([], _).
different_from([H|T], E) :-
E \= H,
different_from(T, E).
Any idea to proceed with this code, or maybe another approach? I mean if my attempt is not good enough, I do not have problem replacing it.
EDIT:
I have atoms, because I do not know how to constraint variables
inside [1, 19], so I am trying to make it work with atoms, for now!
I want my code to test if matrix contains unique elements, i.e., for
every element found in the matrix, there is no duplicate element in
the matrix.
So far, I have only predicates that should help, nothing more, since
I am stuck.
A possible query: diff_matrix([[1,2,3],[4,5,6],[7,8,9]]).
A very compact, maybe inefficient, method based on indexing
rc(M,R,C,E) :- nth1(R,M,Row),nth1(C,Row,E).
diff_matrix(M) :-
forall((rc(M,I,J,X),rc(M,U,V,Y)), ((I\=U;J\=V)->X\=Y;true)).
edit
rc/4 is the relation among matrix M, row index R (1 based), column index C, and element E.
forall(Cond,Action) documentation states:
For all alternative bindings of Cond, Action can be proven.
So we can read diff_matrix/1 as
for all elements X (let's say, M[I,J]) and Y (M[U,V]) either I=U and J=V or X \= Y (doesn't unify)
Related
i'm writing a function that returns true if E is the second largest element from the list, especially trying to use the library https://www.swi-prolog.org/pldoc/man?section=lists
like this:
secLarg([], E).
secLarg([_], E).
secLarg([T], E) :- L is max_member(T, E), delete(T, L), max_member(E, L).
so using some sort of composition of library functions max_member and delete, however this solution is not working, as max_member appears to return only true/false, not what the specific largest element is. do you have any idea about how could I find if E is the second largest element by any way using these functions?
The problem is that L is max_member(T, E) does not make much sense. A predicate does not return a value: it either succeeds or fails. It uses unification to unify a variable with the result.
If you use [T] to unify with, you will only unify with lists with exactly one element. Whereas you probably want to unify with lists with an arbitrary number of elements.
delete/3 also does not alter the list, it produces a new list where it removed the largest member:
secLarg(Xs, E) :-
max_member(Lg, Xs),
delete(Xs, Lg, Xs1),
max_member(E, Xs1).
It also does not make much sense to write secLarg([], E) and secLarg([_], E), since for such lists, there is no second largest:
% secLarg([], E).
% secLarg([_], E).
secLarg(Xs, E) :-
max_member(Lg, Xs),
delete(Xs, Lg, Xs1),
max_member(E, Xs1).
Beware that delete/3 will delete all elements with the given value. Indeed:
?- delete([1,4,2,5,4], 4, R).
R = [1, 2, 5].
So if there is a list where the largest value occurs multiple times, it will not select the largest value (which is also the second largest one).
I want to write a code that multiplies lists representing a number, like:
?- times([1,1,1], [1,1], Res).
Res = [1,1,1,1,1,1].
times([], _, []). % base case
times([_|T], Lis, [Lis|H]) :-
times(T, Lis, H).
I already have the code above and it kinda does what I want but not really. For example when asking:
?- times([1,1,1], [1,1], Res)
Res = [[1,1],[1,1],[1,1]].
The idea is there, but I just don't know how to fix that, I understand why it's happening (I'm adding a list as head), so I just wondered if anybody could help me.
Thanks in advance.
[Lis|H] will use Lis as first element, regardless whether Lis is a list or not. You should take a look at append/3 [swi-doc] for example to append two lists:
times([], _, []).
times([_|T], Lis, R) :-
append(Lis, H, R),
times(T, Lis, H).
currently learning about logic in computing as well as the foundations of Prolog. Please bear with me in my fumbling speech!
I've been faced with a problem where, given an query of a list of lists containing integers, one must devise a way to calculate the highest sum of all the lists using recursion.
For example:
?- getSum([[1,3,6],[9,5,2],[3,4,7]], X).
X = 16.
Should be the output.
I believe the correct way to find the sum of a list is:
sum([],0).
sum([Head|Body], Output) :- sum(Body, BodySum),
Output is Head + BodySum.
However I need to compare the sums before displaying the result, do I have to call to another conditional inside the sum recursion?
Thanks
Several comments first:
Naming: you probably want to name your predicate so that it is obvious what it does. And, Prolog prefers names_like_this to namesInCamelCase. So maybe, call it max_sublist_sum, maybe?
Implementation: in your question you say, "using recursion". Must you use recursion, or do you think that using recursion is your only choice? Since this is a trivial problem, it can be solved using library predicates and avoiding recursion altogether. For example, to find the sums of each sub-list:
maplist(sum_list, List_of_lists, Sums)
Now you have reduced your list of lists to a list of sums. You can find the largest of a list of numbers:
max_list(List_of_numbers, Max_number)
So, your problem becomes:
?- maplist(sum_list, [[1,3,6],[9,5,2],[3,4,7]], Sums),
max_list(Sums, Max_sum).
Sums = [10, 16, 14],
Max_sum = 16.
Now, it may seem as a good exercise to implement each of sum_list/2 and max_list/2, but a good starting point would be to look at the library implementation of these two. Same goes for the definition of maplist/3
You can also intertwine the two:
max_sublist_sum0([H|T], Max) :-
sum_list(H, Sum),
max_sublist_sum0_(T, Sum, Max).
max_sublist_sum0_([], Max, Max).
max_sublist_sum0_([H|T], M0, Max) :-
sum_list(H, Sum),
( Sum > M0
-> max_sublist_sum0_(T, Sum, Max)
; max_sublist_sum0_(T, M0, Max)
).
The helper predicate max_sublist_sum_/3 is in practice a fold:
max_sum(L, M0, M) :-
sum_list(L, Sum),
M is max(M0, Sum).
max_sublist_sum1([H|T], Max) :-
sum_list(H, Sum),
foldl(max_sum, T, Sum, Max).
However, this is still much more code than the original suggestion:
max_sublist_sum(L, M) :-
maplist(list_sum, L, S),
max_list(S, M).
Interestingly, on my computer this last version is also fastest for somewhat larger lists, and takes about the same time as the faster of the other two.
You don't need to call another condition inside the recursion, you have to decompose the problem into calculating the sum and the maximum. Following a classic implementation of a max predicate, where the second argument is the current maximum, this would be something like:
max([], X, X).
max([H|T], X, Y) :-
sum(H, S),
S < X,
max(T, X, Y).
max([H|T], X, Y) :-
sum(H, S),
S >= X,
max(T, S, Y).
getSum(L, X) :- max(L, 0, X).
You could make this code more efficient and elegant by using an if-construct or a cut, I leave this to you.
I'm trying to write a predicate is_multi(M), defined as:
every element of M has the form X / N, where X is an atom, and N is an integer greater than 0;
M does not contain two elements with the same atom, for what
is_multi([]).
is_multi([a / 2, b / 2]).
are satisfied, but
is_multi([a, b/2]).
is_multi([a/0, b/2]).
is_multi([a/2, 2/4])
is_multi([a/2, b/3, a/2])
is_multi([a/3, b/-4, c/1])
are not.
Here's what I have written so far:
is_multi(M) :- M = [].
is_multi(M) :-
M = [Head|Tail],
Head = X/N,
integer(N),
N > 0,
is_multi(Tail).
But it does not compare two elements if with the same atom. For example, is_multi([a/2, a/3]) is not satisfied. I got stuck for one day with this; could somebody give me some hints?
First, you can simplify your code considerably by moving some of your unifications from the body to the head.
is_multi([]).
is_multi([X/N|Tail]) :-
integer(N), N > 0,
is_multi(Tail).
Cleaning it up reveals one thing you're not doing here which is in your spec is checking that X is an atom. Fix by adding atom(X) to the body.
OK, so this takes care of the basic form, but doesn't ensure that the atoms do not repeat. The simplest thing to do would be to split this into two checks, one that checks that each item is well-formed, and one that checks that the list is well-formed. In fact, I would be inclined to use maplist/2 with a predicate that checks a single element. But all you really have to do is something like this:
is_valid([]).
is_valid([X/_|T]) :- is_valid(T), \+ memberchk(X/_, T).
This just says that the empty list is valid, and if the tail is valid, a list is valid if X over something doesn't occur in the tail.
If that's all you wanted, stop reading there. If you want to refactor, this is how I would approach it:
well_formed(X/N) :- atom(X), integer(N), N > 0.
no_repeating_numerators([]).
no_repeating_numerators([X/_|T]) :- no_repeating_numerators(T), \+ memberchk(X/_, T).
is_multi(L) :- maplist(well_formed, L), no_repeating_numerators(L).
Just to complete Daniel's instructive answer (+1 by me), I want to showcase how your task could be solved by means of some library predicates:
is_multi(L) :-
forall(select(E, L, R),
(E = A/N, atom(A), integer(N), N > 0, \+memberchk(A/_, R))).
question is:
when we key in mem([1,2,3,4,5]).
we will get the output as bellow:
odd=3
even=2
my coding is like that but cannot run. can help me check where is my mistake??
mem(X,[X|L]).
mem(X,[element|L]):-
mem([X,L]).
count([],L,L).
count([X|H],L1,L2):-
write(even),
X%2=0,nl,
write(odd),
X%2>=1,nl,
count([H],[X|L1],L2).
thanks for your helping.
The procedures you have written do two different things and don't actually belong together. mem/2 is equivalent to the usually builtin member/2 except that your definition contains an error: in the second clause element is an atom instead of a variable so it will not match other elements of the list. The usual definition is
member(X, [X|_]).
member(X, [_|L]) :- member(X, L).
Note that this definition will not only test if a term is an element of a list but can even be use to generate a list.
What exactly are you trying to do in count/3: split the list into two lists, one containing odd and the other containing even; or count the number of odd and even elements? The splitting could be done with something like:
count([], [], []).
count([X|L], O, E) :- X rem 2 =/= 0, count(L, [X|O], E).
count([X|L], O, E) :- X rem 2 =:= 0, count(L, O, [X|E]).
Note that =/= /2 and =:= / 2 force evaluation of arguments as arithmetic expressions while = /2 attempts to unify its arguments.
Counting the number of odds and evens can be done in a similar fashion, and is left as an exercise for the reader. :-)