Search code examples
prologstack-overflowgnu-prolog

I wrote a program to handle unit conversions in Prolog, but I always get stack-overflows: Do you know why?


The problem continues regardless of refactoring, but it changes, if I switch line 6 and 7 I get different results? How could that even be possible?

If relevent this is gnuprolog on a MacOS Monterey (version 12.6.2) device.

Here is the relevent code:

conversion(meters, 82/25, feet).
conversion(feet,   12/1,  in  ).
conversion(hr,     60/1,  min ).
conversion(min,    60/1,  sec ).

conversion(Unit1, X/Y, Unit2)     :- conversion(Unit2, Y/X, Unit1), !.
conversion(Unit1, Num/Den, Unit3) :- conversion(Unit1, X/Y, Unit2), conversion(Unit2, A/B, Unit3), Num is X * A, Den is Y*B.

Whever I enter a question that requires more then a single inversion (as in the second to last rule) I get an error. So,

conversion(meters,X,in).  
conversion(hr,X,sec).
conversion(in, X, meters).

Cause,

Fatal Error: local stack overflow (size: 16384 Kb, reached: 16384 Kb, environment variable used: LOCALSZ)

But

conversion(min,X,hr).
conversion(feet,X,meters).

Produce the expected results. Any wisdom would be greatly appreciated!


Solution

  • The following appears to work, thanks @brebs!

    conversion(meters, 82/25,feet   ).
    conversion(feet,   12/1, inches ).
    conversion(hours,  60/1, minutes).
    conversion(minutes,60/1, seconds).
    
    walk(Unit1, X/Y, Unit3, Vs) :-
         conversion(Unit1, X/Y, Unit3);
         conversion(Unit3, Y/X, Unit1);
         \+ member(Unit2, Vs),
         walk(Unit1, A/B,  Unit2, [Unit2|Vs]),
         walk(Unit2, C/D , Unit3, [Unit2|Vs]),
         N is A * C, M is B * D,
         gcd(N,M,Z),
         X is N // Z,
         Y is M // Z.
    
    ratio(Unit1, X/Y, Unit2) :- walk(Unit1, X/Y, Unit2, []).
    
    gcd(X, 0, X):- !.
    gcd(0, X, X):- !.
    gcd(X, Y, D):- X =< Y, !, Z is Y - X, gcd(X, Z, D).
    gcd(X, Y, D):- gcd(Y, X, D).