Related
modThreeModFive(X) :- X > 0, X < 1000, 0 is mod(X, 5) ; 0 is mod(X, 3).
I'm wondering what the simplest way would be to get the sum of values of X for which the statement is true, given that the number of solutions is finite.
Is this even possible in Prolog, or am I forced to fill a list with integers [1, 1000], and then test them individually?
Being so different from imperative languages, the easiest way is to use a library predicate:
?- [user].
|: modThreeModFive(X) :- X > 0, X < 1000, 0 is mod(X, 5) ; 0 is mod(X, 3).
|:
% user://1 compiled 0.05 sec, 1 clauses
true.
?- aggregate(sum(X),(between(1,1000,X),modThreeModFive(X)),Sum).
Sum = 266333.
Not every Prolog has such library, then the alternative would be to - as you already suggested - to first get the list of values, then sum them together:
?- findall(X,(between(1,1000,X),modThreeModFive(X)),L),sumlist(L,Sum).
L = [3, 5, 6, 9, 10, 12, 15, 15, 18|...],
Sum = 266333.
If your Prolog allows for non backtrackable assignment, you could implement by yourself some of the basic functionalities found in library(aggregate).
OT: the version summing a list shows a bug in your logic: 15 is a solution in both branches. Instead of disjunction, you should use an if/then/else construct. Like in
?- [user].
|: modThreeModFive(X) :- 0 is mod(X, 5) -> true ; 0 is mod(X, 3).
Warning: user://2:21:
Warning: Redefined static procedure modThreeModFive/1
Warning: Previously defined at user://1:8
|:
% user://2 compiled 0.00 sec, 1 clauses
true.
?- findall(X,(between(1,1000,X),modThreeModFive(X)),L),sumlist(L,Sum).
L = [3, 5, 6, 9, 10, 12, 15, 18, 20|...],
Sum = 234168.
or just a cut !/0 to commit the first outcome. It's an useful exercise to find out the right position in such simple predicate...
A good language for logic programming should allow the programmer to use a language close to the language used by the mathematicians. Therefore, I have always considered the lack of proper universal quantifier in Prolog an important shortcoming.
Today an idea came to me how to define something much better than forall and foreach.
forany(Var, {Context}, Condition, Body)
This predicate tries to prove Body for all instantiations Var gets successively on backtracking over Condition. All variables in Condition and Body are considered local unless listed in Var or Context. Condition is not permitted to modify in any way the variables listed in Context, otherwise forany won't work correctly.
Here is the implementation (based on yall):
forany(V, {Vars}, Goal1, Goal2) :-
( bagof(V, {V,Vars}/Goal1, Solutions)
-> maplist({Vars}/[V]>>Goal2, Solutions)
; true ).
My first question is about the second argument of forany. I'd like to eliminate it.
Now some examples
Construct a list of the first 8 squares:
?- length(X,8), forany(N, {X}, between(1,8,N),
(Q is N*N, nth1(N, X, Q))).
X = [1, 4, 9, 16, 25, 36, 49, 64].
Reverse a list:
?- X=[1,2,3,4,5], length(X,N), length(Y,N),
forany(I, {X,Y,N}, between(1,N,I),
(J is N-I+1, nth1(I,X,A), nth1(J,Y,A))).
X = [1, 2, 3, 4, 5],
N = 5,
Y = [5, 4, 3, 2, 1].
Subset:
subset(X, Y) :- forany(A, {X,Y}, member(A,X), member(A, Y)).
A funny way to generate all permutations of a list without duplicates:
permutation(X, Y) :-
length(X, N), length(Y, N), subset(X, Y).
?- permutation([1,2,3],X).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
X = [2, 1, 3] ;
X = [2, 3, 1] ;
X = [3, 1, 2] ;
X = [3, 2, 1] ;
false.
A funny way to sort a list of different integers. Notice that constraints are used to make the list sorted so most permutations won't be generated:
sorted(X) :- forany(A-B, {X}, append(_, [A,B|_], X),
A#<B).
?- X=[7,3,8,2,6,4,9,5,1], length(X, N), length(Y, N),
sorted(Y), subset(X,Y).
X = [7, 3, 8, 2, 6, 4, 9, 5, 1],
N = 9,
Y = [1, 2, 3, 4, 5, 6, 7, 8, 9] .
The problem
It seems that this forany works brilliantly when constraints are not used. Also, it can be used to generate constraints, but at least on SWI-Prolog there are problems when constraints already have been generated. The reason for this is that forany uses bagof and according to the manual of SWI-Prolog:
Term-copying operations (assertz/1, retract/1, findall/3, copy_term/2, etc.) generally also copy constraints. The effect varies from ok, silent copying of huge constraint networks to violations of the internal consistency of constraint networks. As a rule of thumb, copying terms holding attributes must be deprecated. If you need to reason about a term that is involved in constraints, use copy_term/3 to obtain the constraints as Prolog goals, and use these goals for further processing.
Here is a demonstration of the problem bagof creates with constraints:
?- X=[A,B,C], dif(C,D), bagof(_, K^member(K,X), _).
X = [A, B, C],
dif(C, _5306),
dif(C, _5318),
dif(C, _5330),
dif(C, D).
As you can see, three unnecessary constraints are created.
My second question is if this is a problem only of SWI-Prolog.
And the third question: is there a way to fix this in SWI-Prolog. The above quote from the manual suggests that copy_term/3 should be used. Unfortunately, I don't understand this suggestion and I don't know if it is useful for forany.
Great news! I was surprised that bagof is written in Prolog. By looking at its code I learned that some things I thought are impossible are in fact possible. And just as the manual of SWI-Prolog suggested, copy_term/3 or rather the similar predicate copy_term_nat/2 helped.
So with great joy I am able to present a fully working (as far as I can tell) universal quantifier for SWI-Prolog:
forany(V, {Vars}, Condition, Body) :-
findall(V-Vars, Condition, Solutions),
% For SWI-Prolog. Can be replaced by Solutions=Clean_solutions in other systems
copy_term_nat(Solutions, Clean_solutions),
forany_execute_goals(Clean_solutions, Vars, V, Body).
forany_execute_goals([], _, _, _).
forany_execute_goals([Sol-NewVars|Solutions], Vars, V, Body) :-
% The following test can be removed
assertion(subsumes_term(NewVars, Vars)),
% or replaced by the following more standard use of throw/1:
% ( subsumes_term(NewVars, Vars)
% -> true
% ; throw('Forbidden instantiation of context variables by the antecedent of forany') ),
NewVars = Vars,
call({Vars}/[V]>>Body, Sol),
forany_execute_goals(Solutions, Vars, V, Body).
I'm trying to get more into learning prolog as I'll be taking an AI class at school next semester. I've been able to get down the basics down and can do relation based stuff, however, I've been trying to learn permutations and combinatronics and they seem pretty straightforward, but it led me to a question that I can't figure out how to solve. Say I wanted to know the permutations of 1's and 0's with a certain condition that there must be atleast 4 1's in a row.
I have no idea where I would start to try and find a solution for this, but in the end I want the code to do something like this:
?- placeOnesAndZeros(9,X).
% where 9 is the length of the list/array and X is the permutations
[0,0,0,0,0,0,0,0,0]
[1,1,1,1,0,0,0,0,0]
[0,1,1,1,1,0,0,0,0]
[0,0,1,1,1,1,0,0,0]
[0,0,0,1,1,1,1,0,0]
[0,0,0,0,1,1,1,1,0]
[0,0,0,0,0,1,1,1,1]
[1,1,1,1,0,1,1,1,1]
[1,1,1,1,1,0,0,0,0]
[0,1,1,1,1,1,0,0,0]
[0,0,1,1,1,1,1,0,0]
[0,0,0,1,1,1,1,1,0]
[0,0,0,0,1,1,1,1,1]
[1,1,1,1,1,1,0,0,0]
[0,1,1,1,1,1,1,0,0]
[0,0,1,1,1,1,1,1,0]
[0,0,0,1,1,1,1,1,1]
[1,1,1,1,1,1,1,0,0]
[0,1,1,1,1,1,1,1,0]
[0,0,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,0]
[0,1,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,1]
Thank you in advance!
EDIT CODE:
printList([ ]).
printList([H|T]) :- print(H), nl, printList(T).
eval([],_).
eval([H|T],[1,0]):-member(H,[1,0]),eval(T,[1,0]).
placeOnesAndZeros(N, L):-length(L,N), eval(L,[1,0]).
Generate and test it's the name of the basic technique used to search a solution space. In Prolog, it's practically built in. Just provide a filter discarding what is not required:
?- placeOnesAndZeros(9,L),once(append(_,[1,1,1,1|_],L)).
once/1 is required, otherwise append/3 could succeed multiple times.
To check the correctness of the approach, here is how to count how many solutions we get:
?- aggregate(count,L^H^T^(placeOnesAndZeros(9,L),once(append(H,[1,1,1,1|T],L))),C).
C = 111.
The quantification on variables L,H,T (these last 2 being introduced only to aggregate) can be avoided using aggregate_all:
?- aggregate_all(count,(placeOnesAndZeros(9,L),once(append(_,[1,1,1,1|_],L))),C).
C = 111.
edit
As #lurker noted, my filter isn't correct. Try instead
atLeastFourOnes(L) :- memberchk(1,L), atLeastFourOnes_(L).
atLeastFourOnes_([]).
atLeastFourOnes_([0|L]) :- atLeastFourOnes_(L).
atLeastFourOnes_([1,1,1,1|L]) :- stripOnes(L,R), atLeastFourOnes_(R).
that yields
?- placeOnesAndZeros(9,L),atLeastFourOnes(L).
L = [1, 1, 1, 1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 0] ;
L = [1, 1, 1, 1, 1, 1, 1, 0, 0] ;
...
?- aggregate(count,L^(placeOnesAndZeros(9,L),atLeastFourOnes(L)),C).
C = 22.
I want to generate a list with all the numbers abc, where a = c and b >= a + c.
I know how to generate the numbers, but I do not know how to add them to the list because I can not do something like L = [Number|L].
I don't know how to define the add predicate... or should I do it in another way?
I have tried defining it as add(Nr, L, [Nr|L])., but I have no idea of what to do after that.
c(0). c(1). c(2). c(3). c(4). c(5). c(6). c(7). c(8). c(9).
bts(L, Lr) :- c(A), A =\= 0, c(C), A =:= C, c(B), C =\=9, B >= A + C,
Nr is A * 100 + B * 10 + C,
add(......).
solve(L) :- bts([], L).
The output should be:
L=[121,131,141,151,161,171,181,191,242,252,262,272,282,292,363,373,383,393,484,494]
You are on the right track. Here are two small tips:
First and most importantly, focus on what a single solution looks like. You can always use meta-predicates like findall/3 and setof/3 to collect all solutions into a list of solutions.
Second, there are more intelligent ways to describe solutions in your case. Currently, you are using generate and test, which is an infeasible strategy for larger problems. Instead, use your Prolog system's constraint solvers to declaratively describe all requirements. This lets the engine apply pruning to avoid generating all combinations.
In total, my recommendation is to do it similar to the following:
abc(Ls) :-
Ls = [A,B,C],
A #= C,
A #\= 0,
C #\= 9,
B #>= A + C,
Ls ins 0..9.
We can now try the most general query to see what solutions look like in general:
?- abc(Ls).
Ls = [_940, _946, _940],
_940 in 1..4,
2*_940#=<_946,
_946 in 2..9.
This is of course not very useful, but it at least tells us that our relation terminates and is deterministic.
This means that so-called labeling, which is the search for concrete solutions will also terminate. That is a very nice property, because it means that the search will always terminate, even if it may take a long time.
In this case, the search is of course trivial, and we can use for example label/1 to enumerate solutions:
?- abc(Ls), label(Ls).
Ls = [1, 2, 1] ;
Ls = [1, 3, 1] ;
Ls = [1, 4, 1] ;
Ls = [1, 5, 1] ;
etc.
Now, to obtain the results you want, we will use findall/3 to collect all solutions into a list:
?- abc(Ls),
findall(N, (label(Ls),
atomic_list_concat(Ls,A),atom_number(A,N)), Ns).
Ls = [_774, _780, _774],
Ns = [121, 131, 141, 151, 161, 171, 181, 191, 242|...],
_774 in 1..4,
2*_774#=<_780,
_780 in 2..9.
I have also taken the liberty to apply a small transformation to each solution, so that you get the desired result immediately.
The formalism I am applying here is called CLP(FD), and the exact details for invoking this mechanism differ slightly between available Prolog systems. Check your system's manual for more information, and see also clpfd.
a simple application of findall/3 and between/3
abc(Ns) :- findall(N, (between(1,9,A),between(1,9,B),C=A,B>=A+C,N is A * 100 + B * 10 + C), Ns).
This is the solution I found:
bts(1000, []) :- !.
bts(Nr, L) :-
N is Nr + 1,
bts(N, X),
once(((number_chars(Nr, [H1, H2, H3]), number_chars(A, [H1]), number_chars(C, [H3]),
A =:= C, number_chars(B, [H2]), B >= A + C,
L = [Nr|X]);
L = X)).
solve(L) :- bts(100, L).
I'm reviewing some exercise for the coming test and having difficulty at this.
Given a list of integers L, define the predicate: add(L,S) which returns a list of integers S in which each element is the sum of all the elements in L up to the same position.
Example:
?- add([1,2,3,4,5],S).
S = [1,3,6,10,15].
So my question is what define the predicate means? It looks pretty general. I've read some threads but they did not provide much. Thanks!
This is a good exercise to familiarize yourself with two important Prolog concepts:
declarative integer arithmetic to reason about integers in all directions
meta-predicates to shorten your code.
We start with a very simple relation, relating an integer I and a sum of integers S0 to a new sum S:
sum_(I, S0, S) :- S #= S0 + I.
Depending on your Prolog system, you may need a directive like:
:- use_module(library(clpfd)).
to use declarative integer arithmetic.
Second, there is a powerful family of meta-predicates (see meta-predicate) called scanl/N, which are described in Richard O'Keefe's Prolog library proposal, and already implemented in some systems. In our case, we only need scanl/4.
Example query:
?- scanl(sum_, [1,2,3,4,5], 0, Sums).
Sums = [0, 1, 3, 6, 10, 15].
Done!
In fact, more than done, because we can use this in all directions, for example:
?- scanl(sum_, Is, 0, Sums).
Is = [],
Sums = [0] ;
Is = [_2540],
Sums = [0, _2540],
_2540 in inf..sup ;
Is = [_3008, _3014],
Sums = [0, _3008, _3044],
_3008+_3014#=_3044 ;
etc.
This is what we expect from a truly relational solution!
Note also the occurrence of 0 as the first element in the list of partial sums. It satisfies your textual description of the task, but not the example you posted. I leave aligning these as an exercise.
Define the predicate simply means write a predicate that does what the question requires.
In your question you have to write the definition of add/2 predicate( "/2" means that it has two arguments). You could write the definition below:
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 is Sum+H,NSum is Sum+H,add1(T,NSum,T1).
The above predicate gives you the desired output. A simple example:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
I think the above or something similar predicate is what someone would wait to see in a test.
Some additional information-issues
The problem with the predicate above is that if you query for example:
?- add(S,L).
S = L, L = [] ;
ERROR: is/2: Arguments are not sufficiently instantiated
As you see when you try to ask when your predicate succeeds it gives an obvious solutions and for further solutions it throws an error. This is not a very good-desired property. You could improve that by using module CLPFD:
:- use_module(library(clpfd)).
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 #= Sum+H,NSum #= Sum+H,add1(T,NSum,T1).
Now some querying:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
?- add(S,[1,3,6]).
S = [1, 2, 3].
?- add(S,L).
S = L, L = [] ;
S = L, L = [_G1007],
_G1007 in inf..sup ;
S = [_G1282, _G1285],
L = [_G1282, _G1297],
_G1282+_G1285#=_G1307,
_G1282+_G1285#=_G1297 ;
...and goes on..
As you can see now the predicate is in the position to give any information you ask! That's because now it has a more relational behavior instead of the functional behavior that it had before due to is/2 predicate. (These are some more information to improve the predicate's behavior. For the test you might not be allowed to use libraries etc... so you may write just a simple solution that at least answers the question).