1

I was having toruble with writing a combinations function in prolog, which follows the following math equation: b! / ((b-c)! * c!) I am new to prolog and not sure what is entirely wrong with it. The error I receive is: ERROR: is/2: Arithmetic: `fact1/2' is not a function

Below is my code:

 %fac(0,1). %fac(N,X) :- N > 0, M is N - 1, fac(M,Y), X is Y * N. fact1(0,Result) :- Result is 1. fact1(N,Result) :- N > 0, N1 is N-1, fact1(N1,Result1), Result is Result1*N. main :- current_prolog_flag(argv,[BB_S,CC_S]), atom_number(BB_S,BB), atom_number(CC_S,CC), %read_input, R1 is 1, R2 is 1, R3 is 1, FB is fact1(BB,R1), ABS is abs(BB - CC), FE is fact1(ABS,R2), FC is fact1(CC,R3), TI is FE * FC, BF is FB / TI, %BF is fac(BB) / (fac(abs(BB-CC)) * fac(CC))), write($BF), halt. 

Thank you for your help.

2 Answers 2

2

Based on the question, I think you have a misconception on what predicates are. Predicates can only result in true or false (well there can of course be an error, or they can loop forever if you see these as "possible outcomes" as well). A predicate can respond with values by unifying variables that are not yet fixed. Typically in Prolog, one makes predicates as generic as possible such that one can call a predicate multidirectional.

You call a predicate like:

FB is fact1(BB,R1), 

But fact1 is not a function (a functor for which in the is/2 predicate, the semantics is known).

A predicate can calculate things and passes results through unification, for example:

?- fac1(5, X). X = 120 . 

we thus make a call to the fac1/2 predidate with the first parameter fixed to 5, and Prolog will unify X to 120.

We can tus rewrite the predicate to:

main :- current_prolog_flag(argv,[BB_S,CC_S]), atom_number(BB_S,BB), atom_number(CC_S,CC), fact1(BB, FB), ABS is abs(BB - CC), fact1(ABS, FA), fact1(CC, FC), Res is FB / (FA * FC), write(Res).

We can also make fac1 more declarative: right now it only works given the first parameter is fixed (or in case the second parameter is 1). Furthermore it is a bit inefficient since it does not make use of tail call optimization (TCO). We can improve the predicate by using the clpfd library, and implement it like:

:- use_module(library(clpfd)). fac(0, 1). fac(I, F) :- I #> 0, F #= I*F1, I1 #= I-1, fac(I1, F1).

Now we can query the factorial relation in several directions:

?- fac(I, 120). I = 5 ; false. ?- fac(I, 130). false. ?- fac(5, 120). true ; false. ?- fac(7, 120). false. ?- fac(7, Y). Y = 5040 ; false. 

We can thus query for which i, i! is equal to 120, etc.

We can also boost performance by implementing a product for a specific range, so:

 b ------ | | | | i i=a+1 

So a prodrange that is basically:

prodrange(A, B, P) :- fac(A, FA), fac(B, FB), P is FB / FA.

but then more efficient, since this is O(a + b), and we can reduce it to O(b - a), with:

prodrange(A, A, 1). prodrange(A, B, P) :- B > A, B1 is B-1, prodrange(A, B1, P1), P is P1 * B1. 

or more declarative:

prodrange(A, A, 1). prodrange(A, B, P) :- B #> A, P #= B*P1, B1 #= B-1, prodrange(A, B1, P1). 

then we can implement a comb/3 predicate to calculate the number of combinations:

comb(BB, CC, Res) :- MX is max(BB, CC), MN is min(BB, CC), prodrange(MN, MX, Num), Abs is MX-MN, fac(Abs, Den), Res is Num / Den.

then the main looks like:

main :- current_prolog_flag(argv,[BB_S,CC_S]), atom_number(BB_S,BB), atom_number(CC_S,CC), comb(BB, CC, BF), print('Number of bracelets: '), write(BF), halt. 
Sign up to request clarification or add additional context in comments.

Comments

1

Never mind. I found a solution. But, for others benefit, I have posted the solution here. Apparently the functions dont have a return and return by placing the value they generate in a given variable.

 %fac(0,1). %fac(N,X) :- N > 0, M is N - 1, fac(M,Y), X is Y * N. fact1(0,Result) :- Result is 1. fact1(N,Result) :- N > 0, N1 is N-1, fact1(N1,Result1), Result is Result1*N. main :- current_prolog_flag(argv,[BB_S,CC_S]), atom_number(BB_S,BB), atom_number(CC_S,CC), %read_input, fact1(BB,FB), %notice change ABS is abs(BB - CC), fact1(ABS,FE), %notice change fact1(CC,FC), %notice change TI is FE * FC, BF is FB / TI, %BF is fac(BB) / (fac(abs(BB-CC)) * fac(CC))), print('Number of bracelets: '), write(BF), halt. 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.