|
1 | | -//! 144-cell verb-role lookup table — 12 semantic families × 12 tense/aspect/mood. |
| 1 | +//! 144-cell verb-role lookup table â 12 semantic families à 12 tense/aspect/mood. |
2 | 2 | //! |
3 | 3 | //! Each cell holds a TEKAMOLO slot prior: which slots a verb of this family |
4 | | -//! and tense expects to be filled. Parsing reduces to (family, tense) → |
5 | | -//! row → fill slots from morphology → NARS-revise truth. |
| 4 | +//! and tense expects to be filled. Parsing reduces to (family, tense) â |
| 5 | +//! row â fill slots from morphology â NARS-revise truth. |
6 | 6 | //! |
7 | | -//! Currently uniform priors; future PR populates from corpus statistics. |
| 7 | +//! Slot priors seeded from grammar-landscape.md §3 TEKAMOLO semantics. |
| 8 | +//! Starter values â tune empirically with corpus statistics. |
8 | 9 | //! |
9 | | -//! See PR #279 outlook E3 + grammar-landscape.md §9. |
| 10 | +//! See PR #279 outlook E3 + grammar-landscape.md §9. |
10 | 11 | //! |
11 | 12 | //! META-AGENT: `pub mod verb_table;` to mod.rs. |
12 | 13 |
|
13 | 14 | use crate::grammar::role_keys::Tense; |
14 | 15 |
|
15 | 16 | /// Twelve top-level semantic families. The naming is deliberately |
16 | 17 | /// process-oriented (verbs as transformations on configurations of |
17 | | -/// the world) rather than syntax-oriented — these are the "roles a |
| 18 | +/// the world) rather than syntax-oriented â these are the "roles a |
18 | 19 | /// predicate plays" that disambiguate which TEKAMOLO slots get filled. |
19 | 20 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
20 | 21 | pub enum VerbFamily { |
@@ -66,24 +67,109 @@ impl VerbRoleTable { |
66 | 67 | } |
67 | 68 | } |
68 | 69 |
|
69 | | -/// Default table with hand-set families per the plan's table: |
70 | | -/// BECOMES → Temporal + Modal high |
71 | | -/// CAUSES → Subject + Object + Kausal high |
72 | | -/// ... |
| 70 | +/// Default table with hand-set families per the plan's table and |
| 71 | +/// grammar-landscape.md §3 TEKAMOLO slot semantics. |
73 | 72 | /// |
74 | | -/// Currently a starter — only a few cells are seeded; uniform fills the |
75 | | -/// rest. The numbers are *priors*, not facts: a future PR replaces them |
76 | | -/// with corpus-derived statistics. Mark this `// starter — tune empirically` |
| 73 | +/// Semantic profiles â starter â tune empirically: |
| 74 | +/// BECOMES â Change verb: high Temporal + Modal |
| 75 | +/// CAUSES â Action verb: high Kausal + Instrument |
| 76 | +/// SUPPORTS â State verb: high Modal, low Temporal |
| 77 | +/// CONTRADICTS â State verb: high Modal + Kausal |
| 78 | +/// REFINES â State verb: high Modal, moderate Kausal |
| 79 | +/// GROUNDS â State verb: high Lokal + Modal |
| 80 | +/// ABSTRACTS â Change verb: high Modal + Temporal |
| 81 | +/// ENABLES â Discovery verb: high Kausal + Lokal |
| 82 | +/// PREVENTS â Action verb: high Kausal + Temporal |
| 83 | +/// TRANSFORMS â Action verb: high Kausal + Temporal + Instrument |
| 84 | +/// MIRRORS â Change verb: high Temporal + Modal + Lokal |
| 85 | +/// DISSOLVES â Change verb: high Temporal + Modal |
| 86 | +/// |
| 87 | +/// The numbers are *priors*, not facts: a future PR replaces them |
| 88 | +/// with corpus-derived statistics. Mark this `// starter â tune empirically` |
77 | 89 | /// in any consumer that depends on specific values. |
78 | 90 | pub fn default_table() -> VerbRoleTable { |
79 | 91 | let mut t = VerbRoleTable::new_uniform(); |
80 | | - let high = SlotPrior { temporal: 0.9, kausal: 0.2, modal: 0.7, lokal: 0.3, instrument: 0.2 }; |
| 92 | + |
| 93 | + // --- Change verbs: high Temporal + Modal --- |
| 94 | + |
| 95 | + // BECOMES: state-change, strongly temporal + modal |
| 96 | + let becomes = SlotPrior { temporal: 0.9, kausal: 0.2, modal: 0.7, lokal: 0.3, instrument: 0.2 }; |
| 97 | + for tense in Tense::ALL { |
| 98 | + t.set(VerbFamily::Becomes, tense, becomes); |
| 99 | + } |
| 100 | + |
| 101 | + // DISSOLVES: destruction-as-change, high temporal + modal |
| 102 | + let dissolves = SlotPrior { temporal: 0.85, kausal: 0.3, modal: 0.7, lokal: 0.25, instrument: 0.2 }; |
| 103 | + for tense in Tense::ALL { |
| 104 | + t.set(VerbFamily::Dissolves, tense, dissolves); |
| 105 | + } |
| 106 | + |
| 107 | + // ABSTRACTS: conceptual transformation, high modal + temporal |
| 108 | + let abstracts = SlotPrior { temporal: 0.7, kausal: 0.25, modal: 0.85, lokal: 0.15, instrument: 0.2 }; |
| 109 | + for tense in Tense::ALL { |
| 110 | + t.set(VerbFamily::Abstracts, tense, abstracts); |
| 111 | + } |
| 112 | + |
| 113 | + // MIRRORS: reflection/symmetry, temporal + modal + lokal |
| 114 | + let mirrors = SlotPrior { temporal: 0.75, kausal: 0.2, modal: 0.7, lokal: 0.6, instrument: 0.15 }; |
| 115 | + for tense in Tense::ALL { |
| 116 | + t.set(VerbFamily::Mirrors, tense, mirrors); |
| 117 | + } |
| 118 | + |
| 119 | + // --- Action verbs: high Kausal + Temporal --- |
| 120 | + |
| 121 | + // CAUSES: strong causal agency, high kausal + instrument |
81 | 122 | let causes = SlotPrior { temporal: 0.4, kausal: 0.95, modal: 0.4, lokal: 0.3, instrument: 0.5 }; |
82 | | - // populate per the plan's family table; mark "starter — tune empirically" |
83 | | - // ... apply for each (family, tense) combination ... |
84 | | - t.set(VerbFamily::Becomes, Tense::Present, high); |
85 | | - t.set(VerbFamily::Causes, Tense::Present, causes); |
86 | | - // (etc — only seed a few; uniform fills the rest) |
| 123 | + for tense in Tense::ALL { |
| 124 | + t.set(VerbFamily::Causes, tense, causes); |
| 125 | + } |
| 126 | + |
| 127 | + // PREVENTS: blocking action, high kausal + temporal |
| 128 | + let prevents = SlotPrior { temporal: 0.7, kausal: 0.9, modal: 0.4, lokal: 0.25, instrument: 0.35 }; |
| 129 | + for tense in Tense::ALL { |
| 130 | + t.set(VerbFamily::Prevents, tense, prevents); |
| 131 | + } |
| 132 | + |
| 133 | + // TRANSFORMS: active change, high kausal + temporal + instrument |
| 134 | + let transforms = SlotPrior { temporal: 0.8, kausal: 0.85, modal: 0.35, lokal: 0.3, instrument: 0.6 }; |
| 135 | + for tense in Tense::ALL { |
| 136 | + t.set(VerbFamily::Transforms, tense, transforms); |
| 137 | + } |
| 138 | + |
| 139 | + // --- State verbs: high Modal, low Temporal --- |
| 140 | + |
| 141 | + // SUPPORTS: epistemic backing, high modal |
| 142 | + let supports = SlotPrior { temporal: 0.2, kausal: 0.35, modal: 0.85, lokal: 0.2, instrument: 0.3 }; |
| 143 | + for tense in Tense::ALL { |
| 144 | + t.set(VerbFamily::Supports, tense, supports); |
| 145 | + } |
| 146 | + |
| 147 | + // CONTRADICTS: logical opposition, high modal + kausal |
| 148 | + let contradicts = SlotPrior { temporal: 0.15, kausal: 0.7, modal: 0.9, lokal: 0.15, instrument: 0.1 }; |
| 149 | + for tense in Tense::ALL { |
| 150 | + t.set(VerbFamily::Contradicts, tense, contradicts); |
| 151 | + } |
| 152 | + |
| 153 | + // REFINES: iterative improvement, high modal, moderate kausal |
| 154 | + let refines = SlotPrior { temporal: 0.3, kausal: 0.4, modal: 0.8, lokal: 0.2, instrument: 0.35 }; |
| 155 | + for tense in Tense::ALL { |
| 156 | + t.set(VerbFamily::Refines, tense, refines); |
| 157 | + } |
| 158 | + |
| 159 | + // GROUNDS: anchoring to context, high lokal + modal |
| 160 | + let grounds = SlotPrior { temporal: 0.25, kausal: 0.3, modal: 0.75, lokal: 0.85, instrument: 0.2 }; |
| 161 | + for tense in Tense::ALL { |
| 162 | + t.set(VerbFamily::Grounds, tense, grounds); |
| 163 | + } |
| 164 | + |
| 165 | + // --- Discovery/enablement verbs: high Kausal + Lokal --- |
| 166 | + |
| 167 | + // ENABLES: facilitation, high kausal + lokal |
| 168 | + let enables = SlotPrior { temporal: 0.35, kausal: 0.8, modal: 0.4, lokal: 0.7, instrument: 0.45 }; |
| 169 | + for tense in Tense::ALL { |
| 170 | + t.set(VerbFamily::Enables, tense, enables); |
| 171 | + } |
| 172 | + |
87 | 173 | t |
88 | 174 | } |
89 | 175 |
|
@@ -117,4 +203,135 @@ mod tests { |
117 | 203 | let p = t.lookup(VerbFamily::Causes, Tense::Present); |
118 | 204 | assert!(p.kausal > 0.8); |
119 | 205 | } |
| 206 | + |
| 207 | + // --- Per-family tests: verify priors are non-zero for at least 2 TEKAMOLO slots --- |
| 208 | + |
| 209 | + /// Helper: count slots that are non-uniform (differ from 0.5 by > 0.05). |
| 210 | + fn count_non_uniform(p: &SlotPrior) -> usize { |
| 211 | + let slots = [p.temporal, p.kausal, p.modal, p.lokal, p.instrument]; |
| 212 | + slots.iter().filter(|&&v| (v - 0.5).abs() > 0.05).count() |
| 213 | + } |
| 214 | + |
| 215 | + #[test] |
| 216 | + fn becomes_change_verb_temporal_modal() { |
| 217 | + let t = default_table(); |
| 218 | + let p = t.lookup(VerbFamily::Becomes, Tense::Present); |
| 219 | + assert!(p.temporal > 0.7, "Becomes should have high temporal"); |
| 220 | + assert!(p.modal > 0.6, "Becomes should have high modal"); |
| 221 | + assert!(count_non_uniform(&p) >= 2); |
| 222 | + } |
| 223 | + |
| 224 | + #[test] |
| 225 | + fn causes_action_verb_kausal_instrument() { |
| 226 | + let t = default_table(); |
| 227 | + let p = t.lookup(VerbFamily::Causes, Tense::Past); |
| 228 | + assert!(p.kausal > 0.8, "Causes should have high kausal"); |
| 229 | + assert!(p.instrument > 0.4, "Causes should have elevated instrument"); |
| 230 | + assert!(count_non_uniform(&p) >= 2); |
| 231 | + } |
| 232 | + |
| 233 | + #[test] |
| 234 | + fn supports_state_verb_modal_high() { |
| 235 | + let t = default_table(); |
| 236 | + let p = t.lookup(VerbFamily::Supports, Tense::Present); |
| 237 | + assert!(p.modal > 0.7, "Supports should have high modal"); |
| 238 | + assert!(p.temporal < 0.4, "Supports should have low temporal"); |
| 239 | + assert!(count_non_uniform(&p) >= 2); |
| 240 | + } |
| 241 | + |
| 242 | + #[test] |
| 243 | + fn contradicts_state_verb_modal_kausal() { |
| 244 | + let t = default_table(); |
| 245 | + let p = t.lookup(VerbFamily::Contradicts, Tense::Future); |
| 246 | + assert!(p.modal > 0.8, "Contradicts should have high modal"); |
| 247 | + assert!(p.kausal > 0.6, "Contradicts should have elevated kausal"); |
| 248 | + assert!(count_non_uniform(&p) >= 2); |
| 249 | + } |
| 250 | + |
| 251 | + #[test] |
| 252 | + fn refines_state_verb_modal() { |
| 253 | + let t = default_table(); |
| 254 | + let p = t.lookup(VerbFamily::Refines, Tense::Perfect); |
| 255 | + assert!(p.modal > 0.7, "Refines should have high modal"); |
| 256 | + assert!(p.temporal < 0.4, "Refines should have low temporal"); |
| 257 | + assert!(count_non_uniform(&p) >= 2); |
| 258 | + } |
| 259 | + |
| 260 | + #[test] |
| 261 | + fn grounds_state_verb_lokal_modal() { |
| 262 | + let t = default_table(); |
| 263 | + let p = t.lookup(VerbFamily::Grounds, Tense::Habitual); |
| 264 | + assert!(p.lokal > 0.7, "Grounds should have high lokal"); |
| 265 | + assert!(p.modal > 0.6, "Grounds should have elevated modal"); |
| 266 | + assert!(count_non_uniform(&p) >= 2); |
| 267 | + } |
| 268 | + |
| 269 | + #[test] |
| 270 | + fn abstracts_change_verb_modal_temporal() { |
| 271 | + let t = default_table(); |
| 272 | + let p = t.lookup(VerbFamily::Abstracts, Tense::PresentContinuous); |
| 273 | + assert!(p.modal > 0.7, "Abstracts should have high modal"); |
| 274 | + assert!(p.temporal > 0.6, "Abstracts should have elevated temporal"); |
| 275 | + assert!(count_non_uniform(&p) >= 2); |
| 276 | + } |
| 277 | + |
| 278 | + #[test] |
| 279 | + fn enables_discovery_verb_kausal_lokal() { |
| 280 | + let t = default_table(); |
| 281 | + let p = t.lookup(VerbFamily::Enables, Tense::Potential); |
| 282 | + assert!(p.kausal > 0.7, "Enables should have high kausal"); |
| 283 | + assert!(p.lokal > 0.6, "Enables should have elevated lokal"); |
| 284 | + assert!(count_non_uniform(&p) >= 2); |
| 285 | + } |
| 286 | + |
| 287 | + #[test] |
| 288 | + fn prevents_action_verb_kausal_temporal() { |
| 289 | + let t = default_table(); |
| 290 | + let p = t.lookup(VerbFamily::Prevents, Tense::Past); |
| 291 | + assert!(p.kausal > 0.8, "Prevents should have high kausal"); |
| 292 | + assert!(p.temporal > 0.6, "Prevents should have elevated temporal"); |
| 293 | + assert!(count_non_uniform(&p) >= 2); |
| 294 | + } |
| 295 | + |
| 296 | + #[test] |
| 297 | + fn transforms_action_verb_kausal_temporal_instrument() { |
| 298 | + let t = default_table(); |
| 299 | + let p = t.lookup(VerbFamily::Transforms, Tense::FuturePerfect); |
| 300 | + assert!(p.kausal > 0.7, "Transforms should have high kausal"); |
| 301 | + assert!(p.temporal > 0.7, "Transforms should have high temporal"); |
| 302 | + assert!(p.instrument > 0.5, "Transforms should have elevated instrument"); |
| 303 | + assert!(count_non_uniform(&p) >= 3); |
| 304 | + } |
| 305 | + |
| 306 | + #[test] |
| 307 | + fn mirrors_change_verb_temporal_modal_lokal() { |
| 308 | + let t = default_table(); |
| 309 | + let p = t.lookup(VerbFamily::Mirrors, Tense::Pluperfect); |
| 310 | + assert!(p.temporal > 0.6, "Mirrors should have elevated temporal"); |
| 311 | + assert!(p.modal > 0.6, "Mirrors should have elevated modal"); |
| 312 | + assert!(p.lokal > 0.5, "Mirrors should have elevated lokal"); |
| 313 | + assert!(count_non_uniform(&p) >= 2); |
| 314 | + } |
| 315 | + |
| 316 | + #[test] |
| 317 | + fn dissolves_change_verb_temporal_modal() { |
| 318 | + let t = default_table(); |
| 319 | + let p = t.lookup(VerbFamily::Dissolves, Tense::Imperative); |
| 320 | + assert!(p.temporal > 0.7, "Dissolves should have high temporal"); |
| 321 | + assert!(p.modal > 0.6, "Dissolves should have elevated modal"); |
| 322 | + assert!(count_non_uniform(&p) >= 2); |
| 323 | + } |
| 324 | + |
| 325 | + #[test] |
| 326 | + fn all_families_have_non_uniform_priors() { |
| 327 | + let t = default_table(); |
| 328 | + for family in VerbFamily::ALL { |
| 329 | + let p = t.lookup(family, Tense::Present); |
| 330 | + assert!( |
| 331 | + count_non_uniform(&p) >= 2, |
| 332 | + "{:?} should have at least 2 non-uniform TEKAMOLO slots", |
| 333 | + family |
| 334 | + ); |
| 335 | + } |
| 336 | + } |
120 | 337 | } |
0 commit comments