crc-framework 0.2.4__tar.gz → 0.2.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crc_framework-0.2.5/.python-version +1 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/Cargo.lock +2 -2
- {crc_framework-0.2.4 → crc_framework-0.2.5}/Cargo.toml +1 -1
- {crc_framework-0.2.4 → crc_framework-0.2.5}/PKG-INFO +1 -1
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/Cargo.toml +1 -1
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/curve_fitting.rs +35 -11
- crc_framework-0.2.5/crates/core/tests/quantile_fit_golden.rs +320 -0
- crc_framework-0.2.5/crates/core/tests/quantile_fit_golden.txt +56 -0
- crc_framework-0.2.5/uv.lock +755 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/.github/workflows/release.yaml +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/.gitignore +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/LICENSE +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/README.md +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/THIRD_PARTY_NOTICES.md +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/constants.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/distribution.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/error.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/lib.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/metrics.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/ag_params.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/energy_params.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/flood_params.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/mod.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/precipitation_thresholds.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/spei_params.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/climate/wind_params.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/mod.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/spatial/continent_r4.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/spatial/geography_r5.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/spatial/ipcc.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/reference/spatial/mod.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/risk.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/spatial.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/crates/core/src/transform.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/pyproject.toml +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/__init__.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/_core.pyi +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/constants.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/__init__.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/base.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/empirical.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/fitted.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/fitting.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/hurdle.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/point_mass.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/distributions/tabulated.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/metrics/__init__.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/metrics/distribution.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/metrics/microscores.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/metrics/risk.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/metrics/spanning.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/models.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/py.typed +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/spatial.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/transforms/__init__.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/transforms/base.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/transforms/builtin.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/python/crc_framework/transforms/climate.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/src/lib.rs +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/tests/test_impacts.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/tests/test_sdk.py +0 -0
- {crc_framework-0.2.4 → crc_framework-0.2.5}/tests/typing_smoke.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -43,7 +43,7 @@ dependencies = [
|
|
|
43
43
|
|
|
44
44
|
[[package]]
|
|
45
45
|
name = "crc-framework-core"
|
|
46
|
-
version = "0.2.
|
|
46
|
+
version = "0.2.5"
|
|
47
47
|
dependencies = [
|
|
48
48
|
"h3o",
|
|
49
49
|
"phf",
|
|
@@ -52,7 +52,7 @@ dependencies = [
|
|
|
52
52
|
|
|
53
53
|
[[package]]
|
|
54
54
|
name = "crc-framework-rs"
|
|
55
|
-
version = "0.2.
|
|
55
|
+
version = "0.2.5"
|
|
56
56
|
dependencies = [
|
|
57
57
|
"crc-framework-core",
|
|
58
58
|
"h3o",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crc-framework
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
6
6
|
Classifier: Operating System :: OS Independent
|
|
@@ -240,6 +240,9 @@ pub(crate) fn fit_quantile_points(
|
|
|
240
240
|
};
|
|
241
241
|
let value_range = values.iter().copied().fold(f64::NEG_INFINITY, f64::max)
|
|
242
242
|
- values.iter().copied().fold(f64::INFINITY, f64::min);
|
|
243
|
+
// Loop-invariant across every start, iteration and objective evaluation of
|
|
244
|
+
// this fit; summed here in the same order the objective used to sum it.
|
|
245
|
+
let weight_sum = weights.iter().sum::<f64>();
|
|
243
246
|
let mut best: Option<SimplexResult> = None;
|
|
244
247
|
|
|
245
248
|
for start in starts {
|
|
@@ -268,6 +271,7 @@ pub(crate) fn fit_quantile_points(
|
|
|
268
271
|
probabilities,
|
|
269
272
|
values,
|
|
270
273
|
weights,
|
|
274
|
+
weight_sum,
|
|
271
275
|
value_scale,
|
|
272
276
|
truncation_atom,
|
|
273
277
|
)
|
|
@@ -403,12 +407,16 @@ fn constrain_quantile_parameters(kind: DistributionKind, parameters: &mut [f64])
|
|
|
403
407
|
}
|
|
404
408
|
}
|
|
405
409
|
|
|
410
|
+
/// `weight_sum` is `weights.iter().sum()`. It is a property of the fit, not of
|
|
411
|
+
/// the trial parameters, so the caller computes it once instead of having every
|
|
412
|
+
/// objective evaluation re-sum the weight vector.
|
|
406
413
|
fn quantile_objective(
|
|
407
414
|
kind: DistributionKind,
|
|
408
415
|
parameters: &[f64],
|
|
409
416
|
probabilities: &[f64],
|
|
410
417
|
values: &[f64],
|
|
411
418
|
weights: &[f64],
|
|
419
|
+
weight_sum: f64,
|
|
412
420
|
value_scale: f64,
|
|
413
421
|
truncation_atom: Option<f64>,
|
|
414
422
|
) -> f64 {
|
|
@@ -425,20 +433,36 @@ fn quantile_objective(
|
|
|
425
433
|
if tail_start.is_some_and(|cdf| !cdf.is_finite() || 1.0 - cdf <= 1.0e-12) {
|
|
426
434
|
return f64::INFINITY;
|
|
427
435
|
}
|
|
428
|
-
|
|
436
|
+
// The truncation branch is loop-invariant, so it is resolved once here
|
|
437
|
+
// rather than per knot. Both arms compute exactly what the single combined
|
|
438
|
+
// loop computed, in the same order.
|
|
429
439
|
let mut loss = 0.0;
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
440
|
+
match tail_start {
|
|
441
|
+
None => {
|
|
442
|
+
for ((&probability, &value), &weight) in probabilities.iter().zip(values).zip(weights) {
|
|
443
|
+
if weight == 0.0 {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
let fitted = distribution.ppf(probability);
|
|
447
|
+
if !fitted.is_finite() {
|
|
448
|
+
return f64::INFINITY;
|
|
449
|
+
}
|
|
450
|
+
loss += weight * ((fitted - value) / value_scale).powi(2);
|
|
451
|
+
}
|
|
433
452
|
}
|
|
434
|
-
|
|
435
|
-
(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
453
|
+
Some(cdf) => {
|
|
454
|
+
for ((&probability, &value), &weight) in probabilities.iter().zip(values).zip(weights) {
|
|
455
|
+
if weight == 0.0 {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
let base_probability = (cdf + probability * (1.0 - cdf)).min(1.0 - 1.0e-15);
|
|
459
|
+
let fitted = distribution.ppf(base_probability);
|
|
460
|
+
if !fitted.is_finite() {
|
|
461
|
+
return f64::INFINITY;
|
|
462
|
+
}
|
|
463
|
+
loss += weight * ((fitted - value) / value_scale).powi(2);
|
|
464
|
+
}
|
|
440
465
|
}
|
|
441
|
-
loss += weight * ((fitted - value) / value_scale).powi(2);
|
|
442
466
|
}
|
|
443
467
|
loss / weight_sum
|
|
444
468
|
}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
//! Bit-exact golden tests for the quantile Nelder-Mead fitting path.
|
|
2
|
+
//!
|
|
3
|
+
//! `fit_quantiles` drives `quantile_nelder_mead`, the simplex optimizer used to
|
|
4
|
+
//! produce production risk-model parameters. These tests pin the exact IEEE-754
|
|
5
|
+
//! bit patterns of the fitted parameters together with the simplex iteration and
|
|
6
|
+
//! evaluation counts, so any change to the optimizer that is meant to be purely
|
|
7
|
+
//! mechanical (allocation strategy, code motion) can be verified as producing
|
|
8
|
+
//! identical output rather than merely similar output.
|
|
9
|
+
//!
|
|
10
|
+
//! The objective calls `exp`, `ln` and `pow` from the platform's libm, so the
|
|
11
|
+
//! table is pinned to the libm that produced it (it was generated on macOS
|
|
12
|
+
//! 15 / aarch64 and verified identical in both debug and release builds). Treat
|
|
13
|
+
//! a mismatch on a different platform as a portability finding to investigate,
|
|
14
|
+
//! not as an automatic regression, and regenerate the table only for an
|
|
15
|
+
//! intentional numerical change:
|
|
16
|
+
//!
|
|
17
|
+
//! ```text
|
|
18
|
+
//! CRC_GOLDEN_REGEN=1 cargo test -p crc-framework-core --test quantile_fit_golden -- --nocapture
|
|
19
|
+
//! ```
|
|
20
|
+
|
|
21
|
+
use crc_framework_core::{DistributionFamily, fit_hurdle_quantiles, fit_quantiles};
|
|
22
|
+
|
|
23
|
+
/// Deterministic value generator: SplitMix64, so the cases are identical on
|
|
24
|
+
/// every platform and every run without pulling in an RNG dependency.
|
|
25
|
+
struct SplitMix64(u64);
|
|
26
|
+
|
|
27
|
+
impl SplitMix64 {
|
|
28
|
+
fn next_u64(&mut self) -> u64 {
|
|
29
|
+
self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15);
|
|
30
|
+
let mut z = self.0;
|
|
31
|
+
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
|
|
32
|
+
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
|
|
33
|
+
z ^ (z >> 31)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Uniform in [0, 1) built from the top 53 bits, i.e. exactly representable.
|
|
37
|
+
fn next_unit(&mut self) -> f64 {
|
|
38
|
+
(self.next_u64() >> 11) as f64 * (1.0 / (1u64 << 53) as f64)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const PROBABILITIES_WIDE: [f64; 13] = [
|
|
43
|
+
0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99,
|
|
44
|
+
];
|
|
45
|
+
const PROBABILITIES_NARROW: [f64; 5] = [0.1, 0.25, 0.5, 0.75, 0.9];
|
|
46
|
+
|
|
47
|
+
/// A single fit problem: strictly increasing probabilities and non-decreasing
|
|
48
|
+
/// values, which is what `fit_quantiles` requires.
|
|
49
|
+
struct Case {
|
|
50
|
+
label: &'static str,
|
|
51
|
+
probabilities: Vec<f64>,
|
|
52
|
+
values: Vec<f64>,
|
|
53
|
+
weights: Option<Vec<f64>>,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// Builds a monotone value curve by accumulating positive jitter onto a base
|
|
57
|
+
/// curve, so the resulting shapes are irregular enough to exercise multi-start
|
|
58
|
+
/// selection, expansion, contraction and shrink branches of the simplex.
|
|
59
|
+
fn monotone_values(seed: u64, count: usize, base: f64, slope: f64, jitter: f64) -> Vec<f64> {
|
|
60
|
+
let mut rng = SplitMix64(seed);
|
|
61
|
+
let mut value = base;
|
|
62
|
+
let mut out = Vec::with_capacity(count);
|
|
63
|
+
for step in 0..count {
|
|
64
|
+
value += slope * (1.0 + step as f64 * 0.1) + jitter * rng.next_unit();
|
|
65
|
+
out.push(value);
|
|
66
|
+
}
|
|
67
|
+
out
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn cases() -> Vec<Case> {
|
|
71
|
+
let wide = PROBABILITIES_WIDE.to_vec();
|
|
72
|
+
let narrow = PROBABILITIES_NARROW.to_vec();
|
|
73
|
+
vec![
|
|
74
|
+
Case {
|
|
75
|
+
label: "wide-gentle",
|
|
76
|
+
probabilities: wide.clone(),
|
|
77
|
+
values: monotone_values(0x1234_5678, wide.len(), 0.0, 1.0, 0.25),
|
|
78
|
+
weights: None,
|
|
79
|
+
},
|
|
80
|
+
Case {
|
|
81
|
+
label: "wide-steep-tail",
|
|
82
|
+
probabilities: wide.clone(),
|
|
83
|
+
values: monotone_values(0xDEAD_BEEF, wide.len(), 2.0, 4.0, 3.0),
|
|
84
|
+
weights: None,
|
|
85
|
+
},
|
|
86
|
+
Case {
|
|
87
|
+
label: "wide-large-scale",
|
|
88
|
+
probabilities: wide.clone(),
|
|
89
|
+
values: monotone_values(0x0BAD_C0DE, wide.len(), 1000.0, 250.0, 90.0),
|
|
90
|
+
weights: None,
|
|
91
|
+
},
|
|
92
|
+
Case {
|
|
93
|
+
label: "wide-tiny-scale",
|
|
94
|
+
probabilities: wide.clone(),
|
|
95
|
+
values: monotone_values(0x00C0_FFEE, wide.len(), 0.001, 0.0004, 0.0002),
|
|
96
|
+
weights: None,
|
|
97
|
+
},
|
|
98
|
+
Case {
|
|
99
|
+
label: "wide-weighted",
|
|
100
|
+
probabilities: wide.clone(),
|
|
101
|
+
values: monotone_values(0xFEED_FACE, wide.len(), 5.0, 2.0, 1.5),
|
|
102
|
+
weights: Some(vec![
|
|
103
|
+
3.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.5, 4.0,
|
|
104
|
+
]),
|
|
105
|
+
},
|
|
106
|
+
Case {
|
|
107
|
+
label: "wide-flat-then-jump",
|
|
108
|
+
probabilities: wide.clone(),
|
|
109
|
+
values: vec![
|
|
110
|
+
0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 3.0, 5.0, 9.0, 14.0, 30.0,
|
|
111
|
+
],
|
|
112
|
+
weights: None,
|
|
113
|
+
},
|
|
114
|
+
Case {
|
|
115
|
+
label: "narrow-gentle",
|
|
116
|
+
probabilities: narrow.clone(),
|
|
117
|
+
values: monotone_values(0xA5A5_5A5A, narrow.len(), 10.0, 3.0, 1.0),
|
|
118
|
+
weights: None,
|
|
119
|
+
},
|
|
120
|
+
Case {
|
|
121
|
+
label: "narrow-negative-support",
|
|
122
|
+
probabilities: narrow.clone(),
|
|
123
|
+
values: monotone_values(0x5150_5150, narrow.len(), -40.0, 6.0, 2.0),
|
|
124
|
+
weights: None,
|
|
125
|
+
},
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// One line per (family, case) with the exact bit patterns of everything the
|
|
130
|
+
/// optimizer produces. Bits, not decimals: this is the whole point of the test.
|
|
131
|
+
fn fingerprint() -> Vec<String> {
|
|
132
|
+
let mut lines = Vec::new();
|
|
133
|
+
for family in DistributionFamily::ALL {
|
|
134
|
+
for case in cases() {
|
|
135
|
+
let outcome = fit_quantiles(
|
|
136
|
+
&case.probabilities,
|
|
137
|
+
&case.values,
|
|
138
|
+
case.weights.as_deref(),
|
|
139
|
+
family,
|
|
140
|
+
);
|
|
141
|
+
let rendered = match outcome {
|
|
142
|
+
Err(error) => format!("err({error})"),
|
|
143
|
+
Ok(result) => {
|
|
144
|
+
let shape = result.distribution.shape;
|
|
145
|
+
let loc = result.distribution.location;
|
|
146
|
+
let scale = result.distribution.scale;
|
|
147
|
+
let diagnostics = result.diagnostics;
|
|
148
|
+
format!(
|
|
149
|
+
"shape={} loc={:016x} scale={:016x} converged={} iterations={} \
|
|
150
|
+
evaluations={} points={} rmse={:016x} nrmse={:016x} r2={:016x} \
|
|
151
|
+
maxres={:016x}",
|
|
152
|
+
shape
|
|
153
|
+
.map_or_else(|| "none".to_owned(), |v| format!("{:016x}", v.to_bits())),
|
|
154
|
+
loc.to_bits(),
|
|
155
|
+
scale.to_bits(),
|
|
156
|
+
diagnostics.converged,
|
|
157
|
+
diagnostics.iterations,
|
|
158
|
+
diagnostics.evaluations,
|
|
159
|
+
diagnostics.point_count,
|
|
160
|
+
diagnostics.rmse.to_bits(),
|
|
161
|
+
diagnostics.normalized_rmse.to_bits(),
|
|
162
|
+
diagnostics.weighted_r_squared.to_bits(),
|
|
163
|
+
diagnostics.maximum_absolute_residual.to_bits(),
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
lines.push(format!("{}/{} {rendered}", family.name(), case.label));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
lines
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[test]
|
|
174
|
+
fn quantile_fits_are_bit_identical_to_golden() {
|
|
175
|
+
let actual = fingerprint();
|
|
176
|
+
|
|
177
|
+
if std::env::var_os("CRC_GOLDEN_REGEN").is_some() {
|
|
178
|
+
println!("---BEGIN GOLDEN---");
|
|
179
|
+
for line in &actual {
|
|
180
|
+
println!("{line}");
|
|
181
|
+
}
|
|
182
|
+
println!("---END GOLDEN---");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let expected: Vec<&str> = GOLDEN.lines().filter(|line| !line.is_empty()).collect();
|
|
187
|
+
assert_eq!(
|
|
188
|
+
actual.len(),
|
|
189
|
+
expected.len(),
|
|
190
|
+
"golden table is stale: case count changed"
|
|
191
|
+
);
|
|
192
|
+
let mut mismatches = Vec::new();
|
|
193
|
+
for (actual_line, expected_line) in actual.iter().zip(&expected) {
|
|
194
|
+
if actual_line != expected_line {
|
|
195
|
+
mismatches.push(format!(
|
|
196
|
+
" expected: {expected_line}\n actual: {actual_line}"
|
|
197
|
+
));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
assert!(
|
|
201
|
+
mismatches.is_empty(),
|
|
202
|
+
"{} of {} quantile fits changed:\n{}",
|
|
203
|
+
mismatches.len(),
|
|
204
|
+
expected.len(),
|
|
205
|
+
mismatches.join("\n")
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const GOLDEN: &str = include_str!("quantile_fit_golden.txt");
|
|
210
|
+
|
|
211
|
+
/// Wall-clock micro-benchmark for the fitting hot path, at the knot widths the
|
|
212
|
+
/// curve_fit_cdf pipeline actually uses (999 knots per curve) plus a narrower
|
|
213
|
+
/// width for contrast. Both objective paths are measured, because that pipeline
|
|
214
|
+
/// overwhelmingly takes the truncated (hurdle) one.
|
|
215
|
+
///
|
|
216
|
+
/// Ignored by default because it is a timing measurement, not an assertion:
|
|
217
|
+
///
|
|
218
|
+
/// ```text
|
|
219
|
+
/// cargo test --release -p crc-framework-core --test quantile_fit_golden -- \
|
|
220
|
+
/// --ignored --nocapture bench_wide_quantile_fits
|
|
221
|
+
/// ```
|
|
222
|
+
#[test]
|
|
223
|
+
#[ignore = "timing benchmark, run explicitly with --ignored"]
|
|
224
|
+
fn bench_wide_quantile_fits() {
|
|
225
|
+
const WARMUP_ROUNDS: usize = 2;
|
|
226
|
+
const MEASURED_ROUNDS: usize = 7;
|
|
227
|
+
const PROBLEMS: usize = 4;
|
|
228
|
+
|
|
229
|
+
/// A curve with `plateau` leading knots pinned at zero (the hurdle atom)
|
|
230
|
+
/// and a strictly increasing tail, which is the shape the pipeline feeds in.
|
|
231
|
+
fn wide_problem(knots: usize, plateau: usize, seed: u64) -> (Vec<f64>, Vec<f64>) {
|
|
232
|
+
let mut rng = SplitMix64(seed);
|
|
233
|
+
let probabilities: Vec<f64> = (1..=knots)
|
|
234
|
+
.map(|index| index as f64 / (knots as f64 + 1.0))
|
|
235
|
+
.collect();
|
|
236
|
+
let mut value = 0.0;
|
|
237
|
+
let mut values = Vec::with_capacity(knots);
|
|
238
|
+
for step in 0..knots {
|
|
239
|
+
if step >= plateau {
|
|
240
|
+
value += 0.05 + rng.next_unit() * (1.0 + step as f64 * 0.01);
|
|
241
|
+
}
|
|
242
|
+
values.push(value);
|
|
243
|
+
}
|
|
244
|
+
(probabilities, values)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for knots in [999usize, 200] {
|
|
248
|
+
let plateau = knots / 4;
|
|
249
|
+
let problems: Vec<(Vec<f64>, Vec<f64>)> = (0..PROBLEMS)
|
|
250
|
+
.map(|seed| wide_problem(knots, plateau, 0x5EED + seed as u64))
|
|
251
|
+
.collect();
|
|
252
|
+
for family in [
|
|
253
|
+
DistributionFamily::GumbelRight,
|
|
254
|
+
DistributionFamily::GenExtreme,
|
|
255
|
+
] {
|
|
256
|
+
for truncated in [false, true] {
|
|
257
|
+
let mut failures = 0usize;
|
|
258
|
+
let mut round = || {
|
|
259
|
+
let start = std::time::Instant::now();
|
|
260
|
+
let mut checksum = 0u64;
|
|
261
|
+
for (probabilities, values) in &problems {
|
|
262
|
+
let fitted = if truncated {
|
|
263
|
+
fit_hurdle_quantiles(
|
|
264
|
+
probabilities,
|
|
265
|
+
values,
|
|
266
|
+
None,
|
|
267
|
+
family,
|
|
268
|
+
values[0],
|
|
269
|
+
probabilities[plateau - 1],
|
|
270
|
+
)
|
|
271
|
+
.map(|result| {
|
|
272
|
+
(
|
|
273
|
+
result.distribution.base().location,
|
|
274
|
+
result.diagnostics.tail.iterations,
|
|
275
|
+
)
|
|
276
|
+
})
|
|
277
|
+
} else {
|
|
278
|
+
fit_quantiles(probabilities, values, None, family).map(|result| {
|
|
279
|
+
(result.distribution.location, result.diagnostics.iterations)
|
|
280
|
+
})
|
|
281
|
+
};
|
|
282
|
+
match fitted {
|
|
283
|
+
// Consume the result so nothing is optimized away.
|
|
284
|
+
Ok((location, iterations)) => {
|
|
285
|
+
checksum = checksum
|
|
286
|
+
.wrapping_mul(0x0100_0000_01b3)
|
|
287
|
+
.wrapping_add(location.to_bits())
|
|
288
|
+
.wrapping_add(iterations as u64);
|
|
289
|
+
}
|
|
290
|
+
Err(_) => failures += 1,
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
(start.elapsed().as_secs_f64(), checksum)
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
for _ in 0..WARMUP_ROUNDS {
|
|
297
|
+
round();
|
|
298
|
+
}
|
|
299
|
+
let mut timings = Vec::with_capacity(MEASURED_ROUNDS);
|
|
300
|
+
let mut checksum = 0u64;
|
|
301
|
+
for _ in 0..MEASURED_ROUNDS {
|
|
302
|
+
let (elapsed, round_checksum) = round();
|
|
303
|
+
checksum = round_checksum;
|
|
304
|
+
timings.push(elapsed);
|
|
305
|
+
}
|
|
306
|
+
timings.sort_by(f64::total_cmp);
|
|
307
|
+
// A benchmark that measured only error returns would be silently
|
|
308
|
+
// meaningless, so the fit failures are reported alongside.
|
|
309
|
+
assert_eq!(failures, 0, "benchmark inputs must produce real fits");
|
|
310
|
+
println!(
|
|
311
|
+
"knots={knots:<4} {:<11} {:<7} best {:>10.2} us/fit median {:>10.2} us/fit checksum {checksum:016x}",
|
|
312
|
+
family.name(),
|
|
313
|
+
if truncated { "hurdle" } else { "plain" },
|
|
314
|
+
timings[0] / PROBLEMS as f64 * 1.0e6,
|
|
315
|
+
timings[timings.len() / 2] / PROBLEMS as f64 * 1.0e6,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
genextreme/wide-gentle shape=3fc84756763e17f6 loc=4020bccaf08d2686 scale=40137aebfc31dc10 converged=true iterations=117 evaluations=213 points=13 rmse=3fe7a205bd93e1ec nrmse=3fa1b3d9914d0ca0 r2=3fef9b920e9b1334 maxres=3ff5041fb6b91722
|
|
2
|
+
genextreme/wide-steep-tail shape=3fc8d6b9ed2e2380 loc=40442509e2f8745c scale=4035d3a5740d9438 converged=true iterations=104 evaluations=192 points=13 rmse=400969158d54a437 nrmse=3fa104c9b88f1f98 r2=3fefa2c31c4dc342 maxres=40158c43684c5d47
|
|
3
|
+
genextreme/wide-large-scale shape=3fcb69bfef93ee14 loc=40a9b86d9f728a82 scale=4093f20ccd622652 converged=true iterations=111 evaluations=199 points=13 rmse=4067177582d6cd68 nrmse=3fa13ce24c18f25e r2=3fefa0d26881e6cf maxres=40751d5290cbe568
|
|
4
|
+
genextreme/wide-tiny-scale shape=3fcb6a8b1cc9f332 loc=3f73f00e06f22e1c scale=3f6173b841df3cdc converged=true iterations=101 evaluations=189 points=13 rmse=3f33a134164ced29 nrmse=3fa0b7422c827f17 r2=3fefa619fbe603e2 maxres=3f41abbeae33d550
|
|
5
|
+
genextreme/wide-weighted shape=3fc9c2b1d335838e loc=4039423b89e64324 scale=40268c6c7066539d converged=true iterations=103 evaluations=196 points=13 rmse=3ffd227e6d10f9eb nrmse=3fa266c59a13ff2b r2=3fefb5aa3371a74e maxres=400ad708f7e34138
|
|
6
|
+
genextreme/wide-flat-then-jump shape=bfdc845bca85c119 loc=3ff0b8b87e2856e6 scale=3ffed607ebd07288 converged=true iterations=127 evaluations=235 points=13 rmse=3fe3cb76bfa065f9 nrmse=3f951d4b77117dd6 r2=3fefd250bdb932c0 maxres=3ff1708669c5d5e0
|
|
7
|
+
genextreme/narrow-gentle shape=3fbf50a9a42e398a loc=4032c1390bcd6b36 scale=40169c9cf6872c2b converged=true iterations=98 evaluations=185 points=5 rmse=3fcd84d0b6af3740 nrmse=3f8cc702e61a4561 r2=3feff2dfdb80647c maxres=3fd68bd2b85ff080
|
|
8
|
+
genextreme/narrow-negative-support shape=3fc40480cc5522b2 loc=c035ac27d81c6da0 scale=4027314e62325634 converged=true iterations=102 evaluations=194 points=5 rmse=3fdb20924a820b8f nrmse=3f8a571314d56d3e r2=3feff506fc402134 maxres=3fe490ca5feb14a0
|
|
9
|
+
weibull_min/wide-gentle shape=4003d944d0df8daa loc=bffc453a8bd7b588 scale=402b4f36569a726e converged=true iterations=116 evaluations=217 points=13 rmse=3fe39f22b1c96b1d nrmse=3f9d654b0a9f6ba2 r2=3fefbac50327709a maxres=3ff165c69b4f4740
|
|
10
|
+
weibull_min/wide-steep-tail shape=40042a0fe17e18a2 loc=c01701d680041c72 scale=404ee6d135d6e89c converged=true iterations=113 evaluations=213 points=13 rmse=40056d821e2f47aa nrmse=3f9cb3d9ff316a3a r2=3fefbdb2f0eb49e2 maxres=40145db6d6af76b0
|
|
11
|
+
weibull_min/wide-large-scale shape=4005627c3aa86d50 loc=407cf053a5242808 scale=40ad3b4f5e3137aa converged=true iterations=118 evaluations=222 points=13 rmse=4063e8a7b523a886 nrmse=3f9db9457157239d r2=3fefb94058d95f35 maxres=4071508a5669cda0
|
|
12
|
+
weibull_min/wide-tiny-scale shape=40056a65b7cebfa6 loc=3f2255ef600ef7e0 scale=3f799b14ffd445f2 converged=true iterations=115 evaluations=216 points=13 rmse=3f30f8598ffa6eaa nrmse=3f9ce6f14e5372b7 r2=3fefbccfc0a9a6d2 maxres=3f3e99fd11be86c0
|
|
13
|
+
weibull_min/wide-weighted shape=4004db71a2266386 loc=3fdb5fde2c4f494f scale=40406a62e6e02c61 converged=true iterations=104 evaluations=193 points=13 rmse=3ff9798d6b602183 nrmse=3fa017005448f123 r2=3fefc72af9703d37 maxres=40061e18df1d4950
|
|
14
|
+
weibull_min/wide-flat-then-jump shape=3fe2848c487656de loc=bf95cb0d4a4bcd98 scale=40011d3b487ee800 converged=true iterations=114 evaluations=212 points=13 rmse=3fc625f638d469c8 nrmse=3f779ff591f3a409 r2=3feffc6ce6441fbe maxres=3fd679bd2b1db06c
|
|
15
|
+
weibull_min/narrow-gentle shape=40015b1e3a3c86f6 loc=40216e6bfda1edfd scale=402cb12b0954350a converged=true iterations=125 evaluations=242 points=5 rmse=3fd28c79f5499804 nrmse=3f92153592e60a3a r2=3fefeb45015e2c8f maxres=3fdd49bd3ecd0600
|
|
16
|
+
weibull_min/narrow-negative-support shape=4002c96657372240 loc=c045ea6909596b69 scale=403ed9bacb628506 converged=true iterations=109 evaluations=213 points=5 rmse=3fe0ca74b82bdbc4 nrmse=3f904dbc72ff3d30 r2=3fefef2f3fb3d270 maxres=3fe88716c2b34f00
|
|
17
|
+
weibull_max/wide-gentle shape=401516a652ad2f67 loc=404105a75cf0c3ca scale=4039ace9414c8f7f converged=true iterations=127 evaluations=244 points=13 rmse=3fe7a205bd93e1e1 nrmse=3fa1b3d9914d0c98 r2=3fef9b920e9b1335 maxres=3ff5041fc3cc0a82
|
|
18
|
+
weibull_max/wide-steep-tail shape=40149ce9336d4a56 loc=40631890b7204bd4 scale=405c1e9c7d11fe62 converged=true iterations=116 evaluations=222 points=13 rmse=400969158d54a42d nrmse=3fa104c9b88f1f91 r2=3fefa2c31c4dc342 maxres=40158c4362426bb7
|
|
19
|
+
weibull_max/wide-large-scale shape=4012ad5dc914fab5 loc=40c21251a401866c scale=40b7486c784d25c1 converged=true iterations=128 evaluations=239 points=13 rmse=4067177582d6cd5d nrmse=3fa13ce24c18f255 r2=3fefa0d26881e6cf maxres=40751d5279acff08
|
|
20
|
+
weibull_max/wide-tiny-scale shape=4012acd3572d604e loc=3f8e56b8cf469fc0 scale=3f845eb1cb5811ce converged=true iterations=136 evaluations=258 points=13 rmse=3f33a134164ced1f nrmse=3fa0b7422c827f0e r2=3fefa619fbe603e3 maxres=3f41abbea69a3528
|
|
21
|
+
weibull_max/wide-weighted shape=4013e0184946d25e loc=405451d759601998 scale=404c0290edc10380 converged=true iterations=106 evaluations=203 points=13 rmse=3ffd227e6d10f9e0 nrmse=3fa266c59a13ff24 r2=3fefb5aa3371a74e maxres=400ad708f87c3318
|
|
22
|
+
weibull_max/wide-flat-then-jump shape=4049000000000000 loc=406ceee7d3cd87ca scale=406cb3df5ae94d42 converged=true iterations=191 evaluations=357 points=13 rmse=400bfb6bdcca1da8 nrmse=3fbdd8fb962cec6f r2=3fea4b56b399e882 maxres=401fe36a7f1133c0
|
|
23
|
+
weibull_max/narrow-gentle shape=40205996024c0146 loc=40503dea532997a2 scale=40471b38200ed362 converged=true iterations=144 evaluations=277 points=5 rmse=3fcd84d0b6af36fc nrmse=3f8cc702e61a451f r2=3feff2dfdb80647c maxres=3fd68bd2e51b0280
|
|
24
|
+
weibull_max/narrow-negative-support shape=401993d7628c7858 loc=404a3d43c0cfb776 scale=405289abd67b9be4 converged=true iterations=129 evaluations=245 points=5 rmse=3fdb20924a820b1d nrmse=3f8a571314d56cd0 r2=3feff506fc402135 maxres=3fe490ca5d3ac8e0
|
|
25
|
+
skewnorm/wide-gentle shape=3ffe483380be5d7e loc=4014fe1c3fd2a91a scale=401cdca9c25641d8 converged=true iterations=157 evaluations=331 points=13 rmse=3feaed6d21fd8d9e nrmse=3fa42b9cdf1cdc2b r2=3fef7d9e38e97a06 maxres=3ff6b1cd2603a360
|
|
26
|
+
skewnorm/wide-steep-tail shape=3ffcc535705fa79e loc=403add93c169f650 scale=403fdc1c7bdfcb3a converged=true iterations=111 evaluations=247 points=13 rmse=400d53c785281afb nrmse=3fa3a45822e5f11d r2=3fef83cdb1375b23 maxres=4019fb8f0a4ae1e0
|
|
27
|
+
skewnorm/wide-large-scale shape=3ff731baf4bf7a58 loc=40a4b2c309c37f2c scale=409b3c8c1835a105 converged=true iterations=126 evaluations=273 points=13 rmse=406b50507b1073f6 nrmse=3fa463bd220dbc25 r2=3fef7ad5ce065891 maxres=40751b83590fcf4c
|
|
28
|
+
skewnorm/wide-tiny-scale shape=3ff732bca301c39d loc=3f6f15a5decf6953 scale=3f67d5378dda9785 converged=true iterations=137 evaluations=297 points=13 rmse=3f375e90a9656680 nrmse=3fa3e68235d4da31 r2=3fef8095cd21ec8e maxres=3f4235e4c5fa3a00
|
|
29
|
+
skewnorm/wide-weighted shape=3ffa64121eb76e58 loc=4032cc3cddbfd616 scale=402fd2b67fc6cf72 converged=true iterations=229 evaluations=444 points=13 rmse=40010659c46c5a8a nrmse=3fa581741b94e032 r2=3fef9a7834b29128 maxres=400af9c9afbeb638
|
|
30
|
+
skewnorm/wide-flat-then-jump shape=4049000000000000 loc=c00cf497d2dd4357 scale=4023b40c004d3510 converged=true iterations=199 evaluations=397 points=13 rmse=400bb939c919477e nrmse=3fbd925fc5704c42 r2=3fea663591ac011e maxres=4020ec3592aa365c
|
|
31
|
+
skewnorm/narrow-gentle shape=4000a28c0a3cdf62 loc=402da21e9dcf2df2 scale=40224295e26e900e converged=true iterations=110 evaluations=244 points=5 rmse=3fcc806690a54455 nrmse=3f8bc92332ebfadd r2=3feff3c374429e3d maxres=3fd7ef08971a3c00
|
|
32
|
+
skewnorm/narrow-negative-support shape=3ffd174ca5641221 loc=c03d050f4ae8122f scale=4031d3b4a73ca5f4 converged=true iterations=266 evaluations=496 points=5 rmse=3fd85eaa6ad68497 nrmse=3f87a9a69131cab3 r2=3feff72506aae07b maxres=3fe1f933f6287e20
|
|
33
|
+
gumbel_r/wide-gentle shape=none loc=401f276e3785f1d6 scale=400f06f1ebfc2eed converged=true iterations=50 evaluations=103 points=13 rmse=3ff6b3aef0cf63d3 nrmse=3fb101519e7e6e1b r2=3fee8d4f51955731 maxres=4009b6673f75d500
|
|
34
|
+
gumbel_r/wide-steep-tail shape=none loc=4042d0c1ff2b540c scale=40314e93abb4d433 converged=true iterations=48 evaluations=99 points=13 rmse=40197b8c175994ed nrmse=3fb111275382e85b r2=3fee88edb4db1364 maxres=402d9ec951337280
|
|
35
|
+
gumbel_r/wide-large-scale shape=none loc=40a8628a0c1e1460 scale=408f048e74ca80ec converged=true iterations=50 evaluations=103 points=13 rmse=40789ea97d5f8966 nrmse=3fb260ea6bd7e0f2 r2=3fee4f3b4204a95b maxres=408b625127c57160
|
|
36
|
+
gumbel_r/wide-tiny-scale shape=none loc=3f72c4dd032a57ac scale=3f5b23c5e6594a09 converged=true iterations=37 evaluations=77 points=13 rmse=3f45681597e8e2a1 nrmse=3fb23a9dd3faf5fd r2=3fee545bd4f9eed8 maxres=3f5814a445621378
|
|
37
|
+
gumbel_r/wide-weighted shape=none loc=4036cd8d448d6646 scale=4021569a93e32d13 converged=true iterations=49 evaluations=101 points=13 rmse=400e9c7a2a9ae6d8 nrmse=3fb3558169eddf5a r2=3feeb7c22246ee15 maxres=401930a516df21e0
|
|
38
|
+
gumbel_r/wide-flat-then-jump shape=none loc=3ffc190472d27a78 scale=401206d9f90f88b7 converged=true iterations=54 evaluations=112 points=13 rmse=400ad8a2317456e2 nrmse=3fbca2cf23af4b9c r2=3feabf84ab58f7fe maxres=401e0cbd84084c38
|
|
39
|
+
gumbel_r/narrow-gentle shape=none loc=403281b9f3e1cd5c scale=4014d4b5052bf922 converged=true iterations=48 evaluations=99 points=5 rmse=3fd86cc0b97313a6 nrmse=3f97cfb3f193bc89 r2=3fefdc0dfdf4ecf9 maxres=3fe1f4be7bb6e8f0
|
|
40
|
+
gumbel_r/narrow-negative-support shape=none loc=c036515451bc70d8 scale=4024ebcf3e708bbf converged=true iterations=50 evaluations=103 points=5 rmse=3fec7a786d62d638 nrmse=3f9ba6efeee7e67c r2=3fefcfa0c33aeb99 maxres=3ff5ae11fa06baf0
|
|
41
|
+
gumbel_l/wide-gentle shape=none loc=402a7bcc54b46218 scale=400d950cfd2fae8f converged=true iterations=49 evaluations=101 points=13 rmse=400364fbb985908c nrmse=3fbd0e2c79bb8ca9 r2=3febc5cfda0d5082 maxres=40134bee20536240
|
|
42
|
+
gumbel_l/wide-steep-tail shape=none loc=404effb8f0957fda scale=40308baf4e44b72f converged=true iterations=49 evaluations=101 points=13 rmse=40254b5aca700dbf nrmse=3fbc861a4a011d54 r2=3febe85a30bf86af maxres=4034fdf581e255de
|
|
43
|
+
gumbel_l/wide-large-scale shape=none loc=40b1acfa0595cf92 scale=408deca2f90348f7 converged=true iterations=49 evaluations=101 points=13 rmse=40826e60ce5ac1de nrmse=3fbb84819fd1e028 r2=3fec35d178cbc564 maxres=4092d0109f2c4f22
|
|
44
|
+
gumbel_l/wide-tiny-scale shape=none loc=3f7c5da533aeb166 scale=3f5a30e898b260d5 converged=true iterations=36 evaluations=75 points=13 rmse=3f500b743e269b17 nrmse=3fbb537b23e44b79 r2=3fec3f074442e602 maxres=3f60464d3207400a
|
|
45
|
+
gumbel_l/wide-weighted shape=none loc=40437f32a514bcb3 scale=40214f2b763b4294 converged=true iterations=48 evaluations=99 points=13 rmse=40183a92d19aa0a8 nrmse=3fbe9b11cb8e8275 r2=3fecc9765c60200a maxres=402499a3d4ad0252
|
|
46
|
+
gumbel_l/wide-flat-then-jump shape=none loc=401d30f60b76ab74 scale=400989ddfd7f49d8 converged=true iterations=51 evaluations=113 points=13 rmse=40193f297be7b45f nrmse=3fcaee0a1dc3f399 r2=3fdad7a1f53c444a maxres=4031d3b2918f3ba9
|
|
47
|
+
gumbel_l/narrow-gentle shape=none loc=4038160567e53a9f scale=401476fb2a856f77 converged=true iterations=49 evaluations=101 points=5 rmse=3ff238f5fa6e7b90 nrmse=3fb1c3ca97e0a8d7 r2=3feebfe0a85035bd maxres=3ffa94dc38a35720
|
|
48
|
+
gumbel_l/narrow-negative-support shape=none loc=c0262e95e72627db scale=4024a072750b64f5 converged=true iterations=48 evaluations=99 points=5 rmse=4001012c3e8e7851 nrmse=3fb082dd8ba3a730 r2=3feeec0f50dfde8d maxres=40086316ffafd28c
|
|
49
|
+
genpareto/wide-gentle shape=bfe5be4b4771d1af loc=3ffbb2e1f76f62be scale=402cbeb1b6697078 converged=true iterations=139 evaluations=255 points=13 rmse=3fd77e4281968cc9 nrmse=3f91990fb7a59a45 r2=3fefe7304705e876 maxres=3fea397e590d894c
|
|
50
|
+
genpareto/wide-steep-tail shape=bfe5e107d29d1856 loc=4025175ec44f495a scale=40501b0a67278d9e converged=true iterations=129 evaluations=235 points=13 rmse=3ffe6c354f89129d nrmse=3f9460296f5e489a r2=3fefde968bf3af5d maxres=401140fcd94f426d
|
|
51
|
+
genpareto/wide-large-scale shape=bfe7bb96f9b719f4 loc=40979533402b4b96 scale=40aed9996f30a7d9 converged=true iterations=130 evaluations=240 points=13 rmse=405ad6324566d1d4 nrmse=3f9408940014c1c8 r2=3fefdfdc89a06cbd maxres=406c1b5eef6992b8
|
|
52
|
+
genpareto/wide-tiny-scale shape=bfe797675ee758e9 loc=3f5f210ec17c0b57 scale=3f7adb0df42663f4 converged=true iterations=124 evaluations=225 points=13 rmse=3f27fb24b38c5594 nrmse=3f946bd8251f3635 r2=3fefde7504043e8d maxres=3f3ab345f2f714f8
|
|
53
|
+
genpareto/wide-weighted shape=bfe5ab0eec563ccb loc=4020992a0bd3d13e scale=404158e0b53f5372 converged=true iterations=105 evaluations=194 points=13 rmse=3fefa431a3f1877b nrmse=3f93fc118b697415 r2=3fefea14b593b4c4 maxres=3ffe309b8855a360
|
|
54
|
+
genpareto/wide-flat-then-jump shape=3fd6d12fdc50a972 loc=bfe1ce296b0417f7 scale=40050413400d1335 converged=true iterations=128 evaluations=235 points=13 rmse=3fd611f7f83879da nrmse=3f878aa219d5d74f r2=3feff1cd5ddfe296 maxres=3fe0f57cd2635ae1
|
|
55
|
+
genpareto/narrow-gentle shape=bfe3e6ee229e1e8c loc=4029968701322d94 scale=402bac63544ea1dc converged=true iterations=127 evaluations=235 points=5 rmse=3fe1c73fa4f54ce8 nrmse=3fa154ef6be55e2f r2=3fefb3d2ce731d03 maxres=3fe6cf92dabde040
|
|
56
|
+
genpareto/narrow-negative-support shape=bfe5bbdb598ac755 loc=c04111886e85d86e scale=403d55b289564103 converged=true iterations=115 evaluations=217 points=5 rmse=3ff1a066395a7e95 nrmse=3fa11d78d0b6e62a r2=3fefb5e04920721a maxres=3ff8e21b7e36aed0
|