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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Hypothesis generation, testing, and scoring.
//!
//! Per the Mathematical Constitution:
//! Hypotheses are formal statements of the form "Condition A ∧
//! Condition B ⇒ Emergent Property C". They are tested on
//! held-out universes and scored using accuracy minus a
//! complexity penalty.
//!
//! # Design
//!
//! Hypotheses are generic over any rule type. The condition function
//! receives a slice of rules and returns a boolean. Testing is
//! performed by the scientific cycle ([`run_cycle`]), which evaluates
//! each hypothesis against held-out test universes and computes
//! accuracy and MDL-penalized scores.
//!
//! # Standard hypotheses
//!
//! Substrate-specific hypothesis sets live in their substrate modules.
//! The core hypothesis infrastructure is substrate-independent.
//!
//! # Quick start
//!
//! ```rust
//! use arco::state::State;
//! use arco::rules::{Rule, NoContext};
//! use arco::hypotheses::Hypothesis;
//! use rand::Rng;
//!
//! #[derive(Clone, PartialEq, Eq, Hash, Debug)]
//! struct MyState { value: u8 }
//!
//! impl State for MyState {
//! type Encoding = Vec<u8>;
//! fn canonical_encoding(&self) -> Self::Encoding { vec![self.value] }
//! fn distance(&self, other: &Self) -> u32 {
//! if self.value == other.value { 0 } else { 1 }
//! }
//! }
//!
//! #[derive(Debug, Clone)]
//! struct MyRule { name: String }
//!
//! impl Rule<MyState> for MyRule {
//! type Context = NoContext;
//! fn name(&self) -> &str { &self.name }
//! fn apply(&self, state: &MyState, _ctx: &NoContext, _rng: &mut dyn Rng) -> MyState {
//! MyState { value: 1 - state.value }
//! }
//! }
//!
//! // Create a hypothesis: rule sets with ≥2 rules → storage
//! let h: Hypothesis<MyRule> = Hypothesis::new(
//! "H_MIN_SIZE",
//! |rules: &[MyRule]| rules.len() >= 2,
//! "storage",
//! "Rule set has at least 2 rules",
//! 1.0,
//! );
//!
//! // Hypotheses are tested by the scientific cycle.
//! // Use `run_cycle()` to evaluate them against held-out data.
//! // The cycle sets `accuracy` and `score` on each hypothesis.
//! assert_eq!(h.accuracy, 0.0); // not yet tested
//! assert_eq!(h.property_name, "storage");
//! ```
use crateConditionPredicate;
// ===================================================================
// Hypothesis
// ===================================================================
/// A falsifiable hypothesis about emergent properties.
///
/// A hypothesis states that rule sets satisfying a structural
/// condition will exhibit a specified emergent property above
/// a calibrated threshold. Hypotheses are tested by the scientific
/// cycle, which sets `accuracy` and `score` based on held-out data.
///
/// # Type parameters
///
/// - `R`: The rule type.
/// Return only hypotheses that survived the complexity penalty.