Skip to content

Commit ef5150c

Browse files
committed
refactoring
1 parent 5a014e1 commit ef5150c

26 files changed

Lines changed: 2512 additions & 1555 deletions

src/models/arctangent_step.rs

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,52 @@
11
use super::common::{is_finite_non_negative, scale_and_mirror_upper_hessian};
22
use ndarray::Array2;
33

4+
const PARAM_COUNT: usize = 4;
5+
6+
#[derive(Clone, Copy)]
7+
struct Params<T> {
8+
amplitude: T,
9+
slope: T,
10+
x0: T,
11+
offset: T,
12+
}
13+
14+
impl Params<f64> {
15+
#[inline]
16+
fn parse(param: &[f64]) -> Self {
17+
let [amplitude, slope, x0, offset]: [f64; PARAM_COUNT] = param
18+
.try_into()
19+
.unwrap_or_else(|_| panic!("expected {} params", PARAM_COUNT));
20+
Self {
21+
amplitude,
22+
slope,
23+
x0,
24+
offset,
25+
}
26+
}
27+
28+
#[inline]
29+
fn value_at(self, x: f64) -> f64 {
30+
self.amplitude * (self.slope * (x - self.x0)).atan() + self.offset
31+
}
32+
33+
#[inline]
34+
fn value_grad_at(self, x: f64, grad: &mut [f64]) -> f64 {
35+
debug_assert_eq!(grad.len(), PARAM_COUNT);
36+
37+
let z = self.slope * (x - self.x0);
38+
let atan_z = z.atan();
39+
let inv_den = 1.0 / (1.0 + z * z);
40+
41+
grad[0] = atan_z;
42+
grad[1] = self.amplitude * (x - self.x0) * inv_den;
43+
grad[2] = -self.amplitude * self.slope * inv_den;
44+
grad[3] = 1.0;
45+
46+
self.amplitude * atan_z + self.offset
47+
}
48+
}
49+
450
/// Вычисляет арктангенс-ступень:
551
/// `f(x) = amplitude * atan(slope * (x - x0)) + offset`,
652
/// где:
@@ -10,31 +56,13 @@ use ndarray::Array2;
1056
/// - `offset` — вертикальный сдвиг.
1157
#[inline]
1258
pub(super) fn value_at(param: &[f64], x: f64) -> f64 {
13-
let amplitude = param[0];
14-
let slope = param[1];
15-
let x0 = param[2];
16-
let offset = param[3];
17-
amplitude * (slope * (x - x0)).atan() + offset
59+
Params::parse(param).value_at(x)
1860
}
1961

62+
#[allow(dead_code)]
2063
#[inline]
2164
pub(super) fn value_grad_at(param: &[f64], x: f64, grad: &mut [f64]) -> f64 {
22-
debug_assert_eq!(grad.len(), 4);
23-
24-
let amplitude = param[0];
25-
let slope = param[1];
26-
let x0 = param[2];
27-
let offset = param[3];
28-
let z = slope * (x - x0);
29-
let atan_z = z.atan();
30-
let inv_den = 1.0 / (1.0 + z * z);
31-
32-
grad[0] = atan_z;
33-
grad[1] = amplitude * (x - x0) * inv_den;
34-
grad[2] = -amplitude * slope * inv_den;
35-
grad[3] = 1.0;
36-
37-
amplitude * atan_z + offset
65+
Params::parse(param).value_grad_at(x, grad)
3866
}
3967

4068
pub(super) fn add_value_grad(
@@ -45,18 +73,15 @@ pub(super) fn add_value_grad(
4573
) {
4674
debug_assert_eq!(x_values.len(), value_first.len());
4775
debug_assert_eq!(gradient.len(), param.len());
76+
let params = Params::parse(param);
4877

49-
let mut point_grad = [0.0; 4];
50-
let mut index = 0;
51-
while index < x_values.len() {
52-
let upstream = value_first[index];
53-
value_grad_at(param, x_values[index], &mut point_grad);
54-
55-
gradient[0] += upstream * point_grad[0];
56-
gradient[1] += upstream * point_grad[1];
57-
gradient[2] += upstream * point_grad[2];
58-
gradient[3] += upstream * point_grad[3];
59-
index += 1;
78+
let mut point_grad = [0.0; PARAM_COUNT];
79+
for (&x, &upstream) in x_values.iter().zip(value_first.iter()) {
80+
params.value_grad_at(x, &mut point_grad);
81+
82+
for (gradient_value, point_grad_value) in gradient.iter_mut().zip(point_grad.iter()) {
83+
*gradient_value += upstream * point_grad_value;
84+
}
6085
}
6186
}
6287

@@ -66,26 +91,24 @@ pub(super) fn add_value_grad_raw_hessian(
6691
value_first: &[f64],
6792
value_second: &[f64],
6893
) -> Option<Array2<f64>> {
69-
if param.len() != 4 {
94+
if param.len() != PARAM_COUNT {
7095
return None;
7196
}
7297

7398
let sample_count = x_values.len();
7499
let sample_scale = 1.0 / sample_count as f64;
75-
let mut hessian = Array2::zeros((4, 4));
76-
let amplitude = param[0];
77-
let slope = param[1];
78-
let x0 = param[2];
100+
let mut hessian = Array2::zeros((PARAM_COUNT, PARAM_COUNT));
101+
let params = Params::parse(param);
79102

80103
let mut index = 0;
81104
while index < sample_count {
82105
let x = x_values[index];
83-
let u = x - x0;
84-
let z = slope * u;
106+
let u = x - params.x0;
107+
let z = params.slope * u;
85108
let atan_z = z.atan();
86109
let inv_den = 1.0 / (1.0 + z * z);
87110
let d2_shape_dz2 = -2.0 * z * inv_den * inv_den;
88-
let model = value_at(param, x);
111+
let model = params.value_at(x);
89112
if !model.is_finite() {
90113
return None;
91114
}
@@ -97,15 +120,15 @@ pub(super) fn add_value_grad_raw_hessian(
97120
}
98121

99122
let jac_a = atan_z;
100-
let jac_b = amplitude * inv_den * u;
101-
let jac_c = -amplitude * inv_den * slope;
123+
let jac_b = params.amplitude * inv_den * u;
124+
let jac_c = -params.amplitude * inv_den * params.slope;
102125
let jac_d = 1.0;
103126

104127
let d2_model_dadb = inv_den * u;
105-
let d2_model_dadc = -inv_den * slope;
106-
let d2_model_dbdb = amplitude * d2_shape_dz2 * u * u;
107-
let d2_model_dbdc = amplitude * (d2_shape_dz2 * (-slope) * u - inv_den);
108-
let d2_model_dcdc = amplitude * d2_shape_dz2 * slope * slope;
128+
let d2_model_dadc = -inv_den * params.slope;
129+
let d2_model_dbdb = params.amplitude * d2_shape_dz2 * u * u;
130+
let d2_model_dbdc = params.amplitude * (d2_shape_dz2 * (-params.slope) * u - inv_den);
131+
let d2_model_dcdc = params.amplitude * d2_shape_dz2 * params.slope * params.slope;
109132

110133
hessian[[0, 0]] += value_second * jac_a * jac_a;
111134
hessian[[0, 1]] += value_second * jac_a * jac_b + value_first * d2_model_dadb;

0 commit comments

Comments
 (0)