prolog - create list from facts by criteria - list

I'm trying to create list from the facts in SWI-Prolog.
There are amount of exapmles but I don't understand how to create list by criteria.
You can see my code below.
Predicate extract doesn't work as I expected.
I need:
L = [depos(sbr, 3000, 3), depos(psb, 4000, 4), depos(hkb, 5000, 5)]
But I get:
?- deposit(X), extract(X, 3, 5, Ls).
X = depos(sbr, 3000, 3),
Ls = [depos(sbr, 3000, 3)] ;
X = depos(psb, 4000, 4),
Ls = [depos(psb, 4000, 4)] ;
X = depos(hkb, 5000, 5),
Ls = [depos(hkb, 5000, 5)] ;
false.
What do I wrong?
% vim: ft=prolog
depos(rsb, 1000, 1).
depos(vtb, 2000, 2).
depos(sbr, 3000, 3).
depos(psb, 4000, 4).
depos(hkb, 5000, 5).
depos(mkb, 6000, 6).
deposit(depos(Bank, Body, Rate)) :- depos(Bank, Body, Rate).
bank(depos(Bank,_,_), Bank).
body(depos(_,Body,_), Body).
rate(depos(_,_,Rate), Rate).
% Usage:
% deposit(X), bank(X, Ba), body(X, Bo), rate(X, Ra).
% Usage: create List from Body
% ?- findall(Bo, depos(Ba, Bo, Ra), L).
% L = [1000, 2000, 3000, 4000, 5000, 6000].
% Usage: create List from Rate
% ?- findall(Ra, depos(Ba, Bo, Ra), L).
% L = [1, 2, 3, 4, 5, 6].
profit(X, Prof) :-
body(X, Body),
rate(X, Rate),
Prof is Body * Rate.
% Usage:
% ?- deposit(X), profit(X, Pro).
% X = depos(rsb, 1000, 1),
% Pro = 1000 ;
% X = depos(vtb, 2000, 2),
% Pro = 4000 ;
critRate(X, From, Before) :-
rate(X, Rate),
Rate >= From,
Rate =< Before.
% Usage:
% ?- deposit(X), critRate(X, 3, 5).
% X = depos(sbr, 3000, 3) ;
% X = depos(psb, 4000, 4) ;
% X = depos(hkb, 5000, 5) ;
critProf(X, From, Before, Prof) :-
profit(X, Prof),
Prof >= From,
Prof =< Before.
% Usage:
% ?- deposit(X), critProf(X, 9000, 25000).
% X = depos(sbr, 3000, 3) ;
% X = depos(psb, 4000, 4) ;
% X = depos(hkb, 5000, 5) ;
% How to create List Ls from deposit with Rate From to Before ???
extract(X, From, Before, Ls) :-
bagof(X, critRate(X, From, Before), Ls).
% Expected:
% L = [depos(sbr, 3000, 3), depos(psb, 4000, 4), depos(hkb, 5000, 5)]

I think your problem is related in structuring your code with 'accessors', like these 3
bank(depos(Bank,_,_), Bank).
body(depos(_,Body,_), Body).
rate(depos(_,_,Rate), Rate).
and using them in a functional fashion.
edit by OP
Can you, please, explain that aspect in more detail? I'm a new in Prolog.
I've read about accessors in Bratko and use it without full understanding.
When I can use and when I don't.
Prolog has a relational data model, so you should rethink your workflow. For instance, simplify extract/4 to extract/3 in this way
extract(From, Before, Ls) :-
bagof(X, (deposit(X),critRate(X, From, Before)), Ls).
and you'll get what you need:
?- extract(3, 5, Ls).
Ls = [depos(sbr, 3000, 3), depos(psb, 4000, 4), depos(hkb, 5000, 5)].
That works! Thank you.
edit by OP
I added new predicate for critProf
extract_prof4(From, Before, Prof, Ls) :-
bagof(X, (deposit(X), critProf(X, From, Before, Prof)), Ls).
and it doesn't work again.
?- extract_prof4(3000,25000,P,L).
P = 4000,
L = [depos(vtb, 2000, 2)] ;
P = 9000,
L = [depos(sbr, 3000, 3)] ;
BUT if I added another predicates (without Prof as an argument), like this:
critProf3(X, From, Before) :-
profit(X, Prof),
Prof >= From,
Prof =< Before.
extract_prof(From, Before, Ls) :-
bagof(X, (deposit(X), critProf3(X, From, Before)), Ls).
they work correctly:
?- extract_prof(3000,25000,L).
L = [depos(vtb, 2000, 2), depos(sbr, 3000, 3), depos(psb, 4000, 4), depos(hkb, 5000, 5)].
Why?

Related

Generate List then Split into Two in Prolog

I am a complete amateur on Prolog so my question might be very basic. I want to automatically generate a list from 1 to N, then split it into even and odd, from just one integer input (so I don't input the list manually). Let's say I input 5, then the result should be like this:
X = [1,3,5]
Y = [2,4]
Doesn't matter which one is X, which one is Y.
How should I tackle this problem?
I know the built-in function to generate list is numlist(1,5,L).
I also found an answer on how to split the list here
I tried to combine those two like this
separate_even_odd(N) :- numlist(1,N,L), separate_even_odd(L, X, Y).
Then call the function separate_even_odd(5).
All i got is True.
Ultimately I want to append the odd list to the even list but let's put that on another story. For now, I just want it splitted.
SWI-Prolog has a library predicate partition/4 that seems it's done to fulfill your needs:
separate_even_odd(Integers, Even, Odd) :-
partition(integer_is_even, Integers, Even, Odd).
integer_is_even(I) :- I mod 2 =:= 0.
Instead of providing the service predicate integer_is_even/1, we could as well use the lambda library(yall):
separate_even_odd(Integers, Even, Odd) :-
partition([I] >> (I mod 2 =:= 0), Integers, Even, Odd).
and we get
?- numlist(1,5,L), separate_even_odd(L, Even, Odd).
L = [1, 2, 3, 4, 5],
Even = [2, 4],
Odd = [1, 3,
Just to illustrate some of the unusual constructs of Prolog (unification and if/then/else), take a look at a simple implementation, in procedural style, without library predicates:
list_with_separate_even_odd(IntegerLow, IntegerHigh, Even, Odd) :-
( IntegerLow > IntegerHigh
-> Even = [], Odd = []
; ( IntegerLow mod 2 =:= 0
-> Even = [IntegerLow|RestEven], Odd = RestOdd
; Even = RestEven, Odd = [IntegerLow|RestOdd]
),
LowSucc is IntegerLow + 1,
list_with_separate_even_odd(LowSucc, IntegerHigh, RestEven, RestOdd)
).
Note in particular how =/2 performs unification, not assigment.
Alternative method, with an introduction to difference lists due to "Ultimately I want to append the odd list to the even list":
between_evens_odds(Upper, Evens, EvensTail, Odds) :-
integer(Upper),
Upper #>= 1,
between_evens_odds_(1, Upper, Evens, EvensTail, Odds).
between_evens_odds_(Upto, Upper, Evens, EvensTail, Odds) :-
compare(Comp, Upper, Upto),
between_evens_odds_comp_(Comp, Upto, Upper, Evens, EvensTail, Odds).
between_evens_odds_comp_(<, _Upto, _Upper, EvensTail, EvensTail, []).
% Started with 1, so final number will also be odd
between_evens_odds_comp_(=, Upto, _Upper, EvensTail, EvensTail, [Upto]).
between_evens_odds_comp_(>, Upto, Upper, [Upto1|Evens], EvensTail, [Upto|Odds]) :-
Upto1 is Upto + 1,
Upto2 is Upto + 2,
between_evens_odds_(Upto2, Upper, Evens, EvensTail, Odds).
Results in swi-prolog:
% Using 0 as an example - it of course fails
?- between(0, 6, Upper), between_evens_odds(Upper, Ev, EvT, Od).
Upper = 1,
Ev = EvT,
Od = [1] ;
Upper = 2,
Ev = [2|EvT],
Od = [1] ;
Upper = 3,
Ev = [2|EvT],
Od = [1, 3] ;
Upper = 4,
Ev = [2, 4|EvT],
Od = [1, 3] ;
Upper = 5,
Ev = [2, 4|EvT],
Od = [1, 3, 5] ;
Upper = 6,
Ev = [2, 4, 6|EvT],
Od = [1, 3, 5].
Here's the magic of difference lists - since we've already iterated through the list of Evens to the end, we can grab the tail of Evens, rather than iterate through all of Evens yet again using append, for performance:
?- between_evens_odds(5, Ev, EvT, Od), EvT = Od.
Ev = [2, 4, 1, 3, 5],
EvT = Od, Od = [1, 3, 5].
A simple and efficient implementation:
separate_odd_even(N, Odd, Even) :-
odd_even_loop(1, N, Odd, Even).
odd_even_loop(M, N, Odd, Even) :-
Bool is sign(abs(N-M)), % reify equality between M and N to avoid non-determinism
odd_even_case(Bool, M, N, Odd, Even).
odd_even_case(0, M, _, [M], []). % M and N are equal
odd_even_case(1, M, N, [M|Odd], Even) :- % M and N are different
M1 is M + 1,
odd_even_loop(M1, N, Even, Odd).
Examples:
?- separate_odd_even(8, O, E).
O = [1, 3, 5, 7],
E = [2, 4, 6, 8].
?- separate_odd_even(9, O, E).
O = [1, 3, 5, 7, 9],
E = [2, 4, 6, 8].
?- separate_odd_even(3, [1,3], E).
E = [2].
?- separate_odd_even(3, O, [2]).
O = [1, 3].
?- separate_odd_even(3, [1,3], [2]).
true.
?- separate_odd_even(3, [1,2], [3]).
false.
?- time(separate_odd_even(1000000, O, E)).
% 3,000,001 inferences, 0.313 CPU in 0.312 seconds (100% CPU, 9600003 Lips)
O = [1, 3, 5, 7, 9, 11, 13, 15, 17|...],
E = [2, 4, 6, 8, 10, 12, 14, 16, 18|...].

filling list with the same integer in prolog

I want to write a function that fill in the list with the same number on prolog. For example, I want the list [_,_,1,_] to be [1,1,1,1] or if the list is all empty [_,_,_,_] it will result in a number of my choice, 5 for example. Can anyone help me with that?
Simplest:
?- L = [_,_,1,_], maplist(=(_), L).
L = [1,1,1,1].
Simple:
all(_,[],[]).
all(H,[H|T],[H|T]) :- all(H,T,T).
That gives me:
?- all(_,[_,_,1,_],Xs).
Xs = [1, 1, 1, 1].
?- all(5,[_,_,_,_],Xs).
Xs = [5, 5, 5, 5].
?- all(5,[_,_,1,_],Xs).
false.
?- all(_,[3,_,1,_],Xs).
false.
:- use_module(library(clpfd)).
fill(Ls, Value) :-
chain(Ls, #=),
Ls = [Value|_].
e.g.
?- Ls = [_,_,1,_], fill(Ls, V).
Ls = [1, 1, 1, 1],
V = 1
?- Ls = [_,_,_,_], fill(Ls, 5).
Ls = [5, 5, 5, 5]
?- Ls = [_,_,1,_], fill(Ls, 7).
false

Sum up a list using Prolog

I want to sum all list elements greater than some given number. Here's the description:
sumup(L, N, GREATN, GEN) sums up the members of list L which are greater than GREATN to a variable N and puts these members into the list GEN.
Sample query:
?- sumup([8, 6, 10, 3, 9, 12], N, 7, GEN).
GEN = [8, 10, 9, 12], % expected answer
N = 39. % 8+10+9+12 = 39
Following is my code:
sum_list([], 0).
sum_list([H|T], Sum) :-
H > 3,
sum_list(T, Rest),
Sum is H + Rest.
sum_list([H|T], Sum) :-
H < 3,
write('').
I've tried the recursive way but I failed. How can I fix it?
Looking at your question and your code, I noticed a few things:
While you speak of "numbers" several times, your samples are integer-only. May we neglect non-integer numbers (float, rational) and handle integers only? I guess so.
There is an auto-loaded SWI-Prolog library(lists) predicate sum_list/2.
Calling your predicate sum_list/2 is an unfortunate choice.
Let's pick another name!
Your definition of sum_list/2 comprises three clauses:
sum_list([], 0).
Okay!
sum_list([H|T], Sum) :- H > 3, sum_list(T, Rest), Sum is H + Rest.
Notice H > 3? Why hardcode the constant integer 3?
sum_list([H|T], Sum) :- H < 3, write('').
That clause is not recursive. We need to see all list elements to calculate the sum, not stop at the first list element H that fulfills H < 3!
What's the use of write('')? I don't see any.
What good is the goal H < 3? Like above, why hardcode the integer 3?
Clause #2 covers H > 3. Clause #3 covers H < 3. What about H = 3?
In this answer we use clpfd, which is present in swi-prolog.
Here's a straight-forward definition of sumup/4 based on clpfd. While it could be improved in several ways (better determinism, accumulator-style, possibly some clever redundant constraints could also help), but for the time being it's a nice first shot:
:- use_module(library(clpfd)).
sumup([], 0, _, []).
sumup([Z|Zs], S0, P, [Z|Xs]) :-
Z #> P,
S0 #= S+Z,
sumup(Zs, S, P, Xs).
sumup([Z|Zs], S, P, Xs) :-
Z #=< P,
sumup(Zs, S, P, Xs).
Sample query as given by the OP:
?- sumup([8,6,10,3,9,12], N, 7, GEN).
N = 39, GEN = [8,10,9,12] % expected answer
; false. % leftover useless choicepoint
No need to write recursive code! Just use tfilter/3, (#<)/3, and clpfd:sum/3 like this:
:- use_module(library(clpfd)).
sumup(Zs, S, P, Xs) :-
tfilter(#<(P), Zs, Xs),
sum(Xs, #=, S).
Sample query:
?- sumup([8,6,10,3,9,12], S, 7, Xs).
S = 39, Xs = [8,10,9,12]. % expected result
Note that above query succeeds deterministically—a clear improvement over this previous answer!
Bonus! As the implementation of sumup/4 is monotonic, we know that the solution of above query is also part of the solution set of every generalization of the query. Look for yourself!
?- sumup([8,6,10,3,9,12], S, E, Xs).
S = 48, E in inf..2 , Xs = [8,6,10,3,9,12]
; S = 45, E in 3..5 , Xs = [8,6,10, 9,12]
; S = 39, E in 6..7 , Xs = [8, 10, 9,12] % <==== solution of above query
; S = 31, E in 8..8 , Xs = [10, 9,12]
; S = 22, E in 9..9 , Xs = [10, 12]
; S = 12, E in 10..11 , Xs = [12]
; S = 0, E in 12..sup, Xs = []
; false.
In SWI-Prolog you can use a fold and simply query:
L=[8, 6, 10, 3, 9, 12], include(<(7),L,Gen), foldl(plus,Gen,0,N).
so that sumup would be written as
sumup(L,N,GreatN,Gen) :-
include(<(GreatN),L,Gen),
foldl(plus,Gen,0,N).
plus/3 is an arithmetic predicate that works well in our case.

Prolog add N to 0 to the list

I want to add to Result list N to 0 digits.
The sample query
?- add(5,R).
should return the answer:
R = [5,4,3,2,1,0].
I already tried the following code but it did not work.
add(0, 0).
add(N, [R]) :-
N1 is N-1,
add(N1, [R|N]).
You're so close!
add(0, [0]).
add(N, [N|R]) :-
N > 0,
N1 is N-1,
add(N1, R).
So, what's different here?
add(0, [0]) has [0] instead of 0 because you're building a list, not an integer; otherwise you get the rather awkward looking [5,4,3,2,1|0] result.
N > 0 as a guard, to ensure that we don't loop crawling through negative numbers forever once we hit the base case.
The work is being done in the head of the second clause of add/2 instead of the body of it. To wit, our pattern is add(N, [N|R]) instead of add(N, [R]). This is because this term adds N to the head of the list rather than adding it before recurring.
Similarly, you have a simple inversion in [R|N]; this would build lists kind of backwards.
All in all, I think you were very close. A little more experimenting at the prompt may have been sufficient to fix it. Have you tried using trace/0 yet?
We show an analog of this answer (which dealed with consecutive integers ascending from 0).
:- use_module(library(clpfd)).
:- set_prolog_flag(toplevel_print_anon, false).
Based on equidistant_stride/2 we query:
?- N = 10, Zs = [N|_Zs0], length(_Zs0, N), equidistant_stride(Zs, -1).
N = 10, Zs = [10,9,8,7,6,5,4,3,2,1,0].
Let's re-run1 the runtime measurements we did in this previous answer!
?- between(1,6,E),
N is 10^E,
garbage_collect,
call_time(numlist(0, N, _), T1_in_ms),
garbage_collect,
call_time((_Zs = [N|_Z], length(_Z, N), equidistant_stride(_Zs, -1)), T2_in_ms).
N = 10, T1_in_ms = 0, T2_in_ms = 0
; N = 100, T1_in_ms = 1, T2_in_ms = 0
; N = 1000, T1_in_ms = 1, T2_in_ms = 1
; N = 10000, T1_in_ms = 3, T2_in_ms = 12
; N = 100000, T1_in_ms = 14, T2_in_ms = 32
; N = 1000000, T1_in_ms = 90, T2_in_ms = 280.
Edit
Past revisions of this answer inadvertently sk(r)ewed runtime measurements in favor of clpfd. How?
It's simple: A reverse/2 goal followed numlist/3, even though it is useless in this setting.
This should be better now: Thx 2 #JanWielemaker 4 reporting!
Footnote 1: Using SWI-Prolog version 7.3.11 (64-bit).
Use clpfd!
:- use_module(library(clpfd)).
:- set_prolog_flag(toplevel_print_anon, false).
We define n_to_0/2 like this:
n_to_0(N,[Z|Zs]) :-
length(Zs,N),
[Z|Zs] ins 0..N,
chain([Z|Zs],#>).
Sample query as given by the OP:
?- n_to_0(5,Zs).
Zs = [5,4,3,2,1,0].
How about the most general query using n_to_0/2?
?- n_to_0(N,Zs).
N = 0, Zs = [0]
; N = 1, Zs = [1,0]
; N = 2, Zs = [2,1,0]
; N = 3, Zs = [3,2,1,0]
; N = 4, Zs = [4,3,2,1,0]
; N = 5, Zs = [5,4,3,2,1,0]
; N = 6, Zs = [6,5,4,3,2,1,0]
...
Edit
#JanWielemaker pointed out that n_to_0/2 (as defined above) is abysmally slow—particularly when comparing it to its non-clpfd counterpart:
Thanks a lot for reporting!
See for yourself...
?- between(1, 3, E),
N is 10^E,
call_time((numlist(0, N, _Zs0), reverse(_Zs0, _)), T1_in_ms),
call_time(n_to_0(N, _), T2_in_ms).
E = 1, N = 10, T1_in_ms = 0, T2_in_ms = 1
; E = 2, N = 100, T1_in_ms = 0, T2_in_ms = 104
; E = 3, N = 1000, T1_in_ms = 0, T2_in_ms = 29701
...
Check out this new, improved, clpfd-based answer!

Prolog - generate correct bracketing

I'd like to get some help in the following exam problem, I have no idea how to do this:
Input: a list of numbers, eg.: [1,2,3,4]
Output: every possible correct bracketing. Eg.: (in case of input [1,2,3,4]):
((1 2) (3 4))
((1 (2 3)) 4)
(1 ((2 3) 4))
(1 (2 (3 4)))
(((1 2) 3) 4)
Bracketing here is like a method with two arguments, for example multiplication - then the output is the possible multiplication orders.
Your assignment could be seen as the inverse of 'computing the yield of a binary tree'.
You can code yield with 2 recursive calls and append/3:
yield((L, R), Y) :-
yield(L, Ly),
yield(R, Ry),
append(Ly, Ry, Y).
yield(T, [T]).
test:
?- yield(((1,2),(3,4)),Y).
Y = [1, 2, 3, 4] ;
Y = [1, 2, (3, 4)] ;
Y = [ (1, 2), 3, 4] ;
Y = [ (1, 2), (3, 4)] ;
Y = [ ((1, 2), 3, 4)].
Thus abstractly, yield/2 should solve your assignment, when called in this way:
?- yield(BinTree, [1,2,3,4]).
but, of course, that do not terminate. Clearly, the SLD resolution (Prolog computing algorithm) can't solve this problem without some help.
But if you recall that append/3 can generate all the alternatives left & right lists that compose the appended:
?- append(L,R,[1,2,3,4]).
L = [],
R = [1, 2, 3, 4] ;
L = [1],
R = [2, 3, 4] ;
L = [1, 2],
R = [3, 4] ;
L = [1, 2, 3],
R = [4] ;
L = [1, 2, 3, 4],
R = [] ;
false.
you can attempt to change the order of calls to get your solution.
Beware that you need sufficiently instantiated arguments before recursing, thus check the 'output' of append. You can test with
...
Yr = [_|_],
...
I also suggest to rename the predicate and change the order of arguments for clarity:
?- brackets([1,2,3,4],B).
B = 1* (2* (3*4)) ;
B = 1* (2*3*4) ;
B = 1*2* (3*4) ;
B = 1* (2*3)*4 ;
B = 1*2*3*4 ;
false.
This code works with SWI-Prolog (nextto/3).
You can explain to Prolog what you want, then ask him all the solutions :
bracket([A,B], [A,B]).
bracket(In, Out) :-
member(X, In),
nextto(X,Y, In),
append_3(A, [X,Y], B, In),
append_3(A, [[X,Y]], B, Temp),
bracket(Temp, Out).
append_3(A,B,C, Out) :-
append(A, B, Temp),
append(Temp, C, Out), !.
all_brackets(R) :-
setof(L, bracket([1,2,3,4], L), R).
you get
?- all_brackets(R), maplist(writeln, R).
[[[1,2],3],4]
[[1,2],[3,4]]
[[1,[2,3]],4]
[1,[[2,3],4]]
[1,[2,[3,4]]]
R = [[[[1,2],3],4],[[1,2],[3,4]],[[1,[2,3]],4],[1,[[2,3],4]],[[1,2],[3,4]],[1,[2,[3,4]]]].