tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

piecewise_linear.rs (11301B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 use euclid::approxeq::ApproxEq;
      6 use style::piecewise_linear::{PiecewiseLinearFunction, PiecewiseLinearFunctionBuilder};
      7 
      8 fn get_linear_keyword_equivalent() -> PiecewiseLinearFunction {
      9    PiecewiseLinearFunctionBuilder::default().build()
     10 }
     11 #[test]
     12 fn linear_keyword_equivalent_in_bound() {
     13    let function = get_linear_keyword_equivalent();
     14    assert!(function.at(0.).approx_eq(&0.));
     15    assert!(function.at(0.5).approx_eq(&0.5));
     16    assert!(function.at(1.0).approx_eq(&1.0));
     17 }
     18 
     19 #[test]
     20 fn linear_keyword_equivalent_out_of_bounds() {
     21    let function = get_linear_keyword_equivalent();
     22    assert!(function.at(-0.1).approx_eq(&-0.1));
     23    assert!(function.at(1.1).approx_eq(&1.1));
     24 }
     25 
     26 fn get_const_function() -> PiecewiseLinearFunction {
     27    let mut builder = PiecewiseLinearFunctionBuilder::default();
     28    builder.push(CONST_VALUE as f32, None);
     29    builder.build()
     30 }
     31 
     32 const CONST_VALUE: f32 = 0.2;
     33 
     34 #[test]
     35 fn const_function() {
     36    let function = get_const_function();
     37    assert!(function.at(0.).approx_eq(&CONST_VALUE));
     38    assert!(function.at(0.5).approx_eq(&CONST_VALUE));
     39    assert!(function.at(1.0).approx_eq(&CONST_VALUE));
     40 }
     41 
     42 #[test]
     43 fn const_function_out_of_bounds() {
     44    let function = get_const_function();
     45    assert!(function.at(-0.1).approx_eq(&CONST_VALUE));
     46    assert!(function.at(1.1).approx_eq(&CONST_VALUE));
     47 }
     48 
     49 #[test]
     50 fn implied_input_spacing() {
     51    let explicit_spacing = {
     52        let mut builder = PiecewiseLinearFunctionBuilder::default();
     53        builder.push(0.0, Some(0.0));
     54        builder.push(1.0, Some(1.0));
     55        builder.build()
     56    };
     57    let implied_spacing = {
     58        let mut builder = PiecewiseLinearFunctionBuilder::default();
     59        builder.push(0.0, None);
     60        builder.push(1.0, None);
     61        builder.build()
     62    };
     63 
     64    assert!(implied_spacing.at(0.).approx_eq(&explicit_spacing.at(0.)));
     65    assert!(implied_spacing.at(0.5).approx_eq(&explicit_spacing.at(0.5)));
     66    assert!(implied_spacing.at(1.0).approx_eq(&explicit_spacing.at(1.0)));
     67 }
     68 
     69 #[test]
     70 fn interpolation() {
     71    let interpolate = {
     72        let mut builder = PiecewiseLinearFunctionBuilder::default();
     73        builder.push(0.0, None);
     74        builder.push(0.7, None);
     75        builder.push(1.0, None);
     76        builder.build()
     77    };
     78    assert!(interpolate.at(0.1).approx_eq(&0.14));
     79    assert!(interpolate.at(0.25).approx_eq(&0.35));
     80    assert!(interpolate.at(0.45).approx_eq(&0.63));
     81    assert!(interpolate.at(0.7).approx_eq(&0.82));
     82    assert!(interpolate.at(0.75).approx_eq(&0.85));
     83    assert!(interpolate.at(0.95).approx_eq(&0.97));
     84 }
     85 
     86 #[test]
     87 fn implied_multiple_input_spacing() {
     88    let multiple_implied = {
     89        let mut builder = PiecewiseLinearFunctionBuilder::default();
     90        builder.push(0.0, None);
     91        builder.push(0.8, None);
     92        builder.push(0.6, None);
     93        builder.push(0.4, None);
     94        builder.push(0.5, Some(0.4));
     95        builder.push(0.1, None);
     96        builder.push(0.9, None);
     97        builder.push(1.0, None);
     98        builder.build()
     99    };
    100    assert!(multiple_implied.at(0.1).approx_eq(&0.8));
    101    assert!(multiple_implied.at(0.2).approx_eq(&0.6));
    102    assert!(multiple_implied.at(0.3).approx_eq(&0.4));
    103    assert!(multiple_implied.at(0.4).approx_eq(&0.5));
    104    assert!(multiple_implied.at(0.6).approx_eq(&0.1));
    105    assert!(multiple_implied.at(0.8).approx_eq(&0.9));
    106    assert!(multiple_implied.at(1.).approx_eq(&1.));
    107 }
    108 
    109 #[test]
    110 fn nonzero_edge_values() {
    111    let nonzero_edges = {
    112        let mut builder = PiecewiseLinearFunctionBuilder::default();
    113        builder.push(0.1, Some(0.0));
    114        builder.push(0.7, Some(1.0));
    115        builder.build()
    116    };
    117    assert!(nonzero_edges.at(0.).approx_eq(&0.1));
    118    assert!(nonzero_edges.at(0.5).approx_eq(&0.4));
    119    assert!(nonzero_edges.at(1.0).approx_eq(&0.7));
    120 }
    121 
    122 #[test]
    123 fn out_of_bounds_extrapolate() {
    124    // General case: extrapolate from the edges' slope
    125    let oob_extend = {
    126        let mut builder = PiecewiseLinearFunctionBuilder::default();
    127        builder.push(0.0, None);
    128        builder.push(0.7, None);
    129        builder.push(1.0, None);
    130        builder.build()
    131    };
    132    assert!(oob_extend.at(-0.25).approx_eq(&-0.35));
    133    assert!(oob_extend.at(1.25).approx_eq(&1.15));
    134 }
    135 
    136 #[test]
    137 fn out_of_bounds_flat() {
    138    // Repeated endpoints: flat extrapolation out-of-bounds
    139    let oob_flat = {
    140        let mut builder = PiecewiseLinearFunctionBuilder::default();
    141        builder.push(0.0, Some(0.0));
    142        builder.push(0.0, Some(0.0));
    143        builder.push(0.7, None);
    144        builder.push(1.0, Some(1.0));
    145        builder.push(1.0, Some(1.0));
    146        builder.build()
    147    };
    148    assert!(oob_flat.at(0.0).approx_eq(&oob_flat.at(-0.25)));
    149    assert!(oob_flat.at(1.0).approx_eq(&oob_flat.at(1.25)));
    150 }
    151 
    152 #[test]
    153 fn flat_region() {
    154    let flat = {
    155        let mut builder = PiecewiseLinearFunctionBuilder::default();
    156        builder.push(0.0, Some(0.0));
    157        builder.push(0.5, Some(0.25));
    158        builder.push(0.5, Some(0.7));
    159        builder.push(1.0, Some(1.0));
    160        builder.build()
    161    };
    162    assert!(flat.at(0.125).approx_eq(&0.25));
    163    assert!(flat.at(0.5).approx_eq(&0.5));
    164    assert!(flat.at(0.85).approx_eq(&0.75));
    165 }
    166 
    167 #[test]
    168 fn step() {
    169    let step = {
    170        let mut builder = PiecewiseLinearFunctionBuilder::default();
    171        builder.push(0.0, Some(0.0));
    172        builder.push(0.0, Some(0.5));
    173        builder.push(1.0, Some(0.5));
    174        builder.push(1.0, Some(1.0));
    175        builder.build()
    176    };
    177    assert!(step.at(0.25).approx_eq(&0.0));
    178    // At the discontinuity, take the right hand side value
    179    assert!(step.at(0.5).approx_eq(&1.0));
    180    assert!(step.at(0.75).approx_eq(&1.0));
    181 }
    182 
    183 #[test]
    184 fn step_multiple_conflicting() {
    185    let step = {
    186        let mut builder = PiecewiseLinearFunctionBuilder::default();
    187        builder.push(0.0, Some(0.0));
    188        builder.push(0.0, Some(0.5));
    189        builder.push(0.75, Some(0.5));
    190        builder.push(0.75, Some(0.5));
    191        builder.push(1.0, Some(0.5));
    192        builder.push(1.0, Some(1.0));
    193        builder.build()
    194    };
    195    assert!(step.at(0.25).approx_eq(&0.0));
    196    assert!(step.at(0.5).approx_eq(&1.0));
    197    assert!(step.at(0.75).approx_eq(&1.0));
    198 }
    199 
    200 #[test]
    201 fn always_monotonic() {
    202    let monotonic = {
    203        let mut builder = PiecewiseLinearFunctionBuilder::default();
    204        builder.push(0.0, Some(0.0));
    205        builder.push(0.3, Some(0.5));
    206        builder.push(0.4, Some(0.4));
    207        builder.push(1.0, Some(1.0));
    208        builder.build()
    209    };
    210    assert!(monotonic.at(0.25).approx_eq(&0.15));
    211    // A discontinuity at x = 0.5 from y = 0.3 to 0.4
    212    assert!(monotonic.at(0.5).approx_eq(&0.4));
    213    assert!(monotonic.at(0.6).approx_eq(&0.52));
    214 }
    215 
    216 #[test]
    217 fn always_monotonic_flat() {
    218    let monotonic = {
    219        let mut builder = PiecewiseLinearFunctionBuilder::default();
    220        builder.push(0.0, Some(0.0));
    221        builder.push(0.2, Some(0.2));
    222        builder.push(0.4, Some(0.1));
    223        builder.push(0.4, Some(0.15));
    224        builder.push(1.0, Some(1.0));
    225        builder.build()
    226    };
    227    assert!(monotonic.at(0.2).approx_eq(&0.4));
    228    // A discontinuity at x = 0.2 from y = 0.2 to 0.4
    229    assert!(monotonic.at(0.3).approx_eq(&0.475));
    230 }
    231 
    232 #[test]
    233 fn always_monotonic_flat_backwards() {
    234    let monotonic = {
    235        let mut builder = PiecewiseLinearFunctionBuilder::default();
    236        builder.push(0.0, Some(0.0));
    237        builder.push(0.2, Some(0.2));
    238        builder.push(0.3, Some(0.3));
    239        builder.push(0.3, Some(0.2));
    240        builder.push(1.0, Some(1.0));
    241        builder.build()
    242    };
    243    assert!(monotonic.at(0.2).approx_eq(&0.2));
    244    assert!(monotonic.at(0.3).approx_eq(&0.3));
    245    assert!(monotonic.at(0.4).approx_eq(&0.4));
    246 }
    247 
    248 #[test]
    249 fn input_out_of_bounds() {
    250    let oob = {
    251        let mut builder = PiecewiseLinearFunctionBuilder::default();
    252        builder.push(0.0, Some(-0.5));
    253        builder.push(1.0, Some(1.5));
    254        builder.build()
    255    };
    256    assert!(oob.at(-0.5).approx_eq(&0.0));
    257    assert!(oob.at(0.0).approx_eq(&0.25));
    258    assert!(oob.at(0.5).approx_eq(&0.5));
    259    assert!(oob.at(1.0).approx_eq(&0.75));
    260    assert!(oob.at(1.5).approx_eq(&1.0));
    261 }
    262 
    263 #[test]
    264 fn invalid_builder_input() {
    265    let built_from_invalid = {
    266        let mut builder = PiecewiseLinearFunctionBuilder::default();
    267        builder.push(0.0, Some(f32::NEG_INFINITY));
    268        builder.push(0.7, Some(f32::NAN));
    269        builder.push(1.0, Some(f32::INFINITY));
    270        builder.build()
    271    };
    272    let equivalent = {
    273        let mut builder = PiecewiseLinearFunctionBuilder::default();
    274        builder.push(0.0, None);
    275        builder.push(0.7, None);
    276        builder.push(1.0, None);
    277        builder.build()
    278    };
    279 
    280    assert!(built_from_invalid.at(0.0).approx_eq(&equivalent.at(0.0)));
    281    assert!(built_from_invalid.at(0.25).approx_eq(&equivalent.at(0.25)));
    282    assert!(built_from_invalid.at(0.5).approx_eq(&equivalent.at(0.5)));
    283    assert!(built_from_invalid.at(0.75).approx_eq(&equivalent.at(0.75)));
    284    assert!(built_from_invalid.at(1.0).approx_eq(&equivalent.at(1.0)));
    285 }
    286 
    287 #[test]
    288 fn input_domain_not_complete() {
    289    let not_covered = {
    290        let mut builder = PiecewiseLinearFunctionBuilder::default();
    291        builder.push(0.2, Some(0.2));
    292        builder.push(0.8, Some(0.8));
    293        builder.build()
    294    };
    295    assert!(not_covered.at(0.0).approx_eq(&0.0));
    296    assert!(not_covered.at(0.5).approx_eq(&0.5));
    297    assert!(not_covered.at(1.0).approx_eq(&1.0));
    298 }
    299 
    300 #[test]
    301 fn input_second_negative() {
    302    let function = {
    303        let mut builder = PiecewiseLinearFunctionBuilder::default();
    304        builder.push(0.0, None);
    305        builder.push(0.0, Some(-0.1));
    306        builder.push(0.3, Some(-0.05));
    307        builder.push(0.5, None);
    308        builder.push(0.2, Some(0.6));
    309        builder.push(1.0, None);
    310        builder.build()
    311    };
    312    let equivalent = {
    313        let mut builder = PiecewiseLinearFunctionBuilder::default();
    314        builder.push(0.0, Some(0.0));
    315        builder.push(0.0, Some(0.0));
    316        builder.push(0.3, Some(0.0));
    317        builder.push(0.5, Some(0.3));
    318        builder.push(0.2, Some(0.6));
    319        builder.push(1.0, Some(1.0));
    320        builder.build()
    321    };
    322    assert!(function.at(-0.1).approx_eq(&equivalent.at(-0.1)));
    323    assert!(function.at(0.0).approx_eq(&equivalent.at(0.0)));
    324    assert!(function.at(0.3).approx_eq(&equivalent.at(0.3)));
    325    assert!(function.at(0.6).approx_eq(&equivalent.at(0.6)));
    326    assert!(function.at(1.0).approx_eq(&equivalent.at(1.0)));
    327 }
    328 
    329 #[test]
    330 fn input_second_last_above_1() {
    331    let function = {
    332        let mut builder = PiecewiseLinearFunctionBuilder::default();
    333        builder.push(0.0, Some(0.0));
    334        builder.push(1.0, Some(2.0));
    335        builder.push(1.0, None);
    336        builder.build()
    337    };
    338    assert!(function.at(-0.5).approx_eq(&-0.25));
    339    assert!(function.at(0.0).approx_eq(&0.0));
    340    assert!(function.at(0.5).approx_eq(&0.25));
    341    assert!(function.at(1.0).approx_eq(&0.5));
    342    assert!(function.at(1.5).approx_eq(&0.75));
    343    assert!(function.at(2.0).approx_eq(&1.0));
    344    assert!(function.at(3.0).approx_eq(&1.0));
    345 }