Prolog decimal number to list of numbers - prolog

I am new to this page, but hopefully, I'll get the help that I need. I need to code a program that gives a list of numbers from 0-9 from a given bigger number. I don't know how to explain it better, so I add the example:
numbertolist(Number,List).
?- numbertolist(1456,List).
List = [1,4,5,6].
The main thing, that I can't use number_chars/2, number_codes/2 functions, which would give this result easily, I should implement all the functions.
number_codes(123456,X), maplist(plus(48),Y,X).
gives
Y = [1,2,3,4,5,6]

A solution without calling number_codes/2 is straight
forward, using the accumulator programming pattern:
number_digits(N, L) :-
number_digits(N, [], L).
number_digits(0, L, L) :- !.
number_digits(N, L, R) :-
D is N rem 10,
M is N // 10,
number_digits(M, [D|L], R).
The Prolog program gives:
?- number_digits(1454, X).
X = [1, 4, 5, 4].

Related

How to check how many elements you've already consumed in Prolog DCGs

Say I have these DCGs:
zorbs([H|T]) --> zorb(H), zorbs(T).
zorbs([]) --> [].
zorb(a) --> [1,2].
zorb(b) --> [3].
zorb(c) --> [6,1,2,2].
I can do this:
?- phrase(zorbs(X), [1,2,3,6,1,2,2]).
X = [a, b, c] .
I can also "reverse" this by doing:
phrase(zorbs([a,b,c]), X).
X = [1, 2, 3, 6, 1, 2, 2].
Now, what I want to do is find a list of numbers with length less than 4 (for example) which these elements "parse" into, returning the rest.
So, for example, given [a,b,c], which would normally relate to [1, 2, 3, 6, 1, 2, 2], I want it to relate to [1, 2, 3] (which has length less than 4) and also give the remainder that couldn't be "reversed," so [c]. I don't really know where to start, as it seems there's no way to reason about the number of elements you've already consumed in a DCG.
Here's a sort-of solution:
X in 0..4,
indomain(X),
Q = [_|_],
prefix(Q, [a,b,c]),
length(A, X),
phrase(zorbs(Q), A).
but I think this is very inefficient, because I think it basically iterates up from nothing, and I want to find the solution with the biggest Q.
There is no direct way how to do this in this case. So your approach is essentially what can be done. That is, you are enumerating all possible solutions and (what you have not shown) selecting them accordingly.
Questions about the biggest and the like include some quantification that you cannot express directly in first order logic.
However, sometimes you can use a couple of tricks.
Sometimes, a partial list like [a,b,c|_] may be helpful.
?- Xs = [_,_,_,_|_], phrase(zorbs(Xs),[1,2,3,6,1,2,2]).
false.
So here we have proven that there is no list of length 4 or longer that corresponds to that sequence. That is, we have proven this for infinitely many lists!
And sometimes, using phrase/3 in place of phrase/2 may help. Say, you have a number sequence that doesn't parse, and you want to know how far it can parse:
?- Ys0 = [1,2,3,6,1,2,7], phrase(zorbs(Xs),Ys0,Ys).
Ys0 = [1,2,3,6,1,2,7], Xs = [], Ys = [1,2,3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "a", Ys = [3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "ab", Ys = [6,1,2,7]
; false.
(This is with the two DCG-rules exchanged)
Can use:
% Like "between", but counts down instead of up
count_down(High, Low, N) :-
integer(High),
integer(Low),
count_down_(High, Low, N).
count_down_(H, L, N) :-
compare(C, H, L),
count_down_comp_(C, H, L, N).
count_down_comp_('=', _H, L, N) :-
% All equal, final
N = L.
% Accept H as the counting-down value
count_down_comp_('>', H, _L, H).
count_down_comp_('>', H, L, N) :-
H0 is H - 1,
% Decrement H towards L, and loop
count_down_(H0, L, N).
... and then start with:
count_down(4, 1, Len), length(Lst, Len), phrase...
Another method is to use freeze to limit a list's length, element-by-element:
max_len_freeze(Lst, MaxLen) :-
compare(C, MaxLen, 0),
max_len_freeze_comp_(C, Lst, MaxLen).
max_len_freeze_comp_('=', [], 0).
max_len_freeze_comp_('>', [_|Lst], MaxLen) :-
succ(MaxLen0, MaxLen),
!,
freeze(Lst, max_len_freeze(Lst, MaxLen0)).
max_len_freeze_comp_('>', [], _).
... and then start with:
max_len_freeze(Lst, 4), phrase...
This will work to find the longest list (maximum length 4) first, since your DCG is greedy (i.e. matching [H|T] before []).

How do i write a rule in prolog called countIt?

Write a function in Scheme or rules in Prolog called countlt that takes a list of numbers, L, and another number, N, and returns the count of numbers less than N in the list L.
?- countlt([6, 1, 9], 4, X).
X = 1.
?- countit([50, 27, 13], 1, X).
X = 0.
Something like this will solve your problem, if you are looking for a solution without that doesn't use any of the built-in or library predicates:
countlt([], _, 0).
countlt([A | B], N, X) :- ((N > A, countlt(B, N, T), X is T + 1); countlt(B, N, X)), !.
You could of course expand this into multiple lines but I find this solution more straightforward and with less tampering with cut operators.

PROLOG program semantic and exercise

First of all I have a doubt about the semantic of a program , for example :
length([],0).
length([_|L],N):-
length(L,N0),
N is N0 + 1.
The first instruction means the base case , or it has other meanings ?
I have to write a prolog program that, given a number, returns a list of numbers from 0 to the given number.
For example, when the input is 5, the output is [0,1,2,3,4,5].
I'm looking for a solution of this problem but I do not know how to start.
There is a predicate in SWI-Prologs library that does almost what you need to do. It is called numlist/3. You can use it with lower and upper boundary:
?- numlist(1, 5, L).
L = [1, 2, 3, 4, 5].
And here the implementation:
numlist(L, U, Ns) :-
must_be(integer, L),
must_be(integer, U),
L =< U,
numlist_(L, U, Ns).
numlist_(U, U, List) :-
!,
List = [U].
numlist_(L, U, [L|Ns]) :-
L2 is L+1,
numlist_(L2, U, Ns).
You can get rid of the upper half of this completely, and lose one argument (your Lower is just 1).
If you play with this a bit you should be able to figure it out.

Can't get minimize from CLPFD to work

Me and a friend are writing a program which is supposed to solve a CLP problem. We want to use minimize to optimize the solution but it won't work, because it keeps saying that the number we get from sum(P,#=,S) is between two numbers (for example 5..7). We haven't been able to find a good way to extract any number from this or manipulate it in any way and are therefore looking for your help.
The problem seems to arise from our gen_var method which says that each element of a list must be between 0 and 1, so some numbers come out as "0..1" instead of being set properly.
Is there any way to use minimize even though we get a number like "5..7" or any way to manipulate that number so that we only get 5? S (the sum of the elements in a list) is what we're trying to minimize.
gen_var(0, []).
gen_var(N, [X|Xs]) :-
N > 0,
M is N-1,
gen_var(M, Xs),
domain([X],0,1).
find([],_).
find([H|T],P):- match(H,P),find(T,P).
match(pri(_,L),P):-member(X,L), nth1(X,P,1).
main(N,L,P,S) :- gen_var(N,P), minimize(findsum(L,P,S),S).
findsum(L,P,S):- find(L,P), sum(P,#=,S).
I've slightly modified your code, to adapt to SWI-Prolog CLP(FD), and it seems to work (kind of). But I think the minimum it's always 0!
:- use_module(library(clpfd)).
gen_var(0, []).
gen_var(N, [X|Xs]) :-
N > 0,
M is N-1,
gen_var(M, Xs),
X in 0..1 .
find([], _).
find([H|T], P):-
match(H, P),
find(T, P).
match(pri(_,L),P):-
member(X, L),
nth1(X, P, 1).
findsum(L,P,S) :-
find(L, P),
sum(P, #=, S).
main(N, L, P, S) :-
gen_var(N, P),
findsum(L, P, S),
labeling([min(S)], P).
Is this output sample a correct subset of the expected outcome?
?- main(3,A,B,C).
A = [],
B = [0, 0, 0],
C = 0 ;
A = [],
B = [0, 0, 1],
C = 1 ;

prolog lists and list manipulation

i am trying to write a binary predicate to take one list, compute mod 5 for each element and then put it in another list. so far, i have done this,
mod5(X,L):- R = [], modhelper(R,L), write(R).
modhelper(X,L):- memb(E,L), mod2(E,Z), addtolist(Z,X,X), modhelper(X,L).
%Get an element from the list L.
memb(E,[E|_]).
memb(E,[_|V]):- memb(E,V).
%If element is integer, return that integer mod 5 else return as is.
mod2(N,Z):- isInt(N) -> Z is N mod 5 ; Z = N.
%add this modified element to the output list.
addtolist(Y,[],[Y]).
addtolist(Y,[H|T],[H|N]):- addtolist(Y,T,N).
memb,mod2, addtolist work as expected but I'm doing something wrong in modhelper which I'm not able to figure out.
Any help is appreciated.
In SWI-Prolog:
mod5(X, Y) :-
Y is X mod 5.
apply_mod5_to_list(L1, L2) :-
maplist(mod5, L1, L2).
Usage:
?- apply_mod5_to_list([2, 4, 6, 8], L2).
L2 = [2, 4, 1, 3].
?- apply_mod5_to_list([2, 4.1, 6, 8], L2).
ERROR: mod/2: Type error: `integer' expected, found `4.1'
?- apply_mod5_to_list([2, not_number, 6, 8], L2).
ERROR: is/2: Arithmetic: `not_number/0' is not a function
You can easily modify this code if you want a slightly different behavior, e.g. if you want to tolerate non-integers (why do you want that btw?).
In case you cannot use maplist, you can implement it yourself, at least a more specialized version of it, e.g. something like this:
partition_the_list_into_first_and_rest([X | Xs], X, Xs).
% The result on an empty list is an empty list
apply_mod5_to_list([], []).
% If the input list contains at least one member
apply_mod5_to_list(L1, L2) :-
partition_the_list_into_first_and_rest(L1, X, Xs),
call(mod5, X, Y),
partition_the_list_into_first_and_rest(L2, Y, Ys),
apply_mod5_to_list(Xs, Ys).
To this code you can still apply a lot of syntactic simplification, which you should probably do to turn it into an acceptable homework solution...

Resources