1use qualia_core_db::deontic_logic::{evaluate_accessible_layers, VcAttributes};
2use qualia_core_db::modalities::epistemic::{
3 evaluate_epistemic_frame, EpistemicStatus, EpistemicVerdict,
4};
5use qualia_core_db::modalities::paraconsistent::route_paraconsistent;
6use qualia_core_db::NQuin;
7use std::fs::File;
8use std::path::Path;
9
10pub fn map_quins(path: &Path) -> std::io::Result<(memmap2::Mmap, usize)> {
11 let file = File::open(path)?;
12 let mmap = unsafe { memmap2::MmapOptions::new().map(&file)? };
13 let len = mmap.len();
14 Ok((mmap, len))
15}
16
17const EMPTY_QUIN: NQuin = NQuin {
18 subject: 0,
19 predicate: 0,
20 object: 0,
21 context: 0,
22 metadata: 0,
23 parity: 0,
24};
25
26fn cast_quins(mmap: &memmap2::Mmap) -> &[NQuin] {
29 match bytemuck::try_cast_slice(mmap.as_ref()) {
30 Ok(q) => q,
31 Err(e) => {
32 eprintln!("cast_slice failed ({e:?}) — file may have a volume header; try stripping with `qualia-cli inspect`");
33 &[]
34 }
35 }
36}
37
38pub fn run_deontic(dataset: &Path, contract_hash: u64) {
41 let (mmap, len) = match map_quins(dataset) {
42 Ok(r) => r,
43 Err(e) => {
44 eprintln!("Cannot open dataset: {e}");
45 return;
46 }
47 };
48 let quins = cast_quins(&mmap);
49 println!("Mapped {} quins ({len} bytes).", quins.len());
50
51 let vc = VcAttributes::from_quins(contract_hash, quins);
52 let storage_dir = std::env::var("QUALIA_DATA_DIR").unwrap_or_else(|_| ".".to_string());
53 let vault = match qualia_core_db::key_vault::KeyVault::load_or_generate(&storage_dir) {
54 Ok(v) => v,
55 Err(e) => {
56 eprintln!("KeyVault error: {e}");
57 return;
58 }
59 };
60 let mut out: [Option<(
61 qualia_core_db::key_vault::SubgraphLayer,
62 qualia_core_db::key_vault::SubgraphKey,
63 )>; 5] = [None, None, None, None, None];
64 let count = evaluate_accessible_layers(&vault, &vc, &[], &mut out);
65 println!("Deontic evaluation for contract 0x{contract_hash:016x}:");
66 if count == 0 {
67 println!(" No permitted layers found.");
68 }
69 for (layer, _key) in out.iter().take(count).flatten() {
70 println!(" Permitted layer: {layer:?}");
71 }
72}
73
74pub fn run_epistemic(dataset: &Path, agent_hash: u64) {
75 let (mmap, len) = match map_quins(dataset) {
76 Ok(r) => r,
77 Err(e) => {
78 eprintln!("Cannot open dataset: {e}");
79 return;
80 }
81 };
82 let quins = cast_quins(&mmap);
83 println!("Mapped {} quins ({len} bytes).", quins.len());
84
85 let empty = EpistemicVerdict {
86 claim: EMPTY_QUIN,
87 status: EpistemicStatus::Uncertain,
88 certainty: 0,
89 };
90 let mut out = vec![empty; 128];
91 match evaluate_epistemic_frame(quins, agent_hash, 0, &mut out) {
92 Ok(n) => println!("Epistemic: {n} verdicts for agent 0x{agent_hash:016x}."),
93 Err(e) => eprintln!("Epistemic error: {e:?}"),
94 }
95}
96
97pub fn run_paraconsistent(dataset: &Path) {
98 let (mmap, len) = match map_quins(dataset) {
99 Ok(r) => r,
100 Err(e) => {
101 eprintln!("Cannot open dataset: {e}");
102 return;
103 }
104 };
105 let quins = cast_quins(&mmap);
106 println!("Mapped {} quins ({len} bytes).", quins.len());
107
108 let mut out_ok = vec![EMPTY_QUIN; quins.len().max(1)];
109 let mut out_iso = vec![EMPTY_QUIN; quins.len().max(1)];
110 match route_paraconsistent(quins, &mut out_ok, &mut out_iso) {
111 Ok((ok, iso)) => {
112 println!("Paraconsistent routing:");
113 println!(" Consistent : {ok}");
114 println!(" Isolated (⊥) : {iso}");
115 }
116 Err(e) => eprintln!("Paraconsistent error: {e:?}"),
117 }
118}
119
120pub fn run_ltl(dataset: &Path, formula_type: &str, hash_a: u64, hash_b: u64) {
123 use qualia_core_db::modalities::temporal_ltl::{evaluate_ltl_trace, LtlFormula};
124
125 let formula = match formula_type.to_ascii_lowercase().as_str() {
126 "globally" | "g" => LtlFormula::Globally(hash_a),
127 "next" | "x" => LtlFormula::Next(hash_a),
128 "until" | "u" => LtlFormula::Until {
129 ante: hash_a,
130 consequent: hash_b,
131 },
132 other => {
133 eprintln!("Unknown LTL operator '{other}'. Use: globally, next, until");
134 return;
135 }
136 };
137
138 let (mmap, _) = match map_quins(dataset) {
139 Ok(r) => r,
140 Err(e) => {
141 eprintln!("Cannot open dataset: {e}");
142 return;
143 }
144 };
145 let trace = cast_quins(&mmap);
146
147 let result = evaluate_ltl_trace(trace, &formula);
148 println!(
149 "LTL trace evaluation ({formula_type} 0x{hash_a:x}): {}",
150 if result { "HOLDS" } else { "VIOLATED" }
151 );
152}
153
154pub fn run_asp(dataset: &Path, base_index: usize) {
155 use qualia_core_db::modalities::asp::{enumerate_stable_models, MAX_STABLE_MODELS};
156
157 let (mmap, _) = match map_quins(dataset) {
158 Ok(r) => r,
159 Err(e) => {
160 eprintln!("Cannot open dataset: {e}");
161 return;
162 }
163 };
164 let quins = cast_quins(&mmap);
165
166 if quins.is_empty() {
167 eprintln!("Empty dataset.");
168 return;
169 }
170 let base = quins.get(base_index).copied().unwrap_or(EMPTY_QUIN);
171 let mut out = [0u64; MAX_STABLE_MODELS];
172 let count = enumerate_stable_models(&base, quins, &mut out);
173 println!("ASP: {count} stable model(s) from base quin at index {base_index}:");
174 for h in &out[..count] {
175 println!(" 0x{h:016x}");
176 }
177}
178
179pub fn run_dl(dataset: &Path, sub_class: u64, super_class: u64) {
180 use qualia_core_db::modalities::dl::check_subsumption_quin;
181
182 let (mmap, _) = match map_quins(dataset) {
183 Ok(r) => r,
184 Err(e) => {
185 eprintln!("Cannot open dataset: {e}");
186 return;
187 }
188 };
189 let tbox = cast_quins(&mmap);
190
191 let result = check_subsumption_quin(sub_class, super_class, tbox);
192 println!(
193 "DL subsumption: 0x{sub_class:x} ⊑ 0x{super_class:x} → {}",
194 if result {
195 "TRUE (subclass confirmed)"
196 } else {
197 "FALSE (not subsumed)"
198 }
199 );
200}
201
202pub fn run_probabilistic(weight: f32, threshold: f32) {
203 use qualia_core_db::modalities::probabilistic::evaluate_threshold;
204 let result = evaluate_threshold(weight, threshold);
205 println!(
206 "Probabilistic: weight={weight:.4}, threshold={threshold:.4} → {}",
207 if result {
208 "ABOVE THRESHOLD"
209 } else {
210 "BELOW THRESHOLD"
211 }
212 );
213}
214
215pub fn run_linear_logic(dataset: &Path, quin_index: usize) {
216 use qualia_core_db::modalities::linear::{consume_quin, is_consumed};
217
218 let (mmap, _) = match map_quins(dataset) {
219 Ok(r) => r,
220 Err(e) => {
221 eprintln!("Cannot open dataset: {e}");
222 return;
223 }
224 };
225 let quins = cast_quins(&mmap);
226
227 match quins.get(quin_index) {
228 None => eprintln!(
229 "Quin index {quin_index} out of range (dataset has {} quins).",
230 quins.len()
231 ),
232 Some(q) => {
233 let consumed_before = is_consumed(q);
234 let mut mutable_q = *q;
235 consume_quin(&mut mutable_q);
236 println!("Linear logic consume on quin[{quin_index}]:");
237 println!(
238 " Before consume: {}",
239 if consumed_before {
240 "already consumed"
241 } else {
242 "available"
243 }
244 );
245 println!(
246 " After consume: {}",
247 if is_consumed(&mutable_q) {
248 "consumed"
249 } else {
250 "still available (check bit encoding)"
251 }
252 );
253 }
254 }
255}
256
257pub fn run_dialectical(dataset: &Path, var1: u64, var2: u64) {
258 use qualia_core_db::modalities::dialectical::{are_confounded, do_intervention};
259
260 let (mmap, _) = match map_quins(dataset) {
261 Ok(r) => r,
262 Err(e) => {
263 eprintln!("Cannot open dataset: {e}");
264 return;
265 }
266 };
267 let graph = cast_quins(&mmap);
268
269 let confounded = are_confounded(graph, var1, var2);
270 println!("Dialectical analysis:");
271 println!(" var1=0x{var1:x}, var2=0x{var2:x}");
272 println!(" Confounded: {confounded}");
273
274 if let Some(effect) = do_intervention(graph, var1, 1, var2) {
275 println!(" Intervention (set var1=1) → effect on var2: {effect:.4}");
276 } else {
277 println!(" Intervention: insufficient data for causal effect estimate.");
278 }
279}
280
281pub fn run_diffusion(graph_id: &str) {
282 use qualia_core_db::modalities::diffusion::trigger_diffusion;
283 let triggered = trigger_diffusion(graph_id);
284 println!(
285 "Diffusion trigger for graph '{}': {}",
286 graph_id,
287 if triggered {
288 "initiated"
289 } else {
290 "already active or no-op"
291 }
292 );
293}
294
295pub fn run_spatio_temporal(
296 action: &str,
297 ax1: f64,
298 ay1: f64,
299 ax2: f64,
300 ay2: f64,
301 bx1: f64,
302 by1: f64,
303 bx2: f64,
304 by2: f64,
305) {
306 use qualia_core_db::modalities::spatio_temporal::{
307 evaluate_rcc8, evaluate_temporal, SpatialRegion, TemporalOp,
308 };
309
310 match action.to_ascii_lowercase().as_str() {
311 "rcc8" => {
312 let region_a =
313 SpatialRegion::new(1, vec![(ax1, ay1), (ax2, ay1), (ax2, ay2), (ax1, ay2)]);
314 let region_b =
315 SpatialRegion::new(2, vec![(bx1, by1), (bx2, by1), (bx2, by2), (bx1, by2)]);
316 let relation = evaluate_rcc8(®ion_a, ®ion_b);
317 println!("RCC8 relation A({ax1},{ay1})-({ax2},{ay2}) vs B({bx1},{by1})-({bx2},{by2}): {relation:?}");
318 }
319 "temporal-before" => {
320 let result = evaluate_temporal(
321 TemporalOp::Before,
322 ax1 as i64,
323 ay1 as i64,
324 bx1 as i64,
325 by1 as i64,
326 );
327 println!("Temporal BEFORE [{ax1}..{ay1}] vs [{bx1}..{by1}]: {result}");
328 }
329 "temporal-meets" => {
330 let result = evaluate_temporal(
331 TemporalOp::Meets,
332 ax1 as i64,
333 ay1 as i64,
334 bx1 as i64,
335 by1 as i64,
336 );
337 println!("Temporal MEETS [{ax1}..{ay1}] vs [{bx1}..{by1}]: {result}");
338 }
339 "temporal-overlaps" => {
340 let result = evaluate_temporal(
341 TemporalOp::Overlaps,
342 ax1 as i64,
343 ay1 as i64,
344 bx1 as i64,
345 by1 as i64,
346 );
347 println!("Temporal OVERLAPS [{ax1}..{ay1}] vs [{bx1}..{by1}]: {result}");
348 }
349 "temporal-during" => {
350 let result = evaluate_temporal(
351 TemporalOp::During,
352 ax1 as i64,
353 ay1 as i64,
354 bx1 as i64,
355 by1 as i64,
356 );
357 println!("Temporal DURING [{ax1}..{ay1}] vs [{bx1}..{by1}]: {result}");
358 }
359 other => {
360 eprintln!("Unknown spatio-temporal action '{other}'. Use: rcc8, temporal-before, temporal-meets, temporal-overlaps, temporal-during");
361 }
362 }
363}
364
365pub fn run_interval(action: &str, start1: i64, end1: i64, start2: i64, end2: i64, point: i64) {
366 use qualia_core_db::modalities::interval_reasoning::TemporalInterval;
367
368 let a = TemporalInterval::new(1, start1, end1);
369 let b = TemporalInterval::new(2, start2, end2);
370
371 match action.to_ascii_lowercase().as_str() {
372 "contains" => println!(
373 "Interval [{start1}..{end1}].contains({point}): {}",
374 a.contains(point)
375 ),
376 "overlaps" => println!(
377 "Interval [{start1}..{end1}] overlaps [{start2}..{end2}]: {}",
378 a.overlaps(&b)
379 ),
380 "intersection" => match a.intersection(&b) {
381 Some(i) => println!("Intersection: [{}..{}]", i.start, i.end),
382 None => println!("Intervals do not intersect."),
383 },
384 "union" => {
385 let u = a.union(&b);
386 println!("Union: [{}..{}]", u.start, u.end);
387 }
388 "gap" => match a.gap(&b) {
389 Some(g) => println!("Gap between intervals: {g} time units"),
390 None => println!("Intervals overlap — no gap."),
391 },
392 other => {
393 eprintln!("Unknown interval action '{other}'. Use: contains, overlaps, intersection, union, gap");
394 }
395 }
396}
397
398pub fn run_graph_topology(dataset: &Path, context: u64) {
399 use qualia_core_db::modalities::graph_theory::analyze_graph_topology;
400
401 let (mmap, _) = match map_quins(dataset) {
402 Ok(r) => r,
403 Err(e) => {
404 eprintln!("Cannot open dataset: {e}");
405 return;
406 }
407 };
408 let quins = cast_quins(&mmap);
409
410 let result = match analyze_graph_topology(quins, context) {
411 Ok(result) => result,
412 Err(err) => {
413 eprintln!("Graph topology analysis failed: {err:?}");
414 return;
415 }
416 };
417 println!("Graph topology analysis (context=0x{context:x}):");
418 println!(" Nodes : {}", result.node_count);
419 println!(" Edges : {}", result.edge_count);
420 println!(" Density : {:.4}", result.density);
421 println!(" Communities : {}", result.communities.len());
422 println!(" Motifs found : {}", result.motifs.len());
423 if !result.top_nodes.is_empty() {
424 println!(" Top nodes by centrality:");
425 for (node_id, score) in result.top_nodes.iter().take(5) {
426 println!(" 0x{node_id:016x} centrality={score:.4}");
427 }
428 }
429}
430
431pub fn run_argumentation(demo: bool, dataset: Option<&Path>) {
432 use qualia_core_db::modalities::argumentation::{
433 create_sanctuary_debate, ArgumentationFramework,
434 };
435
436 let framework: ArgumentationFramework = if demo || dataset.is_none() {
437 create_sanctuary_debate()
438 } else {
439 let (mmap, _) = match dataset.map(|p| map_quins(p)).unwrap() {
442 Ok(r) => r,
443 Err(e) => {
444 eprintln!("Cannot open dataset: {e}");
445 return;
446 }
447 };
448 let quins = cast_quins(&mmap);
449 let attack_pred = qualia_core_db::q_hash("attacks");
450 let mut fw = ArgumentationFramework::new();
451 for q in quins {
452 if q.predicate == attack_pred {
453 fw.add_attack(qualia_core_db::modalities::argumentation::Attack {
454 attacker: q.subject,
455 target: q.object,
456 attack_type: qualia_core_db::modalities::argumentation::AttackType::Rebuttal,
457 strength: 1.0,
458 });
459 }
460 }
461 fw
462 };
463
464 let grounded = framework.grounded_extension();
465 println!("Argumentation framework analysis:");
466 println!(" Arguments : {}", framework.arguments.len());
467 println!(" Attacks : {}", framework.attacks.len());
468 println!(" Grounded ext : {} argument(s)", grounded.len());
469 if grounded.is_empty() {
470 println!(" (empty grounded extension — all arguments attacked)");
471 }
472 for id in &grounded {
473 if let Some(arg) = framework.arguments.get(id) {
474 println!(" 0x{id:016x} \"{}\"", arg.content);
475 } else {
476 println!(" 0x{id:016x}");
477 }
478 }
479}
480
481pub fn run_control_feedback(kp: f64, ki: f64, kd: f64, setpoint: f64, measurement: f64) {
482 use qualia_core_db::modalities::control_feedback::{FeedbackController, PidParameters};
483
484 let params = PidParameters {
485 kp,
486 ki,
487 kd,
488 output_min: f64::NEG_INFINITY,
489 output_max: f64::INFINITY,
490 };
491 let mut ctrl = FeedbackController::new("cli".to_string(), setpoint, measurement, params);
492 let output = ctrl.compute_output();
493 println!("PID controller:");
494 println!(" Kp={kp}, Ki={ki}, Kd={kd}");
495 println!(" Setpoint={setpoint}, Measurement={measurement}");
496 println!(" Control output: {output:.6}");
497}
498
499pub fn run_neuro_symbolic() {
500 use qualia_core_db::neuro_symbolic_sieve::SieveLexSpec;
501 use qualia_core_db::q_hash;
502
503 let spec = SieveLexSpec::fever_observation();
505
506 println!("Neuro-symbolic grammar sieve — fever observation demo");
507 println!(" The sieve constrains LLM token generation to well-typed NQuins.");
508 println!(" Token masks are built from the '.q42.lex' lexicon at runtime.");
509 println!();
510 println!(" State machine: ExpectSubject → ExpectPredicate → ExpectObject → Complete");
511 println!();
512 println!(" Allowed hashes:");
513 for i in 0..spec.subjects_len as usize {
514 println!(
515 " Subject[{i}] : 0x{:016x} (q_hash(\"Patient\") = 0x{:016x})",
516 spec.subjects[i],
517 q_hash("Patient")
518 );
519 }
520 for i in 0..spec.predicates_len as usize {
521 println!(
522 " Predicate[{i}] : 0x{:016x} (q_hash(\"fever\") = 0x{:016x})",
523 spec.predicates[i],
524 q_hash("fever")
525 );
526 }
527 for i in 0..spec.objects_len as usize {
528 println!(
529 " Object[{i}] : 0x{:016x} (q_hash(\"True\") = 0x{:016x})",
530 spec.objects[i],
531 q_hash("True")
532 );
533 }
534 println!();
535 let full = SieveLexSpec::graph_mutation_default();
537 println!(
538 " graph_mutation_default spec ({} subjects, {} predicates, {} objects):",
539 full.subjects_len, full.predicates_len, full.objects_len
540 );
541 for i in 0..full.subjects_len as usize {
542 println!(" Subject[{i}] : 0x{:016x}", full.subjects[i]);
543 }
544 for i in 0..full.predicates_len as usize {
545 println!(" Predicate[{i}] : 0x{:016x}", full.predicates[i]);
546 }
547 for i in 0..full.objects_len as usize {
548 println!(" Object[{i}] : 0x{:016x}", full.objects[i]);
549 }
550 println!();
551 println!(" At inference time, NeuroSymbolicSieve::from_lex_and_tokenizer() maps each");
552 println!(" hash to allowed token IDs from the GGUF vocabulary. Any token not in the");
553 println!(" current mask has its logit set to -∞, enforcing SHACL-typed output.");
554}