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
71
72
73
74
75
76
77
78
79
//! Stochastic gradient descent with seeded coordinate-subsampled steps.
//!
//! Pure SGD samples a mini-batch each step; with an analytic [`Objective`] that
//! exposes only a full gradient, this implementation injects the stochasticity by
//! sampling a random subset of gradient coordinates to update each step (a
//! coordinate-wise stochastic step), driven by [`SplitMix64`] so a fixed seed
//! reproduces the run byte-for-byte.
use crate;
use crateSplitMix64;
/// Minimizes `obj` by seeded stochastic coordinate gradient steps.
///
/// Each step computes the full gradient, then updates each coordinate only with
/// probability one-half (chosen via `rng`), giving a reproducible stochastic
/// trajectory. Convergence is declared when the full gradient norm falls below
/// `tol`.
///
/// # Arguments
///
/// * `obj` — the objective to minimize.
/// * `x0` — the starting point.
/// * `lr` — the learning rate.
/// * `max_iter` — the iteration budget.
/// * `tol` — the gradient-norm convergence threshold.
/// * `rng` — the seeded PRNG controlling which coordinates update; the same seed
/// reproduces the run exactly.
///
/// # Returns
///
/// An [`OptimizeResult`] reporting the located point, value, iteration count, and
/// status.
///
/// # Examples
///
/// ```
/// use stats_claw::optimizers::gradient::sgd;
/// use stats_claw::optimizers::objectives::Quadratic;
/// use stats_claw::rng::SplitMix64;
///
/// let obj = Quadratic::new(vec![2.0, -1.0]);
/// let mut rng = SplitMix64::new(42);
/// let r = sgd(&obj, &[0.0, 0.0], 0.1, 50_000, 1e-10, &mut rng);
/// // SGD is stochastic — just assert the objective decreased.
/// assert!(r.fx < 1.0, "f(x) was {}", r.fx);
/// ```