@@ -62,10 +62,7 @@ pub(super) fn polynomial_cost_scalar(
6262 }
6363
6464 let mut sum = 0.0 ;
65- let mut index = 0 ;
66- while index < x_values. len ( ) {
67- let x = x_values[ index] ;
68- let y = y_values[ index] ;
65+ for ( & x, & y) in x_values. iter ( ) . zip ( y_values. iter ( ) ) {
6966 let model = param
7067 . iter ( )
7168 . copied ( )
@@ -82,7 +79,6 @@ pub(super) fn polynomial_cost_scalar(
8279 if !sum. is_finite ( ) {
8380 return LARGE_COST ;
8481 }
85- index += 1 ;
8682 }
8783
8884 sum / x_values. len ( ) as f64
@@ -100,11 +96,13 @@ pub(super) fn inverse_cost_scalar(
10096 }
10197
10298 let mut sum = 0.0 ;
103- let mut index = 0 ;
104- while index < x_values. len ( ) {
105- let x = positive_x ( x_values[ index] ) ;
106- let y = y_values[ index] ;
107- let residual = ( param[ 0 ] + param[ 1 ] / x) - y;
99+ let & [ a, b, ..] = param else {
100+ unreachable ! ( "inverse model requires two parameters" ) ;
101+ } ;
102+
103+ for ( & x, & y) in x_values. iter ( ) . zip ( y_values. iter ( ) ) {
104+ let x = positive_x ( x) ;
105+ let residual = ( a + b / x) - y;
108106 if !residual. is_finite ( ) {
109107 return LARGE_COST ;
110108 }
@@ -116,7 +114,6 @@ pub(super) fn inverse_cost_scalar(
116114 if !sum. is_finite ( ) {
117115 return LARGE_COST ;
118116 }
119- index += 1 ;
120117 }
121118
122119 sum / x_values. len ( ) as f64
@@ -131,10 +128,7 @@ pub(super) fn accumulate_polynomial_gradient_scalar(
131128) {
132129 debug_assert_eq ! ( x_values. len( ) , y_values. len( ) ) ;
133130 debug_assert_eq ! ( gradient. len( ) , param. len( ) ) ;
134- let mut index = 0 ;
135- while index < x_values. len ( ) {
136- let x = x_values[ index] ;
137- let y = y_values[ index] ;
131+ for ( & x, & y) in x_values. iter ( ) . zip ( y_values. iter ( ) ) {
138132 let model = param
139133 . iter ( )
140134 . copied ( )
@@ -146,7 +140,6 @@ pub(super) fn accumulate_polynomial_gradient_scalar(
146140 * gradient_value += residual * basis;
147141 basis *= x;
148142 }
149- index += 1 ;
150143 }
151144}
152145
@@ -159,14 +152,18 @@ pub(super) fn accumulate_inverse_gradient_scalar(
159152) {
160153 debug_assert_eq ! ( x_values. len( ) , y_values. len( ) ) ;
161154 debug_assert ! ( gradient. len( ) >= 2 ) ;
162- let mut index = 0 ;
163- while index < x_values. len ( ) {
164- let x = positive_x ( x_values[ index] ) ;
165- let y = y_values[ index] ;
166- let residual = loss_metric. residual_derivative ( ( param[ 0 ] + param[ 1 ] / x) - y) ;
167- gradient[ 0 ] += residual;
168- gradient[ 1 ] += residual / x;
169- index += 1 ;
155+ let & [ a, b, ..] = param else {
156+ unreachable ! ( "inverse model requires two parameters" ) ;
157+ } ;
158+ let [ gradient_0, gradient_1, ..] = gradient else {
159+ unreachable ! ( "inverse gradient requires two parameters" ) ;
160+ } ;
161+
162+ for ( & x, & y) in x_values. iter ( ) . zip ( y_values. iter ( ) ) {
163+ let x = positive_x ( x) ;
164+ let residual = loss_metric. residual_derivative ( ( a + b / x) - y) ;
165+ * gradient_0 += residual;
166+ * gradient_1 += residual / x;
170167 }
171168}
172169
@@ -226,23 +223,24 @@ pub(super) fn polynomial_cost_simd(
226223
227224 let mut sum = Vf64 :: splat ( 0.0 ) ;
228225 let mut tail_sum = 0.0 ;
229- let mut index = 0 ;
230- while index + Vf64 :: LEN <= x_values. len ( ) {
231- let x = Vf64 :: from_slice ( & x_values[ index..index + Vf64 :: LEN ] ) ;
232- let y = Vf64 :: from_slice ( & y_values[ index..index + Vf64 :: LEN ] ) ;
226+ let ( x_chunks, x_tail) = x_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
227+ let ( y_chunks, y_tail) = y_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
228+ debug_assert_eq ! ( x_chunks. len( ) , y_chunks. len( ) ) ;
229+ debug_assert_eq ! ( x_tail. len( ) , y_tail. len( ) ) ;
230+
231+ for ( x_chunk, y_chunk) in x_chunks. iter ( ) . zip ( y_chunks. iter ( ) ) {
232+ let x = Vf64 :: from_array ( * x_chunk) ;
233+ let y = Vf64 :: from_array ( * y_chunk) ;
233234
234235 let mut model = Vf64 :: splat ( 0.0 ) ;
235236 for coefficient in param. iter ( ) . copied ( ) {
236237 model = model * x + Vf64 :: splat ( coefficient) ;
237238 }
238239
239240 sum += value_from_residual_simd ( loss_metric, model - y) ;
240- index += Vf64 :: LEN ;
241241 }
242242
243- while index < x_values. len ( ) {
244- let x = x_values[ index] ;
245- let y = y_values[ index] ;
243+ for ( & x, & y) in x_tail. iter ( ) . zip ( y_tail. iter ( ) ) {
246244 let model = param
247245 . iter ( )
248246 . copied ( )
@@ -259,7 +257,6 @@ pub(super) fn polynomial_cost_simd(
259257 if !tail_sum. is_finite ( ) {
260258 return LARGE_COST ;
261259 }
262- index += 1 ;
263260 }
264261
265262 let total = sum. reduce_sum ( ) + tail_sum;
@@ -280,24 +277,29 @@ pub(super) fn inverse_cost_simd(
280277 if x_values. is_empty ( ) {
281278 return 0.0 ;
282279 }
280+ let & [ a_scalar, b_scalar, ..] = param else {
281+ unreachable ! ( "inverse model requires two parameters" ) ;
282+ } ;
283283
284284 let mut sum = Vf64 :: splat ( 0.0 ) ;
285285 let mut tail_sum = 0.0 ;
286- let mut index = 0 ;
287- let a = Vf64 :: splat ( param[ 0 ] ) ;
288- let b = Vf64 :: splat ( param[ 1 ] ) ;
286+ let ( x_chunks, x_tail) = x_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
287+ let ( y_chunks, y_tail) = y_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
288+ debug_assert_eq ! ( x_chunks. len( ) , y_chunks. len( ) ) ;
289+ debug_assert_eq ! ( x_tail. len( ) , y_tail. len( ) ) ;
290+
291+ let a = Vf64 :: splat ( a_scalar) ;
292+ let b = Vf64 :: splat ( b_scalar) ;
289293 let eps = Vf64 :: splat ( super :: PARAM_EPS ) ;
290- while index + Vf64 :: LEN <= x_values . len ( ) {
291- let x = Vf64 :: from_slice ( & x_values [ index..index + Vf64 :: LEN ] ) . simd_max ( eps) ;
292- let y = Vf64 :: from_slice ( & y_values [ index..index + Vf64 :: LEN ] ) ;
294+ for ( x_chunk , y_chunk ) in x_chunks . iter ( ) . zip ( y_chunks . iter ( ) ) {
295+ let x = Vf64 :: from_array ( * x_chunk ) . simd_max ( eps) ;
296+ let y = Vf64 :: from_array ( * y_chunk ) ;
293297 sum += value_from_residual_simd ( loss_metric, ( a + b / x) - y) ;
294- index += Vf64 :: LEN ;
295298 }
296299
297- while index < x_values. len ( ) {
298- let x = positive_x ( x_values[ index] ) ;
299- let y = y_values[ index] ;
300- let residual = ( param[ 0 ] + param[ 1 ] / x) - y;
300+ for ( & x, & y) in x_tail. iter ( ) . zip ( y_tail. iter ( ) ) {
301+ let x = positive_x ( x) ;
302+ let residual = ( a_scalar + b_scalar / x) - y;
301303 if !residual. is_finite ( ) {
302304 return LARGE_COST ;
303305 }
@@ -309,7 +311,6 @@ pub(super) fn inverse_cost_simd(
309311 if !tail_sum. is_finite ( ) {
310312 return LARGE_COST ;
311313 }
312- index += 1 ;
313314 }
314315
315316 let total = sum. reduce_sum ( ) + tail_sum;
@@ -332,10 +333,15 @@ pub(super) fn accumulate_polynomial_gradient_simd(
332333 debug_assert ! ( gradient. len( ) <= MAX_POLYNOMIAL_PARAMS ) ;
333334
334335 let mut accum = [ Vf64 :: splat ( 0.0 ) ; MAX_POLYNOMIAL_PARAMS ] ;
335- let mut index = 0 ;
336- while index + Vf64 :: LEN <= x_values. len ( ) {
337- let x = Vf64 :: from_slice ( & x_values[ index..index + Vf64 :: LEN ] ) ;
338- let y = Vf64 :: from_slice ( & y_values[ index..index + Vf64 :: LEN ] ) ;
336+ let accum = & mut accum[ ..gradient. len ( ) ] ;
337+ let ( x_chunks, x_tail) = x_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
338+ let ( y_chunks, y_tail) = y_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
339+ debug_assert_eq ! ( x_chunks. len( ) , y_chunks. len( ) ) ;
340+ debug_assert_eq ! ( x_tail. len( ) , y_tail. len( ) ) ;
341+
342+ for ( x_chunk, y_chunk) in x_chunks. iter ( ) . zip ( y_chunks. iter ( ) ) {
343+ let x = Vf64 :: from_array ( * x_chunk) ;
344+ let y = Vf64 :: from_array ( * y_chunk) ;
339345
340346 let mut model = Vf64 :: splat ( 0.0 ) ;
341347 for coefficient in param. iter ( ) . copied ( ) {
@@ -344,20 +350,17 @@ pub(super) fn accumulate_polynomial_gradient_simd(
344350 let residual_derivative = residual_derivative_simd ( loss_metric, model - y) ;
345351
346352 let mut basis = Vf64 :: splat ( 1.0 ) ;
347- for gradient_index in ( 0 ..gradient . len ( ) ) . rev ( ) {
348- accum [ gradient_index ] += residual_derivative * basis;
353+ for accum_value in accum . iter_mut ( ) . rev ( ) {
354+ * accum_value += residual_derivative * basis;
349355 basis *= x;
350356 }
351- index += Vf64 :: LEN ;
352357 }
353358
354- for ( gradient_index , value ) in gradient. iter_mut ( ) . enumerate ( ) {
355- * value += accum [ gradient_index ] . reduce_sum ( ) ;
359+ for ( value , accum_value ) in gradient. iter_mut ( ) . zip ( accum . iter ( ) . copied ( ) ) {
360+ * value += accum_value . reduce_sum ( ) ;
356361 }
357362
358- while index < x_values. len ( ) {
359- let x = x_values[ index] ;
360- let y = y_values[ index] ;
363+ for ( & x, & y) in x_tail. iter ( ) . zip ( y_tail. iter ( ) ) {
361364 let model = param
362365 . iter ( )
363366 . copied ( )
@@ -369,7 +372,6 @@ pub(super) fn accumulate_polynomial_gradient_simd(
369372 * gradient_value += residual * basis;
370373 basis *= x;
371374 }
372- index += 1 ;
373375 }
374376}
375377
@@ -382,32 +384,39 @@ pub(super) fn accumulate_inverse_gradient_simd(
382384) {
383385 debug_assert_eq ! ( x_values. len( ) , y_values. len( ) ) ;
384386 debug_assert ! ( gradient. len( ) >= 2 ) ;
387+ let & [ a_scalar, b_scalar, ..] = param else {
388+ unreachable ! ( "inverse model requires two parameters" ) ;
389+ } ;
390+ let [ gradient_scalar_0, gradient_scalar_1, ..] = gradient else {
391+ unreachable ! ( "inverse gradient requires two parameters" ) ;
392+ } ;
385393
386394 let mut gradient_0 = Vf64 :: splat ( 0.0 ) ;
387395 let mut gradient_1 = Vf64 :: splat ( 0.0 ) ;
388- let a = Vf64 :: splat ( param [ 0 ] ) ;
389- let b = Vf64 :: splat ( param [ 1 ] ) ;
396+ let a = Vf64 :: splat ( a_scalar ) ;
397+ let b = Vf64 :: splat ( b_scalar ) ;
390398 let eps = Vf64 :: splat ( super :: PARAM_EPS ) ;
391399
392- let mut index = 0 ;
393- while index + Vf64 :: LEN <= x_values. len ( ) {
394- let x = Vf64 :: from_slice ( & x_values[ index..index + Vf64 :: LEN ] ) . simd_max ( eps) ;
395- let y = Vf64 :: from_slice ( & y_values[ index..index + Vf64 :: LEN ] ) ;
400+ let ( x_chunks, x_tail) = x_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
401+ let ( y_chunks, y_tail) = y_values. as_chunks :: < { Vf64 :: LEN } > ( ) ;
402+ debug_assert_eq ! ( x_chunks. len( ) , y_chunks. len( ) ) ;
403+ debug_assert_eq ! ( x_tail. len( ) , y_tail. len( ) ) ;
404+
405+ for ( x_chunk, y_chunk) in x_chunks. iter ( ) . zip ( y_chunks. iter ( ) ) {
406+ let x = Vf64 :: from_array ( * x_chunk) . simd_max ( eps) ;
407+ let y = Vf64 :: from_array ( * y_chunk) ;
396408 let residual_derivative = residual_derivative_simd ( loss_metric, ( a + b / x) - y) ;
397409 gradient_0 += residual_derivative;
398410 gradient_1 += residual_derivative / x;
399- index += Vf64 :: LEN ;
400411 }
401412
402- gradient [ 0 ] += gradient_0. reduce_sum ( ) ;
403- gradient [ 1 ] += gradient_1. reduce_sum ( ) ;
413+ * gradient_scalar_0 += gradient_0. reduce_sum ( ) ;
414+ * gradient_scalar_1 += gradient_1. reduce_sum ( ) ;
404415
405- while index < x_values. len ( ) {
406- let x = positive_x ( x_values[ index] ) ;
407- let y = y_values[ index] ;
408- let residual = loss_metric. residual_derivative ( ( param[ 0 ] + param[ 1 ] / x) - y) ;
409- gradient[ 0 ] += residual;
410- gradient[ 1 ] += residual / x;
411- index += 1 ;
416+ for ( & x, & y) in x_tail. iter ( ) . zip ( y_tail. iter ( ) ) {
417+ let x = positive_x ( x) ;
418+ let residual = loss_metric. residual_derivative ( ( a_scalar + b_scalar / x) - y) ;
419+ * gradient_scalar_0 += residual;
420+ * gradient_scalar_1 += residual / x;
412421 }
413422}
0 commit comments