Here is a snippet of cryptarithmetic in prolog
sum1( [D1|N1], [D2|N2], [D|N], C1, C, Digs1, Digs) :-
sum1( N1, N2, N, C1, C2, Digs1, Digs2),
digitsum( D1, D2, C2, D, C, Digs2, Digs).
As below explains
sum1( N1, N2, N, C1, C, Digits1, Digits)
where N1, N2 and N are our three numbers,
C1 is carry from the right, and
C is carry to the left (after the summation).
Digits1 is the list of available digits for instantiating the
variables in N1, N2, and N.
Digits is the list of digits that were not used in the
instantiation of these variables.
I really don't get it what does C1 mean in sum1( [D1|N1], [D2|N2], [D|N], C1, C, Digs1, Digs), for C2 stands for carry form right, C stands for carry to the left, then what does C1 stand for?
C,C1,C2 can only assume 0,1 values. Arithmetic rules require that C1 will be 0 in first call, and C will be 0 on last call. C2 become C on recursive call, then it propagates the carry after the sum. C1 it's the carry added to N1,N2 to get N.
Related
The scenario is to mimic rolling 3 six-sided die in Prolog while trying to obey the recursive nature of prolog. This is easily done with the Fibonacci series
n_factorial(N, F) :-
N #> 0,
F #= N*F1,
N1 #= N-1,
n_factorial(N1, F1).
I'm having difficulty translating this to the dice paradigm, where we add a random number to the sum.
# N = number of dice, S = number of sides, R = result
roll_dice(N, S, R) :-
N1 #> 0,
R = random_between(1, S, R1),
N1 #= N-1,
roll_dice(N1, S, R1).
throws an error but neglects the sum anyway. I would normally use += in other languages.
A few things not quite right there:
R = random_between(1, S, R1) stores that structure in R, it does not generate random numbers.
R1 is used for "the random number you get for rolling one die" and "the sum of all the random numbers from rolling all the remaining dice" and it is unlikely those will be the same value, and when they isn't the same, that will fail.
There is no code to do the summing. (The equivalent of the Factorial video using F #= N * F1)
No recursive base case (the first line of the factorial from the video is not shown in your question, it is n_factorial(0, 1).). When N dice remaining gets down to 0, there is nothing to handle that case.
Here is one implementation:
:- use_module(library(clpfd)).
roll_dice(0, _, 0).
roll_dice(NDice, Sides, Sum) :-
NDice #> 0,
random_between(1, Sides, Roll),
Sum #= Roll + RunningTotal,
NDiceLeft #= NDice - 1,
roll_dice(NDiceLeft, Sides, RunningTotal).
while trying to obey the recursive nature of Prolog.
I guess that's important to understand; this can be done with less bolierplate and fewer temporary variables to name, e.g.:
roll_dice(NDice, Sides, Sum) :-
length(Rolls, NDice),
maplist(random(1, Sides), Rolls),
sum_list(Rolls, Sum).
which makes a list Rolls the right size to hold all the rolls, fills them in using maplist to apply random on each of them, and sums that list for the answer.
I'd do something along the lines of:
roll(N,S,R) :- positive_int(N), positive_int(S), roller(N,S,0,R) .
positive_int(N) :- integer(N), N > 0 .
roller(0,_,R,R) .
roller(N,S,T,R) :-
T1 is 1+random(S),
N1 is N-1,
roller(N1,S,T1,R)
.
Can someone explain how this code works. I am new to Prolog and I am having trouble thinking like a Prolog programmer.
When you input a number followed by a comma and any variable name, it gives you the sum up to that number
sum_to(1,1) :- !.
sum_to(N, R) :- N1 is N-1, sum_to(N1,TR), R is TR + N.
So sum_to(4, N) gives N = 10.
Your definition can be equivalently written as
sum_to( N, R) :- N = 1, R = 1, !.
sum_to( N, R) :- N1 is N-1, sum_to( N1, R1), R is R1+N.
This is a recursive definition -- it contains a call to the same predicate as the predicate itself. Under the condition that you're going to always call it with a free variable as the second argument and a concrete (hopefully positive) number as the first argument, it expresses a function which calculates the second argument's value from the given first argument.
Thus what you have is a recursive functional definition.
Now let's work through some examples, from the simplest to the progressively more and more complex:
sum_to( 1, R1) :- 1 = 1, R1 = 1, !.
\______________/
R1 = 1.
sum_to( 2, R2) :- N1 is 2-1, sum_to( N1, R1), R2 is R1+2.
\________/
N1 is 1, sum_to( 1, R1),
\____________/
R1 = 1, R2 is 1+2
\_____________________________________/
R2 = 3.
sum_to( 3, R3) :- N2 is 3-1, sum_to( N2, R2), R3 is R2+3.
\________/
N2 is 2, sum_to( 2, R2),
\____......____/
\__________________/
R2 = 3, R3 is 3+3
\_____________________________________________/
R3 = 6.
Right? As the execution progresses through the goals left to right, our variables take on their concrete values one after the other, thus enabling the execution of the next goal, and the next, which instantiate yet more variables, until the final value becomes known.
Now do sum_to( 4, R4).
This is a very imperative-style program implementing an inductive definition concidentally written in Prolog.
It relates two numbers:
In the first clause 1 is related to 1. The ! indicates that the interpreter should stop looking for further solutions in the sum_to/2 predicate.
If the first clause doesn't match (because any of the arguments in the call was different from 1) then the second clause is examined.
And now we simply:
Compute N1 as N-1
Make a recursive call with N1, and getting a value in TR such that N1 and TR are related via sum_to/2 (i.e. TR should be the sum of all integers up to N1). Once we get that, we compute R as the sum of TR and N.
The sum_to relation is correct for the first argument being 1.
The sum_to relation at N is correct if the sum_to relation is correct for N-1.
Computation will terminate if the recursive call "makes something smaller" on each call and will eventually hit a smallest value. It does indeed make N smaller on each call and will eventually hit 1. (Unless one calls this predicate with a 0 N or smaller. Then: catastrophe!)
Looking good.
(Incidentally, inductive definitions tend to go from a constant x to +oo, i.e. "going upwards"; above I am stating correctness moving from any N down towards 1. Am I justified in doing so?)
The problem is to count the number of triplets such that
a * b = c
where a1 <= a <= a2 and b1 <= b <= b2 and c1 <= c <= c2
Input will be a1,a2,b1,b2,c1,c2
The solution that I can think is to use two nested loop that iterates from a1 to a2 and second one from b1 to b2 and multiply each of them and see if the multiplied value lies in the range c1 to c2 then increment the count.
How to efficiently solve the problem when constraints are very high i.e all a1,a2,b1,b2,c1,c2 can have value between 0 to 1000000000.
Part 1: Solution with O(a2 - a1) complexity.
First, notice that given a certain a, we can easily count the number of b values with b1 <= b <= b2, which also satisfy c1 <= a * b <= c2. The latter condition is equivalent to c1 / a <= b <= c2 / a, thus we need to count the number of integers b which satisfy max(b1, c1/a) <= b <= min(b2, c2/a).
This number is N(a) = floor(min(b2, c2/a)) - ceil(max(b1, c1/a)) + 1 -- relation (1).
The solution to the problem is N(a1) + N(a1 + 1) + ... + N(a2).
This is more efficient than looping over all (a, b) pairs and checking their product, however, it may still not be fast enough for the given magnitude of the inputs -- the complexity is O(a2 - a1). Since the problem is symmetrical in a and b, it might be more advantageous to use the O(b2 - b1) complexity.
In the following two parts I will describe a more efficient solution.
Part 2: Reducing the problem to simpler ones.
Let us denote as N(a1, a2, b1, b2, c1, c2) the value that we need to calculate.
Notice that we can reduce the problem into two problems with c1 = 0, using:
N(a1, a2, b1, b2, c1, c2) = N(a1, a2, b1, b2, 0, c2) - N(a1, a2, b1, b2, 0, c1 - 1).
We can take this further and reduce a problem where c1 = 0 into two problems where b1 = 0 and c1 = 0. This can be done using:
N(a1, a2, b1, b2, 0, C) = N(a1, a2, 0, b2, 0, C) - N(a1, a2, 0, b1 - 1, 0, C).
Similarly, we can reduce a problem where b1 = 0 and c1 = 0 into two problems with a1 = 0, b1 = 0, c1 = 0.
Therefore, it is enough to solve simpler problems which require to compute values of the following form: N(0, A, 0, B, 0, C), i.e. we need to count the number of triplets of natural numbers (a, b, c), with c = a * b, a <= A, b <= B, c <= C.
Part 3: Solution with O(sqrt(c2)) complexity.
One next useful observation is that since a * b = c <= C, at least one of the following relations is true: a <= sqrt(C), or b <= sqrt(C) -- observation (2).
In the first part of the proof (relation 1) it was shown that we can efficiently calculate (in O(1)) the number of good b values if a is fixed. Using that relation, we can efficiently count the number of triples with a <= sqrt(C) -- in O(sqrt(C)).
What remains to do is to calculate the number of triplets with a > sqrt(C). According to observation (2), we know that in this case it is required to have b <= sqrt(C).
Thus, for any b in {0, 1, 2, ..., sqrt(C)} we have to count the number of good a values such that sqrt(C) < a < A. We can once again apply relation (1) (with reversed roles for a and b this time -- we are now given b and calculate the number of good a values, which is subject to the constraint of belonging to a certain interval). For each b in {0, 1, 2, ..., sqrt(C)}, we can count the number of good a in O(1) -- therefore the complexity for this case is again O(sqrt(C)).
Using the above results, we get an overall complexity of O(sqrt(C)). Returning to the initial problem, this involves an O(sqrt(c2)) complexity.
Use the fac that ab = ba. I.e. if you have tried a=2, b=3, there is no sense in also trying a=3, b=2.
Also, once a*b > c2, there is no sense in increasing a or b.
I have a simple function below which takes 2 lists ( with the same size) and a variable which stores some result.
My intention was to compare the first list's head with the second one and increase the result by one, and return it.
But instead I get true / false.
myfunction( [], [], 0).
myfunction([H1|T1], [H2|T2], N) :-
H1 > H2 -> myfunction(T1, T2, N1 + 1); myfunction(T1, T2, N1), N is N1 .
You're treating Prolog like an imperative/procedural language, but it doesn't work that way. You should read through some Prolog tutorials and/or books.
In Prolog, you define a predicate which defines a relation. When you define a predicate with variables, you are saying that, These variables are related in such and such a way if.... If Prolog succeeds in verifying the relation is true, the predicate response with "true" or "yes". Otherwise, it responds with "false" or "no".
Here's a rework of what you're trying to do:
my_predicate([], [], 0).
This relation is the "base case" and says that the count of cases where the corresponding values in the first list are greater than the second when the lists are empty is 0.
my_predicate([H1|T1], [H2|T2], N) :-
my_predicate(T1, T2, N1),
( H1 > H2
-> N is N1 + 1
; N = N1
).
This relation says that N is the count of cases where the corresponding values in the first list are greater than the second if N1 is the count of cases for the tails, and N is N1 + 1 if the current head is greater, otherwise N is N1.
If you want to make it tail recursive for efficiency, you can use an accumulator:
my_predicate(L1, L2, N) :-
my_predicate(L1, L2, 0, N).
my_predicate([], [], N, N).
my_predicate([H1|T1], [H2|T2], A, N) :-
( H1 > H2
-> A1 is A + 1
; A1 = A
),
my_predicate(T1, T2, A1, N).
Note that the above definition of my_predicate/3 assumes you want failure if the lists are different length. If you don't want failure in those cases, you would need to redefine the base case(s).
Is it possibile associate costant and variable in the same argument?
For example:
expression(N):-
write(t N),
N1 is N+1,
expression(N1).
where t N become t1, t2, t3... etc. How can I do this?
In SWI prolog:
expression(N) :-
atom_concat('t', N, TN), % Note: N must be instantiated in this case
write(TN),
N1 is N+1,
expression(N1).
Interestingly, SWI is happy with this even if N is an integer or an atom (it will treat N as an atom in that case). GNU doesn't like it if N is an integer. So you have to convert it first:
expression(N) :-
number_atom(N, AtomN), % Note: N must be instantiated in this case
atom_concat('t', AtomN, TN),
write(TN),
N1 is N+1,
expression(N1).