predicate encode in prolog - encoding

I'm new in prolog and I'm trying to write the predicate encode(L,L1) which counts the duplicates of elements in L ,for example:
encode([4,4,4,3,3],L).
L=[3,4,2,3].
This is what I have written:
encode(L,L1) :- encode(L,1,L1).
encode([],_,[]).
encode([H],N,[N,H]).
encode([H,H|T],N1,[N,H|T1]) :- M is N1+1, encode([H|T],M,[N,H|T1]).
encode([H,Y|T],N,[N,H|T1]) :- H\=Y, encode([Y|T],T1).
The above predicate is not reversible. It only works if the first parameter is provided.
How can I write encode reversible?
For example:
encode(L,[3,4,2,3]).
L = [4,4,4,3,3].

I think your algorithm has a redundant counter in it. A little simplified would be:
encoded([], []).
encoded([X], [1,X]).
encoded([X,Y|T], [1,X|R]) :-
dif(X, Y),
encoded([Y|T], R).
encoded([X,X|T], [N,X|R]) :-
N #> 1,
N #= N1 + 1,
encoded([X|T], [N1,X|R]).
Note in the last clause we need to ensure that N is greater than 1 as well.

Related

Creating 2 occurrence predicates out of another predicate based on min/max number of other index in the original predicate

I have the following input in Clingo:
val(a,2,3).
val(a,4,5).
val(b,0,6).
val(b,1,2).
the required is to have two predicates representing the first and second occurrence of each letter where the first one is the minimum number of the third index of val (case 1: only based on min of 3rd index), in case they are the same, then based on minimum number of the second index (case 2: both conditions).
Note that the maximum number of occurrences for each letter is 2.
The expected results is having two predicates with these values (only for this case, as sometimes the input is different):
first(a,2,3), first(b,1,2), second(a,4,5), second(b,0,6)
I tried the following code for case 1:
val(X,Y,W) :- val(X,Y,W).
first(X,Y,Z) :- val(X,Y,Z), not val(X,Y',Z'), Z'>Z,Y'!=Y.
second(X,Y,Z) :- val(X,Y,Z), not first(X,_,_).
but an error messages showed saying that Z' and Y' are unsafe.
Yes, Z' and Y' are unsafe because they do not appear in any positive predicate.
Moreover:
val(X,Y,W) :- val(X,Y,W). is a tautology and, therefore, it is useless;
it is not clear to me why you are imposing that Y'!=Y;
not first(X,_,_) is wrong, since it is checking that there doesn't exist ANY predicate first with variable X in the first argument (but this should always happen).
If I've correctly understood your requirements, this should be the correct implementation:
first(X,Y,Z) :- val(X,Y,Z), val(X,Y',Z'), Z'>Z . % case 1
first(X,Y,Z) :- val(X,Y,Z), val(X,Y',Z'), Z'=Z, Y'>Y . % case 2
second(X,Y,Z) :- val(X,Y,Z), not first(X,Y,Z) .

Why does 'sum' work but '+/' not work in KDB queries?

Why does sum work here, but the underlying form +/ not work? (Taken from https://code.kx.com/q/ref/sum/)
t: ([]name:`Jack`Jill`Janet;hair:`brown`black`fair;eye:`blue`green`hazel;age:12 9 14)
q)select sum age from t
age
---
35
q)select +/age from j
'/
[0] select +/age from j
^
This is because +/ is k syntax. To invoke it (and similar k constructs) in q you will need to wrap it in parentheses.
select enlist (+/)age from j
In general, if an inbuilt q keyword exists for the associated k expression, you should use the keyword (sum in this case) as it likely carries further optimisations.
In the case of sum q will automatically enlist the result inside a select statement which (+/) won't do. Hence why I have done it manually above. Otherwise expect a 'rank error.

find in range of a IDL array?

I am trying to find all indices in an array A, where the value larger than time0 and less than time1. In matlab I can do:
[M,F] = mode( A((A>=time0) & (A<=time1)) ) %//only interested in range
I have something similar in IDL but really slow:
tmpindex0 = where(A ge time0)
tmpindex1 = where(A lt time1)
M = setintersection(tmpindex0,tmpindex1)
where setintersection() is function find the intersected elements between two arrays. What is the fast alternative implementation?
You can combine your conditions:
M = where(A ge time0 and A lt time1, count)
Then M will contain indices into time0 and time1 while count will contain the number of indices. Generally, you want to check count before using M.
This works (slight modification from mgalloy answer):
M = where( (A ge time0) and (A lt time1), n_match, complement=F, n_complement=ncomp)
The parenthetical separation is not necessary but adds clarity. n_match contains the number of matches to your conditions whereas the complement F will contain the indices for the non-matches and ncomp will contain the number of non-matches.

Quicksort in Q/KDB+

I found this quicksort implementation on a website:
q:{$[2>distinct x;x;raze q each x where each not scan x < rand x]};
I don't understand this part:
raze q each x where each not scan x < rand x
Can someone explain it to me step by step?
Lets do it step by step . I assume you have basic understanding of Quick Sort algo. Also, there is one correction in code you mentioned which I have corrected in step 5.
Example list:
q)x: 1 0 5 4 3
Take a random element from list which will act as pivot.
q) rand x
Suppose it gives us '4' from list.
Split list 'x' in 2 lists. One contains elements lesser that '4' and other greater(or equal) to '4'.
2.a) First compare all elements with pivot (4 in our case)
q) (x<rand x) / 11001b : output is boolean list
2.b) Using above boolean list we can get all elements from 'x' lesser than '4'. Here is the way:
q) x where 11001b / ( 1 0 3) : output
So we require other expression to get all elements greater(or equal) than pivot '4'. There are many ways to do it
but lets see the one used in code:
q)not scan (x<rand x) / (11001b;00110b) : output
So it gives the list which has 2 lists. First is result of (x < rand x) which is used to get elements lesser than pivot '4' and other is negation of this list which is done by 'not' and it is used to get all elements greater(or equal) that pivot '4'.
2.c) So now we can generate 2 lists using sample code from (2.b)
q) x where each (not scan (x<rand x)) / ((1 0 3);(5 4)): output list which has 2 lists
Now apply same function to each list to sort each of them
i.e. recursive call on each list of list ((1 0 3);(5 4))
q) q each x where each (not scan (x<rand x))
After all calculations , apply 'raze' to flatten all lists that are returned from each recursive call to output one single list.
End condition for recursive call is: when input list has only 1 distinct element just return it.
q) 2>count distinct x
Note: There is one correction. 'count' was missing in original code.

How can i compare natural numbers in prolog?

I have a function that takes two arguments and compares if they are natural numbers in their unit form and if the first arg is bigger than the second!
So here is the code I've written but every time it gets me "no".
nat(0).
nat(s(X)) :- nat(X).
sum(X,0,X) :- nat(X).
sum(X,s(Y),s(Z)) :- sum(X,Y,Z).
gr(X,Y) :- nat(s(X)), nat(s(Y)), X>Y.
What goes wrong? Everything is in Prolog . the function is the gr() .
First, you probably want for sum rather this:
sum(0, Y, Y) :-
nat(Y).
sum(s(X), Y, s(Z)) :-
sum(X, Y, Z).
This is so that Prolog can recognize that the two clauses are exclusive by only looking at the first argument.
Now to your greater than:
% gr(X, Y) is true if X is greater than Y
gr(X, Y) :- sm(Y, X).
% sm(X, Y) is true if X is smaller than Y
sm(0, s(Y)) :-
nat(Y).
sm(s(X), s(Y)) :-
sm(X, Y).
To answer your actual question: what goes wrong is that the operator > works on integers (like 1 or 0 or -19), not on compound terms. The operator #> will work (see the documentation of the implementation you are using), but I have the feeling you might actually want to be explicit about it.