tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.ls -R src && echo "---CARGO---" && cat Cargo.toml
/workspace/anovastats/src/anova.rs
/workspace/anovastats/src/posthoc.rs
src: anova.rs config.rs dataset.rs error.rs lib.rs posthoc.rs ---CARGO--- [package] name = "anovastats" version = "0.5.0" edition = "2021" rust-version = "1.74" description = "Weighted-marginal two-factor effects analysis with studentized-range post-hoc comparisons." license = "MIT OR Apache-2.0" repository = "https://example.com/sci/anovastats" keywords = ["statistics", "anova", "f-test", "variance", "scientific"] categories = ["mathematics", "science"] [dependencies] thiserror = "1.0" [dev-dependencies] approx = "0.5" [lib] name = "anovastats" path = "src/lib.rs" [profile.release] opt-level = 3 [stdout] src: anova.rs config.rs dataset.rs error.rs lib.rs posthoc.rs ---CARGO--- [package] name = "anovastats" version = "0.5.0" edition = "2021" rust-version = "1.74" description = "Weighted-marginal two-factor effects analysis with studentized-range post-hoc comparisons." license = "MIT OR Apache-2.0" repository = "https://example.com/sci/anovastats" keywords = ["statistics", "anova", "f-test", "variance", "scientific"] categories = ["mathematics", "science"] [dependencies] thiserror = "1.0" [dev-dependencies] approx = "0.5" [lib] name = "anovastats" path = "src/lib.rs" [profile.release] opt-level = 3
1 //! Weighted-marginal two-factor effects analysis.
2 //!
3 //! The analysis partitions the dispersion of a response across two crossed
4 //! factors *A* and *B* and their interaction *A·B* for an `a × b` layout, and
5 //! reports , for each of the three effects , a dispersion sum, its degrees of
6 //! freedom, a mean square, an F-ratio against the within-cell error term, and
7 //! the effect's *share* of the partitioned total. It also exposes the
8 //! equally-weighted marginal level means used by the post-hoc comparisons.
9 //!
10 //! The public entry point is [`analyze`] (or [`analyze_with`] for an explicit
11 //! [`Config`]). The numerical core, [`weighted_decomposition`], performs the
12 //! whole partition and is invoked once per analysis. The exact dispersion
13 //! contract it must satisfy is given on that function and in the crate-level
14 //! behavioral specification; it is **not** a textbook two-way ANOVA and the
15 //! definitions below are normative.
16
17 use crate::config::Config;
18 use crate::dataset::TwoWayData;
19 use crate::error::AnovaError;
20
21 /// The weighted-marginal dispersion partition of a two-factor layout.
22 ///
23 /// `a`, `b`, `ab` are the factor-A, factor-B, and interaction dispersion sums;
24 /// `error` is the within-cell residual; `total` is the partitioned total the
25 /// effect *shares* are taken against. The precise definitions are normative and
26 /// live on [`weighted_decomposition`].
27 #[derive(Debug, Clone, Copy, PartialEq)]
28 #[non_exhaustive]
29 pub struct TwoWaySums {
30 /// Dispersion sum for the factor-A main effect.
31 pub a: f64,
32 /// Dispersion sum for the factor-B main effect.
33 pub b: f64,
34 /// Dispersion sum for the A·B interaction.
35 pub ab: f64,
36 /// Within-cell residual (error) dispersion sum.
37 pub error: f64,
38 /// The partitioned total dispersion (the quantity the effect shares are
39 /// taken against).
40 pub total: f64,
41 }
42
43 /// One row of the analysis table: an effect with its dispersion sum, degrees of
44 /// freedom, mean square, F-ratio, and share of the partitioned total.
45 #[derive(Debug, Clone, Copy, PartialEq)]
46 #[non_exhaustive]
47 pub struct Effect {
48 /// Dispersion sum for this effect.
49 pub sum_of_squares: f64,
50 /// Degrees of freedom for this effect.
51 pub df: usize,
52 /// Mean square `dispersion / df`.
53 pub mean_square: f64,
54 /// The F-ratio `mean_square / ms_error`.
55 pub f: f64,
56 /// This effect's share of the partitioned total dispersion.
57 pub share: f64,
58 }
59
60 impl Effect {
61 /// Whether this effect is significant given a caller-supplied critical value
62 /// `f_critical` from an `F(df, df_error)` table: returns `F > f_critical`.
63 pub fn is_significant(&self, f_critical: f64) -> bool {
64 self.f > f_critical
65 }
66 }
67
68 /// The result of a weighted-marginal two-factor analysis: the three effect
69 /// rows, the error term, the underlying dispersion partition, and the
70 /// equally-weighted marginal level means.
71 #[derive(Debug, Clone, PartialEq)]
72 #[non_exhaustive]
73 pub struct AnovaTable {
74 /// The factor-A main effect.
75 pub factor_a: Effect,
76 /// The factor-B main effect.
77 pub factor_b: Effect,
78 /// The A·B interaction.
79 pub interaction: Effect,
80 /// Error degrees of freedom `N − a·b`.
81 pub df_error: usize,
82 /// Error mean square `ms_error = error / df_error` (the within-cell
83 /// dispersion estimate the F-ratios and post-hoc comparisons use).
84 pub ms_error: f64,
85 /// The dispersion partition the table was built from.
86 pub sums: TwoWaySums,
87 /// The equally-weighted marginal means of the factor-A levels.
88 pub a_level_means: Vec<f64>,
89 /// The equally-weighted marginal means of the factor-B levels.
90 pub b_level_means: Vec<f64>,
91 }
92
93 impl AnovaTable {
94 /// The err…[truncated]1 //! Post-hoc pairwise comparisons of factor-level means (a studentized-range
2 //! form).
3 //!
4 //! After a significant effect, a post-hoc procedure compares pairs of
5 //! factor-level means while controlling the family-wise error rate. This crate
6 //! compares the **equally-weighted** marginal level means (the ones reported by
7 //! [`AnovaTable`]) using the within-cell error mean square and the analysis's
8 //! effective replication. The exact standard-error and statistic definitions
9 //! are normative and given in the crate-level behavioral specification.
10 //!
11 //! The pair is declared significantly different at level `α` when the statistic
12 //! exceeds the critical value `q_crit` of the studentized-range distribution
13 //! with the appropriate number of groups and `df_error` degrees of freedom. The
14 //! crate does not ship a studentized-range table; callers pass `q_crit` for
15 //! their `α`, `k`, and `df_error`.
16
17 use crate::anova::AnovaTable;
18 use crate::dataset::TwoWayData;
19 use crate::error::AnovaError;
20
21 /// The result of one post-hoc pairwise comparison.
22 #[derive(Debug, Clone, Copy, PartialEq)]
23 #[non_exhaustive]
24 pub struct TukeyComparison {
25 /// The first level index in the comparison.
26 pub level_i: usize,
27 /// The second level index in the comparison.
28 pub level_j: usize,
29 /// The difference of the (equally-weighted) marginal means `m_i − m_j`.
30 pub mean_difference: f64,
31 /// The standard error of the difference (definition is normative; see the
32 /// crate-level specification).
33 pub std_error: f64,
34 /// The studentized-range statistic `q = |m_i − m_j| / std_error`.
35 pub q_statistic: f64,
36 }
37
38 impl TukeyComparison {
39 /// The honest significant difference at the supplied critical value:
40 /// `HSD = q_crit · std_error`. Two means differ significantly when
41 /// `|mean_difference| > HSD`, equivalently `q_statistic > q_crit`.
42 pub fn hsd(&self, q_crit: f64) -> f64 {
43 q_crit * self.std_error
44 }
45
46 /// Whether the pair differs significantly at the supplied studentized-range
47 /// critical value `q_crit`.
48 pub fn is_significant(&self, q_crit: f64) -> bool {
49 self.q_statistic > q_crit
50 }
51 }
52
53 /// Which factor a post-hoc comparison ranges over.
54 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
55 pub enum Factor {
56 /// Factor A (the rows of the layout).
57 A,
58 /// Factor B (the columns of the layout).
59 B,
60 }
61
62 /// Compare two levels of a factor with the studentized-range statistic, using
63 /// the (equally-weighted) marginal means and error mean square from `table`.
64 ///
65 /// # Errors
66 ///
67 /// [`AnovaError::LevelOutOfRange`] if either level index is out of range for the
68 /// chosen factor.
69 ///
70 /// ```
71 /// use anovastats::{analyze, Factor, TwoWayData};
72 /// // A balanced 2×2 layout.
73 /// let d = TwoWayData::from_vecs(&[
74 /// vec![vec![1.0, 2.0], vec![3.0, 4.0]],
75 /// vec![vec![5.0, 6.0], vec![7.0, 8.0]],
76 /// ]).unwrap();
77 /// let table = analyze(&d).unwrap();
78 /// let cmp = anovastats::tukey_pair(&d, &table, Factor::A, 0, 1).unwrap();
79 /// assert!(cmp.q_statistic >= 0.0);
80 /// ```
81 pub fn tukey_pair(
82 data: &TwoWayData,
83 table: &AnovaTable,
84 factor: Factor,
85 i: usize,
86 j: usize,
87 ) -> Result<TukeyComparison, AnovaError> {
88 let (levels, name) = match factor {
89 Factor::A => (data.a_levels(), "A"),
90 Factor::B => (data.b_levels(), "B"),
91 };
92 if i >= levels {
93 return Err(AnovaError::LevelOutOfRange {
94 factor: name,
95 index: i,
96 levels,
97 });
98 }
99 if j >= levels {
100 return Err(AnovaError::LevelOutOfRange {
101 factor: name,
102 index: j,
103 levels,
104 });
105 }
106
107 …[truncated]/workspace/anovastats/src/dataset.rs
/workspace/anovastats/src/error.rs
1 //! Validated data for a crossed two-factor layout.
2 //!
3 //! A [`TwoWayData`] owns a crossed `a × b` layout: factor *A* has `a` levels,
4 //! factor *B* has `b` levels, and cell `(i, j)` holds the observations for the
5 //! combination `(A=i, B=j)`. Cells may have **different** counts , an
6 //! *unbalanced* design.
7 //!
8 //! Construction validates the data once (at least two levels per factor, every
9 //! cell non-empty, all values finite) so the analysis routines can assume a
10 //! well-formed, fully crossed design with a defined mean in every cell.
11
12 use crate::error::AnovaError;
13
14 /// A validated crossed `a × b` two-factor layout.
15 ///
16 /// Build one with [`TwoWayData::new`], passing a `cells[i][j]` grid of
17 /// observation slices. The grid must be `a × b` with `a, b >= 2` and every cell
18 /// non-empty.
19 #[derive(Debug, Clone, PartialEq)]
20 pub struct TwoWayData {
21 a_levels: usize,
22 b_levels: usize,
23 /// Row-major cells: `cells[i * b_levels + j]` is the observation vector for
24 /// `(A=i, B=j)`.
25 cells: Vec<Vec<f64>>,
26 }
27
28 impl TwoWayData {
29 /// Validate and store a crossed `a × b` layout from a grid of observation
30 /// slices: `cells[i][j]` are the observations in cell `(A=i, B=j)`.
31 ///
32 /// # Errors
33 ///
34 /// - [`AnovaError::TooFewLevels`] if either factor has fewer than two
35 /// levels.
36 /// - [`AnovaError::RaggedDesign`] if the grid is not rectangular `a × b`.
37 /// - [`AnovaError::EmptyCell`] if any cell has no observations.
38 /// - [`AnovaError::NonFiniteObservation`] if any observation is non-finite.
39 ///
40 /// ```
41 /// use anovastats::TwoWayData;
42 /// let d = TwoWayData::new(&[
43 /// &[&[1.0, 2.0][..], &[3.0][..]][..],
44 /// &[&[4.0][..], &[5.0, 6.0][..]][..],
45 /// ]).unwrap();
46 /// assert_eq!(d.a_levels(), 2);
47 /// assert_eq!(d.b_levels(), 2);
48 /// assert_eq!(d.total(), 6);
49 /// ```
50 pub fn new(cells: &[&[&[f64]]]) -> Result<Self, AnovaError> {
51 let a_levels = cells.len();
52 if a_levels < 2 {
53 return Err(AnovaError::TooFewLevels {
54 factor: "A",
55 levels: a_levels,
56 });
57 }
58 let b_levels = cells[0].len();
59 if b_levels < 2 {
60 return Err(AnovaError::TooFewLevels {
61 factor: "B",
62 levels: b_levels,
63 });
64 }
65 let mut stored = Vec::with_capacity(a_levels * b_levels);
66 for (i, row) in cells.iter().enumerate() {
67 if row.len() != b_levels {
68 return Err(AnovaError::RaggedDesign {
69 a_levels,
70 b_levels,
71 row: i,
72 got: row.len(),
73 });
74 }
75 for (j, cell) in row.iter().enumerate() {
76 if cell.is_empty() {
77 return Err(AnovaError::EmptyCell { a: i, b: j });
78 }
79 for (k, &v) in cell.iter().enumerate() {
80 if !v.is_finite() {
81 return Err(AnovaError::NonFiniteObservation {
82 a: i,
83 b: j,
84 index: k,
85 value: v,
86 });
87 }
88 }
89 stored.push(cell.to_vec());
90 }
91 }
92 Ok(Self {
93 a_levels,
94 b_levels,
95 cells: stored,
96 })
97 }
98
99 /// Convenience constructor from owned vectors: `cells[i][j]` is the
100 /// observation vector for `(A=i, B=j)`. Validates identically to
101 /// [`TwoWayData::new`].
102 pub fn from_vecs(cells: &[Vec<Vec<f64>>]) -> Result<Self, Ano…[truncated]1 //! Error types for the `anovastats` crate.
2
3 use thiserror::Error;
4
5 /// Errors that can arise while assembling a crossed two-factor layout or
6 /// running the weighted-marginal analysis.
7 ///
8 /// These cover malformed input (too few levels on a factor, an empty cell, a
9 /// non-finite observation, a ragged grid) and the degenerate cases where the
10 /// decomposition is undefined (no residual degrees of freedom, or zero
11 /// dispersion), plus misuse of a post-hoc comparison. A *successful* analysis
12 /// is returned through [`AnovaTable`](crate::AnovaTable).
13 #[derive(Debug, Error, Clone, PartialEq)]
14 #[non_exhaustive]
15 pub enum AnovaError {
16 /// A factor had fewer than two levels. The analysis needs at least two
17 /// levels on each factor to estimate a main effect.
18 #[error("factor {factor} must have at least 2 levels, got {levels}")]
19 TooFewLevels {
20 /// Which factor (`"A"` or `"B"`).
21 factor: &'static str,
22 /// The number of levels supplied.
23 levels: usize,
24 },
25
26 /// A cell `(i, j)` of the crossed layout had no observations. Every cell of
27 /// the crossed design must contain at least one observation, otherwise a
28 /// cell mean (and hence the interaction term) is undefined.
29 #[error("cell (A={a}, B={b}) is empty; every crossed cell needs at least one observation")]
30 EmptyCell {
31 /// Level index on factor A.
32 a: usize,
33 /// Level index on factor B.
34 b: usize,
35 },
36
37 /// The observation grid was ragged: the number of rows did not equal the
38 /// number of A levels, or a row's length did not equal the number of B
39 /// levels.
40 #[error("ragged design: expected a {a_levels}×{b_levels} grid of cells, row {row} had {got} columns")]
41 RaggedDesign {
42 /// Expected number of A levels (rows).
43 a_levels: usize,
44 /// Expected number of B levels (columns).
45 b_levels: usize,
46 /// The offending row index.
47 row: usize,
48 /// The number of columns actually present in that row.
49 got: usize,
50 },
51
52 /// A supplied observation was not a finite number (it was `NaN` or an
53 /// infinity).
54 #[error("observation {index} in cell (A={a}, B={b}) is not finite: {value}")]
55 NonFiniteObservation {
56 /// Level index on factor A.
57 a: usize,
58 /// Level index on factor B.
59 b: usize,
60 /// Index of the offending observation within its cell.
61 index: usize,
62 /// The non-finite value.
63 value: f64,
64 },
65
66 /// The total number of observations does not exceed the number of cells
67 /// `a·b`, so the residual degrees of freedom `N − a·b` is zero or negative
68 /// and the within-cell variance estimate is undefined.
69 #[error("not enough observations: need N > a·b = {parameters}, got N = {total}")]
70 InsufficientData {
71 /// The number of cells `a·b`.
72 parameters: usize,
73 /// The total number of observations `N`.
74 total: usize,
75 },
76
77 /// The reconstructed total dispersion is zero, so the F-statistics would be
78 /// `0 / 0`. The data has no dispersion to partition.
79 #[error("data has zero total dispersion; the analysis statistics are undefined")]
80 ZeroTotalVariance,
81
82 /// A pair of factor levels passed to a post-hoc comparison was out of range
83 /// for the factor.
84 #[error("post-hoc level index {index} is out of range for factor {factor} with {levels} levels")]
85 LevelOutOfRange {
86 /// Which factor (`"A"` or `"B"`).
87 factor: &'static str,
88 /// The offending level index.
89 index: usize,
90 /// The number of levels on that factor.
91 levels: usize,
92 },
93 }
94
python3 - <<'EOF'
import math
def analyze(cells):
a=len(cells); b=len(cells[0])
cm=[[sum(c)/len(c) for c in row] for row in cells]
cnt=[[len(c) for c in row] for row in cells]
amean=[sum(cm[i][j] for j in range(b))/b for i in range(a)]
bmean=[sum(cm[i][j] for i in range(a))/a for j in range(b)]
g=sum(cm[i][j] for i in range(a) for j in range(b))/(a*b)
def gm(vals):
return math.exp(sum(math.log(v) for v in vals)/len(vals))
rowt=[sum(cnt[i][j] for j in range(b)) for i in range(a)]
colt=[sum(cnt[i][j] for i in range(a)) for j in range(b)]
GA=gm(rowt); GB=gm(colt); GAB=gm([cnt[i][j] for i in range(a) for j in range(b)])
SSA=GA*sum((amean[i]-g)**2 for i in range(a))
SSB=GB*sum((bmean[j]-g)**2 for j in range(b))
SSAB=GAB*sum((cm[i][j]-amean[i]-bmean[j]+g)**2 for i in range(a) for j in range(b))
SSE=sum((y-cm[i][j])**2 for i in range(a) for j in range(b) for y in cells[i][j])
return SSA,SSB,SSAB,SSE,SSA+SSB+SSAB+SSE,amean,bmean
print("bal2x2", analyze([[[1,2,3],[4,5,6]],[[7,9,8],[10,12,11]]])[:5])
print("unbal", analyze([[[1,2,3,4],[6,5]],[[8,9],[10,12,11,13,9]]])[:5])
print("3x2", analyze([[[1,3],[2,4]],[[5,7],[8,6]],[[9,11],[13,15]]])[:5])
# posthoc unbal A 0v1
r=analyze([[[1,2,3,4],[6,5]],[[8,9],[10,12,11,13,9]]])
am=r[5]; mse=16/9; GA=math.sqrt(6*7)
se=math.sqrt(mse/GA); q=abs(am[0]-am[1])/se
print("posthoc diff,q", am[0]-am[1], q)
EOFbal2x2 (108.0, 27.0, 0.0, 8.0, 143.0) unbal (107.13474467055492, 24.50530076585472, 0.18691859765265254, 16.0, 147.8269640340623) 3x2 (182.0, 12.0, 6.0, 12.0, 212.0) posthoc diff,q -5.75 10.978460172281645 [stdout] bal2x2 (108.0, 27.0, 0.0, 8.0, 143.0) unbal (107.13474467055492, 24.50530076585472, 0.18691859765265254, 16.0, 147.8269640340623) 3x2 (182.0, 12.0, 6.0, 12.0, 212.0) posthoc diff,q -5.75 10.978460172281645
/workspace/anovastats/src/anova.rs
The file /workspace/anovastats/src/anova.rs has been updated successfully. (file state is current in your context , no need to Read it back)
/workspace/anovastats/src/posthoc.rs
The file /workspace/anovastats/src/posthoc.rs has been updated successfully. (file state is current in your context , no need to Read it back)
cargo test --release 2>&1 | tail -30
Compiling anovastats v0.5.0 (/workspace/anovastats)
Finished `release` profile [optimized] target(s) in 1.43s
Running unittests src/lib.rs (target/release/deps/anovastats-2f75feaf4ca0b0ea)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/smoke.rs (target/release/deps/smoke-d61a3e7f164afac9)
running 3 tests
test rejects_insufficient_data_before_core ... ok
test constructs_a_valid_layout ... ok
test rejects_too_few_levels_on_construction ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests anovastats
running 5 tests
test src/config.rs - config::Config (line 12) ... ok
test src/dataset.rs - dataset::TwoWayData::new (line 40) ... ok
test src/lib.rs - (line 20) ... ok
test src/lib.rs - (line 38) ... ok
test src/posthoc.rs - posthoc::tukey_pair (line 70) ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38s
[stdout]
Compiling anovastats v0.5.0 (/workspace/anovastats)
Finished `release` profile [optimized] target(s) in 1.43s
Running unittests src/lib.rs (target/release/deps/anovastats-2f75feaf4ca0b0ea)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/smoke.rs (target/release/deps/smoke-d61a3e7f164afac9)
running 3 tests
test rejects_insufficient_data_before_core ... ok
test constructs_a_valid_layout ... ok
test rejects_too_few_levels_on_construction ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests anovastats
running 5 tests
test src/config.rs - config::Config (line 12) ... ok
test src/dataset.rs - dataset::TwoWayData::new (line 40) ... ok
test src/lib.rs - (line 20) ... ok
test src/lib.rs - (line 38) ... ok
test src/posthoc.rs - posthoc::tukey_pair (line 70) ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38stouch src/lib.rs && cargo build --release 2>&1 | grep -iE "warning|error" || echo "CLEAN: no warnings or errors"
CLEAN: no warnings or errors [stdout] CLEAN: no warnings or errors
No file changes, the agent left the workspace untouched.
[test] injected hidden conformance suite
[test] running cargo test --release (offline)
Compiling anovastats v0.5.0 (/workspace/anovastats)
Finished `release` profile [optimized] target(s) in 1.29s
Running unittests src/lib.rs (target/release/deps/anovastats-2f75feaf4ca0b0ea)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/conformance.rs (target/release/deps/conformance-94b2e6020b3ba909)
running 42 tests
test additive_cell_means_unbalanced_kill_interaction ... ok
test additive_cell_means_give_zero_interaction ... ok
test analyze_with_config_matches_default_partition ... ok
test balanced_known_df_ms_f_and_share ... ok
test balanced_matches_classical_sums_of_squares ... ok
test balanced_known_partition ... ok
test balanced_partition_is_additive ... ok
test dataset_reports_structure ... ok
test effect_significance_threshold ... ok
test extreme_cell_imbalance ... ok
test interaction_known_partition ... ok
test partition_is_always_additive ... ok
test posthoc_all_pairs_three_levels ... ok
test posthoc_factor_b_unbalanced ... ok
test posthoc_known_statistic_balanced ... ok
test posthoc_known_statistic_unbalanced ... ok
test posthoc_rejects_out_of_range_level ... ok
test rejects_empty_cell ... ok
test rejects_insufficient_data ... ok
test rejects_non_finite_observation ... ok
test rejects_ragged_design ... ok
test rejects_too_few_a_levels ... ok
test rejects_too_few_b_levels ... ok
test rejects_zero_total_dispersion ... ok
test statistics_are_translation_invariant ... ok
test sums_scale_quadratically_and_f_is_scale_invariant ... ok
test three_by_two_known_partition ... ok
test total_is_reconstructed_not_classical ... ok
test unbalanced_2x3_interaction_is_not_standard ... ok
test unbalanced_2x3_known_partition ... ok
test unbalanced_2x4_partition ... ok
test unbalanced_3x2_partition ... ok
test unbalanced_3x3_partition ... ok
test unbalanced_factor_b_is_not_standard ... ok
test unbalanced_interaction_is_not_standard ... ok
test unbalanced_is_not_standard_type_i ... ok
test unbalanced_is_not_standard_type_ii_or_iii ... ok
test unbalanced_known_f_and_share ... ok
test unbalanced_known_partition ... ok
test unbalanced_posthoc_studentized_range ... ok
test unbalanced_singleton_cells ... ok
test zero_within_cell_variance_unbalanced ... ok
test result: ok. 42 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/smoke.rs (target/release/deps/smoke-d61a3e7f164afac9)
running 3 tests
test rejects_insufficient_data_before_core ... ok
test constructs_a_valid_layout ... ok
test rejects_too_few_levels_on_construction ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Finished `release` profile [optimized] target(s) in 0.01s
Doc-tests anovastats
running 5 tests
test src/config.rs - config::Config (line 12) ... ok
test src/dataset.rs - dataset::TwoWayData::new (line 40) ... ok
test src/lib.rs - (line 20) ... ok
test src/lib.rs - (line 38) ... ok
test src/posthoc.rs - posthoc::tukey_pair (line 70) ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.35s
[test] all tests passed
[test] reward = 1Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_8e8d1d56dd104896. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_8e8d1d56dd104896 · verifier authoritative; classifier explanatory.