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).
Related
I want to find rhyming couplets of a poem so I need to compare last syllables of two verses of the poem.
cmp([A|As], [B|Bs]) :- cmp(As, A, Bs, B).
cmp(A, [B], B, [A]).
cmp([_, A|As], X, [_, B|Bs], Y) :- cmp([A|As], X, [B|Bs], Y).
I need, for example, to check if "[They, put, me, in, the, oven, to, bake]" and "[Me, a, deprived, and, miserable, cake]" rhymes, so I suppose I should check if last elements of these two lists are the same.
With this code i tried to compare first and last elements of my lists but it doesn't work neither.
Some Prolog systems provide a lists library with a last/2 predicate that you can call. The usual definition is:
last([Head| Tail], Last) :-
last(Tail, Head, Last).
last([], Last, Last).
last([Head| Tail], _, Last) :-
last(Tail, Head, Last).
Note that this definition avoid a spurious choice-point, thanks to first-argument indexing, when calling the predicate with a bound list.
Using the last/2 predicate you can write:
compare_verses(Versus1, Versus2) :-
last(Versus1, Word1),
last(Versus2, Word2),
same_last_syllable(Word1, Word2).
You will now need to define the same_last_syllable /2 predicate. That will require breaking a word into a list of syllables. That doesn't seem to be trivial (see e.g. https://www.logicofenglish.com/blog/65-syllables/285-how-to-divide-a-word-into-syllables) and I'm not aware of a open source Prolog library performing it.
It sounds like you need, at least in part, a way to identify the last element of a list:
last_of( [X], X ).
last_of( [_|X], Y ) :- last_of(X, Y).
I have to check if a list contains an even number of an element without built-ins.
Example:
containsEvenNumber([a,b,c,a,a], a).
returns false
containsEvenNumber([a,b,c,a], a).
returns true
Current state:
not(A) :-
A, !,
fail.
not(_).
equal([E|_], E).
containsEvenNumber([], _).
containsEvenNumber([E|Tail], E) :-
unevenCount(Tail, E).
containsEvenNumber([Head|Tail], E) :-
not(equal([Head|Tail], E)),
evenCount(Tail, E).
evenCount([], _).
evenCount([E|Tail], E) :-
unevenCount(Tail, E).
evenCount([Head, Tail], E) :-
not(equal([Head|Tail], E)),
unevenCount(Tail, E).
unevenCount([], _) :-
fail.
unevenCount([E, Tail], E) :-
evenCount(Tail, E).
unevenCount([Head, Tail], E) :-
not(equal([Head|Tail], E)),
unevenCount(Tail, E).
I try to switch between states upon the occurrence of the element.
It doesn't work because I never go into the state, where the head is not the element or rather said, I also go into the state and return false when the head is the element.
How can I make it work/fix it?
The "switching between states" is actually a good way to solve this problem. The logic should follow these simple rules:
There are an even number of X elements in [X|Xs] if there are an odd number of X elements in Xs.
There are an even number of X elements in [Y|Xs] if X and Y are different, and there are an even number of X elements in Xs.
There are an odd number of X elements in [X|Xs] if there are an even number of X elements in Xs.
There are an odd number of X elements in [Y|Xs] if X and Y are different, and there are an odd number of X elements in Xs.
Then you have the base cases:
There are an even number of any element in [].
There are an odd number of X in [X].
You just need to write these rules as Prolog. However, your implementation has a few issues.
In a few cases, you are writing a list as [Head, Tail] instead of [Head|Tail]. [Head, Tail] is a list of exactly two elements. Also, your base case for unevenCount/2 (which I assume you mean odd count) is incorrect. If you have a base case that always fails, then your predicate will always fail. With few exceptions, you should write your predicate clauses to succeed, not fail. Failure will occur automatically when success cannot be achieved.
Let's try to write out the rules above. ISO Prologs already have \+, so you do not need to define not/1. Also, writing equal([E|_], E). is unnecessary. You can do this directly in your code with simplicity.
evenCount(_, []). % base case for even
evenCount(X, [X|Xs]) :- % rule #1
oddCount(X, Xs).
evenCount(X, [Y|Xs]) :- % rule #2
dif(X, Y),
evenCount(X, Xs).
oddCount(X, [X]). % base case for odd
oddCount(X, [X|Xs]) :- % rule #3
evenCount(X, Xs).
oddCount(X, [Y|Xs]) :- % rule #4
dif(X, Y),
oddCount(X, Xs).
SWI Prolog defines dif/2. You could also use \== but it's not purely defined (and so doesn't behave as generally) as dif/2.
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)
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. :-)