Related
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.
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
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.
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.
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!