6
6
// option. This file may not be copied, modified, or distributed
7
7
// except according to those terms.
8
8
9
- use std:: ops:: Add ;
10
- use libnum:: { self , Zero , Float } ;
9
+ use std:: ops:: { Add , Sub , Div , Mul } ;
10
+ use libnum:: { self , Zero , Float , FromPrimitive } ;
11
11
use itertools:: free:: enumerate;
12
12
13
13
use imp_prelude:: * ;
@@ -34,14 +34,25 @@ pub trait Interpolate<T> {
34
34
fn upper_index ( q : f64 , len : usize ) -> usize {
35
35
Self :: float_percentile_index ( q, len) . ceil ( ) as usize
36
36
}
37
+
38
+ fn float_percentile_index_fraction ( q : f64 , len : usize ) -> f64 {
39
+ Self :: float_percentile_index ( q, len) - ( Self :: lower_index ( q, len) as f64 )
40
+ }
41
+
37
42
fn needs_lower ( q : f64 , len : usize ) -> bool ;
38
43
fn needs_upper ( q : f64 , len : usize ) -> bool ;
39
- fn interpolate ( lower : Option < T > , upper : Option < T > , q : f64 , len : usize ) -> T ;
44
+ fn interpolate < D > ( lower : Option < Array < T , D > > ,
45
+ upper : Option < Array < T , D > > ,
46
+ q : f64 ,
47
+ len : usize ) -> Array < T , D >
48
+ where D : Dimension ;
40
49
}
41
50
42
51
pub struct Upper ;
43
52
pub struct Lower ;
44
53
pub struct Nearest ;
54
+ pub struct Midpoint ;
55
+ pub struct Linear ;
45
56
46
57
impl < T > Interpolate < T > for Upper {
47
58
fn needs_lower ( _q : f64 , _len : usize ) -> bool {
@@ -50,7 +61,10 @@ impl<T> Interpolate<T> for Upper {
50
61
fn needs_upper ( _q : f64 , _len : usize ) -> bool {
51
62
true
52
63
}
53
- fn interpolate ( _lower : Option < T > , upper : Option < T > , _q : f64 , _len : usize ) -> T {
64
+ fn interpolate < D > ( _lower : Option < Array < T , D > > ,
65
+ upper : Option < Array < T , D > > ,
66
+ _q : f64 ,
67
+ _len : usize ) -> Array < T , D > {
54
68
upper. unwrap ( )
55
69
}
56
70
}
@@ -62,7 +76,10 @@ impl<T> Interpolate<T> for Lower {
62
76
fn needs_upper ( _q : f64 , _len : usize ) -> bool {
63
77
false
64
78
}
65
- fn interpolate ( lower : Option < T > , _upper : Option < T > , _q : f64 , _len : usize ) -> T {
79
+ fn interpolate < D > ( lower : Option < Array < T , D > > ,
80
+ _upper : Option < Array < T , D > > ,
81
+ _q : f64 ,
82
+ _len : usize ) -> Array < T , D > {
66
83
lower. unwrap ( )
67
84
}
68
85
}
@@ -75,7 +92,10 @@ impl<T> Interpolate<T> for Nearest {
75
92
fn needs_upper ( q : f64 , len : usize ) -> bool {
76
93
!<Self as Interpolate < T > >:: needs_lower ( q, len)
77
94
}
78
- fn interpolate ( lower : Option < T > , upper : Option < T > , q : f64 , len : usize ) -> T {
95
+ fn interpolate < D > ( lower : Option < Array < T , D > > ,
96
+ upper : Option < Array < T , D > > ,
97
+ q : f64 ,
98
+ len : usize ) -> Array < T , D > {
79
99
if <Self as Interpolate < T > >:: needs_lower ( q, len) {
80
100
lower. unwrap ( )
81
101
} else {
@@ -84,6 +104,48 @@ impl<T> Interpolate<T> for Nearest {
84
104
}
85
105
}
86
106
107
+ impl < T > Interpolate < T > for Midpoint
108
+ where T : Add < T , Output = T > + Div < T , Output = T > + Clone + FromPrimitive
109
+ {
110
+ fn needs_lower ( _q : f64 , _len : usize ) -> bool {
111
+ true
112
+ }
113
+ fn needs_upper ( _q : f64 , _len : usize ) -> bool {
114
+ true
115
+ }
116
+ fn interpolate < D > ( lower : Option < Array < T , D > > ,
117
+ upper : Option < Array < T , D > > ,
118
+ _q : f64 , _len : usize ) -> Array < T , D >
119
+ where D : Dimension
120
+ {
121
+ let denom = T :: from_u8 ( 2 ) . unwrap ( ) ;
122
+ ( lower. unwrap ( ) + upper. unwrap ( ) ) . mapv_into ( |x| x / denom. clone ( ) )
123
+ }
124
+ }
125
+
126
+ impl < T > Interpolate < T > for Linear
127
+ where T : Add < T , Output = T > + Sub < T , Output = T > + Mul < T , Output = T > + Clone + FromPrimitive
128
+ {
129
+ fn needs_lower ( _q : f64 , _len : usize ) -> bool {
130
+ true
131
+ }
132
+ fn needs_upper ( _q : f64 , _len : usize ) -> bool {
133
+ true
134
+ }
135
+ fn interpolate < D > ( lower : Option < Array < T , D > > ,
136
+ upper : Option < Array < T , D > > ,
137
+ q : f64 , len : usize ) -> Array < T , D >
138
+ where D : Dimension
139
+ {
140
+ let fraction = T :: from_f64 (
141
+ <Self as Interpolate < T > >:: float_percentile_index_fraction ( q, len)
142
+ ) . unwrap ( ) ;
143
+ let a = lower. unwrap ( ) . mapv_into ( |x| x * fraction. clone ( ) ) ;
144
+ let b = upper. unwrap ( ) . mapv_into ( |x| x * ( T :: from_u8 ( 1 ) . unwrap ( ) - fraction. clone ( ) ) ) ;
145
+ a + b
146
+ }
147
+ }
148
+
87
149
/// Numerical methods for arrays.
88
150
impl < A , S , D > ArrayBase < S , D >
89
151
where S : Data < Elem =A > ,
@@ -187,8 +249,8 @@ impl<A, S, D> ArrayBase<S, D>
187
249
/// as the element that would be indexed as `(N-1)q` if the lane were to be sorted
188
250
/// in increasing order.
189
251
/// If `(N-1)q` is not an integer the desired percentile lies between
190
- /// two data points: we return the lower, nearest or higher datapoint depending
191
- /// on `interpolation_strategy `.
252
+ /// two data points: we return the lower, nearest, higher or interpolated
253
+ /// value depending on the type `Interpolate` bound `I `.
192
254
///
193
255
/// Some examples:
194
256
/// - `q=0.` returns the minimum along each 1-dimensional lane;
@@ -214,7 +276,7 @@ impl<A, S, D> ArrayBase<S, D>
214
276
where D : RemoveAxis ,
215
277
A : Ord + Clone + Zero ,
216
278
S : DataMut ,
217
- I : Interpolate < Array < A , D :: Smaller > > ,
279
+ I : Interpolate < A > ,
218
280
{
219
281
assert ! ( ( 0. <= q) && ( q <= 1. ) ) ;
220
282
let mut lower = None ;
0 commit comments