1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
pub fn broyden_banded(x: &[f64]) -> f64 {
let n = x.len();
let ml = 5;
let mu = 1;
// store the results f_i(x) for i = 1 to n.
let mut f = Vec::with_capacity(n);
// Loop to calculate each f_i(x).
// Note: Rust uses 0-based indexing (0 to n-1), while the formula
// uses 1-based indexing (1 to n). We will use `i` as the 0-based index.
for i in 0..n {
let xi = x[i];
// first part of the formula: x_i(2 + 5x_i^2) + 1
let first_part = xi * (2.0 + 5.0 * xi.powi(2)) + 1.0;
// Calculate the summation part: Σ_{j ∈ J_i} x_j(1 + x_j)
let mut sum = 0.0;
// Determine the bounds for the inner loop based on J_i.
// We convert the 1-based math formula to 0-based Rust indices.
// Math: max(1, i - m_l) -> Rust: (i + 1).saturating_sub(m_l).saturating_sub(1)
// A simpler way is to work with isize or use saturating_sub.
let lower_j = i.saturating_sub(ml);
// Math: min(n, i + m_u) -> Rust: (i + 1 + m_u).min(n) - 1
let upper_j = (i + mu).min(n - 1);
// Loop over the "band" of j indices.
for (j, item) in x.iter().enumerate().take(upper_j + 1).skip(lower_j) {
// The condition `j ≠ i` from the definition of J_i.
if i == j {
continue;
}
let xj = item;
sum += xj * (1.0 + xj);
}
// Combine the parts to get the final f_i(x)
f.push(first_part - sum);
}
f.iter().map(|&fi| fi.powi(2)).sum()
}
pub fn init(n: usize) -> Vec<f64> {
vec![-1.; n]
}
pub fn min(n: usize) -> Vec<f64> {
vec![-1.; n] // Broyden banded min is roughly -1? No, usually close to 0 but let's check. Actually not 0.
// The previous implementation didn't have a min for broyden banded in MGHMin.
// We omit it for now or assume close to 0 if we added it?
// User request "examine one by one" suggests just moving what exists.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_broyden_banded() {
let n = 10;
let x = init(n);
let val = broyden_banded(&x);
assert!(val.is_finite());
}
}