Reputation: 21
I have this following code:
factor_in_inches(Unit, Scale) :- recursiveScale(Unit, Scale, inch).
%Part3
scale_factor(Unit1, Unit2, Factor) :- recursiveScale(Unit2, Factor, Unit1).
%Part 1 - wrote alternate scale function so I could keep part instead of deleting for part 2
findScale(Unit1, Scale, Unit2) :-
scale(Unit1, Scale, Unit2);
scale(Unit2, Scale1, Unit1),
Scale is float(1/Scale1).
%need to flip scales because not all units have direct conversions to eachother
%have to find reciprocal conversion and then flip it
%Part2
%have to use findScale instead of regular scale because otherwise
%the recursive fucntion did not work for direct conversions to inches
%had to use findScale to get base conversions for inches
recursiveScale(Big, Scale, Smallest) :-
findScale(Big, Scale, Smallest);
recursiveScale(Smaller, MoreScale, Smallest),
findScale(Big, ScaleAgain, Smaller),
Scale is float(ScaleAgain * MoreScale).
%Part 4
convert(Unit1, Quantity1, Unit2, Quantity2) :-
factor_in_inches(Unit1, Factor1),
factor_in_inches(Unit2, Factor2),
Factor1 is round((Factor2 * Quantity2)/ Quantity1).
And it is based on these facts:
scale(foot, 12, inch).
scale(yard, 3, foot).
scale(rod, 198, inch).
scale(chain, 22, yard).
scale(furlong, 40, rod).
scale(mile, 8, furlong).
scale(league, 3, mile).
I am trying to run the following tests cases to test my "convert" predicate but on the third test it gets stuck on an infinite loop.
test(convert) :- convert(foot, 2, inch, 24.0).
test(convert) :- convert(foot, 6, yard, 2.0).
test(convert) :- convert(chain, 2, foot, 132.0).
How would I go about stopping the backtracking so this last test would not run infinitely?
Thank you.
Upvotes: 1
Views: 141
Reputation: 60014
Seems it could be a lot simpler:
factor_in_inches(inch, 1) :- !.
factor_in_inches(Unit, Scale) :-
scale(Unit, Scale1, Down),
factor_in_inches(Down, Scale2),
Scale is Scale1 * Scale2.
edit
The cut is there for efficiency, removing it - i.e. the first clause become
factor_in_inches(inch, 1).
you can enumerate all factors:
?- factor_in_inches(U,S).
U = inch,
S = 1 ;
U = foot,
S = 12 ;
U = yard,
S = 36 ;
U = rod,
S = 198 ;
U = chain,
S = 792 ;
U = furlong,
S = 7920 ;
U = mile,
S = 63360 ;
U = league,
S = 190080 ;
false.
Upvotes: 1
Reputation: 15316
There is no reason in this problem for anything to run indefinitely.
You would just scale-down a value in some original denomination to "inches". Then scale-up the "inches" value to the target denomination.
The findScale/3
predicate already looks fishy. You want to scale-down, as in
findScale(Big, Scale, Smallest)
. However, the third line tries to find scale(Unit2, Scale1, Unit1)
where Unit2
is a larger scale than Unit1
. No such fact exists in the database.
findScale(Unit1, Scale, Unit2) :-
scale(Unit1, Scale, Unit2);
scale(Unit2, Scale1, Unit1),
Scale is float(1/Scale1).
What you want is a predicate
conversionFactor(U1,U2,F) :- larger(U1,U2),
stepDown(U1,Ux,Fx),
conversionFactor(Ux,U2,Fxx),
F is Fx*Fxx.
conversionFactor(U1,U2,F) :- larger(U2,U1),
conversionFactor(U2,U1,Fx),
F is 1.0/Fx.
conversionFactor(U1,U2,F) :- \+ larger(U1,U2), \+ larger(U2,U1), % incomparable
conversionFactor(U1,inch,Fa),
conversionFactor(inch,U2,Fb),
F is Fa*Fb.
conversionFactor(U,U,1.0).
There is no backtracking, because there really is no choice to be had. It's just a recursive call.
Upvotes: 0
Reputation: 10102
Here is the responsible part of your program why any of your queries does not terminate. It is not only the last one! To see this, ask Query, false
in stead.
recursiveScale(Big, Scale, Smallest) :- ( false,findScale(Big, Scale, Smallest); recursiveScale(Smaller, MoreScale, Smallest), false,findScale(Big, ScaleAgain, Smaller),Scale is float(ScaleAgain * MoreScale)). factor_in_inches(Unit, Scale) :- recursiveScale(Unit, Scale, inch), false. convert(Unit1, Quantity1, Unit2, Quantity2) :- factor_in_inches(Unit1, Factor1), false,factor_in_inches(Unit2, Factor2),Factor1 is round((Factor2 * Quantity2)/ Quantity1). ?- convert(chain, 2, foot, 132.0).
This fragment called a failure-slice is intimately related to your program. For, if this fragment loops, then your program will loop too. I obtained this fragment simply by adding goals false
into your program. What is interesting is that all the arguments of convert/4
are effectively ignored. Therefore, all queries will loop. Even those, where you believed that they terminate.
To fix this, you have to modify something in the visible part. It seems that you misunderstood disjunction. Always put ;
in front, or simply look what listing/1
suggests. For more, see tag failure-slice.
Upvotes: 3