@@ -78,33 +78,29 @@ impl PiecewiseLinearFn {
78
78
}
79
79
80
80
/// Replaces the represented function with the maximum of itself and a provided line
81
- pub fn max_with ( & mut self , slope : f64 , intercept : f64 ) {
82
- self . recent_lines . push ( ( slope , intercept ) ) ;
81
+ pub fn max_with ( & mut self , new_m : f64 , new_b : f64 ) {
82
+ self . recent_lines . push ( ( new_m , new_b ) ) ;
83
83
}
84
84
85
- fn update_envelope ( & mut self ) {
86
- self . recent_lines . sort_unstable_by ( asserting_cmp) ;
87
- self . intersections . clear ( ) ;
88
-
89
- for ( new_m, new_b) in merge_sorted ( self . recent_lines . drain ( ..) , self . sorted_lines . drain ( ..) )
90
- {
91
- while let Some ( & ( last_m, last_b) ) = self . sorted_lines . last ( ) {
92
- // If slopes are equal, get rid of the old line as its intercept is lower
93
- if ( new_m - last_m) . abs ( ) > 1e-9 {
94
- let intr = ( new_b - last_b) / ( last_m - new_m) ;
95
- if self . intersections . last ( ) < Some ( & intr) {
96
- self . intersections . push ( intr) ;
97
- break ;
98
- }
85
+ /// Similar to max_with but requires that (new_m, new_b) be the largest pair so far
86
+ fn max_with_sorted ( & mut self , new_m : f64 , new_b : f64 ) {
87
+ while let Some ( & ( last_m, last_b) ) = self . sorted_lines . last ( ) {
88
+ // If slopes are equal, get rid of the old line as its intercept is lower
89
+ if ( new_m - last_m) . abs ( ) > 1e-9 {
90
+ let intersect = ( new_b - last_b) / ( last_m - new_m) ;
91
+ if self . intersections . last ( ) < Some ( & intersect) {
92
+ self . intersections . push ( intersect) ;
93
+ break ;
99
94
}
100
- self . intersections . pop ( ) ;
101
- self . sorted_lines . pop ( ) ;
102
95
}
103
- self . sorted_lines . push ( ( new_m, new_b) ) ;
96
+ self . intersections . pop ( ) ;
97
+ self . sorted_lines . pop ( ) ;
104
98
}
99
+ self . sorted_lines . push ( ( new_m, new_b) ) ;
105
100
}
106
101
107
- fn eval_helper ( & self , x : f64 ) -> f64 {
102
+ /// Evaluates the function at x
103
+ fn eval_unoptimized ( & self , x : f64 ) -> f64 {
108
104
let idx = slice_lower_bound ( & self . intersections , & x) ;
109
105
self . recent_lines
110
106
. iter ( )
@@ -114,12 +110,17 @@ impl PiecewiseLinearFn {
114
110
. unwrap_or ( -1e18 )
115
111
}
116
112
117
- /// Evaluates the function at x
113
+ /// Evaluates the function at x with good amortized runtime
118
114
pub fn evaluate ( & mut self , x : f64 ) -> f64 {
119
115
if self . recent_lines . len ( ) > self . merge_threshold {
120
- self . update_envelope ( ) ;
116
+ self . recent_lines . sort_unstable_by ( asserting_cmp) ;
117
+ self . intersections . clear ( ) ;
118
+ let all_lines = merge_sorted ( self . recent_lines . drain ( ..) , self . sorted_lines . drain ( ..) ) ;
119
+ for ( new_m, new_b) in all_lines {
120
+ self . max_with_sorted ( new_m, new_b) ;
121
+ }
121
122
}
122
- self . eval_helper ( x)
123
+ self . eval_unoptimized ( x)
123
124
}
124
125
}
125
126
0 commit comments