@@ -643,7 +643,7 @@ impl Price {
643643
644644#[ cfg( test) ]
645645mod test {
646- // use quickcheck::TestResult;
646+ use quickcheck:: TestResult ;
647647 use std:: convert:: TryFrom ;
648648
649649 use crate :: price:: {
@@ -2051,135 +2051,134 @@ mod test {
20512051 fails ( i64:: MIN , pc ( 100 , 10 , -9 ) , 0 , pc ( 0 , 12 , -9 ) , 0 , -9 ) ;
20522052 }
20532053
2054- // pub fn construct_quickcheck_affine_combination_price(price: i64) -> Price {
2055- // return Price {
2056- // price: price,
2057- // conf: 0,
2058- // expo: -9,
2059- // publish_time: 0,
2060- // };
2061- // }
2062-
2063- // // quickcheck to confirm affine_combination introduces no error if normalization done
2064- // explicitly // on prices first this quickcheck calls affine_combination with two sets of
2065- // almost // identical inputs: the first set has potentially unnormalized prices, the second
2066- // set // simply has the normalized versions of those prices this set of checks should pass
2067- // because // normalization is automatically performed on the prices before they are
2068- // multiplied // this set of checks passing indicates that it doesn't matter whether the
2069- // prices passed in are // normalized
2070- // #[quickcheck]
2071- // fn quickcheck_affine_combination_normalize_prices(
2072- // x1_inp: i32,
2073- // p1: i32,
2074- // x2_inp: i32,
2075- // p2: i32,
2076- // x_query_inp: i32,
2077- // ) -> TestResult {
2078- // // generating xs and prices from i32 to limit the range to reasonable values and guard
2079- // // against overflow/bespoke constraint setting for quickcheck
2080- // let y1 = construct_quickcheck_affine_combination_price(i64::try_from(p1).ok().unwrap());
2081- // let y2 = construct_quickcheck_affine_combination_price(i64::try_from(p2).ok().unwrap());
2082-
2083- // let x1 = i64::try_from(x1_inp).ok().unwrap();
2084- // let x2 = i64::try_from(x2_inp).ok().unwrap();
2085- // let x_query = i64::try_from(x_query_inp).ok().unwrap();
2086-
2087- // // stick with single expo for ease of testing and generation
2088- // let pre_add_expo = -9;
2089-
2090- // // require x2 > x1, as needed for affine_combination
2091- // if x1 >= x2 {
2092- // return TestResult::discard();
2093- // }
2094-
2095- // // original result
2096- // let result_orig = Price::affine_combination(x1, y1, x2, y2, x_query,
2097- // pre_add_expo).unwrap();
2098-
2099- // let y1_norm = y1.normalize().unwrap();
2100- // let y2_norm = y2.normalize().unwrap();
2101-
2102- // // result with normalized price inputs
2103- // let result_norm =
2104- // Price::affine_combination(x1, y1_norm, x2, y2_norm, x_query, pre_add_expo).unwrap();
2105-
2106- // // results should match exactly
2107- // TestResult::from_bool(result_norm == result_orig)
2108- // }
2109-
2110- // // quickcheck to confirm affine_combination introduces bounded error if close fraction x/y
2111- // // passed in first this quickcheck calls affine_combination with two sets of similar inputs:
2112- // // the first set has xs generated by the quickcheck generation process, leading to
2113- // potentially // inexact fractions that don't fit within 8 digits of precision the second
2114- // set "normalizes" // down to 8 digits of precision by setting x1 to 0, x2 to 100_000_000,
2115- // and xquery // proportionally based on the bounds described in the docstring of
2116- // affine_combination, we // expect error due to this to be leq 4*10^-7
2117- // #[quickcheck]
2118- // fn quickcheck_affine_combination_normalize_fractions(
2119- // x1_inp: i32,
2120- // p1: i32,
2121- // x2_inp: i32,
2122- // p2: i32,
2123- // x_query_inp: i32,
2124- // ) -> TestResult {
2125- // // generating xs and prices from i32 to limit the range to reasonable values and guard
2126- // // against overflow/bespoke constraint setting for quickcheck
2127- // let y1 = construct_quickcheck_affine_combination_price(i64::try_from(p1).ok().unwrap());
2128- // let y2 = construct_quickcheck_affine_combination_price(i64::try_from(p2).ok().unwrap());
2129-
2130- // let x1 = i64::try_from(x1_inp).ok().unwrap();
2131- // let x2 = i64::try_from(x2_inp).ok().unwrap();
2132- // let x_query = i64::try_from(x_query_inp).ok().unwrap();
2133-
2134- // // stick with single expo for ease of testing and generation
2135- // let pre_add_expo = -9;
2136-
2137- // // require x2 > x1, as needed for affine_combination
2138- // if x1 >= x2 {
2139- // return TestResult::discard();
2140- // }
2141-
2142- // // constrain x_query to be within 5 interval lengths of x1 or x2
2143- // if (x_query > x2 + 5 * (x2 - x1)) || (x_query < x1 - 5 * (x2 - x1)) {
2144- // return TestResult::discard();
2145- // }
2146-
2147- // // generate new xs based on scaling x_1 --> 0, x_2 --> 10^8
2148- // let x1_new: i64;
2149- // let xq_new: i64;
2150- // let x2_new: i64;
2151-
2152- // if x2 == 0 {
2153- // x1_new = x1;
2154- // xq_new = x_query;
2155- // x2_new = x2;
2156- // } else {
2157- // let mut frac_q2 = Price::fraction(x_query - x1, x2 - x1).unwrap();
2158- // frac_q2 = frac_q2.scale_to_exponent(-8).unwrap();
2159-
2160- // x1_new = 0;
2161- // xq_new = frac_q2.price;
2162- // x2_new = 100_000_000 as i64;
2163- // }
2164-
2165- // // original result
2166- // let result_orig = Price::affine_combination(x1, y1, x2, y2, x_query, pre_add_expo)
2167- // .unwrap()
2168- // .scale_to_exponent(-7)
2169- // .unwrap();
2170-
2171- // // xs "normalized" result
2172- // let result_norm = Price::affine_combination(x1_new, y1, x2_new, y2, xq_new, pre_add_expo)
2173- // .unwrap()
2174- // .scale_to_exponent(-7)
2175- // .unwrap();
2176-
2177- // // compute difference in prices
2178- // let price_diff = result_norm.add(&result_orig.cmul(-1, 0).unwrap()).unwrap();
2179-
2180- // // results should differ by less than 4*10^-7
2181- // TestResult::from_bool((price_diff.price < 4) && (price_diff.price > -4))
2182- // }
2054+ pub fn construct_quickcheck_affine_combination_price ( price : i64 ) -> Price {
2055+ return Price {
2056+ price : price,
2057+ conf : 0 ,
2058+ expo : -9 ,
2059+ publish_time : 0 ,
2060+ } ;
2061+ }
2062+
2063+ // quickcheck to confirm affine_combination introduces no error if normalization done
2064+ // explicitly on prices first this quickcheck calls affine_combination with two sets of
2065+ // almost identical inputs: the first set has potentially unnormalized prices, the second
2066+ // set simply has the normalized versions of those prices this set of checks should pass
2067+ // because normalization is automatically performed on the prices before they are
2068+ // multiplied this set of checks passing indicates that it doesn't matter whether the
2069+ // prices passed in are normalized
2070+ #[ quickcheck]
2071+ fn quickcheck_affine_combination_normalize_prices (
2072+ x1_inp : i32 ,
2073+ p1 : i32 ,
2074+ x2_inp : i32 ,
2075+ p2 : i32 ,
2076+ x_query_inp : i32 ,
2077+ ) -> TestResult {
2078+ // generating xs and prices from i32 to limit the range to reasonable values and guard
2079+ // against overflow/bespoke constraint setting for quickcheck
2080+ let y1 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p1) . ok ( ) . unwrap ( ) ) ;
2081+ let y2 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p2) . ok ( ) . unwrap ( ) ) ;
2082+
2083+ let x1 = i64:: try_from ( x1_inp) . ok ( ) . unwrap ( ) ;
2084+ let x2 = i64:: try_from ( x2_inp) . ok ( ) . unwrap ( ) ;
2085+ let x_query = i64:: try_from ( x_query_inp) . ok ( ) . unwrap ( ) ;
2086+
2087+ // stick with single expo for ease of testing and generation
2088+ let pre_add_expo = -9 ;
2089+
2090+ // require x2 > x1, as needed for affine_combination
2091+ if x1 >= x2 {
2092+ return TestResult :: discard ( ) ;
2093+ }
2094+
2095+ // original result
2096+ let result_orig = Price :: affine_combination ( x1, y1, x2, y2, x_query, pre_add_expo) . unwrap ( ) ;
2097+
2098+ let y1_norm = y1. normalize ( ) . unwrap ( ) ;
2099+ let y2_norm = y2. normalize ( ) . unwrap ( ) ;
2100+
2101+ // result with normalized price inputs
2102+ let result_norm =
2103+ Price :: affine_combination ( x1, y1_norm, x2, y2_norm, x_query, pre_add_expo) . unwrap ( ) ;
2104+
2105+ // results should match exactly
2106+ TestResult :: from_bool ( result_norm == result_orig)
2107+ }
2108+
2109+ // quickcheck to confirm affine_combination introduces bounded error if close fraction x/y
2110+ // passed in first this quickcheck calls affine_combination with two sets of similar inputs:
2111+ // the first set has xs generated by the quickcheck generation process, leading to
2112+ // potentially inexact fractions that don't fit within 8 digits of precision the second
2113+ // set "normalizes" down to 8 digits of precision by setting x1 to 0, x2 to 100_000_000,
2114+ // and xquery proportionally based on the bounds described in the docstring of
2115+ // affine_combination, we expect error due to this to be leq 4*10^-7
2116+ #[ quickcheck]
2117+ fn quickcheck_affine_combination_normalize_fractions (
2118+ x1_inp : i32 ,
2119+ p1 : i32 ,
2120+ x2_inp : i32 ,
2121+ p2 : i32 ,
2122+ x_query_inp : i32 ,
2123+ ) -> TestResult {
2124+ // generating xs and prices from i32 to limit the range to reasonable values and guard
2125+ // against overflow/bespoke constraint setting for quickcheck
2126+ let y1 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p1) . ok ( ) . unwrap ( ) ) ;
2127+ let y2 = construct_quickcheck_affine_combination_price ( i64:: try_from ( p2) . ok ( ) . unwrap ( ) ) ;
2128+
2129+ let x1 = i64:: try_from ( x1_inp) . ok ( ) . unwrap ( ) ;
2130+ let x2 = i64:: try_from ( x2_inp) . ok ( ) . unwrap ( ) ;
2131+ let x_query = i64:: try_from ( x_query_inp) . ok ( ) . unwrap ( ) ;
2132+
2133+ // stick with single expo for ease of testing and generation
2134+ let pre_add_expo = -9 ;
2135+
2136+ // require x2 > x1, as needed for affine_combination
2137+ if x1 >= x2 {
2138+ return TestResult :: discard ( ) ;
2139+ }
2140+
2141+ // constrain x_query to be within 5 interval lengths of x1 or x2
2142+ if ( x_query > x2 + 5 * ( x2 - x1) ) || ( x_query < x1 - 5 * ( x2 - x1) ) {
2143+ return TestResult :: discard ( ) ;
2144+ }
2145+
2146+ // generate new xs based on scaling x_1 --> 0, x_2 --> 10^8
2147+ let x1_new: i64 ;
2148+ let xq_new: i64 ;
2149+ let x2_new: i64 ;
2150+
2151+ if x2 == 0 {
2152+ x1_new = x1;
2153+ xq_new = x_query;
2154+ x2_new = x2;
2155+ } else {
2156+ let mut frac_q2 = Price :: fraction ( x_query - x1, x2 - x1) . unwrap ( ) ;
2157+ frac_q2 = frac_q2. scale_to_exponent ( -8 ) . unwrap ( ) ;
2158+
2159+ x1_new = 0 ;
2160+ xq_new = frac_q2. price ;
2161+ x2_new = 100_000_000 as i64 ;
2162+ }
2163+
2164+ // original result
2165+ let result_orig = Price :: affine_combination ( x1, y1, x2, y2, x_query, pre_add_expo)
2166+ . unwrap ( )
2167+ . scale_to_exponent ( -7 )
2168+ . unwrap ( ) ;
2169+
2170+ // xs "normalized" result
2171+ let result_norm = Price :: affine_combination ( x1_new, y1, x2_new, y2, xq_new, pre_add_expo)
2172+ . unwrap ( )
2173+ . scale_to_exponent ( -7 )
2174+ . unwrap ( ) ;
2175+
2176+ // compute difference in prices
2177+ let price_diff = result_norm. add ( & result_orig. cmul ( -1 , 0 ) . unwrap ( ) ) . unwrap ( ) ;
2178+
2179+ // results should differ by less than 4*10^-7
2180+ TestResult :: from_bool ( ( price_diff. price < 4 ) && ( price_diff. price > -4 ) )
2181+ }
21832182
21842183 #[ test]
21852184 fn test_fraction ( ) {
0 commit comments