From a3bb288f015b52ad23e0ad1cbbdc76bef8701e3e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 28 Apr 2020 19:22:20 -0600 Subject: [PATCH 1/4] check that lower bound on term expansion drain is below the len of the term expansion vector, queue (#416) --- src/prolog/machine/code_repo.rs | 21 ++++++++++++++++----- src/prolog/machine/term_expansion.rs | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/prolog/machine/code_repo.rs b/src/prolog/machine/code_repo.rs index eba8c5c9..78f3a548 100644 --- a/src/prolog/machine/code_repo.rs +++ b/src/prolog/machine/code_repo.rs @@ -53,12 +53,23 @@ impl CodeRepo { self.term_dir .get_mut(&key) .map(|entry| { - ( - Predicate((entry.0).0.drain(len..).collect()), - entry.1.drain(queue_len..).collect(), - ) + let terms = + if len < (entry.0).0.len() { + (entry.0).0.drain(len ..).collect() + } else { + vec![] + }; + + let queue = + if queue_len < entry.1.len() { + entry.1.drain(queue_len ..).collect() + } else { + VecDeque::new() + }; + + (Predicate(terms), queue) }) - .unwrap_or((Predicate::new(), VecDeque::from(vec![]))) + .unwrap_or((Predicate::new(), VecDeque::new())) } pub(crate) diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 06d7b3be..d2b6419c 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -181,6 +181,7 @@ impl<'a> TermStream<'a> { te_len, te_queue_len, ); + let goal_expansion_additions = self.wam.code_repo.truncate_terms( (clause_name!("goal_expansion"), 2), ge_len, From 1d339f74d14d38b8173e43e6983d336c91f8e8d5 Mon Sep 17 00:00:00 2001 From: notoria Date: Wed, 29 Apr 2020 02:44:13 +0200 Subject: [PATCH 2/4] Implemented predicate mediants/2 with Stern-Brocot tree --- src/prolog/lib/arithmetic.pl | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/prolog/lib/arithmetic.pl b/src/prolog/lib/arithmetic.pl index 406e8473..ccbdc0dd 100644 --- a/src/prolog/lib/arithmetic.pl +++ b/src/prolog/lib/arithmetic.pl @@ -1,4 +1,4 @@ -:- module(arithmetic, [msb/2, lsb/2]). +:- module(arithmetic, [lsb/2, msb/2, mediants/2]). :- use_module(library(error)). @@ -25,3 +25,28 @@ msb_(X, M, N) :- X1 is X >> 1, M1 is M + 1, msb_(X1, M1, N). + +mediants_precision(1.0e-15). + +mediants(Real, Fraction) :- + builtins:must_be_number(Real, mediants), + Fraction = P/Q, + mediants_precision(Eps), + R is abs(Real), + stern_brocot(Eps, R, P1/Q), + P is sign(Real) * P1. + +% If 0 <= Eps <= 1e-16 then the search is for "infinite" precision. +stern_brocot(Eps, Real, Fraction) :- + Rn is Real - Eps, + Rp is Real + Eps, + stern_brocot_(Rn, Rp, 0/1, 1/0, Fraction). + +stern_brocot_(Rn, Rp, A/B, C/D, Fraction) :- + M0 is A + C, + M1 is B + D, + M is M0 / M1, + ( M < Rn -> stern_brocot_(Rn, Rp, M0/M1, C/D, Fraction) + ; M > Rp -> stern_brocot_(Rn, Rp, A/B, M0/M1, Fraction) + ; Fraction = M0/M1 + ). From f7b49740c19e4adaeda2a21c9a224ce44ab5487d Mon Sep 17 00:00:00 2001 From: notoria Date: Wed, 29 Apr 2020 14:18:20 +0200 Subject: [PATCH 3/4] Removed predicate mediants/2 and added stern_brocot/3 --- src/prolog/lib/arithmetic.pl | 77 +++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/prolog/lib/arithmetic.pl b/src/prolog/lib/arithmetic.pl index ccbdc0dd..7ba31567 100644 --- a/src/prolog/lib/arithmetic.pl +++ b/src/prolog/lib/arithmetic.pl @@ -1,4 +1,4 @@ -:- module(arithmetic, [lsb/2, msb/2, mediants/2]). +:- module(arithmetic, [lsb/2, msb/2, stern_brocot/3]). :- use_module(library(error)). @@ -26,21 +26,65 @@ msb_(X, M, N) :- M1 is M + 1, msb_(X1, M1, N). -mediants_precision(1.0e-15). +stern_brocot(E0/E1, Fraction0, Fraction) :- + P1/Q1 = Fraction0, + !, + ( \+ integer(E0) -> type_error(integer, E0, stern_brocot/3) + ; \+ integer(E1) -> type_error(integer, E1, stern_brocot/3) + ; \+ integer(P1) -> type_error(integer, P1, stern_brocot/3) + ; \+ integer(Q1) -> type_error(integer, Q1, stern_brocot/3) + ; S is sign(E0) * sign(E1), S < 0 -> + domain_error(not_less_than_zero, E0/E1, stern_brocot/3) + ; P2 is abs(P1), + Q2 is abs(Q1), + Qn1n is P2 * E1 - Q2 * E0, + Qn1d is Q2 * E1, + simplify_fraction(Qn1n/Qn1d, Qn1), + Qp1n is P2 * E1 + Q2 * E0, + Qp1d = Qn1d, + simplify_fraction(Qp1n/Qp1d, Qp1), + fraction_stern_brocot_(Qn1, Qp1, 0/1, 1/0, P3/Q3), + P4 is sign(P1) * sign(Q1) * P3, + Fraction = P4/Q3 + ). -mediants(Real, Fraction) :- - builtins:must_be_number(Real, mediants), - Fraction = P/Q, - mediants_precision(Eps), - R is abs(Real), - stern_brocot(Eps, R, P1/Q), - P is sign(Real) * P1. +% If 0 <= Eps0 <= 1e-16 then the search is for "infinite" precision. +stern_brocot(Eps0, Real0, Fraction) :- + ( Real0 = R1/R2 -> + builtins:must_be_number(R1, stern_brocot/3), + builtins:must_be_number(R2, stern_brocot/3), + Real is R1/R2 + ; builtins:must_be_number(Real0, stern_brocot/3), + Real = Real0 + ), + ( Eps0 = E0/E1 -> + builtins:must_be_number(E0, stern_brocot/3), + builtins:must_be_number(E1, stern_brocot/3), + % Eps is Eps0 % doesn't work + Eps is E0/E1 + ; Eps = Eps0 + ), + S is sign(Eps), + ( S < 0 -> domain_error(not_less_than_zero, Eps0, stern_brocot/3) + ; Rn is abs(Real) - Eps, + Rp is abs(Real) + Eps, + stern_brocot_(Rn, Rp, 0/1, 1/0, P1/Q), + P is sign(Real) * P1, + Fraction = P/Q + ). -% If 0 <= Eps <= 1e-16 then the search is for "infinite" precision. -stern_brocot(Eps, Real, Fraction) :- - Rn is Real - Eps, - Rp is Real + Eps, - stern_brocot_(Rn, Rp, 0/1, 1/0, Fraction). +fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :- + Fn1 is A + C, + Fd1 is B + D, + simplify_fraction(Fn1/Fd1, Fn/Fd), + S1 is sign(Fn * Qnd - Fd * Qnn), + S2 is sign(Fn * Qpd - Fd * Qpn), + ( S1 < 0 -> + fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, Fn/Fd, C/D, Fraction) + ; S2 > 0 -> + fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, Fn/Fd, Fraction) + ; Fraction = Fn/Fd + ). stern_brocot_(Rn, Rp, A/B, C/D, Fraction) :- M0 is A + C, @@ -50,3 +94,8 @@ stern_brocot_(Rn, Rp, A/B, C/D, Fraction) :- ; M > Rp -> stern_brocot_(Rn, Rp, A/B, M0/M1, Fraction) ; Fraction = M0/M1 ). + +simplify_fraction(A0/B0, A/B) :- + G is gcd(A0, B0), + A is A0 div G, + B is B0 div G. From a3715802013898b1375ff5e338d67ec9cbb88bf2 Mon Sep 17 00:00:00 2001 From: notoria Date: Wed, 29 Apr 2020 18:27:34 +0200 Subject: [PATCH 4/4] Add rational_numerator_denominator/3, number_to_rational/2 and renamed stern_brocot/3 to number_to_rational/3 --- src/prolog/lib/arithmetic.pl | 119 ++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/src/prolog/lib/arithmetic.pl b/src/prolog/lib/arithmetic.pl index 7ba31567..310d08a0 100644 --- a/src/prolog/lib/arithmetic.pl +++ b/src/prolog/lib/arithmetic.pl @@ -1,6 +1,10 @@ -:- module(arithmetic, [lsb/2, msb/2, stern_brocot/3]). +:- module(arithmetic, [lsb/2, msb/2, number_to_rational/2, + number_to_rational/3, + rational_numerator_denominator/3]). +:- use_module(library(charsio), [write_term_to_chars/3]). :- use_module(library(error)). +:- use_module(library(lists), [append/3, member/2]). lsb(X, N) :- builtins:must_be_number(X, lsb/2), @@ -26,76 +30,79 @@ msb_(X, M, N) :- M1 is M + 1, msb_(X1, M1, N). -stern_brocot(E0/E1, Fraction0, Fraction) :- - P1/Q1 = Fraction0, - !, - ( \+ integer(E0) -> type_error(integer, E0, stern_brocot/3) - ; \+ integer(E1) -> type_error(integer, E1, stern_brocot/3) - ; \+ integer(P1) -> type_error(integer, P1, stern_brocot/3) - ; \+ integer(Q1) -> type_error(integer, Q1, stern_brocot/3) - ; S is sign(E0) * sign(E1), S < 0 -> - domain_error(not_less_than_zero, E0/E1, stern_brocot/3) - ; P2 is abs(P1), - Q2 is abs(Q1), - Qn1n is P2 * E1 - Q2 * E0, - Qn1d is Q2 * E1, - simplify_fraction(Qn1n/Qn1d, Qn1), - Qp1n is P2 * E1 + Q2 * E0, - Qp1d = Qn1d, - simplify_fraction(Qp1n/Qp1d, Qp1), - fraction_stern_brocot_(Qn1, Qp1, 0/1, 1/0, P3/Q3), - P4 is sign(P1) * sign(Q1) * P3, - Fraction = P4/Q3 - ). +number_to_rational(Real0, Fraction) :- + ( var(Real0) -> instantiation_error(number_to_rational/2) + ; Real0 = R1/R2 -> + ( member(R, [R1, R2]), \+ number(R) -> + type_error(number, R, number_to_rational/2) + ; Real = R1/R2 + ) + ; number(Real0), + Real = Real0/1 + ), + number_to_rational(1.0e-6/1, Real, Fraction). % If 0 <= Eps0 <= 1e-16 then the search is for "infinite" precision. -stern_brocot(Eps0, Real0, Fraction) :- - ( Real0 = R1/R2 -> - builtins:must_be_number(R1, stern_brocot/3), - builtins:must_be_number(R2, stern_brocot/3), - Real is R1/R2 - ; builtins:must_be_number(Real0, stern_brocot/3), - Real = Real0 +number_to_rational(Eps0, Real0, Fraction) :- + ( var(Eps0) -> instantiation_error(number_to_rational/3) + ; Eps0 = E0/E1 -> + ( member(E, [E0, E1]), \+ number(E) -> + type_error(number, E, number_to_rational/3) + ; Eps = E0/E1 + ) + ; number(Eps0), + Eps = Eps0/1 ), - ( Eps0 = E0/E1 -> - builtins:must_be_number(E0, stern_brocot/3), - builtins:must_be_number(E1, stern_brocot/3), - % Eps is Eps0 % doesn't work - Eps is E0/E1 - ; Eps = Eps0 + ( var(Real0) -> instantiation_error(number_to_rational/3) + ; Real0 = R1/R2 -> + ( member(R, [R1, R2]), \+ number(R) -> + type_error(number, R, number_to_rational/3) + ; Real = R1/R2 + ) + ; number(Real0), + Real = Real0/1 ), - S is sign(Eps), - ( S < 0 -> domain_error(not_less_than_zero, Eps0, stern_brocot/3) - ; Rn is abs(Real) - Eps, - Rp is abs(Real) + Eps, - stern_brocot_(Rn, Rp, 0/1, 1/0, P1/Q), - P is sign(Real) * P1, - Fraction = P/Q + E0/E1 = Eps, + P0/Q0 = Real, + S is sign(E0) * sign(E1), + ( S < 0 -> domain_error(not_less_than_zero, Eps0, number_to_rational/3) + ; P1 is abs(P0), + Q1 is abs(Q0), + Qn1n is P1 * E1 - Q1 * E0, + Qn1d is Q1 * E1, + Qn1 = Qn1n/Qn1d, + Qp1n is P1 * E1 + Q1 * E0, + Qp1d = Qn1d, + Qp1 = Qp1n/Qp1d, + stern_brocot_(Qn1, Qp1, 0/1, 1/0, P2/Q2), + P3 is sign(P0) * sign(Q0) * P2, + Fraction is P3 rdiv Q2 ). -fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :- +number(X) :- + ( integer(X) + ; float(X) + ; rational(X) + ). + +stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :- Fn1 is A + C, Fd1 is B + D, simplify_fraction(Fn1/Fd1, Fn/Fd), S1 is sign(Fn * Qnd - Fd * Qnn), S2 is sign(Fn * Qpd - Fd * Qpn), - ( S1 < 0 -> - fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, Fn/Fd, C/D, Fraction) - ; S2 > 0 -> - fraction_stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, Fn/Fd, Fraction) + ( S1 < 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, Fn/Fd, C/D, Fraction) + ; S2 > 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, Fn/Fd, Fraction) ; Fraction = Fn/Fd ). -stern_brocot_(Rn, Rp, A/B, C/D, Fraction) :- - M0 is A + C, - M1 is B + D, - M is M0 / M1, - ( M < Rn -> stern_brocot_(Rn, Rp, M0/M1, C/D, Fraction) - ; M > Rp -> stern_brocot_(Rn, Rp, A/B, M0/M1, Fraction) - ; Fraction = M0/M1 - ). - simplify_fraction(A0/B0, A/B) :- G is gcd(A0, B0), A is A0 div G, B is B0 div G. + +rational_numerator_denominator(R, N, D) :- + write_term_to_chars(R, [], Cs), + append(Ns, [' ', r, d, i, v, ' '|Ds], Cs), + number_chars(N, Ns), + number_chars(D, Ds).