Prolog - List manipulation, if--then--else, recursion - list

The goal:
rovarsprak([104, 101, 106], B).
B = [104,111,104,101,106,111,106]
[104, 101, 106] = "hej"
B = "hohejoj"
Currently:
rovarsprak([104, 101, 106], B).
B = [104,111,104,106,111,106]
[104, 101, 106] = "hej"
B = "hohjoj"
(E.g. I'm loosing the middle, non-affected, element (101 = "e").)
The code:
voal(97). % 97 = a
voal(111). % 111 = o
voal(117). % 117 = u
voal(101). % 101 = e
voal(105). % 105 = i
voal(121). % 121 = y
isLowerCase(A) :-
A > 96, % small A is 97
A < 123. % small Z is 122
rovarsprak([], []).
rovarsprak([A|AS], [X,Y,Z|ZS]) :-
A = X, A = Z, Y = 111,
isLowerCase(A),
(\+ voal(A)) % if
-> rovarsprak(AS, ZS) % then
; rovarsprak(AS, [X,Y,Z|ZS]). % else
I feel like I'm missing the point here...

The problem is in else case where you call recursively your predicate without having instantiate any of X,Y,Z. You should instantiate X=A so your list will not ignore A as it does now. So the only change you need is adding A=X after ; and call rovarsprak(AS, [Y,Z|ZS]). since X is instantiated:
rovarsprak([], []).
rovarsprak([A|AS], [X,Y,Z|ZS]) :-
A = X, A = Z, Y = 111,
isLowerCase(A),
(\+ voal(A)) % if
-> rovarsprak(AS, ZS) % then
; A=X,rovarsprak(AS, [Y,Z|ZS]). % else
Example:
?- rovarsprak([104, 101, 106], B).
B = [104, 111, 104, 101, 106, 111, 106].

Related

Find repetitions in a list

How would I go about finding consecutive repetition of a string in a list in prolog.
What I'm exactly trying to find, for example, is this:
input => output
AAAAAA => 6*(A)
ABABAB => 3*(AB)
ABCABCABC => 3*(ABC)
I wrote a DCG grammar for this and I'm trying to have it give me this as a result.
Here's the grammar, if needed:
exp --> term.
exp --> term, [+], exp.
term --> factor.
term --> digit, [*], exp.
factor --> elem.
factor --> ['S'], ['['], sym, [']']. %S[(A)(B),(C)]
factor --> ['<'], alt, ['>'], ['/'], ['<'], alt, ['>']. %<(A)>/<(B)(C)(D)>
factor --> ['('], exp, [')'].
sym --> factor.
sym --> factor, [','], factor.
sym --> factor, sym.
alt --> factor.
alt --> factor, alt.
elem --> char.
elem --> char, elem.
char --> [D], {is_alnum(D)}.
digit --> [D], {is_alnum(D)}.
digit --> [D], {number(D)}.
nbr_to_char(N, Cs) :-
name(Cs, [N]).
str_to_list(S, Cs) :-
name(S, Xs),
maplist(nbr_to_char, Xs, Cs).
eval(L) :-
str_to_list(L, X),
exp(X, []).
Thanks for any help.
I think what you're after is pack(dcg_util).
But also consider append/2:
?- A=`ababab`.
A = [97, 98, 97, 98, 97, 98].
?- append([X,X,X],$A).
X = [97, 98],
A = [97, 98, 97, 98, 97, 98] ;
false.
Now, if we just find an easy way to make lists of repeated variables, we have a fairly powerful construct, we can use to tackle to problem. Let's try:
?- length(L,3),maplist(=(X),L).
L = [X, X, X].
So:
?- length(L,_),maplist(=(X),L),append(L,$A).
L = [[97, 98, 97, 98, 97, 98]],
X = A, A = [97, 98, 97, 98, 97, 98] ;
L = [[97, 98], [97, 98], [97, 98]],
X = [97, 98],
A = [97, 98, 97, 98, 97, 98] ;
^CAction (h for help) ? abort
% Execution Aborted
oops, never ending story... but a bit boring. Need a bit more code, enforcing the domain knowledge (bagging, really...)
?- length($A,U),between(1,U,N),length(L,N),maplist(=(X),L),append(L,$A).
U = 6,
N = 1,
L = [[97, 98, 97, 98, 97, 98]],
X = A, A = A, A = [97, 98, 97, 98, 97, 98] ;
U = 6,
N = 3,
L = [[97, 98], [97, 98], [97, 98]],
X = [97, 98],
A = A, A = [97, 98, 97, 98, 97, 98] ;
false.

SML Create a function that finds numbers not divisible from list

Write a function N that for a
given natural number r (2 in the example), a list of natural numbers x1..xn,
and a list of natural numbers q1..qm (n, m ≥ 0), returns a
list of length n whose i’th element is a list of the natural
numbers in the interval [xi − r, xi + r] that are not
divisible by any of the numbers in q1..qm.
- N 2 [25, 50, 90, 11] [2,3,7];
val it = [[23,25] , [] , [89] , [11, 13]] :
int list list
You could define the function as follows:
fun divisible (q::qs, x) = if (x mod q = 0) then true else divisible(qs, x)
| divisible (nil, x) = false;
fun N r xs qs = let
val cs = map(fn x => List.tabulate(1+2*r, fn y => x + y - r))(xs);
in
map(fn bs => List.filter(fn x => not (divisible(qs,x))) (bs))(cs)
end;
For the given example it gives:
- N 2 [25, 50, 90, 11] [2,3,7];
val it = [[23,25],[],[89],[11,13]] : int list list

all subsets with all elements of a list in prolog

I'm trying to compute a list of all subsets of a given list with all its elements, but so far I've only succeeded to find subsets of two elements, but this is not a right solution for my problem.. can anyone help me? I know that problems like this are solved by using backtracking method, but in Prolog, I'm not sure how this should be written.. The source code is like this:
subs(_, [], []).
subs(H, [H1|Tail], [[H,H1]|Ta]):-
subs(H, Tail, Ta).
generatesubs([], []).
generatesubs([H], [H]).
generatesubs([H|Tail], [R|Ta]):-
subs(H, Tail, R),
generatesubs(Tail, Ta).
main1([], []).
main1([H], [H]):-
is_list(H).
main1([H|Tail], [H|Ta]):-
is_list(H),
main1(Tail, Ta).
main1([_|Tail], Ta):-
main1(Tail, Ta).
main([], []).
main(H ,R):-
generatesubs(H, G),
main1(G,R).
Thanks in advance! :)
Use dcg!
list_allsubseqs(Es, Uss) :-
list_acc_allsubseqs(Es, [[]], Uss).
lists_prependum([] , _) --> [].
lists_prependum([Es|Ess], E) --> [[E|Es]], lists_prependum(Ess, E).
list_acc_allsubseqs([] , Uss , Uss).
list_acc_allsubseqs([E|Es], Uss0, Uss) :-
list_acc_allsubseqs(Es, Uss0, Uss1),
phrase(lists_prependum(Uss1,E), Uss, Uss1).
Sample queries:
?- list_allsubseqs([], Xss).
Xss = [[]].
?- list_allsubseqs([a], Xss).
Xss = [[a], []].
?- list_allsubseqs([a,b], Xss).
Xss = [[a,b], [a], [b], []].
?- list_allsubseqs([a,b,c], Xss).
Xss = [[a,b,c], [a,b], [a,c], [a],
[b,c], [b], [c], []].
?- list_allsubseqs([a,b,c,d], Xss).
Xss = [[a,b,c,d], [a,b,c], [a,b,d], [a,b], [a,c,d], [a,c], [a,d], [a],
[b,c,d], [b,c], [b,d], [b], [c,d], [c], [d], []].
So... how does list_allsubseqs/2 fare in comparison to findall/3 plus list_subseq/2? What about memory consumption? What about runtime?
Let's dig deeper!
First, for the sake of completeness, here's the code of good-ol' vanilla list_subseq/2:
list_subseq([], []).
list_subseq([E|Es], [E|Xs]) :- list_subseq(Es, Xs).
list_subseq([_|Es], Xs ) :- list_subseq(Es, Xs).
In the following we use swi-prolog version 7.3.11 (64-bit).
:- set_prolog_flag(toplevel_print_anon, false). % hide some substitutions
:- set_prolog_stack(global, limit(2*10**9)). % cf. SWI-FAQ on "stack sizes"
Let's investigate!
?- between(18, 22, N),
numlist(1, N, _Es),
member(How, [findall_subseq, list_allsubseqs]),
garbage_collect,
call_time(( How = findall_subseq, findall(Xs,list_subseq(_Es,Xs),_)
; How = list_allsubseqs, list_allsubseqs(_Es,_)), T_in_ms),
statistics(globalused, Mem_in_B).
N = 18, How = findall_subseq, Mem_in_B = 62_915_848, T_in_ms = 185
; N = 18, How = list_allsubseqs, Mem_in_B = 12_584_904, T_in_ms = 22
;
N = 19, How = findall_subseq, Mem_in_B = 132_121_888, T_in_ms = 361
; N = 19, How = list_allsubseqs, Mem_in_B = 25_167_888, T_in_ms = 42
;
N = 20, How = findall_subseq, Mem_in_B = 276_825_400, T_in_ms = 804
; N = 20, How = list_allsubseqs, Mem_in_B = 50_333_784, T_in_ms = 80
;
N = 21, How = findall_subseq, Mem_in_B = 578_815_312, T_in_ms = 1_973
; N = 21, How = list_allsubseqs, Mem_in_B = 100_665_504, T_in_ms = 154
;
N = 22, How = findall_subseq, Mem_in_B = 1_207_960_936, T_in_ms = 3_966
; N = 22, How = list_allsubseqs, Mem_in_B = 201_328_872, T_in_ms = 290.

PROLOG Print numbers that end in 7 and the sum of its digits is greater than 100

I need to make a predicate that receives a numeric list and print only the numbers that end in 7 and that the sum of its digits is greater than 100
I made the predicates for separated but I need help making a union of the two predicates, I mean that the two predicates go into one only predicate, this is what I did so far:
%sum of digits greater than 100
multi(X):-
0 is X mod 100
sum([],0).
sum([P|Q],Z).
multi(P), sum(Q,Z1), Z is P + Z1.
sum([P|Q],Z).
not multi(P), sum(Q,Z).
%print the numbers that end in 7
end(Y):-
7 is Y mod 10.
listend([],0).
listend([P|Q]):-
end(P),write(P), nl, listend(Q).
listend([P|Q]):-
not(end(P)), listend(Q).
Use clpfd!
:- use_module(library(clpfd)).
We do it like this:
n_base10(N, Ds) :-
n_base_digits(N, 10, Ds).
n_base_digits(Expr, Base, Ds) :-
Base #> 1,
Ds = [_|_],
N #= Expr,
N #>= 0, % N is non-negative
n_base_ref_acc_digits(N, Base, Ds, [], Ds).
n_base_ref_acc_digits(N, Base, Ref, Ds0, Ds) :-
zcompare(Order, N, Base),
order_n_base_ref_acc_digits(Order, N, Base, Ref, Ds0, Ds).
order_n_base_ref_acc_digits(<, N, _, [_] , Ds0, [N|Ds0]).
order_n_base_ref_acc_digits(=, _, _, [_,_] , Ds0, [1,0|Ds0]).
order_n_base_ref_acc_digits(>, N, Base, [_|Rs], Ds0, Ds) :-
N0 #= N // Base,
N1 #= N mod Base,
n_base_ref_acc_digits(N0, Base, Rs, [N1|Ds0], Ds).
Some simple queries1:
?- n_base10(_, []).
false.
?- X #< 0, n_base10(X, Ds).
false.
?- n_base10(123, [1,2,3]).
true.
?- n_base10(123, Ds).
Ds = [1,2,3].
?- n_base10(N, [1,7,9]).
N = 179
; false.
?- n_base10(459183754813957135135239458256, Ds).
Ds = [4,5,9,1,8,3,7,5,4,8,1,3,9,5,7,1,3,5,1,3,5,2,3,9,4,5,8,2,5,6].
How about using bases other than 10?
?- member(Base,[2,8,10,16,36]), n_base_digits(N,Base,[1,2,3,4]).
Base = 8, N = 668
; Base = 10, N = 1234
; Base = 16, N = 4660
; Base = 36, N = 49360
; false.
?- member(Base,[2,8,10,16,36]), n_base_digits(101,Base,Ds).
Base = 2, Ds = [1,1,0,0,1,0,1]
; Base = 8, Ds = [1,4,5]
; Base = 10, Ds = [1,0,1]
; Base = 16, Ds = [6,5]
; Base = 36, Ds = [2,29].
OK! Works as expected.
Let's find integers with digit sum greater than 100 and 7 as the least significant decimal digit!
?- set_prolog_flag(toplevel_print_anon, false).
true.
?- _S #> 100,
n_base10(N, _Ds),
lists:last(_Ds, 7),
clpfd:sum(_Ds, #=, _S),
clpfd:labeling([ff,min(N)], _Ds).
N = 499999999997
; N = 589999999997
; N = 598999999997
...
Now, on to the "filtering" part of your question... it's as easy as 1, 2, 3.
First, we define (#)/2 based on (#)/1 . It fits the reification scheme (of if_/3, (=)/3, etc.) which already has been used in a lot of logically-pure Prolog answers on StackOverflow.
#(G_0, T) :- #var(T), #G_0, T = true.
Second, we define reified versions of the clpfd predicates (#=)/2 and (#>)/2.
#=(X, Y, T) :- X #= Y #<==> B, bool01_t(B, T).
#>(X, Y, T) :- X #> Y #<==> B, bool01_t(B, T).
Last, using Prolog lambdas, tfilter/3 and ','/3, we inquire:
?- use_module(library(lambda)).
true.
?- Zs0 = [ /* Es: list of sample integers */
499999999997, /* (digit sum = 101) */
9899999999970, /* (digit sum = 105) */
516666669999997, /* (digit sum = 103) */
5000007, /* (digit sum = 12) */
598999999997 /* (digit sum = 101) */
],
tfilter(\N^( /* N: candidate integer */
#n_base10(N, Ds), /* Ds: base-10 representation */
#lists:last(Ds, D1), /* D1: least significant digit */
D1 #= 7, /* D1: equal to 7 */
#clpfd:sum(Ds, #=, S), /* S: digit sum */
S #> 100 /* S: greater than 100 */
),
Zs0,
Zs).
Zs0 = [499999999997,9899999999970,516666669999997,5000007,598999999997],
Zs = [499999999997, 516666669999997, 598999999997].
Works like a charm!
Footnote 1: Using SWI-Prolog version 7.3.10 (64-bit AMD64)
This works for me:
?- filter([147, 24, 57, 17, 3667], X), write(X), nl, fail.
sumdigits(0, 0).
sumdigits(X, Z) :-
X > 0,
Z1 is X mod 10,
X2 is X // 10,
sumdigits(X2, Z2),
Z is Z1 + Z2.
filter([], []).
filter([H|X], [H|Y]) :-
sumdigits(H, D),
D > 10,
7 is H mod 10, !,
filter(X, Y).
filter([_|X], Y) :- filter(X, Y).
I get:
[147, 57, 3667]
No.
I assumed you meant that the sum of the digits was greater than 10, rather than 100.

Split a number into a list of digits in Prolog

I've been having trouble trying to split numbers into lists using Prolog, e.g. 123456 becomes [1,2,3,4,5,6].
Can you please help me work out how to do this?
the builtins available are ISO standard:
?- number_codes(123456,X),format('~s',[X]).
123456
X = [49, 50, 51, 52, 53, 54].
?- number_chars(123456,X),format('~s',[X]).
123456
X = ['1', '2', '3', '4', '5', '6'].
I also have some very old code I developed for my interpreter. := must be renamed is to run with standard Prologs. But then you are best served from above builtins...
itoa(N, S) :-
N < 0, !,
NN := 0 - N,
iptoa(NN, SR, _),
reverse(SR, SN),
append("-", SN, S).
itoa(N, S) :-
iptoa(N, SR, _),
reverse(SR, S).
iptoa(V, [C], 1) :-
V < 10, !,
C := V + 48.
iptoa(V, [C|S], Y) :-
M := V / 10,
iptoa(M, S, X),
Y := X * 10,
C := V - M * 10 + 48.
edit here the additional call required to get numbers:
?- number_codes(123456,X), maplist(plus(48),Y,X).
X = [49, 50, 51, 52, 53, 54],
Y = [1, 2, 3, 4, 5, 6].
You could first create a reverse list:
//Base step
splitRev(0,[]).
//Recursive step
splitRev(N,[A|As]) :- N1 is floor(N/10), A is N mod 10, splitRev(N1,As).
The recursive step works like this:
N1 is floor(N/10)
divides N by 10 and rounds it down. So 538 becomes 53.8 becomes 53.
It cuts off the last digit.
A is N mod 10
takes the remainder of N divided by 10. 538 mod 10 equals 8.
So you get only the last digit.
Now for splitting the list you only need to reverse the list created by splitRev/2.
So predicate split/2 is defined as:
split(N,L1) :- splitRev(N,L2), reverse(L1,L2).
Note that reverse/2 is a built-in predicate.
I hope this helps!