% rationals, ....
% this is less than the least efficient implementation

 % rationals_division/3, rationals_add_list/2,
 % rationals_addition/3, rationals_cutoff/2, rationals_is_rat/2.
 % rationals_hyphened_product_sum_list/4, rationals_multiplication/3.

 % Should have two version for the operations,
 % one with and one without simlification,
 % agrregates calling the not simplifying operation.

rationals_division( NomNom/NomDnm, DnmNom/DnmDnm, Simplified ) :-
	long_int_times( NomNom, DnmDnm, ResNom ),
	long_int_times( NomDnm, DnmNom, ResDnm ).
	% ResNom is NomNom * DnmDnm,
	% ResDnm is NomDnm * DnmNom,
	rationals_simplify( ResNom/ResDnm, Simplified ).

rationals_multiplication( Nom1/Dnm1, Nom2/Dnm2, Simplified ) :-
	long_int_times( Nom1, Dnm1, ResNom ),
	long_int_times( NomNom, DnmDnm, ResNom ),
	% ResNom is Nom1 * Nom2,
	% ResDnm is Dnm1 * Dnm2,
	% ( (\+integer(ResNom);\+integer(ResDnm)) -> 
		% then we have an overflow
		% Goal = rationals_multiplication( Nom1/Dnm1, Nom2/Dnm2, Simplified ),
		% throw( pfd(rats(int_overflow(ResNom,ResDnm),Goal)) )
		% ;
		% true
	% ),
	% !,
	rationals_simplify( ResNom/ResDnm, Simplified ).

% rationals_multiplication_wo( Nom1/Dnm1, Nom2/Dnm2, Simplified ) :-
	% ResNom is Nom1 * Nom2,
	% % ResDnm is Dnm1 * Dnm2,
	% ( (\+integer(ResNom);\+integer(ResDnm)) -> 
		% % then we have an overflow
		% trace,
		% ( ResNom < ResDnm ->
			% CrDnm is integer(ResDnm/ResNom),
			% Simplified = 1 / CrDnm
			% ;
			% CrNom is integer(ResNom/ResDnm),
			% Simplified = CrNom / 1
		% )
		% ;
		% rationals_simplify( ResNom/ResDnm, Simplified )
	% ),
	% !.

rationals_addition( LNom/LDnm, RNom/RDnm, Simplified ) :-
	rationals_lcd_factors( LDnm, RDnm, ResDnm, LFctr, RFctr ),
	long_int_times( LNom, LFctr, Prd1 ),
	long_int_times( RNom, RFctr, Prd2 ),
	long_int_plus( Prd1, Prd2, ResNom ),
	% ResNom is LNom * LFctr + RNom * RFctr,
	rationals_simplify( ResNom/ResDnm, Simplified ).
		% maybe there is something simpler in this case.

rationals_subtraction( LNom/LDnm, RNom/RDnm,  Simplified ) :-
	rationals_lcd_factors( LDnm, RDnm, ResDnm, LFctr, RFctr ),
	long_int_times( LNom, LFctr, Prd1 ),
	long_int_times( RNom, RFctr, Prd2 ),
	long_int_minus( Prd1, Prd2, ResNom ),
	% ResNom is LNom * LFctr - RNom * RFctr.
	rationals_simplify( ResNom/ResDnm, Simplified ).
	% rationals_sign_normalise( ResNom, ResDnm, Quotient ).

rationals_sign_normalise( Nom, Dnm, Quotient ) :-
	( Dnm < 0 ->
		( Nom < 0 -> 
			AbsNom is abs(Nom),
			AbsDnm is abs(Dnm),
			Quotient = AbsNom / AbsDnm
			;
			AbsDnm is abs(Dnm),
			Quotient = ( - Nom / AbsDnm )
		)
		;
		Quotient = Nom / Dnm
	).

rationals_subtract_this_list( [], _This, [] ).
rationals_subtract_this_list( [H|T], This, [SH|ST] ) :-
	rationals_subtraction( H, This, SH ),
	rationals_subtract_this_list( T, This, ST ).

rationals_all_multiply_list( [], _Nom/_Dnm, [] ). 
rationals_all_multiply_list( [H|T], Multi, [MTH|MsTT] ) :-
	rationals_multiplication( H, Multi, MTH ),
	rationals_all_multiply_list( T, Multi, MsTT ).

% rationals_add_list( [], 0/1 ). % double check that this is ok
rationals_add_list( [H], H ) :-
	!.
rationals_add_list( [H|T], Res ) :-
        rationals_add_list( T, H, Res ).

rationals_add_list( [], Ans, Ans ).
	% rationals_simplify( Ans, Simplified ).
rationals_add_list( [H|T], Acc, Res ) :-
	rationals_addition( H, Rat, Acc, NewAcc ),
	rationals_add_list( T, NewAcc, Res ).

rationals_multiply_list( List, Result ) :-
	rationals_multiply_list( List, 1/1, Result ).

rationals_multiply_list( [], Acc, Acc  ). 
rationals_multiply_list( [H|T], Acc, Res ) :-
	rationals_multiplication( Acc, H, NewAcc ),
	rationals_multiply_list( T, NewAcc, Res ).

rationals_lcd_factors( NatOne, NatTwo, LCD, OneFact, TwoFact ) :-
	gcd( NatOne, NatTwo, GCD ),
	OneFact is NatTwo // GCD,
	TwoFact is NatOne // GCD,
	LCD is OneFact * TwoFact * GCD.

rationals_hyphened_product_sum_list( HList, LList, RList, PrSum ) :-
	rationals_hyphened_product_sum_list_1( HList, 0/1, LList, RList, PrSum ).
rationals_hyphened_product_sum_list_1( [LH-RH|T], Acc, [LH|LT], [RH|RT], PS ) :-
	rationals_multiplication( LH, RH, Product ),
	rationals_addition( Product, Acc, NewAcc ),
	rationals_hyphened_product_sum_list_1( T, NewAcc, LT, RT, PS ).
rationals_hyphened_product_sum_list_1( [], Res, [], [], Res ).
	
rationals_cutoff( excl(Numb1), Numb2 ) :- 
	!, 
	rationals_cutoff_1( Numb1, Numb2, excl ).
rationals_cutoff( incl(Numb1), Numb2 ) :- 
	!,
	rationals_cutoff_1( Numb1, Numb2, incl ).
rationals_cutoff( Numb1, Numb2 ) :- 
	rationals_cutoff_1( Numb1, Numb2, incl ).

rationals_cutoff_1( MayRat1, MayRat2, ExInCl ) :-
	rationals_is_rat( MayRat1, Nom1/Den1 ),
	rationals_is_rat( MayRat2, Nom2/Den2 ),
	FactNom is Nom1 * Den2,
	FactDen is Den1 * Nom2,
	( FactNom > FactDen -> true
		;
		rationals_cutoff_eq( ExInCl, FactNom, FactDen )
	).

rationals_cutoff_eq( incl, Fact, Fact ).

rationals_is_rat( Var, Var ) :- var(Var),!.
rationals_is_rat( Nom/Den, Nom/Den ) :- !.
rationals_is_rat( 0, 0/1 ) :- !.
rationals_is_rat( 1, 1/1 ).

rationals_simplify( Nom/Dnm, SNom/SDnm ) :-
	gcd( Nom, Dnm, Gcd ),
	SNom is Nom // Gcd,
	SDnm is Dnm // Gcd.

% rationals_iinv( Nom/Dnm, 1/Dnm 

% rationals_abs_list
% assume negative Rats have sign at the Nominator.
% no Rat is allowed with negative signs on both the 
% Nominator and Denominator.
%
rationals_abs_list( [], [] ).
rationals_abs_list( [Nom/Dnm|T], [AbsH|AbsT] ) :-
	( Nom < 0 -> 
		AbsNom is abs(Nom),
		AbsH = AbsNom / Dnm
		;
		( Nom = 0 -> 
			write( error(division_by_zero,rationals_abs_list/2) ),
			nl, abort
			;
			AbsH =  Nom / Dnm
		)
	),
	rationals_abs_list( T, AbsT ).

rationals_integer_to( Int, Int/1 ).
		
rationals_invert_approx_list( [], [] ).
rationals_invert_approx_list( [Nom/Dnm|T], [NNm/1|NT] ) :- 
	( Nom > 0 -> 
		NNm is integer( (Dnm / Nom) )
		;
		( Nom = 0 -> 
			Error = division_by_zero_while_inverting,
			Clause= rationals_invert_approx_list(
					 	[Nom/Dnm|T], [NNm/1|NT] ), 
			throw( pfd(rats(Error,Clause)) )
			;
			NNm is - integer( Dnm / Dnm )
		)
	),
	rationals_invert_approx_list( T, NT ).

rationals_invert_list( [], [] ).
rationals_invert_list( [Nom/Dnm|T], [NNm/NDm|NT] ) :- 
	( Nom > 0 -> 
		NNm = Dnm,
		NDm = Nom
		;
		( Nom = 0 -> 
			write( error(division_by_zero,rationals_invert_list/2) ),
			nl, abort
			;
			NNm = - Dnm,
			NDm = Nom
		)
	),
	rationals_invert_list( T, NT ).

gcd( M, N, C ) :-
	( N =:= 0 -> C is M
		  ;  NewN is M mod N,
		     gcd( N, NewN, C )
	).

% probability_measure_constraint( Constr, MethPrbs, ConstrProb, Measrs ) :-

rationals_to_probabilities( Rats, Probs ) :-
	rationals_add_list( Rats, Sum ),
	rationals_invert_list( [Sum], [MUs] ),
	rationals_all_multiply_list( Rats, MUs, Probs ).
	
	
measure_constraint( MethPrbs, ConstrProb, Measrs ) :-
	rationals_all_multiply_list( MethPrbs, ConstrProb, Measrs ).

is_only_rational( Rat, Goal, ArgNo ) :-
	( var(Rat) -> 
		print_message( error, domain_error(Goal,ArgNo,ratinal-(IntP/IntQ),Rat) )
		;
		(Rat = _Nmn/_Dnm -> 
			true
			;
			print_message( error, domain_error(Goal,ArgNo,ratinal-(IntP/IntQ),Rat) )
		)
	).

rationals_is_wo( Nom/Dnm, Nom/Dnm ) :-
	!.
rationals_is_wo( Float, Rat ) :-
	( Float > 1 -> 
		Rat = Integer,
		% then we have an overflow
		trace,
		( ResNom < ResDnm ->
			CrDnm is integer(ResDnm/ResNom),
			Simplified = 1 / CrDnm
			;
			CrNom is integer(ResNom/ResDnm),
			Simplified = CrNom / 1
		)
		;
