Fair non-binary random item - prolog

Is it possible to get an item of a list of tuples randomly regarding its own random value with a fair share?
For example:
X = [(0.60, test1), (0.20, test2), (0.20, test3)]
In this case test1 has a 60% probability of getting chosen over the other ones.
I tried using maybe/1 but that gives me a "binary chance" over each one whereas I want a fair chance for each member of the list if that makes sense.

You can easily adapt the solution from this answer (from which i copied the predicates choice/3 and choice/4), in this way:
solve:-
X = [(0.60, test1), (0.20, test2), (0.20, test3)],
findall(P,member((P,_),X),LP),
findall(T,member((_,T),X),LT),
choice(LT,LP,V),
writeln(V).
choice([X|_], [P|_], Cumul, Rand, X) :-
Rand < Cumul + P.
choice([_|Xs], [P|Ps], Cumul, Rand, Y) :-
Cumul1 is Cumul + P,
Rand >= Cumul1,
choice(Xs, Ps, Cumul1, Rand, Y).
choice([X], [P], Cumul, Rand, X) :-
Rand < Cumul + P.
choice(Xs, Ps, Y) :- random(R), choice(Xs, Ps, 0, R, Y), !.
And then call ?- solve. This is a basic solution, it can be improved, for instance without calling findall/2 two times... An interesting alternative is to use probabilistic logic programming, check it out.

Related

Magic Square NxN

I'm new to Prolog and I'm trying to write fully working magic square program, but to say the truth I don't really know how to do, I have started but I feel that I'm doing it wrong. I'm sharing my code and I hope someone will help me, now when numbers are good I get true, but when they are not I get like out of stack error... (here is only checking rows and columns I know about obliquely check)
thanks for your attention!
:- use_module(library(clpfd)).
:- use_module(library(lists)).
magicSq(List, N) :-
Number is N * N,
belongs(Number ,List), % check if numbers are correct.
all_different(List), % check if numbers not occur.
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma), % check column
checkR(List,1,N,Suma). % check row
belongs(0, _).
belongs(N, List) :- member(N,List) , Index is N - 1 , belongs(Index, List).
consecutiveSum(_, 0 , _,0).
consecutiveSum(List, HowMuch , From,Sum):-
Index is HowMuch - 1,
From1 is From +1,
nth1(From, List,Element),
consecutiveSum(List,Index,From1,Z),
Sum is Z + Element,!.
sumObliCol(0,_, [], _,_). % sums by columns or obliquely
sumObliCol(X,Number, [H|T], Ind, Residue) :-
Index is Ind + 1,
Y is mod(Index,Number),
Y =:= Residue,
sumObliCol(Z,Number, T, Index,Residue),
X is Z + H, !.
sumObliCol(X,Number, [_|T], Ind,Residue) :-
Index is Ind + 1,
sumObliCol(X,Number, T, Index,Residue).
checkC(_,0,_,_). % check column
checkC(List,N, Number,Answ):-
N1 is N-1,
checkC(List,N1, Number,Answ),
sumObliCol(Ats,Number,List,0,N1),Ats is Answ,!.
checkR(_,N,Number,_):- N>(Number*Number). % check row
checkR(List,N,Number,Answ):-
consecutiveSum(List,Number,N,Sum), Sum is Answ,
N1 is N + Number,
checkR(List,N1, Number,Answ),!.
In programming one often assumes that
everything is deeply intertwingled ... since the cross-connections among the myriad topics of this world/program simply cannot be divided up neatly.1
But in Prolog, sometimes, we can divide things up much more neatly. In particular, if you concentrate on a single property like non-termination. So let's consider magic squares of size one — very magic indeed! Like so using a failure-slice:
?- magicSq(Xs,1), false.
magicSq(List, N) :-
Number is N * N,
belongs(Number ,List), false,
all_different(List),
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma),
checkR(List,1,N,Suma).
belongs(0, _) :- false.
belongs(N1, List) :-
member(N1,List), false,
N2 is N1 - 1,
belongs(N2, List).
That's all you need to understand! Evidently, the List is unconstrained and thus the goal member(N1, List) cannot terminate. That's easy to fix, adding a goal length(List, Number). And still, the program does not terminate but in a different area:
?- magicSq(Xs,1), false.
magicSq(List, N) :-
Number is N * N,
length(List, Number),
belongs(Number ,List), false,
all_different(List),
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma),
checkR(List,1,N,Suma).
belongs(0, _) :- false.
belongs(N1, List) :-
member(N1,List),
N2 is N1 - 1,
belongs(N2, List), false.
Now this does not terminate, for N1 may be negative, too. We need to improve that adding N1 > 0.
Now, considering the program with a false in front of all_different/1, I get:
?- time(magicSq(List, 3)).
% 8,571,007 inferences
That looks like an awful lot of inferences! In fact, what you are doing is to enumerate all possible configurations first. Thus, you do not use the powers of constraint programming. Please go through tutorials on this. Start here.
However, the problems do not stop here! There is much more to it, but the remaining program is very difficult to understand, for you are using the ! in completely unrelated places.

Prolog issue with max list function: nondeterm vs procedure

I am trying to do a small project in prolog where a user can input a list and then it calculates the average, max in the list etc. etc.
So far so good, but I ran into a problem when writing the max function (finds max number in the list). The code is:
maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.
The function itself works separately, but I get this error message:
The predicate 'forma::maxN/2 (i,o)', which is declared as 'procedure', is actually 'nondeterm' forma.pro
This is my predicate in the *.cl definition:
maxN: (integer* Z, integer U) procedure (i,o).
I cannot declare it as nondeterm because it causes issues with my whole form. Can you help me/give a hint how to make it a procedure? I am thinking I have to make a cut somewhere but my attempts have failed so far.
P.S. I am using Visual Prolog 7.4.
Edit: After trying the alternatives proposed to make the two rules into one or with an accumulator, I now get that the predicate is 'determ' instead of a procedure. According to my Prolog guide that means that the predicate doesn't have multiple solutions now, but instead has a chance to fail. Basically all code variations I've done up to now lead me to a 'determ'.
The problem is that Prolog sees a choice point between your second and third rules. In other words, you, the human, know that both X > M and M >= X cannot both be true, but Prolog is not able to infer that.
IMO the best thing to do would be to rephrase those two rules with one rule:
maxN([X], X) :- !.
maxN([X|L], Max) :-
maxN(L, M),
X > M -> Max = X
; Max = M.
This way there isn't ever an extra choice point that would need to be pruned with a cut.
Following #CapelliC's advice, you could also reformulate this with an accumulator:
maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).
maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :-
X > Y -> maxN_loop(Xs, X, Max)
; maxN_loop(Xs, Y, Max).
sorry, I don't know the Prolog dialect you're using, my advice is to try to add a cut after the second clause:
maxN([X|L],X) :- maxN(L,M), X > M, !.
Generally, I think a recursive procedure can be made deterministic transforming it to tail recursive. Unfortunately, this requires to add an accumulator:
maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).
Of course, top level call should become
maxN([F|L],M) :- maxN(L,F,M).

Finding query for which a prolog program gives incorrect result

This Prolog program defines the third argument to be the maximum value of the first two numeric arguments:
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y).
I think that this program works just fine. But I am told that it can give incorrect result. Can you tell when and why?
This is a textbook example.
?- max(5,1,1).
true.
Homework: Why is the program wrong? How do we make the program correct?
EDIT
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y).
Our intention is to say:
If X is greater than Y, then Max is X. Otherwise, Max must be Y.
Instead, what is say is:
When the first and third arguments (X and Max) can be unified, and X is greater than Y, succeed. Otherwise, if the second and third arguments (Y and Max) can be unified, succeed.
The obvious problem arises then the first and third arguments cannot be unified, but the second and the third can.
Instead:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.
or
max(X, Y, Max) :- X >= Y, !, Max = X.
max(_, Max, Max).
It does work fine, provided the third argument is uninstantiated. The danger here would be if there were a way to backtrack into the second rule, or if the third argument is instantiated to the same value as the second. It's not particularly safe looking because max(X, Y, Y). is equal to max(_, Y, Y) which just sets the result to the second value without any thought. The cut at the end of the first rule effectively ensures that backtracking will not commence if X >= Y, so the second rule should only be entered when X < Y and Z is not already equal to Y.
Though it mostly works, it's not a good habit to get into. People new to Prolog tend to think procedurally and making use of the cut like this to ensure a particular result through procedural trickery ultimately holds you back and leads to convoluted Prolog that cannot be driven in different and interesting ways. There are several other ways of writing this predicate that work just as well but do not rely on the cut to ensure their behavior, for instance:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.
or
max(X, Y, Z) :- X >= Y -> Z = X ; Z = Y.
Neither of these is vulnerable to the problem of the third being instantiated. Interestingly, this is a great illustration of the difference between a red cut and a green cut. Your code has a red cut, where the behavior is dependent on the cut, but if I simply change my first solution to this:
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y) :- X < Y.
That's a green cut, because the behavior is not dependent on the cut, but Prolog's performance may improve slightly since it won't backtrack into the second clause to try it. Here we're explicitly telling Prolog, don't both making the next check because we know it will fail. With a red cut, there's no other check which will fail.
It's unfortunate that stating the condition twice feels redundant but relying on a single rule feels clunky. In practice, my experience is that scenarios like these are not ultimately all that common; usually you have atoms or structures you can match in the head of the clause that create behavior like we have in my first substitute, but without needing a body. For example:
perform(scan(target, X, Y)) :- ...
perform(scan(calibration, X)) :- ...
This has the same effect: Prolog will backtrack until it unifies successfully, then it will back track again, but the exclusive nature of the matching will prevent another body from being executed. If we find out it's spending too much time backtracking we can add cuts to improve the performance, but in practice it's unlikely to be a problem.

Simple Prolog Program - Is a value inside or outside of a range?

I am trying to write a program that takes 3 integers I, J, and K and returns true if K is in the range of I and J and false if it falls outside the range.
The logic is super easy of course, but I am not understanding the syntax of Prolog enough to implement it.
How would I go about solving this task. This is the code I've currently got:
i(10).
j(20).
k(21).
inRange(i, j, k):-
(k > i, k < j).
The first rule of Prolog's syntax one needs to remember is that the case of the first letter in things that start in a letter matters: what looks like a variable in many other languages may actually be an atom in Prolog.
If an identifier starts in a lower case letter, it's not a variable, it's a so-called atom. Unlike variables, atoms are constant. They cannot be bound to other values by means of unification, so inRange(i, j, k) cannot possibly work. You need
inRange(I, J, K) :- K > I, K < J.
Now your logic works as expected:
:- inRange(0, 10, 5), write(yes).
writes yes, while goals
:- inRange(0, 10, -1), write(yes).
:- inRange(0, 10, 11), write(yes).
both fail. Here is a quick demo on ideone.
You probably want to use variables (which must begin with a capital letter):
in_range(X,Y,Z) :- X < Y, X < Z, Y > Z.
Now depending how you define something to be in the range, you maybe would prefer:
in_range(X,Y,Z) :- X =< Y, X =< Z, Z =< Y.
These two versions require that all three numbers are instantiated, which means, you can only ask a question like:
?- in_range(1,10,4).
true.
but not:
?- in_range(1,10,X).
X=1;
X=2;
...
X=10.
How about the built-in predicate between/3? Try it out with:
?- between(1,5,3).
or
?- between(1,5,10).
or even:
?- between(1,5,X).

What is the bottleneck in this primes related predicate?

So here it is : I'm trying to calculate the sum of all primes below two millions (for this problem), but my program is very slow. I do know that the algorithm in itself is terribly bad and a brute force one, but it seems way slower than it should to me.
Here I limit the search to 20,000 so that the result isn't waited too long.
I don't think that this predicate is difficult to understand but I'll explain it anyway : I calculate the list of all the primes below 20,000 and then sum them. The sum part is fine, the primes part is really slow.
problem_010(R) :-
p010(3, [], Primes),
sumlist([2|Primes], R).
p010(20001, Primes, Primes) :- !.
p010(Current, Primes, Result) :-
(
prime(Current, Primes)
-> append([Primes, [Current]], NewPrimes)
; NewPrimes = Primes
),
NewCurrent is Current + 2,
p010(NewCurrent, NewPrimes, Result).
prime(_, []) :- !.
prime(N, [Prime|_Primes]) :- 0 is N mod Prime, !, fail.
prime(ToTest, [_|Primes]) :- prime(ToTest, Primes).
I'd like some insight about why it is so slow. Is it a good implementation of the stupid brute force algorithm, or is there some reason that makes Prolog fall?
EDIT : I already found something, by appending new primes instead of letting them in the head of the list, I have primes that occur more often at start so it's ~3 times faster. Still need some insight though :)
First, Prolog does not fail here.
There are very smart ways how to generate prime numbers. But as a cheap start simply accumulate the primes in reversed order! (7.9s -> 2.6s) In this manner the smaller ones are tested sooner. Then, consider to test only against primes up to 141. Larger primes cannot be a factor.
Then, instead of stepping only through numbers not divisible by 2, you might add 3, 5, 7.
There are people writing papers on this "problem". See, for example this paper, although it's a bit of a sophistic discussion what the "genuine" algorithm actually was, 22 centuries ago when the latest release of the abacus was celebrated as Salamis tablets.
Consider using for example a sieve method ("Sieve of Eratosthenes"): First create a list [2,3,4,5,6,....N], using for example numlist/3. The first number in the list is a prime, keep it. Eliminate its multiples from the rest of the list. The next number in the remaining list is again a prime. Again eliminate its multiples. And so on. The list will shrink quite rapidly, and you end up with only primes remaining.
First of all, appending at the end of a list using append/3 is quite slow. If you must, then use difference lists instead. (Personally, I try to avoid append/3 as much as possible)
Secondly, your prime/2 always iterates over the whole list when checking a prime. This is unnecessarily slow. You can instead just check id you can find an integral factor up to the square root of the number you want to check.
problem_010(R) :-
p010(3, 2, R).
p010(2000001, Primes, Primes) :- !.
p010(Current, In, Result) :-
( prime(Current) -> Out is In+Current ; Out=In ),
NewCurrent is Current + 2,
p010(NewCurrent, Out, Result).
prime(2).
prime(3).
prime(X) :-
integer(X),
X > 3,
X mod 2 =\= 0,
\+is_composite(X, 3). % was: has_factor(X, 3)
is_composite(X, F) :- % was: has_factor(X, F)
X mod F =:= 0, !.
is_composite(X, F) :-
F * F < X,
F2 is F + 2,
is_composite(X, F2).
Disclaimer: I found this implementation of prime/1 and has_factor/2 by googling.
This code gives:
?- problem_010(R).
R = 142913828922
Yes (12.87s cpu)
Here is even faster code:
problem_010(R) :-
Max = 2000001,
functor(Bools, [], Max),
Sqrt is integer(floor(sqrt(Max))),
remove_multiples(2, Sqrt, Max, Bools),
compute_sum(2, Max, 0, R, Bools).
% up to square root of Max, remove multiples by setting bool to 0
remove_multiples(I, Sqrt, _, _) :- I > Sqrt, !.
remove_multiples(I, Sqrt, Max, Bools) :-
arg(I, Bools, B),
(
B == 0
->
true % already removed: do nothing
;
J is 2*I, % start at next multiple of I
remove(J, I, Max, Bools)
),
I1 is I+1,
remove_multiples(I1, Sqrt, Max, Bools).
remove(I, _, Max, _) :- I > Max, !.
remove(I, Add, Max, Bools) :-
arg(I, Bools, 0), % remove multiple by setting bool to 0
J is I+Add,
remove(J, Add, Max, Bools).
% sum up places that are not zero
compute_sum(Max, Max, R, R, _) :- !.
compute_sum(I, Max, RI, R, Bools) :-
arg(I, Bools, B),
(B == 0 -> RO = RI ; RO is RI + I ),
I1 is I+1,
compute_sum(I1, Max, RO, R, Bools).
This runs an order of magnitude faster than the code I gave above:
?- problem_010(R).
R = 142913828922
Yes (0.82s cpu)
OK, before the edit the problem was just the algorithm (imho).
As you noticed, it's more efficient to check if the number is divided by the smaller primes first; in a finite set, there are more numbers divisible by 3 than by 32147.
Another algorithm improvement is to stop checking when the primes are greater than the square root of the number.
Now, after your change there are indeed some prolog issues:
you use append/3. append/3 is quite slow since you have to traverse the whole list to place the element at the end.
Instead, you should use difference lists, which makes placing the element at the tail really fast.
Now, what is a difference list? Instead of creating a normal list [1,2,3] you create this one [1,2,3|T]. Notice that we leave the tail uninstantiated. Then, if we want to add one element (or more) at the end of the list we can simply say T=[4|NT]. awesome?
The following solution (accumulate primes in reverse order, stop when prime>sqrt(N), difference lists to append) takes 0.063 for 20k primes and 17sec for 2m primes while your original code took 3.7sec for 20k and the append/3 version 1.3sec.
problem_010(R) :-
p010(3, Primes, Primes),
sumlist([2|Primes], R).
p010(2000001, _Primes,[]) :- !. %checking for primes till 2mil
p010(Current, Primes,PrimesTail) :-
R is sqrt(Current),
(
prime(R,Current, Primes)
-> PrimesTail = [Current|NewPrimesTail]
; NewPrimesTail = PrimesTail
),
NewCurrent is Current + 2,
p010(NewCurrent, Primes,NewPrimesTail).
prime(_,_, Tail) :- var(Tail),!.
prime(R,_N, [Prime|_Primes]):-
Prime>R.
prime(_R,N, [Prime|_Primes]) :-0 is N mod Prime, !, fail.
prime(R,ToTest, [_|Primes]) :- prime(R,ToTest, Primes).
also, considering adding the numbers while you generate them to avoid the extra o(n) because of sumlist/2
in the end, you can always implement the AKS algorithm that runs in polynomial time (XD)

Resources