1#[cfg(feature = "host-io")]
8use std::borrow::Cow;
9#[cfg(feature = "host-io")]
10use std::collections::BTreeMap;
11use std::collections::BTreeSet;
12use std::sync::Arc;
13#[cfg(feature = "host-io")]
14use std::sync::{Mutex, MutexGuard};
15
16use xlog_core::{symbol, Result, XlogError};
17use xlog_cuda::CudaKernelProvider;
18use xlog_ir::EirEpistemicMode;
19#[cfg(feature = "host-io")]
20use xlog_logic::ast::ProbEngine;
21use xlog_logic::ast::{Atom, Evidence, Program, Term};
22use xlog_logic::parse_program;
23use xlog_runtime::{EpistemicGpuBatchExecutionResult, EpistemicGpuExecutionResult};
24
25use crate::compilation::{encode_cnf_gpu, GpuPirGraph, GpuPirRoots};
26#[cfg(feature = "host-io")]
27use crate::epistemic::EpistemicAssumptionKind;
28use crate::epistemic::EpistemicEvidenceTerm;
29use crate::epistemic::{
30 AcceptedWorldViewEvidence, CircuitUpdate, CircuitUpdateMode, EpistemicAssumption,
31 EpistemicCircuit,
32};
33#[cfg(feature = "host-io")]
34use crate::exact::ExactProgramOrigin;
35#[cfg(feature = "host-io")]
36use crate::exact::{ExactCircuitWitness, ExactResult, ExactResultWithGrads, ProbVarInfo};
37use crate::exact::{ExactDdnnfProgram, GpuConfig};
38use crate::pir::{PirNode, PirNodeId};
39#[cfg(feature = "host-io")]
40use crate::provenance::AggregateLiftStatus;
41use crate::provenance::Value;
42use crate::provenance::{extract_from_program, Provenance};
43
44macro_rules! epistemic_prob_trace_transaction {
45 ($adapter:ident, $body:block) => {{
46 let trace_before = $adapter.trace;
47 let result: Result<_> = (|| $body)();
48 match result {
49 Ok(value) => Ok(value),
50 Err(err) => {
51 $adapter.trace = trace_before;
52 Err(err)
53 }
54 }
55 }};
56}
57
58macro_rules! checked_prob_trace_counter_inc {
59 ($adapter:ident, $field:ident) => {{
60 $adapter.trace.$field = EpistemicProbProductionAdapter::checked_trace_counter_add(
61 $adapter.trace.$field,
62 1,
63 stringify!($field),
64 )?;
65 }};
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum EpistemicProbProductionCapabilityStatus {
71 Available,
73 Blocked,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub struct EpistemicProbProductionCapabilities {
80 pub gpu_exact_provenance: EpistemicProbProductionCapabilityStatus,
82 pub gpu_pir_cnf: EpistemicProbProductionCapabilityStatus,
84 pub gpu_knowledge_compilation: EpistemicProbProductionCapabilityStatus,
86 pub gpu_exact_query_and_gradient: EpistemicProbProductionCapabilityStatus,
88 pub fixture_circuit_allowed: bool,
90 pub gpu_knowledge_compilation_blocker: &'static str,
92}
93
94pub fn production_capabilities() -> EpistemicProbProductionCapabilities {
100 EpistemicProbProductionCapabilities {
101 gpu_exact_provenance: EpistemicProbProductionCapabilityStatus::Available,
102 gpu_pir_cnf: EpistemicProbProductionCapabilityStatus::Available,
103 gpu_knowledge_compilation: EpistemicProbProductionCapabilityStatus::Available,
104 gpu_exact_query_and_gradient: EpistemicProbProductionCapabilityStatus::Available,
105 fixture_circuit_allowed: false,
106 gpu_knowledge_compilation_blocker: "",
107 }
108}
109
110#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
112pub struct EpistemicProbProductionTrace {
113 pub gpu_exact_source_compiles: u64,
115 pub gpu_exact_program_compiles: u64,
117 pub gpu_conditioned_circuit_reuses: u64,
119 pub gpu_conditioned_circuit_preparation_compiles: u64,
121 pub gpu_conditioned_circuit_materializations: u64,
123 pub gpu_conditioned_circuit_disk_cache_restores: u64,
125 pub gpu_conditioned_circuit_gpu_cache_hits: u64,
127 pub gpu_conditioned_circuit_generation: u64,
129 pub gpu_conditioned_circuit_cache_slot: u64,
131 pub accepted_world_view_evidence_consumed: u64,
133 pub accepted_g91_world_view_evidence_consumed: u64,
136 pub accepted_faeel_world_view_evidence_consumed: u64,
138 pub accepted_evidence_assumptions_consumed: u64,
140 pub accepted_gpu_nonzero_arity_evidence_assumptions_consumed: u64,
142 pub accepted_gpu_max_evidence_arity_consumed: u32,
144 pub accepted_gpu_tuple_key_column_reads_consumed: u64,
146 pub accepted_gpu_final_tuple_row_filters_consumed: u64,
148 pub accepted_gpu_final_tuple_negated_row_filters_consumed: u64,
150 pub accepted_gpu_row_specific_membership_row_capacity_consumed: u64,
152 pub accepted_gpu_row_filter_fallback_row_capacity_consumed: u64,
154 pub accepted_gpu_constraint_relations_checked_consumed: u64,
156 pub accepted_gpu_constraint_row_count_device_reads_consumed: u64,
158 pub accepted_gpu_batch_evidence_consumed: u64,
160 pub accepted_gpu_batch_component_evidence_consumed: u64,
162 pub accepted_incremental_circuit_updates: u64,
166 pub gpu_exact_query_evaluations: u64,
168 pub gpu_source_exact_query_evaluations: u64,
170 pub gpu_program_exact_query_evaluations: u64,
172 pub gpu_exact_gradient_evaluations: u64,
174 pub gpu_source_exact_gradient_evaluations: u64,
176 pub gpu_program_exact_gradient_evaluations: u64,
178 pub gpu_source_conditioned_gradient_evaluations: u64,
180 pub gpu_program_conditioned_gradient_evaluations: u64,
182 pub gpu_pir_graph_uploads: u64,
184 pub gpu_source_pir_graph_uploads: u64,
186 pub gpu_program_pir_graph_uploads: u64,
188 pub gpu_cnf_encodes: u64,
190 pub gpu_source_cnf_encodes: u64,
192 pub gpu_program_cnf_encodes: u64,
194 pub gpu_knowledge_compilation_end_to_end_runs: u64,
196 pub accepted_gpu_production_path_events: u64,
198 pub gpu_source_knowledge_compilation_end_to_end_runs: u64,
200 pub gpu_program_knowledge_compilation_end_to_end_runs: u64,
202 pub gpu_conditioned_evidence_facts: u64,
204 pub accepted_conditioned_world_view_evidence_consumed: u64,
206 pub accepted_source_conditioned_world_view_evidence_consumed: u64,
208 pub accepted_program_conditioned_world_view_evidence_consumed: u64,
210 pub gpu_conditioned_nonzero_arity_evidence_facts: u64,
212 pub gpu_conditioned_max_evidence_arity: u32,
214 pub gpu_conditioned_negative_evidence_facts: u64,
216 pub gpu_source_conditioned_evidence_facts: u64,
218 pub gpu_source_conditioned_nonzero_arity_evidence_facts: u64,
220 pub gpu_source_conditioned_max_evidence_arity: u32,
222 pub gpu_program_conditioned_evidence_facts: u64,
224 pub gpu_program_conditioned_nonzero_arity_evidence_facts: u64,
226 pub gpu_program_conditioned_max_evidence_arity: u32,
228 pub gpu_source_conditioned_negative_evidence_facts: u64,
230 pub gpu_program_conditioned_negative_evidence_facts: u64,
232 pub gpu_conditioned_know_evidence_facts: u64,
234 pub gpu_conditioned_possible_evidence_facts: u64,
236 pub gpu_conditioned_not_known_evidence_facts: u64,
238 pub gpu_conditioned_not_possible_evidence_facts: u64,
240 pub gpu_source_conditioned_know_evidence_facts: u64,
242 pub gpu_source_conditioned_possible_evidence_facts: u64,
244 pub gpu_source_conditioned_not_known_evidence_facts: u64,
246 pub gpu_source_conditioned_not_possible_evidence_facts: u64,
248 pub gpu_program_conditioned_know_evidence_facts: u64,
250 pub gpu_program_conditioned_possible_evidence_facts: u64,
252 pub gpu_program_conditioned_not_known_evidence_facts: u64,
254 pub gpu_program_conditioned_not_possible_evidence_facts: u64,
256}
257
258impl EpistemicProbProductionTrace {
259 fn checked_gpu_production_path_events(&self) -> Result<u64> {
260 Self::checked_production_event_sum(
261 "gpu_production_path_events",
262 &[
263 self.gpu_exact_source_compiles,
264 self.gpu_exact_program_compiles,
265 self.gpu_conditioned_circuit_reuses,
266 self.gpu_exact_query_evaluations,
267 self.gpu_source_exact_query_evaluations,
268 self.gpu_program_exact_query_evaluations,
269 self.gpu_exact_gradient_evaluations,
270 self.gpu_source_exact_gradient_evaluations,
271 self.gpu_program_exact_gradient_evaluations,
272 self.gpu_source_conditioned_gradient_evaluations,
273 self.gpu_program_conditioned_gradient_evaluations,
274 self.gpu_pir_graph_uploads,
275 self.gpu_source_pir_graph_uploads,
276 self.gpu_program_pir_graph_uploads,
277 self.gpu_cnf_encodes,
278 self.gpu_source_cnf_encodes,
279 self.gpu_program_cnf_encodes,
280 self.gpu_knowledge_compilation_end_to_end_runs,
281 self.gpu_source_knowledge_compilation_end_to_end_runs,
282 self.gpu_program_knowledge_compilation_end_to_end_runs,
283 ],
284 )
285 }
286
287 fn checked_production_event_sum(counter: &str, values: &[u64]) -> Result<u64> {
288 values.iter().try_fold(0u64, |acc, value| {
289 acc.checked_add(*value)
290 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
291 construct: "epistemic probabilistic production trace accounting".to_string(),
292 context: format!(
293 "GPU probability production counter {counter} overflowed while adding \
294 {value} to {acc}"
295 ),
296 })
297 })
298 }
299
300 fn require_pir_cnf_accounting_pair(
301 construct: &'static str,
302 pir_graph_uploads: u64,
303 cnf_encodes: u64,
304 path: &'static str,
305 ) -> Result<()> {
306 if pir_graph_uploads != cnf_encodes {
307 return Err(XlogError::UnsupportedEpistemicConstruct {
308 construct: construct.to_string(),
309 context: format!(
310 "PIR/CNF production accounting must match for {path} path, got \
311 pir_graph_uploads={} cnf_encodes={}",
312 pir_graph_uploads, cnf_encodes
313 ),
314 });
315 }
316 Ok(())
317 }
318
319 fn require_pir_cnf_accounting(&self) -> Result<()> {
320 let construct = "epistemic probabilistic production metric gate";
321 Self::require_pir_cnf_accounting_pair(
322 construct,
323 self.gpu_pir_graph_uploads,
324 self.gpu_cnf_encodes,
325 "aggregate",
326 )?;
327 Self::require_pir_cnf_accounting_pair(
328 construct,
329 self.gpu_source_pir_graph_uploads,
330 self.gpu_source_cnf_encodes,
331 "source",
332 )?;
333 Self::require_pir_cnf_accounting_pair(
334 construct,
335 self.gpu_program_pir_graph_uploads,
336 self.gpu_program_cnf_encodes,
337 "program",
338 )
339 }
340
341 pub fn require_accepted_gpu_tuple_evidence_trace(&self) -> Result<()> {
343 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
344 > self.accepted_evidence_assumptions_consumed
345 {
346 return Err(XlogError::UnsupportedEpistemicConstruct {
347 construct: "epistemic probabilistic production metric gate".to_string(),
348 context: format!(
349 "accepted nonzero-arity evidence assumptions cannot exceed accepted \
350 evidence assumptions: nonzero={} total={}",
351 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
352 self.accepted_evidence_assumptions_consumed
353 ),
354 });
355 }
356 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
357 && self.accepted_gpu_max_evidence_arity_consumed > 0
358 {
359 return Err(XlogError::UnsupportedEpistemicConstruct {
360 construct: "epistemic probabilistic production metric gate".to_string(),
361 context: format!(
362 "accepted max evidence arity {} requires at least one accepted \
363 nonzero-arity GPU evidence assumption",
364 self.accepted_gpu_max_evidence_arity_consumed
365 ),
366 });
367 }
368 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed > 0
369 && self.accepted_gpu_max_evidence_arity_consumed == 0
370 {
371 return Err(XlogError::UnsupportedEpistemicConstruct {
372 construct: "epistemic probabilistic production metric gate".to_string(),
373 context: format!(
374 "accepted nonzero-arity GPU evidence requires accepted max evidence arity, \
375 got nonzero_assumptions={} max_arity=0",
376 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
377 ),
378 });
379 }
380 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
381 && self.accepted_gpu_tuple_key_column_reads_consumed != 0
382 {
383 return Err(XlogError::UnsupportedEpistemicConstruct {
384 construct: "epistemic probabilistic production metric gate".to_string(),
385 context: format!(
386 "accepted tuple-key reads require accepted nonzero-arity GPU evidence, got \
387 nonzero_assumptions=0 tuple_key_reads={}",
388 self.accepted_gpu_tuple_key_column_reads_consumed
389 ),
390 });
391 }
392 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed > 0
393 && self.accepted_gpu_tuple_key_column_reads_consumed == 0
394 {
395 return Err(XlogError::UnsupportedEpistemicConstruct {
396 construct: "epistemic probabilistic production metric gate".to_string(),
397 context: format!(
398 "accepted nonzero-arity GPU evidence requires tuple-key device column reads, \
399 got nonzero_assumptions={} tuple_key_reads=0",
400 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
401 ),
402 });
403 }
404 if self.accepted_gpu_final_tuple_negated_row_filters_consumed
405 > self.accepted_gpu_final_tuple_row_filters_consumed
406 {
407 return Err(XlogError::UnsupportedEpistemicConstruct {
408 construct: "epistemic probabilistic production metric gate".to_string(),
409 context: format!(
410 "accepted negated final-tuple row filters cannot exceed total row filters: \
411 negated={} total={}",
412 self.accepted_gpu_final_tuple_negated_row_filters_consumed,
413 self.accepted_gpu_final_tuple_row_filters_consumed
414 ),
415 });
416 }
417 if self.accepted_gpu_final_tuple_row_filters_consumed == 0
418 && (self.accepted_gpu_row_specific_membership_row_capacity_consumed != 0
419 || self.accepted_gpu_row_filter_fallback_row_capacity_consumed != 0)
420 {
421 return Err(XlogError::UnsupportedEpistemicConstruct {
422 construct: "epistemic probabilistic production metric gate".to_string(),
423 context: format!(
424 "accepted row-specific/fallback tuple capacity requires accepted GPU row \
425 filters, got row_filters=0 row_specific_capacity={} fallback_capacity={}",
426 self.accepted_gpu_row_specific_membership_row_capacity_consumed,
427 self.accepted_gpu_row_filter_fallback_row_capacity_consumed
428 ),
429 });
430 }
431 if self.accepted_gpu_final_tuple_row_filters_consumed > 0
432 && self.accepted_gpu_row_specific_membership_row_capacity_consumed == 0
433 {
434 return Err(XlogError::UnsupportedEpistemicConstruct {
435 construct: "epistemic probabilistic production metric gate".to_string(),
436 context: format!(
437 "accepted GPU final-tuple row filters require row-specific model-slot \
438 capacity, got row_filters={} row_specific_capacity=0",
439 self.accepted_gpu_final_tuple_row_filters_consumed
440 ),
441 });
442 }
443 if self.accepted_gpu_constraint_row_count_device_reads_consumed
444 > self.accepted_gpu_constraint_relations_checked_consumed
445 {
446 return Err(XlogError::UnsupportedEpistemicConstruct {
447 construct: "epistemic probabilistic production metric gate".to_string(),
448 context: format!(
449 "accepted constraint row-count device reads cannot exceed checked reduced \
450 constraint relations, got reads={} checked={}",
451 self.accepted_gpu_constraint_row_count_device_reads_consumed,
452 self.accepted_gpu_constraint_relations_checked_consumed
453 ),
454 });
455 }
456 Ok(())
457 }
458
459 pub fn require_accepted_gpu_world_view_evidence_trace(&self) -> Result<()> {
461 let mode_count = self
462 .accepted_g91_world_view_evidence_consumed
463 .checked_add(self.accepted_faeel_world_view_evidence_consumed)
464 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
465 construct: "epistemic probabilistic production metric gate".to_string(),
466 context: "accepted GPU world-view mode counters overflowed".to_string(),
467 })?;
468 if self.accepted_world_view_evidence_consumed != 0
469 && mode_count != self.accepted_world_view_evidence_consumed
470 {
471 return Err(XlogError::UnsupportedEpistemicConstruct {
472 construct: "epistemic probabilistic production metric gate".to_string(),
473 context: format!(
474 "accepted GPU world-view evidence must be classified by epistemic mode, got \
475 evidence={} gelfond_1991={} faeel={}",
476 self.accepted_world_view_evidence_consumed,
477 self.accepted_g91_world_view_evidence_consumed,
478 self.accepted_faeel_world_view_evidence_consumed
479 ),
480 });
481 }
482 if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
483 > self.accepted_evidence_assumptions_consumed
484 {
485 return Err(XlogError::UnsupportedEpistemicConstruct {
486 construct: "epistemic probabilistic production metric gate".to_string(),
487 context: format!(
488 "accepted nonzero-arity GPU evidence assumptions cannot exceed accepted \
489 assumptions, got nonzero={} assumptions={}",
490 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
491 self.accepted_evidence_assumptions_consumed
492 ),
493 });
494 }
495 if self.accepted_world_view_evidence_consumed != 0
496 && self.accepted_evidence_assumptions_consumed
497 < self.accepted_world_view_evidence_consumed
498 {
499 return Err(XlogError::UnsupportedEpistemicConstruct {
500 construct: "epistemic probabilistic production metric gate".to_string(),
501 context: format!(
502 "accepted GPU world-view evidence requires at least one accepted epistemic \
503 assumption per evidence record, got evidence={} assumptions={}",
504 self.accepted_world_view_evidence_consumed,
505 self.accepted_evidence_assumptions_consumed
506 ),
507 });
508 }
509 if self.accepted_gpu_batch_component_evidence_consumed
510 < self.accepted_gpu_batch_evidence_consumed
511 {
512 return Err(XlogError::UnsupportedEpistemicConstruct {
513 construct: "epistemic probabilistic production metric gate".to_string(),
514 context: format!(
515 "accepted GPU batch component evidence must cover accepted batch evidence, \
516 got batches={} components={}",
517 self.accepted_gpu_batch_evidence_consumed,
518 self.accepted_gpu_batch_component_evidence_consumed
519 ),
520 });
521 }
522 if self.accepted_gpu_batch_component_evidence_consumed
523 > self.accepted_world_view_evidence_consumed
524 {
525 return Err(XlogError::UnsupportedEpistemicConstruct {
526 construct: "epistemic probabilistic production metric gate".to_string(),
527 context: format!(
528 "accepted GPU batch component evidence cannot exceed accepted world-view \
529 evidence, got components={} evidence={}",
530 self.accepted_gpu_batch_component_evidence_consumed,
531 self.accepted_world_view_evidence_consumed
532 ),
533 });
534 }
535 if self.accepted_conditioned_world_view_evidence_consumed
536 > self.accepted_world_view_evidence_consumed
537 {
538 return Err(XlogError::UnsupportedEpistemicConstruct {
539 construct: "epistemic probabilistic production metric gate".to_string(),
540 context: format!(
541 "accepted conditioned world-view evidence cannot exceed accepted world-view \
542 evidence, got conditioned={} evidence={}",
543 self.accepted_conditioned_world_view_evidence_consumed,
544 self.accepted_world_view_evidence_consumed
545 ),
546 });
547 }
548 Ok(())
549 }
550
551 fn require_conditioned_counter_sum(
552 counter: &'static str,
553 aggregate: u64,
554 source: u64,
555 program: u64,
556 ) -> Result<()> {
557 let expected = source.checked_add(program).ok_or_else(|| {
558 XlogError::UnsupportedEpistemicConstruct {
559 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
560 context: format!(
561 "conditioned evidence counter {counter} overflowed while adding source={} \
562 program={}",
563 source, program
564 ),
565 }
566 })?;
567 if aggregate != expected {
568 return Err(XlogError::UnsupportedEpistemicConstruct {
569 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
570 context: format!(
571 "conditioned evidence counter {counter} must equal source+program, got \
572 aggregate={} source={} program={}",
573 aggregate, source, program
574 ),
575 });
576 }
577 Ok(())
578 }
579
580 fn require_gpu_path_counter_sum(
581 counter: &'static str,
582 aggregate: u64,
583 source: u64,
584 program: u64,
585 ) -> Result<()> {
586 let expected = source.checked_add(program).ok_or_else(|| {
587 XlogError::UnsupportedEpistemicConstruct {
588 construct: "epistemic probabilistic production metric gate".to_string(),
589 context: format!(
590 "GPU production path counter {counter} overflowed while adding source={} \
591 program={}",
592 source, program
593 ),
594 }
595 })?;
596 if aggregate != expected {
597 return Err(XlogError::UnsupportedEpistemicConstruct {
598 construct: "epistemic probabilistic production metric gate".to_string(),
599 context: format!(
600 "GPU production path accounting must match source+program for {counter}, \
601 got aggregate={} source={} program={}",
602 aggregate, source, program
603 ),
604 });
605 }
606 Ok(())
607 }
608
609 fn require_gpu_path_accounting(&self) -> Result<()> {
610 Self::require_gpu_path_counter_sum(
611 "exact_query_evaluations",
612 self.gpu_exact_query_evaluations,
613 self.gpu_source_exact_query_evaluations,
614 self.gpu_program_exact_query_evaluations,
615 )?;
616 Self::require_gpu_path_counter_sum(
617 "exact_gradient_evaluations",
618 self.gpu_exact_gradient_evaluations,
619 self.gpu_source_exact_gradient_evaluations,
620 self.gpu_program_exact_gradient_evaluations,
621 )?;
622 Self::require_gpu_path_counter_sum(
623 "pir_graph_uploads",
624 self.gpu_pir_graph_uploads,
625 self.gpu_source_pir_graph_uploads,
626 self.gpu_program_pir_graph_uploads,
627 )?;
628 Self::require_gpu_path_counter_sum(
629 "cnf_encodes",
630 self.gpu_cnf_encodes,
631 self.gpu_source_cnf_encodes,
632 self.gpu_program_cnf_encodes,
633 )?;
634 Self::require_gpu_path_counter_sum(
635 "knowledge_compilation_end_to_end_runs",
636 self.gpu_knowledge_compilation_end_to_end_runs,
637 self.gpu_source_knowledge_compilation_end_to_end_runs,
638 self.gpu_program_knowledge_compilation_end_to_end_runs,
639 )
640 }
641
642 pub fn require_conditioned_evidence_trace(&self) -> Result<()> {
644 Self::require_conditioned_counter_sum(
645 "accepted_world_view_evidence",
646 self.accepted_conditioned_world_view_evidence_consumed,
647 self.accepted_source_conditioned_world_view_evidence_consumed,
648 self.accepted_program_conditioned_world_view_evidence_consumed,
649 )?;
650 Self::require_conditioned_counter_sum(
651 "evidence_facts",
652 self.gpu_conditioned_evidence_facts,
653 self.gpu_source_conditioned_evidence_facts,
654 self.gpu_program_conditioned_evidence_facts,
655 )?;
656 Self::require_conditioned_counter_sum(
657 "nonzero_arity_evidence_facts",
658 self.gpu_conditioned_nonzero_arity_evidence_facts,
659 self.gpu_source_conditioned_nonzero_arity_evidence_facts,
660 self.gpu_program_conditioned_nonzero_arity_evidence_facts,
661 )?;
662 Self::require_conditioned_counter_sum(
663 "negative_evidence_facts",
664 self.gpu_conditioned_negative_evidence_facts,
665 self.gpu_source_conditioned_negative_evidence_facts,
666 self.gpu_program_conditioned_negative_evidence_facts,
667 )?;
668 Self::require_conditioned_counter_sum(
669 "know_evidence_facts",
670 self.gpu_conditioned_know_evidence_facts,
671 self.gpu_source_conditioned_know_evidence_facts,
672 self.gpu_program_conditioned_know_evidence_facts,
673 )?;
674 Self::require_conditioned_counter_sum(
675 "possible_evidence_facts",
676 self.gpu_conditioned_possible_evidence_facts,
677 self.gpu_source_conditioned_possible_evidence_facts,
678 self.gpu_program_conditioned_possible_evidence_facts,
679 )?;
680 Self::require_conditioned_counter_sum(
681 "not_known_evidence_facts",
682 self.gpu_conditioned_not_known_evidence_facts,
683 self.gpu_source_conditioned_not_known_evidence_facts,
684 self.gpu_program_conditioned_not_known_evidence_facts,
685 )?;
686 Self::require_conditioned_counter_sum(
687 "not_possible_evidence_facts",
688 self.gpu_conditioned_not_possible_evidence_facts,
689 self.gpu_source_conditioned_not_possible_evidence_facts,
690 self.gpu_program_conditioned_not_possible_evidence_facts,
691 )?;
692
693 if (self.gpu_conditioned_evidence_facts != 0
694 && self.accepted_conditioned_world_view_evidence_consumed == 0)
695 || (self.gpu_source_conditioned_evidence_facts != 0
696 && self.accepted_source_conditioned_world_view_evidence_consumed == 0)
697 || (self.gpu_program_conditioned_evidence_facts != 0
698 && self.accepted_program_conditioned_world_view_evidence_consumed == 0)
699 {
700 return Err(XlogError::UnsupportedEpistemicConstruct {
701 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
702 context: format!(
703 "conditioned exact evidence facts require accepted conditioned world-view \
704 evidence, got facts={} evidence={} source_facts={} source_evidence={} \
705 program_facts={} program_evidence={}",
706 self.gpu_conditioned_evidence_facts,
707 self.accepted_conditioned_world_view_evidence_consumed,
708 self.gpu_source_conditioned_evidence_facts,
709 self.accepted_source_conditioned_world_view_evidence_consumed,
710 self.gpu_program_conditioned_evidence_facts,
711 self.accepted_program_conditioned_world_view_evidence_consumed
712 ),
713 });
714 }
715
716 if self.gpu_conditioned_evidence_facts
717 < self.accepted_conditioned_world_view_evidence_consumed
718 || self.gpu_source_conditioned_evidence_facts
719 < self.accepted_source_conditioned_world_view_evidence_consumed
720 || self.gpu_program_conditioned_evidence_facts
721 < self.accepted_program_conditioned_world_view_evidence_consumed
722 {
723 return Err(XlogError::UnsupportedEpistemicConstruct {
724 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
725 context: format!(
726 "conditioned exact evidence facts must cover each accepted conditioned \
727 world-view evidence record, got facts={} evidence={} source_facts={} \
728 source_evidence={} program_facts={} program_evidence={}",
729 self.gpu_conditioned_evidence_facts,
730 self.accepted_conditioned_world_view_evidence_consumed,
731 self.gpu_source_conditioned_evidence_facts,
732 self.accepted_source_conditioned_world_view_evidence_consumed,
733 self.gpu_program_conditioned_evidence_facts,
734 self.accepted_program_conditioned_world_view_evidence_consumed
735 ),
736 });
737 }
738
739 if self.gpu_conditioned_nonzero_arity_evidence_facts > self.gpu_conditioned_evidence_facts
740 || self.gpu_source_conditioned_nonzero_arity_evidence_facts
741 > self.gpu_source_conditioned_evidence_facts
742 || self.gpu_program_conditioned_nonzero_arity_evidence_facts
743 > self.gpu_program_conditioned_evidence_facts
744 {
745 return Err(XlogError::UnsupportedEpistemicConstruct {
746 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
747 context: format!(
748 "conditioned nonzero-arity facts cannot exceed conditioned evidence facts: \
749 nonzero={} total={} source_nonzero={} source_total={} program_nonzero={} \
750 program_total={}",
751 self.gpu_conditioned_nonzero_arity_evidence_facts,
752 self.gpu_conditioned_evidence_facts,
753 self.gpu_source_conditioned_nonzero_arity_evidence_facts,
754 self.gpu_source_conditioned_evidence_facts,
755 self.gpu_program_conditioned_nonzero_arity_evidence_facts,
756 self.gpu_program_conditioned_evidence_facts
757 ),
758 });
759 }
760 if self.gpu_conditioned_negative_evidence_facts > self.gpu_conditioned_evidence_facts
761 || self.gpu_source_conditioned_negative_evidence_facts
762 > self.gpu_source_conditioned_evidence_facts
763 || self.gpu_program_conditioned_negative_evidence_facts
764 > self.gpu_program_conditioned_evidence_facts
765 {
766 return Err(XlogError::UnsupportedEpistemicConstruct {
767 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
768 context: format!(
769 "conditioned negative facts cannot exceed conditioned evidence facts: \
770 negative={} total={} source_negative={} source_total={} program_negative={} \
771 program_total={}",
772 self.gpu_conditioned_negative_evidence_facts,
773 self.gpu_conditioned_evidence_facts,
774 self.gpu_source_conditioned_negative_evidence_facts,
775 self.gpu_source_conditioned_evidence_facts,
776 self.gpu_program_conditioned_negative_evidence_facts,
777 self.gpu_program_conditioned_evidence_facts
778 ),
779 });
780 }
781
782 let operator_fact_count = self
783 .gpu_conditioned_know_evidence_facts
784 .checked_add(self.gpu_conditioned_possible_evidence_facts)
785 .and_then(|sum| sum.checked_add(self.gpu_conditioned_not_known_evidence_facts))
786 .and_then(|sum| sum.checked_add(self.gpu_conditioned_not_possible_evidence_facts))
787 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
788 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
789 context: "conditioned operator evidence fact counters overflowed".to_string(),
790 })?;
791 if operator_fact_count != self.gpu_conditioned_evidence_facts {
792 return Err(XlogError::UnsupportedEpistemicConstruct {
793 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
794 context: format!(
795 "conditioned operator evidence facts must equal total evidence facts, got \
796 operators={} total={}",
797 operator_fact_count, self.gpu_conditioned_evidence_facts
798 ),
799 });
800 }
801
802 let source_operator_fact_count = self
803 .gpu_source_conditioned_know_evidence_facts
804 .checked_add(self.gpu_source_conditioned_possible_evidence_facts)
805 .and_then(|sum| sum.checked_add(self.gpu_source_conditioned_not_known_evidence_facts))
806 .and_then(|sum| {
807 sum.checked_add(self.gpu_source_conditioned_not_possible_evidence_facts)
808 })
809 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
810 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
811 context: "source conditioned operator evidence fact counters overflowed"
812 .to_string(),
813 })?;
814 if source_operator_fact_count != self.gpu_source_conditioned_evidence_facts {
815 return Err(XlogError::UnsupportedEpistemicConstruct {
816 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
817 context: format!(
818 "source conditioned operator evidence facts must equal source evidence \
819 facts, got operators={} total={}",
820 source_operator_fact_count, self.gpu_source_conditioned_evidence_facts
821 ),
822 });
823 }
824
825 let program_operator_fact_count = self
826 .gpu_program_conditioned_know_evidence_facts
827 .checked_add(self.gpu_program_conditioned_possible_evidence_facts)
828 .and_then(|sum| sum.checked_add(self.gpu_program_conditioned_not_known_evidence_facts))
829 .and_then(|sum| {
830 sum.checked_add(self.gpu_program_conditioned_not_possible_evidence_facts)
831 })
832 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
833 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
834 context: "program conditioned operator evidence fact counters overflowed"
835 .to_string(),
836 })?;
837 if program_operator_fact_count != self.gpu_program_conditioned_evidence_facts {
838 return Err(XlogError::UnsupportedEpistemicConstruct {
839 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
840 context: format!(
841 "program conditioned operator evidence facts must equal program evidence \
842 facts, got operators={} total={}",
843 program_operator_fact_count, self.gpu_program_conditioned_evidence_facts
844 ),
845 });
846 }
847
848 let expected_max_arity = self
849 .gpu_source_conditioned_max_evidence_arity
850 .max(self.gpu_program_conditioned_max_evidence_arity);
851 if self.gpu_conditioned_max_evidence_arity != expected_max_arity {
852 return Err(XlogError::UnsupportedEpistemicConstruct {
853 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
854 context: format!(
855 "conditioned max evidence arity must equal max(source, program), got \
856 aggregate={} source={} program={}",
857 self.gpu_conditioned_max_evidence_arity,
858 self.gpu_source_conditioned_max_evidence_arity,
859 self.gpu_program_conditioned_max_evidence_arity
860 ),
861 });
862 }
863 if (self.gpu_conditioned_nonzero_arity_evidence_facts == 0)
864 != (self.gpu_conditioned_max_evidence_arity == 0)
865 {
866 return Err(XlogError::UnsupportedEpistemicConstruct {
867 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
868 context: format!(
869 "conditioned max evidence arity must be nonzero exactly when nonzero-arity \
870 facts are present, got nonzero={} max_arity={}",
871 self.gpu_conditioned_nonzero_arity_evidence_facts,
872 self.gpu_conditioned_max_evidence_arity
873 ),
874 });
875 }
876 if (self.gpu_source_conditioned_nonzero_arity_evidence_facts == 0)
877 != (self.gpu_source_conditioned_max_evidence_arity == 0)
878 {
879 return Err(XlogError::UnsupportedEpistemicConstruct {
880 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
881 context: format!(
882 "source conditioned max evidence arity must be nonzero exactly when \
883 source nonzero-arity facts are present, got nonzero={} max_arity={}",
884 self.gpu_source_conditioned_nonzero_arity_evidence_facts,
885 self.gpu_source_conditioned_max_evidence_arity
886 ),
887 });
888 }
889 if (self.gpu_program_conditioned_nonzero_arity_evidence_facts == 0)
890 != (self.gpu_program_conditioned_max_evidence_arity == 0)
891 {
892 return Err(XlogError::UnsupportedEpistemicConstruct {
893 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
894 context: format!(
895 "program conditioned max evidence arity must be nonzero exactly when \
896 program nonzero-arity facts are present, got nonzero={} max_arity={}",
897 self.gpu_program_conditioned_nonzero_arity_evidence_facts,
898 self.gpu_program_conditioned_max_evidence_arity
899 ),
900 });
901 }
902 if (self.accepted_evidence_assumptions_consumed != 0
903 || self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed != 0
904 || self.accepted_gpu_max_evidence_arity_consumed != 0)
905 && (self.gpu_conditioned_evidence_facts > self.accepted_evidence_assumptions_consumed
906 || self.gpu_conditioned_nonzero_arity_evidence_facts
907 > self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
908 || self.gpu_conditioned_max_evidence_arity
909 > self.accepted_gpu_max_evidence_arity_consumed)
910 {
911 return Err(XlogError::UnsupportedEpistemicConstruct {
912 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
913 context: format!(
914 "conditioned evidence facts must be bounded by accepted GPU evidence, got \
915 facts={}/{} nonzero={}/{} max_arity={}/{}",
916 self.gpu_conditioned_evidence_facts,
917 self.accepted_evidence_assumptions_consumed,
918 self.gpu_conditioned_nonzero_arity_evidence_facts,
919 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
920 self.gpu_conditioned_max_evidence_arity,
921 self.accepted_gpu_max_evidence_arity_consumed
922 ),
923 });
924 }
925 Ok(())
926 }
927
928 pub fn require_production_metric_eligibility(&self) -> Result<()> {
935 let capabilities = production_capabilities();
936 if capabilities.fixture_circuit_allowed {
937 return Err(XlogError::UnsupportedEpistemicConstruct {
938 construct: "epistemic probabilistic production metric gate".to_string(),
939 context: "bounded EpistemicCircuit fixtures are not allowed for production metrics"
940 .to_string(),
941 });
942 }
943 if capabilities.gpu_exact_provenance != EpistemicProbProductionCapabilityStatus::Available {
944 return Err(XlogError::UnsupportedEpistemicConstruct {
945 construct: "epistemic probabilistic production metric gate".to_string(),
946 context: "GPU exact/provenance production capability is not available".to_string(),
947 });
948 }
949 if capabilities.gpu_pir_cnf != EpistemicProbProductionCapabilityStatus::Available {
950 return Err(XlogError::UnsupportedEpistemicConstruct {
951 construct: "epistemic probabilistic production metric gate".to_string(),
952 context: "GPU PIR/CNF production capability is not available".to_string(),
953 });
954 }
955 if capabilities.gpu_knowledge_compilation
956 != EpistemicProbProductionCapabilityStatus::Available
957 {
958 return Err(XlogError::UnsupportedEpistemicConstruct {
959 construct: "epistemic probabilistic production metric gate".to_string(),
960 context: capabilities.gpu_knowledge_compilation_blocker.to_string(),
961 });
962 }
963 if capabilities.gpu_exact_query_and_gradient
964 != EpistemicProbProductionCapabilityStatus::Available
965 {
966 return Err(XlogError::UnsupportedEpistemicConstruct {
967 construct: "epistemic probabilistic production metric gate".to_string(),
968 context: "GPU exact query/gradient production capability is not available"
969 .to_string(),
970 });
971 }
972 if self.accepted_world_view_evidence_consumed == 0 {
973 return Err(XlogError::UnsupportedEpistemicConstruct {
974 construct: "epistemic probabilistic production metric gate".to_string(),
975 context: "production probability metrics require accepted world-view evidence"
976 .to_string(),
977 });
978 }
979 let gpu_production_path_events = self.checked_gpu_production_path_events()?;
980 if gpu_production_path_events == 0 {
981 return Err(XlogError::UnsupportedEpistemicConstruct {
982 construct: "epistemic probabilistic production metric gate".to_string(),
983 context: "production probability metrics require an existing GPU exact/provenance/PIR/CNF/knowledge-compilation counter"
984 .to_string(),
985 });
986 }
987 if self.accepted_gpu_production_path_events == 0 {
988 return Err(XlogError::UnsupportedEpistemicConstruct {
989 construct: "epistemic probabilistic production metric gate".to_string(),
990 context: "production probability metrics require GPU exact/provenance/PIR/CNF/knowledge-compilation work inside an accepted world-view evidence gate"
991 .to_string(),
992 });
993 }
994 if self.accepted_gpu_production_path_events > gpu_production_path_events {
995 return Err(XlogError::UnsupportedEpistemicConstruct {
996 construct: "epistemic probabilistic production metric gate".to_string(),
997 context: format!(
998 "accepted GPU probability production events cannot exceed total GPU production events: accepted={} total={}",
999 self.accepted_gpu_production_path_events, gpu_production_path_events
1000 ),
1001 });
1002 }
1003 if self.accepted_gpu_production_path_events < self.accepted_world_view_evidence_consumed {
1004 return Err(XlogError::UnsupportedEpistemicConstruct {
1005 construct: "epistemic probabilistic production metric gate".to_string(),
1006 context: format!(
1007 "accepted GPU probability production events must cover each accepted \
1008 world-view evidence record, got accepted_events={} evidence={}",
1009 self.accepted_gpu_production_path_events,
1010 self.accepted_world_view_evidence_consumed
1011 ),
1012 });
1013 }
1014 self.require_accepted_gpu_world_view_evidence_trace()?;
1015 self.require_accepted_gpu_tuple_evidence_trace()?;
1016 self.require_conditioned_evidence_trace()?;
1017 self.require_pir_cnf_accounting()?;
1018 self.require_gpu_path_accounting()?;
1019 Ok(())
1020 }
1021
1022 fn require_conditioned_evidence_metric_witness(&self) -> Result<()> {
1023 if self.accepted_conditioned_world_view_evidence_consumed == 0
1024 || self.gpu_conditioned_evidence_facts == 0
1025 {
1026 return Err(XlogError::UnsupportedEpistemicConstruct {
1027 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
1028 context:
1029 "production probability metrics require accepted world-view evidence compiled as exact evidence facts"
1030 .to_string(),
1031 });
1032 }
1033 Ok(())
1034 }
1035
1036 pub fn require_conditioned_evidence_metric_eligibility(&self) -> Result<()> {
1043 self.require_production_metric_eligibility()?;
1044 self.require_conditioned_evidence_metric_witness()?;
1045 if self.gpu_conditioned_nonzero_arity_evidence_facts > 0
1046 && self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
1047 {
1048 return Err(XlogError::UnsupportedEpistemicConstruct {
1049 construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
1050 context: format!(
1051 "conditioned nonzero-arity evidence facts require accepted GPU nonzero-arity \
1052 assumptions, got conditioned_nonzero={} accepted_nonzero={}",
1053 self.gpu_conditioned_nonzero_arity_evidence_facts,
1054 self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
1055 ),
1056 });
1057 }
1058 Ok(())
1059 }
1060}
1061
1062#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1064pub struct EpistemicProbPirCnfEvidence {
1065 pub pir_nodes: usize,
1067 pub root_count: usize,
1069 pub cnf_var_cap: u32,
1071 pub cnf_clause_cap: u32,
1073 pub cnf_lit_cap: u32,
1075}
1076
1077#[derive(Clone, Copy)]
1079pub struct EpistemicProbGpuExecutionEvidence<'a> {
1080 pub result: &'a EpistemicGpuExecutionResult,
1082 pub assumptions: &'a [EpistemicAssumption],
1084}
1085
1086pub struct EpistemicProbGpuBatchExecutionEvidence<'a> {
1088 pub batch: &'a EpistemicGpuBatchExecutionResult,
1090 pub assumptions_by_component: &'a [&'a [EpistemicAssumption]],
1092}
1093
1094#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1095enum EpistemicProbPirCnfPath {
1096 Source,
1097 Program,
1098}
1099
1100pub struct EpistemicProbProductionAdapter {
1102 config: GpuConfig,
1103 trace: EpistemicProbProductionTrace,
1104}
1105
1106#[derive(Clone)]
1114pub struct PreparedConditionedProgram {
1115 #[cfg(feature = "host-io")]
1116 state: Arc<Mutex<PreparedConditionedState>>,
1117}
1118
1119#[cfg(feature = "host-io")]
1125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1126pub struct ConditionedCircuitWitness {
1127 pub preparation_compiles: u64,
1129 pub materializations: u64,
1131 pub disk_cache_restores: u64,
1133 pub gpu_cache_hits: u64,
1135 pub circuit_generation: u64,
1137 pub cache_slot: u32,
1139}
1140
1141#[cfg(feature = "host-io")]
1142fn source_has_only_gpu_count_lift_queries(provenance: &Provenance) -> bool {
1143 !provenance.queries.is_empty()
1144 && provenance.evidence.is_empty()
1145 && provenance.choice_probs.is_empty()
1146 && provenance.queries.iter().all(|query| {
1147 provenance.aggregate_lifting.iter().any(|entry| {
1148 entry.status == AggregateLiftStatus::Fired
1149 && entry.operator == "count"
1150 && entry.deterministic_rows == 0
1151 && entry.predicate == query.predicate
1152 })
1153 })
1154}
1155
1156#[cfg(feature = "host-io")]
1157struct PreparedConditionedState {
1158 exact: ExactDdnnfProgram,
1159 evaluation_trace: EpistemicProbProductionTrace,
1160 initial_circuit: ExactCircuitWitness,
1161 successful_reuses: u64,
1162}
1163
1164#[cfg(feature = "host-io")]
1165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1166struct PreparedCircuitSnapshot {
1167 circuit: ExactCircuitWitness,
1168 successful_reuses: u64,
1169}
1170
1171#[cfg(feature = "host-io")]
1172impl PreparedConditionedState {
1173 fn ensure_usable(&self) -> Result<()> {
1174 self.exact.ensure_usable()
1175 }
1176
1177 fn snapshot(&self) -> Result<PreparedCircuitSnapshot> {
1178 self.ensure_usable()?;
1179 let circuit = self.exact.circuit_witness()?;
1180 if circuit.circuit_generation != self.initial_circuit.circuit_generation
1181 || circuit.cache_slot != self.initial_circuit.cache_slot
1182 {
1183 return Err(XlogError::Compilation(
1184 "Prepared conditioned circuit identity changed after preparation".to_string(),
1185 ));
1186 }
1187 Ok(PreparedCircuitSnapshot {
1188 circuit,
1189 successful_reuses: self.successful_reuses,
1190 })
1191 }
1192
1193 fn record_successful_reuse(&mut self) -> Result<PreparedCircuitSnapshot> {
1194 let before = self.snapshot()?;
1195 self.successful_reuses = self.successful_reuses.checked_add(1).ok_or_else(|| {
1196 XlogError::Compilation(
1197 "Prepared conditioned circuit reuse counter overflowed".to_string(),
1198 )
1199 })?;
1200 let after = self.snapshot()?;
1201 debug_assert_eq!(
1202 before.circuit.circuit_generation,
1203 after.circuit.circuit_generation
1204 );
1205 debug_assert_eq!(before.circuit.cache_slot, after.circuit.cache_slot);
1206 Ok(after)
1207 }
1208}
1209
1210#[cfg(feature = "host-io")]
1211impl PreparedConditionedProgram {
1212 fn new(
1213 exact: ExactDdnnfProgram,
1214 preparation_trace: EpistemicProbProductionTrace,
1215 ) -> Result<Self> {
1216 let initial_circuit = exact.circuit_witness()?;
1217 validate_single_circuit_materialization(initial_circuit)?;
1218 if initial_circuit.compiler_invocations > 1 {
1219 return Err(XlogError::Compilation(format!(
1220 "Prepared conditioned circuit invoked the GPU compiler {} times",
1221 initial_circuit.compiler_invocations
1222 )));
1223 }
1224 Ok(Self {
1225 state: Arc::new(Mutex::new(PreparedConditionedState {
1226 exact,
1227 evaluation_trace: reuse_trace_template(preparation_trace),
1228 initial_circuit,
1229 successful_reuses: 0,
1230 })),
1231 })
1232 }
1233
1234 fn lock_state(&self) -> Result<MutexGuard<'_, PreparedConditionedState>> {
1235 self.state.lock().map_err(|_| {
1236 XlogError::Execution(
1237 "Prepared conditioned state mutex is poisoned and permanently invalid".to_string(),
1238 )
1239 })
1240 }
1241
1242 fn apply_fact_probability_update(
1243 &self,
1244 apply: impl FnOnce(&mut ExactDdnnfProgram) -> Result<()>,
1245 ) -> Result<()> {
1246 let mut state = self.lock_state()?;
1247 let before = state.snapshot()?;
1248 let update_result = apply(&mut state.exact);
1249 if let Err(update_error) = update_result {
1250 if state.ensure_usable().is_err() {
1251 return Err(update_error);
1252 }
1253 let after = state.snapshot()?;
1254 if before != after {
1255 return Err(XlogError::Compilation(
1256 "Failed fact probability update changed the prepared circuit identity or compile ledger"
1257 .to_string(),
1258 ));
1259 }
1260 return Err(update_error);
1261 }
1262 let after = state.snapshot()?;
1263 if before != after {
1264 return Err(XlogError::Compilation(
1265 "Fact probability update changed the prepared circuit identity or compile ledger"
1266 .to_string(),
1267 ));
1268 }
1269 Ok(())
1270 }
1271
1272 #[cfg(feature = "host-io")]
1274 pub fn evaluate(&self) -> Result<(ExactResult, EpistemicProbProductionTrace)> {
1275 let mut state = self.lock_state()?;
1276 let before = state.snapshot()?;
1277 let result = state.exact.evaluate()?;
1278 let after = state.record_successful_reuse()?;
1279 let trace = query_reuse_trace(state.evaluation_trace, before, after)?;
1280 trace.require_conditioned_evidence_metric_eligibility()?;
1281 Ok((result, trace))
1282 }
1283
1284 #[cfg(feature = "host-io")]
1286 pub fn evaluate_with_grads(
1287 &self,
1288 ) -> Result<(ExactResultWithGrads, EpistemicProbProductionTrace)> {
1289 let mut state = self.lock_state()?;
1290 let before = state.snapshot()?;
1291 let result = state.exact.evaluate_gpu_with_grads()?;
1292 let after = state.record_successful_reuse()?;
1293 let trace = gradient_reuse_trace(state.evaluation_trace, before, after)?;
1294 trace.require_conditioned_evidence_metric_eligibility()?;
1295 Ok((result, trace))
1296 }
1297
1298 pub fn prob_var_map(&self) -> Result<Vec<ProbVarInfo>> {
1300 let state = self.lock_state()?;
1301 state.snapshot()?;
1302 state.exact.checked_prob_var_map()
1303 }
1304
1305 pub fn circuit_witness(&self) -> Result<ConditionedCircuitWitness> {
1307 let state = self.lock_state()?;
1308 conditioned_circuit_witness(state.snapshot()?)
1309 }
1310
1311 #[cfg(feature = "host-io")]
1317 pub fn set_fact_probabilities(&self, updates: &BTreeMap<u32, f64>) -> Result<()> {
1318 self.apply_fact_probability_update(|exact| exact.set_fact_probabilities(updates))
1319 }
1320
1321 #[cfg(all(test, feature = "host-io"))]
1322 fn set_fact_probabilities_with_device_failures(
1323 &self,
1324 updates: &BTreeMap<u32, f64>,
1325 fail_after_successful_writes: Option<usize>,
1326 fail_after_successful_rollback_writes: Option<usize>,
1327 ) -> Result<()> {
1328 self.apply_fact_probability_update(|exact| {
1329 exact.set_fact_probabilities_with_device_failures_for_test(
1330 updates,
1331 fail_after_successful_writes,
1332 fail_after_successful_rollback_writes,
1333 )
1334 })
1335 }
1336}
1337
1338#[cfg(feature = "host-io")]
1339fn conditioned_circuit_witness(
1340 snapshot: PreparedCircuitSnapshot,
1341) -> Result<ConditionedCircuitWitness> {
1342 validate_single_circuit_materialization(snapshot.circuit)?;
1343 Ok(ConditionedCircuitWitness {
1344 preparation_compiles: snapshot.circuit.compiler_invocations,
1345 materializations: snapshot.circuit.materializations,
1346 disk_cache_restores: snapshot.circuit.disk_cache_restores,
1347 gpu_cache_hits: snapshot.circuit.gpu_cache_hits,
1348 circuit_generation: snapshot.circuit.circuit_generation,
1349 cache_slot: snapshot.circuit.cache_slot,
1350 })
1351}
1352
1353#[cfg(feature = "host-io")]
1354fn validate_single_circuit_materialization(circuit: ExactCircuitWitness) -> Result<()> {
1355 let origins = circuit
1356 .compiler_invocations
1357 .checked_add(circuit.disk_cache_restores)
1358 .and_then(|count| count.checked_add(circuit.gpu_cache_hits))
1359 .ok_or_else(|| {
1360 XlogError::Compilation(
1361 "Prepared conditioned circuit materialization ledger overflowed".to_string(),
1362 )
1363 })?;
1364 if circuit.materializations != 1 || origins != 1 {
1365 return Err(XlogError::Compilation(format!(
1366 "Prepared conditioned circuit requires one materialization from one compile/cache event, got materializations={} compiler_invocations={} disk_cache_restores={} gpu_cache_hits={}",
1367 circuit.materializations,
1368 circuit.compiler_invocations,
1369 circuit.disk_cache_restores,
1370 circuit.gpu_cache_hits
1371 )));
1372 }
1373 Ok(())
1374}
1375
1376#[cfg(feature = "host-io")]
1377fn reuse_trace_template(
1378 mut preparation_trace: EpistemicProbProductionTrace,
1379) -> EpistemicProbProductionTrace {
1380 preparation_trace.gpu_exact_query_evaluations = 0;
1381 preparation_trace.gpu_source_exact_query_evaluations = 0;
1382 preparation_trace.gpu_program_exact_query_evaluations = 0;
1383 preparation_trace.gpu_exact_gradient_evaluations = 0;
1384 preparation_trace.gpu_source_exact_gradient_evaluations = 0;
1385 preparation_trace.gpu_program_exact_gradient_evaluations = 0;
1386 preparation_trace.gpu_source_conditioned_gradient_evaluations = 0;
1387 preparation_trace.gpu_program_conditioned_gradient_evaluations = 0;
1388 preparation_trace.gpu_pir_graph_uploads = 0;
1389 preparation_trace.gpu_source_pir_graph_uploads = 0;
1390 preparation_trace.gpu_program_pir_graph_uploads = 0;
1391 preparation_trace.gpu_cnf_encodes = 0;
1392 preparation_trace.gpu_source_cnf_encodes = 0;
1393 preparation_trace.gpu_program_cnf_encodes = 0;
1394 preparation_trace.gpu_knowledge_compilation_end_to_end_runs = 0;
1395 preparation_trace.gpu_source_knowledge_compilation_end_to_end_runs = 0;
1396 preparation_trace.gpu_program_knowledge_compilation_end_to_end_runs = 0;
1397 preparation_trace.accepted_gpu_production_path_events = 0;
1398 preparation_trace
1399}
1400
1401#[cfg(feature = "host-io")]
1402fn query_reuse_trace(
1403 mut trace: EpistemicProbProductionTrace,
1404 before: PreparedCircuitSnapshot,
1405 after: PreparedCircuitSnapshot,
1406) -> Result<EpistemicProbProductionTrace> {
1407 apply_authoritative_reuse_witness(&mut trace, before, after)?;
1408 trace.gpu_exact_query_evaluations = trace.gpu_conditioned_circuit_reuses;
1409 trace.gpu_source_exact_query_evaluations = trace.gpu_conditioned_circuit_reuses;
1410 trace.accepted_gpu_production_path_events = trace.checked_gpu_production_path_events()?;
1411 Ok(trace)
1412}
1413
1414#[cfg(feature = "host-io")]
1415fn gradient_reuse_trace(
1416 mut trace: EpistemicProbProductionTrace,
1417 before: PreparedCircuitSnapshot,
1418 after: PreparedCircuitSnapshot,
1419) -> Result<EpistemicProbProductionTrace> {
1420 apply_authoritative_reuse_witness(&mut trace, before, after)?;
1421 trace.gpu_exact_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1422 trace.gpu_source_exact_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1423 trace.gpu_source_conditioned_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1424 trace.accepted_gpu_production_path_events = trace.checked_gpu_production_path_events()?;
1425 Ok(trace)
1426}
1427
1428#[cfg(feature = "host-io")]
1429fn apply_authoritative_reuse_witness(
1430 trace: &mut EpistemicProbProductionTrace,
1431 before: PreparedCircuitSnapshot,
1432 after: PreparedCircuitSnapshot,
1433) -> Result<()> {
1434 if before.circuit.circuit_generation != after.circuit.circuit_generation
1435 || before.circuit.cache_slot != after.circuit.cache_slot
1436 {
1437 return Err(XlogError::Compilation(
1438 "Prepared conditioned circuit identity changed during evaluation".to_string(),
1439 ));
1440 }
1441 trace.gpu_exact_source_compiles = after
1442 .circuit
1443 .compiler_invocations
1444 .checked_sub(before.circuit.compiler_invocations)
1445 .ok_or_else(|| {
1446 XlogError::Compilation(
1447 "Prepared conditioned compiler invocation ledger regressed".to_string(),
1448 )
1449 })?;
1450 trace.gpu_exact_program_compiles = 0;
1451 trace.gpu_conditioned_circuit_reuses = after
1452 .successful_reuses
1453 .checked_sub(before.successful_reuses)
1454 .ok_or_else(|| {
1455 XlogError::Compilation(
1456 "Prepared conditioned circuit reuse counter regressed".to_string(),
1457 )
1458 })?;
1459 let witness = conditioned_circuit_witness(after)?;
1460 trace.gpu_conditioned_circuit_preparation_compiles = witness.preparation_compiles;
1461 trace.gpu_conditioned_circuit_materializations = witness.materializations;
1462 trace.gpu_conditioned_circuit_disk_cache_restores = witness.disk_cache_restores;
1463 trace.gpu_conditioned_circuit_gpu_cache_hits = witness.gpu_cache_hits;
1464 trace.gpu_conditioned_circuit_generation = witness.circuit_generation;
1465 trace.gpu_conditioned_circuit_cache_slot = u64::from(witness.cache_slot);
1466 if trace.gpu_exact_source_compiles != 0
1467 || trace.gpu_exact_program_compiles != 0
1468 || trace.gpu_conditioned_circuit_reuses != 1
1469 {
1470 return Err(XlogError::Compilation(format!(
1471 "Prepared conditioned evaluation must not compile and must reuse one circuit, got source_compiles={} program_compiles={} reuses={}",
1472 trace.gpu_exact_source_compiles,
1473 trace.gpu_exact_program_compiles,
1474 trace.gpu_conditioned_circuit_reuses
1475 )));
1476 }
1477 Ok(())
1478}
1479
1480#[cfg(feature = "host-io")]
1481#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1482enum EpistemicProbConditionedEvidencePath {
1483 Source,
1484 Program,
1485}
1486
1487impl EpistemicProbProductionAdapter {
1488 fn checked_trace_counter_add(current: u64, delta: u64, counter: &str) -> Result<u64> {
1489 current
1490 .checked_add(delta)
1491 .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
1492 construct: "epistemic probabilistic production trace accounting".to_string(),
1493 context: format!(
1494 "accepted GPU probability trace counter {counter} overflowed while adding \
1495 {delta} to {current}"
1496 ),
1497 })
1498 }
1499
1500 #[cfg(feature = "host-io")]
1501 fn record_gpu_exact_query_evaluation(&mut self, program: &ExactDdnnfProgram) -> Result<()> {
1502 checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
1503 match program.origin() {
1504 ExactProgramOrigin::Source => {
1505 checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
1506 }
1507 ExactProgramOrigin::Program => {
1508 checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
1509 }
1510 }
1511 Ok(())
1512 }
1513
1514 #[cfg(feature = "host-io")]
1515 fn record_gpu_exact_gradient_evaluation(&mut self, program: &ExactDdnnfProgram) -> Result<()> {
1516 self.record_gpu_exact_gradient_evaluation_for_origin(program.origin())
1517 }
1518
1519 #[cfg(feature = "host-io")]
1520 fn record_gpu_exact_gradient_evaluation_for_origin(
1521 &mut self,
1522 origin: ExactProgramOrigin,
1523 ) -> Result<()> {
1524 checked_prob_trace_counter_inc!(self, gpu_exact_gradient_evaluations);
1525 match origin {
1526 ExactProgramOrigin::Source => {
1527 checked_prob_trace_counter_inc!(self, gpu_source_exact_gradient_evaluations);
1528 }
1529 ExactProgramOrigin::Program => {
1530 checked_prob_trace_counter_inc!(self, gpu_program_exact_gradient_evaluations);
1531 }
1532 }
1533 Ok(())
1534 }
1535
1536 pub fn new(config: GpuConfig) -> Self {
1538 Self {
1539 config,
1540 trace: EpistemicProbProductionTrace::default(),
1541 }
1542 }
1543
1544 pub fn trace(&self) -> EpistemicProbProductionTrace {
1546 self.trace
1547 }
1548
1549 pub fn apply_accepted_world_view_to_circuit(
1555 &mut self,
1556 circuit: &mut EpistemicCircuit,
1557 evidence: AcceptedWorldViewEvidence,
1558 ) -> Result<CircuitUpdate> {
1559 epistemic_prob_trace_transaction!(self, {
1560 self.consume_accepted_evidence(&evidence)?;
1561 let update = circuit.apply_accepted_world_view(evidence)?;
1562 if update.mode == CircuitUpdateMode::IncrementalEvidence {
1563 self.trace.accepted_incremental_circuit_updates = Self::checked_trace_counter_add(
1564 self.trace.accepted_incremental_circuit_updates,
1565 1,
1566 "accepted_incremental_circuit_updates",
1567 )?;
1568 }
1569 Ok(update)
1570 })
1571 }
1572
1573 pub fn apply_accepted_world_view_to_circuit_with_gpu_execution_result(
1575 &mut self,
1576 circuit: &mut EpistemicCircuit,
1577 provider: &CudaKernelProvider,
1578 result: &EpistemicGpuExecutionResult,
1579 assumptions: Vec<EpistemicAssumption>,
1580 ) -> Result<CircuitUpdate> {
1581 let evidence =
1582 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1583 self.apply_accepted_world_view_to_circuit(circuit, evidence)
1584 }
1585
1586 pub fn apply_accepted_world_views_to_circuit_for_gpu_batch_execution_result(
1588 &mut self,
1589 circuit: &mut EpistemicCircuit,
1590 provider: &CudaKernelProvider,
1591 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1592 ) -> Result<Vec<CircuitUpdate>> {
1593 epistemic_prob_trace_transaction!(self, {
1594 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1595 provider,
1596 evidence,
1597 "epistemic probabilistic incremental circuit batch production",
1598 )?;
1599
1600 let mut updates = Vec::with_capacity(accepted.len());
1601 for evidence in accepted {
1602 updates.push(self.apply_accepted_world_view_to_circuit(circuit, evidence)?);
1603 }
1604 Ok(updates)
1605 })
1606 }
1607
1608 fn accepted_world_views_from_gpu_batch_execution_evidence(
1609 &mut self,
1610 provider: &CudaKernelProvider,
1611 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1612 construct: &str,
1613 ) -> Result<Vec<AcceptedWorldViewEvidence>> {
1614 if evidence.batch.results.is_empty() {
1615 return Err(XlogError::UnsupportedEpistemicConstruct {
1616 construct: construct.to_string(),
1617 context: "probabilistic batch gating requires at least one accepted GPU component"
1618 .to_string(),
1619 });
1620 }
1621 if evidence.assumptions_by_component.len() != evidence.batch.results.len() {
1622 return Err(XlogError::UnsupportedEpistemicConstruct {
1623 construct: construct.to_string(),
1624 context: format!(
1625 "assumption group count {} does not match GPU batch component count {}",
1626 evidence.assumptions_by_component.len(),
1627 evidence.batch.results.len()
1628 ),
1629 });
1630 }
1631 let batch_trace = evidence.batch.trace;
1632 if batch_trace.component_count != evidence.batch.results.len()
1633 || batch_trace.gpu_runtime_component_executions != evidence.batch.results.len()
1634 || batch_trace.tracked_dtoh_calls != 0
1635 || batch_trace.tracked_htod_calls != 0
1636 || batch_trace.tracked_data_plane_htod_calls != 0
1637 || batch_trace.per_candidate_host_round_trips != 0
1638 || batch_trace.violated_constraint_relations != 0
1639 || !batch_trace.aggregate_kernel_timing.is_recorded()
1640 {
1641 return Err(XlogError::UnsupportedEpistemicConstruct {
1642 construct: construct.to_string(),
1643 context: format!(
1644 "accepted GPU batch evidence requires complete GPU component execution and \
1645 zero observed hot-path transfers outside bounded launch metadata plus \
1646 aggregate CUDA-event timing, got components={}/{}, dtoh_calls={}, \
1647 htod_calls={}, data_plane_htod_calls={}, launch_metadata_htod_calls={}, \
1648 round_trips={}, constraint_violations={}, aggregate_timing_recorded={}",
1649 batch_trace.gpu_runtime_component_executions,
1650 batch_trace.component_count,
1651 batch_trace.tracked_dtoh_calls,
1652 batch_trace.tracked_htod_calls,
1653 batch_trace.tracked_data_plane_htod_calls,
1654 batch_trace.tracked_launch_metadata_htod_calls,
1655 batch_trace.per_candidate_host_round_trips,
1656 batch_trace.violated_constraint_relations,
1657 batch_trace.aggregate_kernel_timing.is_recorded()
1658 ),
1659 });
1660 }
1661 evidence.batch.require_trace_matches_components(construct)?;
1662
1663 let mut accepted = Vec::with_capacity(evidence.batch.results.len());
1664 for (result, assumptions) in evidence
1665 .batch
1666 .results
1667 .iter()
1668 .zip(evidence.assumptions_by_component.iter())
1669 {
1670 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1671 provider,
1672 result,
1673 (*assumptions).to_vec(),
1674 )?);
1675 }
1676
1677 self.trace.accepted_gpu_batch_evidence_consumed = Self::checked_trace_counter_add(
1678 self.trace.accepted_gpu_batch_evidence_consumed,
1679 1,
1680 "accepted_gpu_batch_evidence_consumed",
1681 )?;
1682 self.trace.accepted_gpu_batch_component_evidence_consumed =
1683 Self::checked_trace_counter_add(
1684 self.trace.accepted_gpu_batch_component_evidence_consumed,
1685 accepted.len() as u64,
1686 "accepted_gpu_batch_component_evidence_consumed",
1687 )?;
1688
1689 Ok(accepted)
1690 }
1691
1692 #[cfg(feature = "host-io")]
1693 fn record_conditioned_evidence_counts(
1694 &mut self,
1695 counts: EpistemicProbConditionedEvidenceCounts,
1696 path: EpistemicProbConditionedEvidencePath,
1697 ) -> Result<()> {
1698 macro_rules! add_counter {
1699 ($field:ident, $delta:expr) => {
1700 self.trace.$field =
1701 Self::checked_trace_counter_add(self.trace.$field, $delta, stringify!($field))?;
1702 };
1703 }
1704
1705 add_counter!(accepted_conditioned_world_view_evidence_consumed, 1);
1706 add_counter!(gpu_conditioned_evidence_facts, counts.total as u64);
1707 add_counter!(
1708 gpu_conditioned_nonzero_arity_evidence_facts,
1709 counts.nonzero_arity as u64
1710 );
1711 self.trace.gpu_conditioned_max_evidence_arity = self
1712 .trace
1713 .gpu_conditioned_max_evidence_arity
1714 .max(counts.max_arity);
1715 add_counter!(
1716 gpu_conditioned_negative_evidence_facts,
1717 counts.negative as u64
1718 );
1719 match path {
1720 EpistemicProbConditionedEvidencePath::Source => {
1721 add_counter!(accepted_source_conditioned_world_view_evidence_consumed, 1);
1722 add_counter!(gpu_source_conditioned_evidence_facts, counts.total as u64);
1723 add_counter!(
1724 gpu_source_conditioned_nonzero_arity_evidence_facts,
1725 counts.nonzero_arity as u64
1726 );
1727 self.trace.gpu_source_conditioned_max_evidence_arity = self
1728 .trace
1729 .gpu_source_conditioned_max_evidence_arity
1730 .max(counts.max_arity);
1731 add_counter!(
1732 gpu_source_conditioned_negative_evidence_facts,
1733 counts.negative as u64
1734 );
1735 add_counter!(
1736 gpu_source_conditioned_know_evidence_facts,
1737 counts.know as u64
1738 );
1739 add_counter!(
1740 gpu_source_conditioned_possible_evidence_facts,
1741 counts.possible as u64
1742 );
1743 add_counter!(
1744 gpu_source_conditioned_not_known_evidence_facts,
1745 counts.not_known as u64
1746 );
1747 add_counter!(
1748 gpu_source_conditioned_not_possible_evidence_facts,
1749 counts.not_possible as u64
1750 );
1751 }
1752 EpistemicProbConditionedEvidencePath::Program => {
1753 add_counter!(accepted_program_conditioned_world_view_evidence_consumed, 1);
1754 add_counter!(gpu_program_conditioned_evidence_facts, counts.total as u64);
1755 add_counter!(
1756 gpu_program_conditioned_nonzero_arity_evidence_facts,
1757 counts.nonzero_arity as u64
1758 );
1759 self.trace.gpu_program_conditioned_max_evidence_arity = self
1760 .trace
1761 .gpu_program_conditioned_max_evidence_arity
1762 .max(counts.max_arity);
1763 add_counter!(
1764 gpu_program_conditioned_negative_evidence_facts,
1765 counts.negative as u64
1766 );
1767 add_counter!(
1768 gpu_program_conditioned_know_evidence_facts,
1769 counts.know as u64
1770 );
1771 add_counter!(
1772 gpu_program_conditioned_possible_evidence_facts,
1773 counts.possible as u64
1774 );
1775 add_counter!(
1776 gpu_program_conditioned_not_known_evidence_facts,
1777 counts.not_known as u64
1778 );
1779 add_counter!(
1780 gpu_program_conditioned_not_possible_evidence_facts,
1781 counts.not_possible as u64
1782 );
1783 }
1784 }
1785 add_counter!(gpu_conditioned_know_evidence_facts, counts.know as u64);
1786 add_counter!(
1787 gpu_conditioned_possible_evidence_facts,
1788 counts.possible as u64
1789 );
1790 add_counter!(
1791 gpu_conditioned_not_known_evidence_facts,
1792 counts.not_known as u64
1793 );
1794 add_counter!(
1795 gpu_conditioned_not_possible_evidence_facts,
1796 counts.not_possible as u64
1797 );
1798 Ok(())
1799 }
1800
1801 fn record_accepted_gpu_production_path_events_since(
1802 &mut self,
1803 events_before: u64,
1804 ) -> Result<()> {
1805 let events_after = self.trace.checked_gpu_production_path_events()?;
1806 let delta = events_after.checked_sub(events_before).ok_or_else(|| {
1807 XlogError::UnsupportedEpistemicConstruct {
1808 construct: "epistemic probabilistic production trace accounting".to_string(),
1809 context: format!(
1810 "accepted GPU probability production events decreased from {events_before} to \
1811 {events_after}"
1812 ),
1813 }
1814 })?;
1815 self.trace.accepted_gpu_production_path_events = Self::checked_trace_counter_add(
1816 self.trace.accepted_gpu_production_path_events,
1817 delta,
1818 "accepted_gpu_production_path_events",
1819 )?;
1820 Ok(())
1821 }
1822
1823 pub fn compile_source_with_accepted_world_view(
1825 &mut self,
1826 source: &str,
1827 evidence: &AcceptedWorldViewEvidence,
1828 ) -> Result<ExactDdnnfProgram> {
1829 epistemic_prob_trace_transaction!(self, {
1830 self.require_accepted_evidence(evidence)?;
1831 let production_events_before = self.trace.checked_gpu_production_path_events()?;
1832 let program = ExactDdnnfProgram::compile_source_with_gpu(source, self.config)?;
1833 require_gpu_exact_backend(&program, "epistemic probabilistic source exact compile")?;
1834 checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
1835 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
1836 self.record_accepted_evidence(evidence)?;
1837 Ok(program)
1838 })
1839 }
1840
1841 pub fn compile_source_with_gpu_execution_result(
1843 &mut self,
1844 source: &str,
1845 provider: &CudaKernelProvider,
1846 result: &EpistemicGpuExecutionResult,
1847 assumptions: Vec<EpistemicAssumption>,
1848 ) -> Result<ExactDdnnfProgram> {
1849 let evidence =
1850 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1851 self.compile_source_with_accepted_world_view(source, &evidence)
1852 }
1853
1854 pub fn compile_source_for_gpu_execution_results(
1856 &mut self,
1857 source: &str,
1858 provider: &CudaKernelProvider,
1859 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
1860 ) -> Result<Vec<ExactDdnnfProgram>> {
1861 epistemic_prob_trace_transaction!(self, {
1862 if evidence_records.is_empty() {
1863 return Err(XlogError::UnsupportedEpistemicConstruct {
1864 construct: "epistemic probabilistic source exact compile batch".to_string(),
1865 context:
1866 "batched source exact compile requires at least one accepted GPU result"
1867 .to_string(),
1868 });
1869 }
1870
1871 let mut accepted = Vec::with_capacity(evidence_records.len());
1872 for record in evidence_records {
1873 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1874 provider,
1875 record.result,
1876 record.assumptions.to_vec(),
1877 )?);
1878 }
1879
1880 let mut programs = Vec::with_capacity(accepted.len());
1881 for evidence in &accepted {
1882 programs.push(self.compile_source_with_accepted_world_view(source, evidence)?);
1883 }
1884 Ok(programs)
1885 })
1886 }
1887
1888 pub fn compile_source_for_gpu_batch_execution_result(
1890 &mut self,
1891 source: &str,
1892 provider: &CudaKernelProvider,
1893 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1894 ) -> Result<Vec<ExactDdnnfProgram>> {
1895 epistemic_prob_trace_transaction!(self, {
1896 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1897 provider,
1898 evidence,
1899 "epistemic probabilistic source exact compile batch production",
1900 )?;
1901
1902 let mut programs = Vec::with_capacity(accepted.len());
1903 for evidence in &accepted {
1904 programs.push(self.compile_source_with_accepted_world_view(source, evidence)?);
1905 }
1906 Ok(programs)
1907 })
1908 }
1909
1910 pub fn compile_program_with_accepted_world_view(
1912 &mut self,
1913 program: &Program,
1914 evidence: &AcceptedWorldViewEvidence,
1915 ) -> Result<ExactDdnnfProgram> {
1916 epistemic_prob_trace_transaction!(self, {
1917 self.require_accepted_evidence(evidence)?;
1918 let production_events_before = self.trace.checked_gpu_production_path_events()?;
1919 let exact = ExactDdnnfProgram::compile_from_program(program, self.config)?;
1920 require_gpu_exact_backend(
1921 &exact,
1922 "epistemic probabilistic parsed-program exact compile",
1923 )?;
1924 checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
1925 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
1926 self.record_accepted_evidence(evidence)?;
1927 Ok(exact)
1928 })
1929 }
1930
1931 pub fn compile_program_with_gpu_execution_result(
1933 &mut self,
1934 program: &Program,
1935 provider: &CudaKernelProvider,
1936 result: &EpistemicGpuExecutionResult,
1937 assumptions: Vec<EpistemicAssumption>,
1938 ) -> Result<ExactDdnnfProgram> {
1939 let evidence =
1940 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1941 self.compile_program_with_accepted_world_view(program, &evidence)
1942 }
1943
1944 pub fn compile_program_for_gpu_execution_results(
1946 &mut self,
1947 program: &Program,
1948 provider: &CudaKernelProvider,
1949 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
1950 ) -> Result<Vec<ExactDdnnfProgram>> {
1951 epistemic_prob_trace_transaction!(self, {
1952 if evidence_records.is_empty() {
1953 return Err(XlogError::UnsupportedEpistemicConstruct {
1954 construct: "epistemic probabilistic parsed-program exact compile batch"
1955 .to_string(),
1956 context: "batched parsed-program exact compile requires at least one accepted GPU result"
1957 .to_string(),
1958 });
1959 }
1960
1961 let mut accepted = Vec::with_capacity(evidence_records.len());
1962 for record in evidence_records {
1963 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1964 provider,
1965 record.result,
1966 record.assumptions.to_vec(),
1967 )?);
1968 }
1969
1970 let mut programs = Vec::with_capacity(accepted.len());
1971 for evidence in &accepted {
1972 programs.push(self.compile_program_with_accepted_world_view(program, evidence)?);
1973 }
1974 Ok(programs)
1975 })
1976 }
1977
1978 pub fn compile_program_for_gpu_batch_execution_result(
1980 &mut self,
1981 program: &Program,
1982 provider: &CudaKernelProvider,
1983 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1984 ) -> Result<Vec<ExactDdnnfProgram>> {
1985 epistemic_prob_trace_transaction!(self, {
1986 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1987 provider,
1988 evidence,
1989 "epistemic probabilistic parsed-program exact compile batch production",
1990 )?;
1991
1992 let mut programs = Vec::with_capacity(accepted.len());
1993 for evidence in &accepted {
1994 programs.push(self.compile_program_with_accepted_world_view(program, evidence)?);
1995 }
1996 Ok(programs)
1997 })
1998 }
1999
2000 #[cfg(feature = "host-io")]
2002 pub fn compile_and_evaluate_source_with_accepted_world_view(
2003 &mut self,
2004 source: &str,
2005 evidence: &AcceptedWorldViewEvidence,
2006 ) -> Result<ExactResult> {
2007 epistemic_prob_trace_transaction!(self, {
2008 self.require_accepted_evidence(evidence)?;
2009 let production_events_before = self.trace.checked_gpu_production_path_events()?;
2010 let program = ExactDdnnfProgram::compile_source_with_gpu(source, self.config)?;
2011 require_gpu_exact_backend(
2012 &program,
2013 "epistemic probabilistic source exact compile/evaluate",
2014 )?;
2015 checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2016 let result = program.evaluate()?;
2017 checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2018 checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
2019 checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2020 checked_prob_trace_counter_inc!(self, gpu_source_knowledge_compilation_end_to_end_runs);
2021 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2022 self.record_accepted_evidence(evidence)?;
2023 Ok(result)
2024 })
2025 }
2026
2027 #[cfg(feature = "host-io")]
2029 pub fn compile_and_evaluate_source_with_gpu_execution_result(
2030 &mut self,
2031 source: &str,
2032 provider: &CudaKernelProvider,
2033 result: &EpistemicGpuExecutionResult,
2034 assumptions: Vec<EpistemicAssumption>,
2035 ) -> Result<ExactResult> {
2036 let evidence =
2037 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2038 self.compile_and_evaluate_source_with_accepted_world_view(source, &evidence)
2039 }
2040
2041 #[cfg(feature = "host-io")]
2043 pub fn compile_and_evaluate_source_for_gpu_execution_results(
2044 &mut self,
2045 source: &str,
2046 provider: &CudaKernelProvider,
2047 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2048 ) -> Result<Vec<ExactResult>> {
2049 epistemic_prob_trace_transaction!(self, {
2050 if evidence_records.is_empty() {
2051 return Err(XlogError::UnsupportedEpistemicConstruct {
2052 construct: "epistemic probabilistic production batch".to_string(),
2053 context:
2054 "batched knowledge compilation requires at least one accepted GPU result"
2055 .to_string(),
2056 });
2057 }
2058
2059 let mut accepted = Vec::with_capacity(evidence_records.len());
2060 for record in evidence_records {
2061 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2062 provider,
2063 record.result,
2064 record.assumptions.to_vec(),
2065 )?);
2066 }
2067
2068 let mut results = Vec::with_capacity(accepted.len());
2069 for evidence in &accepted {
2070 results.push(
2071 self.compile_and_evaluate_source_with_accepted_world_view(source, evidence)?,
2072 );
2073 }
2074 Ok(results)
2075 })
2076 }
2077
2078 #[cfg(feature = "host-io")]
2080 pub fn compile_and_evaluate_source_for_gpu_batch_execution_result(
2081 &mut self,
2082 source: &str,
2083 provider: &CudaKernelProvider,
2084 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2085 ) -> Result<Vec<ExactResult>> {
2086 epistemic_prob_trace_transaction!(self, {
2087 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2088 provider,
2089 evidence,
2090 "epistemic probabilistic batch production",
2091 )?;
2092
2093 let mut results = Vec::with_capacity(accepted.len());
2094 for evidence in &accepted {
2095 results.push(
2096 self.compile_and_evaluate_source_with_accepted_world_view(source, evidence)?,
2097 );
2098 }
2099 Ok(results)
2100 })
2101 }
2102
2103 #[cfg(feature = "host-io")]
2105 pub fn compile_and_evaluate_conditioned_source_with_accepted_world_view(
2106 &mut self,
2107 source: &str,
2108 evidence: &AcceptedWorldViewEvidence,
2109 ) -> Result<ExactResult> {
2110 epistemic_prob_trace_transaction!(self, {
2111 let program = parse_program(source)?;
2112 let provenance = extract_from_program(&program)?;
2113 self.compile_and_evaluate_conditioned_program_with_path(
2114 &program,
2115 &provenance,
2116 evidence,
2117 EpistemicProbConditionedEvidencePath::Source,
2118 "epistemic probabilistic conditioned source exact compile/evaluate",
2119 )
2120 })
2121 }
2122
2123 #[cfg(feature = "host-io")]
2125 pub fn compile_and_evaluate_conditioned_source_with_gpu_execution_result(
2126 &mut self,
2127 source: &str,
2128 provider: &CudaKernelProvider,
2129 result: &EpistemicGpuExecutionResult,
2130 assumptions: Vec<EpistemicAssumption>,
2131 ) -> Result<ExactResult> {
2132 let evidence =
2133 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2134 self.compile_and_evaluate_conditioned_source_with_accepted_world_view(source, &evidence)
2135 }
2136
2137 #[cfg(feature = "host-io")]
2142 pub fn prepare_conditioned_source_with_accepted_world_view(
2143 &mut self,
2144 source: &str,
2145 evidence: &AcceptedWorldViewEvidence,
2146 ) -> Result<PreparedConditionedProgram> {
2147 epistemic_prob_trace_transaction!(self, {
2148 let program = parse_program(source)?;
2149 let provenance = extract_from_program(&program)?;
2150 self.prepare_conditioned_program_with_accepted_world_view(
2151 &program,
2152 &provenance,
2153 evidence,
2154 )
2155 })
2156 }
2157
2158 #[cfg(feature = "host-io")]
2160 pub fn prepare_conditioned_source_with_gpu_execution_result(
2161 &mut self,
2162 source: &str,
2163 provider: &CudaKernelProvider,
2164 result: &EpistemicGpuExecutionResult,
2165 assumptions: Vec<EpistemicAssumption>,
2166 ) -> Result<PreparedConditionedProgram> {
2167 let evidence =
2168 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2169 self.prepare_conditioned_source_with_accepted_world_view(source, &evidence)
2170 }
2171
2172 #[cfg(feature = "host-io")]
2173 fn prepare_conditioned_program_with_accepted_world_view(
2174 &mut self,
2175 program: &Program,
2176 provenance: &Provenance,
2177 evidence: &AcceptedWorldViewEvidence,
2178 ) -> Result<PreparedConditionedProgram> {
2179 let evidence = accepted_evidence_for_provenance(evidence, provenance)?;
2180 let evidence = evidence.as_ref();
2181 if program.directives.prob_engine_or_default() != ProbEngine::ExactDdnnf {
2182 return Err(XlogError::UnsupportedEpistemicConstruct {
2183 construct: "reusable conditioned circuit".to_string(),
2184 context: "reusable conditioned programs require the exact Decision-DNNF engine; Monte Carlo programs cannot expose mutable CNF fact weights"
2185 .to_string(),
2186 });
2187 }
2188 if source_has_only_gpu_count_lift_queries(provenance) {
2189 return Err(XlogError::UnsupportedEpistemicConstruct {
2190 construct: "reusable conditioned circuit".to_string(),
2191 context: "GPU count-lift exact programs do not expose mutable CNF fact variables"
2192 .to_string(),
2193 });
2194 }
2195 self.require_accepted_evidence(evidence)?;
2196 let production_events_before = self.trace.checked_gpu_production_path_events()?;
2197 let (conditioned_program, evidence_counts) =
2198 condition_program_with_accepted_evidence_using_provenance(
2199 program, provenance, evidence,
2200 )?;
2201 let exact = ExactDdnnfProgram::compile_from_program(&conditioned_program, self.config)?;
2202 if exact.uses_gpu_native_count_lift() {
2203 return Err(XlogError::UnsupportedEpistemicConstruct {
2204 construct: "reusable conditioned circuit".to_string(),
2205 context: "GPU count-lift exact programs do not expose mutable CNF fact weights"
2206 .to_string(),
2207 });
2208 }
2209 require_gpu_exact_backend(
2210 &exact,
2211 "epistemic probabilistic reusable conditioned source exact compile",
2212 )?;
2213 checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2214 self.record_conditioned_evidence_counts(
2215 evidence_counts,
2216 EpistemicProbConditionedEvidencePath::Source,
2217 )?;
2218 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2219 self.record_accepted_evidence(evidence)?;
2220 PreparedConditionedProgram::new(exact, self.trace)
2221 }
2222
2223 #[cfg(feature = "host-io")]
2225 pub fn compile_and_evaluate_conditioned_source_for_gpu_execution_results(
2226 &mut self,
2227 source: &str,
2228 provider: &CudaKernelProvider,
2229 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2230 ) -> Result<Vec<ExactResult>> {
2231 epistemic_prob_trace_transaction!(self, {
2232 if evidence_records.is_empty() {
2233 return Err(XlogError::UnsupportedEpistemicConstruct {
2234 construct: "epistemic probabilistic conditioned production batch".to_string(),
2235 context: "batched conditioned knowledge compilation requires at least one accepted GPU result"
2236 .to_string(),
2237 });
2238 }
2239
2240 let mut accepted = Vec::with_capacity(evidence_records.len());
2241 for record in evidence_records {
2242 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2243 provider,
2244 record.result,
2245 record.assumptions.to_vec(),
2246 )?);
2247 }
2248
2249 let program = parse_program(source)?;
2250 let provenance = extract_from_program(&program)?;
2251 let mut results = Vec::with_capacity(accepted.len());
2252 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2253 let filtered_evidence;
2254 let evidence = if record.assumptions.is_empty() {
2255 filtered_evidence =
2256 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2257 &filtered_evidence
2258 } else {
2259 evidence
2260 };
2261 results.push(self.compile_and_evaluate_conditioned_program_with_path(
2262 &program,
2263 &provenance,
2264 evidence,
2265 EpistemicProbConditionedEvidencePath::Source,
2266 "epistemic probabilistic conditioned source exact compile/evaluate",
2267 )?);
2268 }
2269 Ok(results)
2270 })
2271 }
2272
2273 #[cfg(feature = "host-io")]
2275 pub fn compile_and_evaluate_conditioned_source_for_gpu_batch_execution_result(
2276 &mut self,
2277 source: &str,
2278 provider: &CudaKernelProvider,
2279 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2280 ) -> Result<Vec<ExactResult>> {
2281 epistemic_prob_trace_transaction!(self, {
2282 let auto_derived_by_component = evidence
2283 .assumptions_by_component
2284 .iter()
2285 .map(|assumptions| assumptions.is_empty())
2286 .collect::<Vec<_>>();
2287 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2288 provider,
2289 evidence,
2290 "epistemic probabilistic batch production",
2291 )?;
2292
2293 let program = parse_program(source)?;
2294 let provenance = extract_from_program(&program)?;
2295 let mut results = Vec::with_capacity(accepted.len());
2296 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2297 let filtered_evidence;
2298 let evidence = if *auto_derived {
2299 filtered_evidence =
2300 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2301 &filtered_evidence
2302 } else {
2303 evidence
2304 };
2305 results.push(self.compile_and_evaluate_conditioned_program_with_path(
2306 &program,
2307 &provenance,
2308 evidence,
2309 EpistemicProbConditionedEvidencePath::Source,
2310 "epistemic probabilistic conditioned source exact compile/evaluate",
2311 )?);
2312 }
2313 Ok(results)
2314 })
2315 }
2316
2317 #[cfg(feature = "host-io")]
2319 pub fn compile_and_evaluate_conditioned_source_with_grads_with_accepted_world_view(
2320 &mut self,
2321 source: &str,
2322 evidence: &AcceptedWorldViewEvidence,
2323 ) -> Result<ExactResultWithGrads> {
2324 epistemic_prob_trace_transaction!(self, {
2325 let program = parse_program(source)?;
2326 let provenance = extract_from_program(&program)?;
2327 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2328 &program,
2329 &provenance,
2330 evidence,
2331 EpistemicProbConditionedEvidencePath::Source,
2332 "epistemic probabilistic conditioned source exact gradient",
2333 )
2334 })
2335 }
2336
2337 #[cfg(feature = "host-io")]
2339 pub fn compile_and_evaluate_conditioned_source_with_grads_with_gpu_execution_result(
2340 &mut self,
2341 source: &str,
2342 provider: &CudaKernelProvider,
2343 result: &EpistemicGpuExecutionResult,
2344 assumptions: Vec<EpistemicAssumption>,
2345 ) -> Result<ExactResultWithGrads> {
2346 epistemic_prob_trace_transaction!(self, {
2347 let auto_derived = assumptions.is_empty();
2348 let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2349 provider,
2350 result,
2351 assumptions,
2352 )?;
2353 let program = parse_program(source)?;
2354 let provenance = extract_from_program(&program)?;
2355 let filtered_evidence;
2356 let evidence = if auto_derived {
2357 filtered_evidence =
2358 evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2359 &filtered_evidence
2360 } else {
2361 &evidence
2362 };
2363 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2364 &program,
2365 &provenance,
2366 evidence,
2367 EpistemicProbConditionedEvidencePath::Source,
2368 "epistemic probabilistic conditioned source exact gradient",
2369 )
2370 })
2371 }
2372
2373 #[cfg(feature = "host-io")]
2375 pub fn compile_and_evaluate_conditioned_source_with_grads_for_gpu_execution_results(
2376 &mut self,
2377 source: &str,
2378 provider: &CudaKernelProvider,
2379 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2380 ) -> Result<Vec<ExactResultWithGrads>> {
2381 epistemic_prob_trace_transaction!(self, {
2382 if evidence_records.is_empty() {
2383 return Err(XlogError::UnsupportedEpistemicConstruct {
2384 construct: "epistemic probabilistic conditioned gradient production batch"
2385 .to_string(),
2386 context: "batched conditioned gradient compilation requires at least one accepted GPU result"
2387 .to_string(),
2388 });
2389 }
2390
2391 let mut accepted = Vec::with_capacity(evidence_records.len());
2392 for record in evidence_records {
2393 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2394 provider,
2395 record.result,
2396 record.assumptions.to_vec(),
2397 )?);
2398 }
2399
2400 let program = parse_program(source)?;
2401 let provenance = extract_from_program(&program)?;
2402 let mut results = Vec::with_capacity(accepted.len());
2403 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2404 let filtered_evidence;
2405 let evidence = if record.assumptions.is_empty() {
2406 filtered_evidence =
2407 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2408 &filtered_evidence
2409 } else {
2410 evidence
2411 };
2412 results.push(
2413 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2414 &program,
2415 &provenance,
2416 evidence,
2417 EpistemicProbConditionedEvidencePath::Source,
2418 "epistemic probabilistic conditioned source exact gradient",
2419 )?,
2420 );
2421 }
2422 Ok(results)
2423 })
2424 }
2425
2426 #[cfg(feature = "host-io")]
2428 pub fn compile_and_evaluate_conditioned_source_with_grads_for_gpu_batch_execution_result(
2429 &mut self,
2430 source: &str,
2431 provider: &CudaKernelProvider,
2432 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2433 ) -> Result<Vec<ExactResultWithGrads>> {
2434 epistemic_prob_trace_transaction!(self, {
2435 let auto_derived_by_component = evidence
2436 .assumptions_by_component
2437 .iter()
2438 .map(|assumptions| assumptions.is_empty())
2439 .collect::<Vec<_>>();
2440 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2441 provider,
2442 evidence,
2443 "epistemic probabilistic batch production",
2444 )?;
2445
2446 let program = parse_program(source)?;
2447 let provenance = extract_from_program(&program)?;
2448 let mut results = Vec::with_capacity(accepted.len());
2449 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2450 let filtered_evidence;
2451 let evidence = if *auto_derived {
2452 filtered_evidence =
2453 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2454 &filtered_evidence
2455 } else {
2456 evidence
2457 };
2458 results.push(
2459 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2460 &program,
2461 &provenance,
2462 evidence,
2463 EpistemicProbConditionedEvidencePath::Source,
2464 "epistemic probabilistic conditioned source exact gradient",
2465 )?,
2466 );
2467 }
2468 Ok(results)
2469 })
2470 }
2471
2472 #[cfg(feature = "host-io")]
2473 fn compile_and_evaluate_conditioned_program_with_path(
2474 &mut self,
2475 program: &Program,
2476 provenance: &Provenance,
2477 evidence: &AcceptedWorldViewEvidence,
2478 path: EpistemicProbConditionedEvidencePath,
2479 backend_context: &'static str,
2480 ) -> Result<ExactResult> {
2481 let evidence = accepted_evidence_for_provenance(evidence, provenance)?;
2482 let evidence = evidence.as_ref();
2483 self.require_accepted_evidence(evidence)?;
2484 let production_events_before = self.trace.checked_gpu_production_path_events()?;
2485 let (program, evidence_counts) = condition_program_with_accepted_evidence_using_provenance(
2486 program, provenance, evidence,
2487 )?;
2488 let exact = ExactDdnnfProgram::compile_from_program(&program, self.config)?;
2489 require_gpu_exact_backend(&exact, backend_context)?;
2490 match path {
2491 EpistemicProbConditionedEvidencePath::Source => {
2492 checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2493 }
2494 EpistemicProbConditionedEvidencePath::Program => {
2495 checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2496 }
2497 }
2498 self.record_conditioned_evidence_counts(evidence_counts, path)?;
2499 let result = exact.evaluate()?;
2500 checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2501 checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2502 match path {
2503 EpistemicProbConditionedEvidencePath::Source => {
2504 checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
2505 checked_prob_trace_counter_inc!(
2506 self,
2507 gpu_source_knowledge_compilation_end_to_end_runs
2508 );
2509 }
2510 EpistemicProbConditionedEvidencePath::Program => {
2511 checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
2512 checked_prob_trace_counter_inc!(
2513 self,
2514 gpu_program_knowledge_compilation_end_to_end_runs
2515 );
2516 }
2517 }
2518 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2519 self.record_accepted_evidence(evidence)?;
2520 Ok(result)
2521 }
2522
2523 #[cfg(feature = "host-io")]
2524 fn compile_and_evaluate_conditioned_program_with_grads_with_path(
2525 &mut self,
2526 program: &Program,
2527 provenance: &Provenance,
2528 evidence: &AcceptedWorldViewEvidence,
2529 path: EpistemicProbConditionedEvidencePath,
2530 backend_context: &'static str,
2531 ) -> Result<ExactResultWithGrads> {
2532 let evidence = accepted_evidence_for_provenance(evidence, provenance)?;
2533 let evidence = evidence.as_ref();
2534 self.require_accepted_evidence(evidence)?;
2535 let production_events_before = self.trace.checked_gpu_production_path_events()?;
2536 let (program, evidence_counts) = condition_program_with_accepted_evidence_using_provenance(
2537 program, provenance, evidence,
2538 )?;
2539 let exact = ExactDdnnfProgram::compile_from_program(&program, self.config)?;
2540 require_gpu_exact_backend(&exact, backend_context)?;
2541 match path {
2542 EpistemicProbConditionedEvidencePath::Source => {
2543 checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2544 }
2545 EpistemicProbConditionedEvidencePath::Program => {
2546 checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2547 }
2548 }
2549 self.record_conditioned_evidence_counts(evidence_counts, path)?;
2550 let result = exact.evaluate_gpu_with_grads()?;
2551 let origin = match path {
2552 EpistemicProbConditionedEvidencePath::Source => ExactProgramOrigin::Source,
2553 EpistemicProbConditionedEvidencePath::Program => ExactProgramOrigin::Program,
2554 };
2555 self.record_gpu_exact_gradient_evaluation_for_origin(origin)?;
2556 checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2557 match path {
2558 EpistemicProbConditionedEvidencePath::Source => {
2559 checked_prob_trace_counter_inc!(self, gpu_source_conditioned_gradient_evaluations);
2560 checked_prob_trace_counter_inc!(
2561 self,
2562 gpu_source_knowledge_compilation_end_to_end_runs
2563 );
2564 }
2565 EpistemicProbConditionedEvidencePath::Program => {
2566 checked_prob_trace_counter_inc!(self, gpu_program_conditioned_gradient_evaluations);
2567 checked_prob_trace_counter_inc!(
2568 self,
2569 gpu_program_knowledge_compilation_end_to_end_runs
2570 );
2571 }
2572 }
2573 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2574 self.record_accepted_evidence(evidence)?;
2575 Ok(result)
2576 }
2577
2578 #[cfg(feature = "host-io")]
2580 pub fn compile_and_evaluate_conditioned_program_with_accepted_world_view(
2581 &mut self,
2582 program: &Program,
2583 evidence: &AcceptedWorldViewEvidence,
2584 ) -> Result<ExactResult> {
2585 epistemic_prob_trace_transaction!(self, {
2586 let provenance = extract_from_program(program)?;
2587 self.compile_and_evaluate_conditioned_program_with_path(
2588 program,
2589 &provenance,
2590 evidence,
2591 EpistemicProbConditionedEvidencePath::Program,
2592 "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2593 )
2594 })
2595 }
2596
2597 #[cfg(feature = "host-io")]
2599 pub fn compile_and_evaluate_conditioned_program_with_gpu_execution_result(
2600 &mut self,
2601 program: &Program,
2602 provider: &CudaKernelProvider,
2603 result: &EpistemicGpuExecutionResult,
2604 assumptions: Vec<EpistemicAssumption>,
2605 ) -> Result<ExactResult> {
2606 epistemic_prob_trace_transaction!(self, {
2607 let auto_derived = assumptions.is_empty();
2608 let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2609 provider,
2610 result,
2611 assumptions,
2612 )?;
2613 let provenance = extract_from_program(program)?;
2614 let filtered_evidence;
2615 let evidence = if auto_derived {
2616 filtered_evidence =
2617 evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2618 &filtered_evidence
2619 } else {
2620 &evidence
2621 };
2622 self.compile_and_evaluate_conditioned_program_with_path(
2623 program,
2624 &provenance,
2625 evidence,
2626 EpistemicProbConditionedEvidencePath::Program,
2627 "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2628 )
2629 })
2630 }
2631
2632 #[cfg(feature = "host-io")]
2634 pub fn compile_and_evaluate_conditioned_program_for_gpu_execution_results(
2635 &mut self,
2636 program: &Program,
2637 provider: &CudaKernelProvider,
2638 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2639 ) -> Result<Vec<ExactResult>> {
2640 epistemic_prob_trace_transaction!(self, {
2641 if evidence_records.is_empty() {
2642 return Err(XlogError::UnsupportedEpistemicConstruct {
2643 construct: "epistemic probabilistic conditioned production batch".to_string(),
2644 context: "batched conditioned program compilation requires at least one accepted GPU result"
2645 .to_string(),
2646 });
2647 }
2648
2649 let mut accepted = Vec::with_capacity(evidence_records.len());
2650 for record in evidence_records {
2651 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2652 provider,
2653 record.result,
2654 record.assumptions.to_vec(),
2655 )?);
2656 }
2657
2658 let provenance = extract_from_program(program)?;
2659 let mut results = Vec::with_capacity(accepted.len());
2660 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2661 let filtered_evidence;
2662 let evidence = if record.assumptions.is_empty() {
2663 filtered_evidence =
2664 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2665 &filtered_evidence
2666 } else {
2667 evidence
2668 };
2669 results.push(self.compile_and_evaluate_conditioned_program_with_path(
2670 program,
2671 &provenance,
2672 evidence,
2673 EpistemicProbConditionedEvidencePath::Program,
2674 "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2675 )?);
2676 }
2677 Ok(results)
2678 })
2679 }
2680
2681 #[cfg(feature = "host-io")]
2683 pub fn compile_and_evaluate_conditioned_program_for_gpu_batch_execution_result(
2684 &mut self,
2685 program: &Program,
2686 provider: &CudaKernelProvider,
2687 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2688 ) -> Result<Vec<ExactResult>> {
2689 epistemic_prob_trace_transaction!(self, {
2690 let auto_derived_by_component = evidence
2691 .assumptions_by_component
2692 .iter()
2693 .map(|assumptions| assumptions.is_empty())
2694 .collect::<Vec<_>>();
2695 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2696 provider,
2697 evidence,
2698 "epistemic probabilistic batch production",
2699 )?;
2700
2701 let provenance = extract_from_program(program)?;
2702 let mut results = Vec::with_capacity(accepted.len());
2703 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2704 let filtered_evidence;
2705 let evidence = if *auto_derived {
2706 filtered_evidence =
2707 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2708 &filtered_evidence
2709 } else {
2710 evidence
2711 };
2712 results.push(self.compile_and_evaluate_conditioned_program_with_path(
2713 program,
2714 &provenance,
2715 evidence,
2716 EpistemicProbConditionedEvidencePath::Program,
2717 "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2718 )?);
2719 }
2720 Ok(results)
2721 })
2722 }
2723
2724 #[cfg(feature = "host-io")]
2726 pub fn compile_and_evaluate_conditioned_program_with_grads_with_accepted_world_view(
2727 &mut self,
2728 program: &Program,
2729 evidence: &AcceptedWorldViewEvidence,
2730 ) -> Result<ExactResultWithGrads> {
2731 epistemic_prob_trace_transaction!(self, {
2732 let provenance = extract_from_program(program)?;
2733 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2734 program,
2735 &provenance,
2736 evidence,
2737 EpistemicProbConditionedEvidencePath::Program,
2738 "epistemic probabilistic conditioned parsed-program exact gradient",
2739 )
2740 })
2741 }
2742
2743 #[cfg(feature = "host-io")]
2745 pub fn compile_and_evaluate_conditioned_program_with_grads_with_gpu_execution_result(
2746 &mut self,
2747 program: &Program,
2748 provider: &CudaKernelProvider,
2749 result: &EpistemicGpuExecutionResult,
2750 assumptions: Vec<EpistemicAssumption>,
2751 ) -> Result<ExactResultWithGrads> {
2752 epistemic_prob_trace_transaction!(self, {
2753 let auto_derived = assumptions.is_empty();
2754 let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2755 provider,
2756 result,
2757 assumptions,
2758 )?;
2759 let provenance = extract_from_program(program)?;
2760 let filtered_evidence;
2761 let evidence = if auto_derived {
2762 filtered_evidence =
2763 evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2764 &filtered_evidence
2765 } else {
2766 &evidence
2767 };
2768 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2769 program,
2770 &provenance,
2771 evidence,
2772 EpistemicProbConditionedEvidencePath::Program,
2773 "epistemic probabilistic conditioned parsed-program exact gradient",
2774 )
2775 })
2776 }
2777
2778 #[cfg(feature = "host-io")]
2780 pub fn compile_and_evaluate_conditioned_program_with_grads_for_gpu_execution_results(
2781 &mut self,
2782 program: &Program,
2783 provider: &CudaKernelProvider,
2784 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2785 ) -> Result<Vec<ExactResultWithGrads>> {
2786 epistemic_prob_trace_transaction!(self, {
2787 if evidence_records.is_empty() {
2788 return Err(XlogError::UnsupportedEpistemicConstruct {
2789 construct: "epistemic probabilistic conditioned gradient production batch"
2790 .to_string(),
2791 context: "batched conditioned program gradient compilation requires at least one accepted GPU result"
2792 .to_string(),
2793 });
2794 }
2795
2796 let mut accepted = Vec::with_capacity(evidence_records.len());
2797 for record in evidence_records {
2798 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2799 provider,
2800 record.result,
2801 record.assumptions.to_vec(),
2802 )?);
2803 }
2804
2805 let provenance = extract_from_program(program)?;
2806 let mut results = Vec::with_capacity(accepted.len());
2807 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2808 let filtered_evidence;
2809 let evidence = if record.assumptions.is_empty() {
2810 filtered_evidence =
2811 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2812 &filtered_evidence
2813 } else {
2814 evidence
2815 };
2816 results.push(
2817 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2818 program,
2819 &provenance,
2820 evidence,
2821 EpistemicProbConditionedEvidencePath::Program,
2822 "epistemic probabilistic conditioned parsed-program exact gradient",
2823 )?,
2824 );
2825 }
2826 Ok(results)
2827 })
2828 }
2829
2830 #[cfg(feature = "host-io")]
2832 pub fn compile_and_evaluate_conditioned_program_with_grads_for_gpu_batch_execution_result(
2833 &mut self,
2834 program: &Program,
2835 provider: &CudaKernelProvider,
2836 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2837 ) -> Result<Vec<ExactResultWithGrads>> {
2838 epistemic_prob_trace_transaction!(self, {
2839 let auto_derived_by_component = evidence
2840 .assumptions_by_component
2841 .iter()
2842 .map(|assumptions| assumptions.is_empty())
2843 .collect::<Vec<_>>();
2844 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2845 provider,
2846 evidence,
2847 "epistemic probabilistic batch production",
2848 )?;
2849
2850 let provenance = extract_from_program(program)?;
2851 let mut results = Vec::with_capacity(accepted.len());
2852 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2853 let filtered_evidence;
2854 let evidence = if *auto_derived {
2855 filtered_evidence =
2856 evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2857 &filtered_evidence
2858 } else {
2859 evidence
2860 };
2861 results.push(
2862 self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2863 program,
2864 &provenance,
2865 evidence,
2866 EpistemicProbConditionedEvidencePath::Program,
2867 "epistemic probabilistic conditioned parsed-program exact gradient",
2868 )?,
2869 );
2870 }
2871 Ok(results)
2872 })
2873 }
2874
2875 #[cfg(feature = "host-io")]
2877 pub fn compile_and_evaluate_program_with_accepted_world_view(
2878 &mut self,
2879 program: &Program,
2880 evidence: &AcceptedWorldViewEvidence,
2881 ) -> Result<ExactResult> {
2882 epistemic_prob_trace_transaction!(self, {
2883 self.require_accepted_evidence(evidence)?;
2884 let production_events_before = self.trace.checked_gpu_production_path_events()?;
2885 let exact = ExactDdnnfProgram::compile_from_program(program, self.config)?;
2886 require_gpu_exact_backend(
2887 &exact,
2888 "epistemic probabilistic parsed-program exact compile/evaluate",
2889 )?;
2890 checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2891 let result = exact.evaluate()?;
2892 checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2893 checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
2894 checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2895 checked_prob_trace_counter_inc!(
2896 self,
2897 gpu_program_knowledge_compilation_end_to_end_runs
2898 );
2899 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2900 self.record_accepted_evidence(evidence)?;
2901 Ok(result)
2902 })
2903 }
2904
2905 #[cfg(feature = "host-io")]
2907 pub fn compile_and_evaluate_program_with_gpu_execution_result(
2908 &mut self,
2909 program: &Program,
2910 provider: &CudaKernelProvider,
2911 result: &EpistemicGpuExecutionResult,
2912 assumptions: Vec<EpistemicAssumption>,
2913 ) -> Result<ExactResult> {
2914 let evidence =
2915 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2916 self.compile_and_evaluate_program_with_accepted_world_view(program, &evidence)
2917 }
2918
2919 #[cfg(feature = "host-io")]
2921 pub fn compile_and_evaluate_program_for_gpu_execution_results(
2922 &mut self,
2923 program: &Program,
2924 provider: &CudaKernelProvider,
2925 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2926 ) -> Result<Vec<ExactResult>> {
2927 epistemic_prob_trace_transaction!(self, {
2928 if evidence_records.is_empty() {
2929 return Err(XlogError::UnsupportedEpistemicConstruct {
2930 construct: "epistemic probabilistic parsed-program production batch"
2931 .to_string(),
2932 context: "batched parsed-program knowledge compilation requires at least one accepted GPU result"
2933 .to_string(),
2934 });
2935 }
2936
2937 let mut accepted = Vec::with_capacity(evidence_records.len());
2938 for record in evidence_records {
2939 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2940 provider,
2941 record.result,
2942 record.assumptions.to_vec(),
2943 )?);
2944 }
2945
2946 let mut results = Vec::with_capacity(accepted.len());
2947 for evidence in &accepted {
2948 results.push(
2949 self.compile_and_evaluate_program_with_accepted_world_view(program, evidence)?,
2950 );
2951 }
2952 Ok(results)
2953 })
2954 }
2955
2956 #[cfg(feature = "host-io")]
2958 pub fn compile_and_evaluate_program_for_gpu_batch_execution_result(
2959 &mut self,
2960 program: &Program,
2961 provider: &CudaKernelProvider,
2962 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2963 ) -> Result<Vec<ExactResult>> {
2964 epistemic_prob_trace_transaction!(self, {
2965 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2966 provider,
2967 evidence,
2968 "epistemic probabilistic batch production",
2969 )?;
2970
2971 let mut results = Vec::with_capacity(accepted.len());
2972 for evidence in &accepted {
2973 results.push(
2974 self.compile_and_evaluate_program_with_accepted_world_view(program, evidence)?,
2975 );
2976 }
2977 Ok(results)
2978 })
2979 }
2980
2981 pub fn encode_source_pir_cnf_with_accepted_world_view(
2983 &mut self,
2984 source: &str,
2985 provider: &Arc<CudaKernelProvider>,
2986 evidence: &AcceptedWorldViewEvidence,
2987 ) -> Result<EpistemicProbPirCnfEvidence> {
2988 epistemic_prob_trace_transaction!(self, {
2989 self.require_accepted_evidence(evidence)?;
2990 let program = parse_program(source)?;
2991 let base_provenance = extract_from_program(&program)?;
2992 self.encode_program_pir_cnf_with_base_provenance(
2993 &program,
2994 &base_provenance,
2995 provider,
2996 evidence,
2997 EpistemicProbPirCnfPath::Source,
2998 )
2999 })
3000 }
3001
3002 pub fn encode_source_pir_cnf_with_gpu_execution_result(
3004 &mut self,
3005 source: &str,
3006 provider: &Arc<CudaKernelProvider>,
3007 result: &EpistemicGpuExecutionResult,
3008 assumptions: Vec<EpistemicAssumption>,
3009 ) -> Result<EpistemicProbPirCnfEvidence> {
3010 epistemic_prob_trace_transaction!(self, {
3011 let auto_derived = assumptions.is_empty();
3012 let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
3013 provider,
3014 result,
3015 assumptions,
3016 )?;
3017 let program = parse_program(source)?;
3018 let base_provenance = extract_from_program(&program)?;
3019 let filtered_evidence;
3020 let evidence = if auto_derived {
3021 filtered_evidence =
3022 evidence_with_provenance_backed_assumptions(&evidence, &base_provenance)?;
3023 &filtered_evidence
3024 } else {
3025 &evidence
3026 };
3027 self.encode_program_pir_cnf_with_base_provenance(
3028 &program,
3029 &base_provenance,
3030 provider,
3031 evidence,
3032 EpistemicProbPirCnfPath::Source,
3033 )
3034 })
3035 }
3036
3037 pub fn encode_source_pir_cnf_for_gpu_execution_results(
3039 &mut self,
3040 source: &str,
3041 provider: &Arc<CudaKernelProvider>,
3042 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3043 ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3044 epistemic_prob_trace_transaction!(self, {
3045 if evidence_records.is_empty() {
3046 return Err(XlogError::UnsupportedEpistemicConstruct {
3047 construct: "epistemic probabilistic source PIR/CNF production batch"
3048 .to_string(),
3049 context:
3050 "batched source PIR/CNF encoding requires at least one accepted GPU result"
3051 .to_string(),
3052 });
3053 }
3054
3055 let mut accepted = Vec::with_capacity(evidence_records.len());
3056 for record in evidence_records {
3057 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3058 provider,
3059 record.result,
3060 record.assumptions.to_vec(),
3061 )?);
3062 }
3063
3064 let program = parse_program(source)?;
3065 let base_provenance = extract_from_program(&program)?;
3066 let mut results = Vec::with_capacity(accepted.len());
3067 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
3068 let filtered_evidence;
3069 let evidence = if record.assumptions.is_empty() {
3070 filtered_evidence =
3071 evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3072 &filtered_evidence
3073 } else {
3074 evidence
3075 };
3076 results.push(self.encode_program_pir_cnf_with_base_provenance(
3077 &program,
3078 &base_provenance,
3079 provider,
3080 evidence,
3081 EpistemicProbPirCnfPath::Source,
3082 )?);
3083 }
3084 Ok(results)
3085 })
3086 }
3087
3088 pub fn encode_source_pir_cnf_for_gpu_batch_execution_result(
3090 &mut self,
3091 source: &str,
3092 provider: &Arc<CudaKernelProvider>,
3093 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3094 ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3095 epistemic_prob_trace_transaction!(self, {
3096 let auto_derived_by_component = evidence
3097 .assumptions_by_component
3098 .iter()
3099 .map(|assumptions| assumptions.is_empty())
3100 .collect::<Vec<_>>();
3101 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3102 provider.as_ref(),
3103 evidence,
3104 "epistemic probabilistic source PIR/CNF batch production",
3105 )?;
3106
3107 let program = parse_program(source)?;
3108 let base_provenance = extract_from_program(&program)?;
3109 let mut results = Vec::with_capacity(accepted.len());
3110 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
3111 let filtered_evidence;
3112 let evidence = if *auto_derived {
3113 filtered_evidence =
3114 evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3115 &filtered_evidence
3116 } else {
3117 evidence
3118 };
3119 results.push(self.encode_program_pir_cnf_with_base_provenance(
3120 &program,
3121 &base_provenance,
3122 provider,
3123 evidence,
3124 EpistemicProbPirCnfPath::Source,
3125 )?);
3126 }
3127 Ok(results)
3128 })
3129 }
3130
3131 pub fn encode_program_pir_cnf_with_accepted_world_view(
3133 &mut self,
3134 program: &Program,
3135 provider: &Arc<CudaKernelProvider>,
3136 evidence: &AcceptedWorldViewEvidence,
3137 ) -> Result<EpistemicProbPirCnfEvidence> {
3138 epistemic_prob_trace_transaction!(self, {
3139 self.require_accepted_evidence(evidence)?;
3140 let base_provenance = extract_from_program(program)?;
3141 self.encode_program_pir_cnf_with_base_provenance(
3142 program,
3143 &base_provenance,
3144 provider,
3145 evidence,
3146 EpistemicProbPirCnfPath::Program,
3147 )
3148 })
3149 }
3150
3151 pub fn encode_program_pir_cnf_with_gpu_execution_result(
3153 &mut self,
3154 program: &Program,
3155 provider: &Arc<CudaKernelProvider>,
3156 result: &EpistemicGpuExecutionResult,
3157 assumptions: Vec<EpistemicAssumption>,
3158 ) -> Result<EpistemicProbPirCnfEvidence> {
3159 epistemic_prob_trace_transaction!(self, {
3160 let auto_derived = assumptions.is_empty();
3161 let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
3162 provider,
3163 result,
3164 assumptions,
3165 )?;
3166 let base_provenance = extract_from_program(program)?;
3167 let filtered_evidence;
3168 let evidence = if auto_derived {
3169 filtered_evidence =
3170 evidence_with_provenance_backed_assumptions(&evidence, &base_provenance)?;
3171 &filtered_evidence
3172 } else {
3173 &evidence
3174 };
3175 self.encode_program_pir_cnf_with_base_provenance(
3176 program,
3177 &base_provenance,
3178 provider,
3179 evidence,
3180 EpistemicProbPirCnfPath::Program,
3181 )
3182 })
3183 }
3184
3185 pub fn encode_program_pir_cnf_for_gpu_execution_results(
3187 &mut self,
3188 program: &Program,
3189 provider: &Arc<CudaKernelProvider>,
3190 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3191 ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3192 epistemic_prob_trace_transaction!(self, {
3193 if evidence_records.is_empty() {
3194 return Err(XlogError::UnsupportedEpistemicConstruct {
3195 construct: "epistemic probabilistic parsed-program PIR/CNF production batch"
3196 .to_string(),
3197 context:
3198 "batched parsed-program PIR/CNF encoding requires at least one accepted GPU result"
3199 .to_string(),
3200 });
3201 }
3202
3203 let mut accepted = Vec::with_capacity(evidence_records.len());
3204 for record in evidence_records {
3205 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3206 provider,
3207 record.result,
3208 record.assumptions.to_vec(),
3209 )?);
3210 }
3211
3212 let base_provenance = extract_from_program(program)?;
3213 let mut results = Vec::with_capacity(accepted.len());
3214 for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
3215 let filtered_evidence;
3216 let evidence = if record.assumptions.is_empty() {
3217 filtered_evidence =
3218 evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3219 &filtered_evidence
3220 } else {
3221 evidence
3222 };
3223 results.push(self.encode_program_pir_cnf_with_base_provenance(
3224 program,
3225 &base_provenance,
3226 provider,
3227 evidence,
3228 EpistemicProbPirCnfPath::Program,
3229 )?);
3230 }
3231 Ok(results)
3232 })
3233 }
3234
3235 pub fn encode_program_pir_cnf_for_gpu_batch_execution_result(
3237 &mut self,
3238 program: &Program,
3239 provider: &Arc<CudaKernelProvider>,
3240 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3241 ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3242 epistemic_prob_trace_transaction!(self, {
3243 let auto_derived_by_component = evidence
3244 .assumptions_by_component
3245 .iter()
3246 .map(|assumptions| assumptions.is_empty())
3247 .collect::<Vec<_>>();
3248 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3249 provider.as_ref(),
3250 evidence,
3251 "epistemic probabilistic parsed-program PIR/CNF batch production",
3252 )?;
3253
3254 let base_provenance = extract_from_program(program)?;
3255 let mut results = Vec::with_capacity(accepted.len());
3256 for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
3257 let filtered_evidence;
3258 let evidence = if *auto_derived {
3259 filtered_evidence =
3260 evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3261 &filtered_evidence
3262 } else {
3263 evidence
3264 };
3265 results.push(self.encode_program_pir_cnf_with_base_provenance(
3266 program,
3267 &base_provenance,
3268 provider,
3269 evidence,
3270 EpistemicProbPirCnfPath::Program,
3271 )?);
3272 }
3273 Ok(results)
3274 })
3275 }
3276
3277 #[cfg(feature = "host-io")]
3279 pub fn evaluate(
3280 &mut self,
3281 program: &ExactDdnnfProgram,
3282 evidence: &AcceptedWorldViewEvidence,
3283 ) -> Result<ExactResult> {
3284 epistemic_prob_trace_transaction!(self, {
3285 self.require_accepted_evidence(evidence)?;
3286 let production_events_before = self.trace.checked_gpu_production_path_events()?;
3287 require_gpu_exact_backend(program, "epistemic probabilistic exact query evaluation")?;
3288 let result = program.evaluate()?;
3289 self.record_gpu_exact_query_evaluation(program)?;
3290 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3291 self.record_accepted_evidence(evidence)?;
3292 Ok(result)
3293 })
3294 }
3295
3296 #[cfg(feature = "host-io")]
3298 pub fn evaluate_with_gpu_execution_result(
3299 &mut self,
3300 program: &ExactDdnnfProgram,
3301 provider: &CudaKernelProvider,
3302 result: &EpistemicGpuExecutionResult,
3303 assumptions: Vec<EpistemicAssumption>,
3304 ) -> Result<ExactResult> {
3305 let evidence =
3306 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
3307 self.evaluate(program, &evidence)
3308 }
3309
3310 #[cfg(feature = "host-io")]
3312 pub fn evaluate_for_gpu_execution_results(
3313 &mut self,
3314 program: &ExactDdnnfProgram,
3315 provider: &CudaKernelProvider,
3316 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3317 ) -> Result<Vec<ExactResult>> {
3318 epistemic_prob_trace_transaction!(self, {
3319 if evidence_records.is_empty() {
3320 return Err(XlogError::UnsupportedEpistemicConstruct {
3321 construct: "epistemic probabilistic query evaluation production batch"
3322 .to_string(),
3323 context: "batched query evaluation requires at least one accepted GPU result"
3324 .to_string(),
3325 });
3326 }
3327
3328 let mut accepted = Vec::with_capacity(evidence_records.len());
3329 for record in evidence_records {
3330 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3331 provider,
3332 record.result,
3333 record.assumptions.to_vec(),
3334 )?);
3335 }
3336
3337 let mut results = Vec::with_capacity(accepted.len());
3338 for evidence in &accepted {
3339 results.push(self.evaluate(program, evidence)?);
3340 }
3341 Ok(results)
3342 })
3343 }
3344
3345 #[cfg(feature = "host-io")]
3347 pub fn evaluate_for_gpu_batch_execution_result(
3348 &mut self,
3349 program: &ExactDdnnfProgram,
3350 provider: &CudaKernelProvider,
3351 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3352 ) -> Result<Vec<ExactResult>> {
3353 epistemic_prob_trace_transaction!(self, {
3354 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3355 provider,
3356 evidence,
3357 "epistemic probabilistic query evaluation batch production",
3358 )?;
3359
3360 let mut results = Vec::with_capacity(accepted.len());
3361 for evidence in &accepted {
3362 results.push(self.evaluate(program, evidence)?);
3363 }
3364 Ok(results)
3365 })
3366 }
3367
3368 #[cfg(feature = "host-io")]
3370 pub fn evaluate_gpu_with_grads(
3371 &mut self,
3372 program: &ExactDdnnfProgram,
3373 evidence: &AcceptedWorldViewEvidence,
3374 ) -> Result<ExactResultWithGrads> {
3375 epistemic_prob_trace_transaction!(self, {
3376 self.require_accepted_evidence(evidence)?;
3377 let production_events_before = self.trace.checked_gpu_production_path_events()?;
3378 require_gpu_exact_backend(
3379 program,
3380 "epistemic probabilistic exact gradient evaluation",
3381 )?;
3382 let result = program.evaluate_gpu_with_grads()?;
3383 self.record_gpu_exact_gradient_evaluation(program)?;
3384 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3385 self.record_accepted_evidence(evidence)?;
3386 Ok(result)
3387 })
3388 }
3389
3390 #[cfg(feature = "host-io")]
3392 pub fn evaluate_gpu_with_grads_with_gpu_execution_result(
3393 &mut self,
3394 program: &ExactDdnnfProgram,
3395 provider: &CudaKernelProvider,
3396 result: &EpistemicGpuExecutionResult,
3397 assumptions: Vec<EpistemicAssumption>,
3398 ) -> Result<ExactResultWithGrads> {
3399 let evidence =
3400 AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
3401 self.evaluate_gpu_with_grads(program, &evidence)
3402 }
3403
3404 #[cfg(feature = "host-io")]
3406 pub fn evaluate_gpu_with_grads_for_gpu_execution_results(
3407 &mut self,
3408 program: &ExactDdnnfProgram,
3409 provider: &CudaKernelProvider,
3410 evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3411 ) -> Result<Vec<ExactResultWithGrads>> {
3412 epistemic_prob_trace_transaction!(self, {
3413 if evidence_records.is_empty() {
3414 return Err(XlogError::UnsupportedEpistemicConstruct {
3415 construct: "epistemic probabilistic gradient evaluation production batch"
3416 .to_string(),
3417 context:
3418 "batched gradient evaluation requires at least one accepted GPU result"
3419 .to_string(),
3420 });
3421 }
3422
3423 let mut accepted = Vec::with_capacity(evidence_records.len());
3424 for record in evidence_records {
3425 accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3426 provider,
3427 record.result,
3428 record.assumptions.to_vec(),
3429 )?);
3430 }
3431
3432 let mut results = Vec::with_capacity(accepted.len());
3433 for evidence in &accepted {
3434 results.push(self.evaluate_gpu_with_grads(program, evidence)?);
3435 }
3436 Ok(results)
3437 })
3438 }
3439
3440 #[cfg(feature = "host-io")]
3442 pub fn evaluate_gpu_with_grads_for_gpu_batch_execution_result(
3443 &mut self,
3444 program: &ExactDdnnfProgram,
3445 provider: &CudaKernelProvider,
3446 evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3447 ) -> Result<Vec<ExactResultWithGrads>> {
3448 epistemic_prob_trace_transaction!(self, {
3449 let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3450 provider,
3451 evidence,
3452 "epistemic probabilistic gradient evaluation batch production",
3453 )?;
3454
3455 let mut results = Vec::with_capacity(accepted.len());
3456 for evidence in &accepted {
3457 results.push(self.evaluate_gpu_with_grads(program, evidence)?);
3458 }
3459 Ok(results)
3460 })
3461 }
3462
3463 fn consume_accepted_evidence(&mut self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3464 self.require_accepted_evidence(evidence)?;
3465 self.record_accepted_evidence(evidence)?;
3466 Ok(())
3467 }
3468
3469 fn require_accepted_evidence(&self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3470 if evidence.world_count() == 0 {
3471 return Err(XlogError::UnsupportedEpistemicConstruct {
3472 construct: "accepted world-view evidence".to_string(),
3473 context: "probabilistic production path requires a non-empty accepted world view"
3474 .to_string(),
3475 });
3476 }
3477 if evidence.gpu_epistemic_mode().is_none() {
3478 return Err(XlogError::UnsupportedEpistemicConstruct {
3479 construct: "accepted world-view evidence".to_string(),
3480 context: "probabilistic production path requires GPU execution evidence; CPU \
3481 world-view evidence is oracle-only"
3482 .to_string(),
3483 });
3484 }
3485 Ok(())
3486 }
3487
3488 fn record_accepted_evidence(&mut self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3489 self.trace.accepted_world_view_evidence_consumed = Self::checked_trace_counter_add(
3490 self.trace.accepted_world_view_evidence_consumed,
3491 1,
3492 "accepted_world_view_evidence_consumed",
3493 )?;
3494 match evidence.gpu_epistemic_mode() {
3495 Some(EirEpistemicMode::G91) => {
3496 self.trace.accepted_g91_world_view_evidence_consumed =
3497 Self::checked_trace_counter_add(
3498 self.trace.accepted_g91_world_view_evidence_consumed,
3499 1,
3500 "accepted_g91_world_view_evidence_consumed",
3501 )?;
3502 }
3503 Some(EirEpistemicMode::Faeel) => {
3504 self.trace.accepted_faeel_world_view_evidence_consumed =
3505 Self::checked_trace_counter_add(
3506 self.trace.accepted_faeel_world_view_evidence_consumed,
3507 1,
3508 "accepted_faeel_world_view_evidence_consumed",
3509 )?;
3510 }
3511 None => {}
3512 }
3513 self.trace.accepted_evidence_assumptions_consumed = Self::checked_trace_counter_add(
3514 self.trace.accepted_evidence_assumptions_consumed,
3515 evidence.assumption_count() as u64,
3516 "accepted_evidence_assumptions_consumed",
3517 )?;
3518 self.trace
3519 .accepted_gpu_nonzero_arity_evidence_assumptions_consumed =
3520 Self::checked_trace_counter_add(
3521 self.trace
3522 .accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
3523 evidence.nonzero_arity_assumption_count() as u64,
3524 "accepted_gpu_nonzero_arity_evidence_assumptions_consumed",
3525 )?;
3526 if evidence.max_assumption_arity() > u32::MAX as usize {
3527 return Err(XlogError::CapacityExceeded {
3528 context: "accepted GPU probability evidence max arity".to_string(),
3529 required: evidence.max_assumption_arity() as u64,
3530 limit: u32::MAX as u64,
3531 unit: "arguments per assumption".to_string(),
3532 });
3533 }
3534 self.trace.accepted_gpu_max_evidence_arity_consumed = self
3535 .trace
3536 .accepted_gpu_max_evidence_arity_consumed
3537 .max(evidence.max_assumption_arity() as u32);
3538 self.trace.accepted_gpu_tuple_key_column_reads_consumed = Self::checked_trace_counter_add(
3539 self.trace.accepted_gpu_tuple_key_column_reads_consumed,
3540 evidence.gpu_tuple_key_column_reads() as u64,
3541 "accepted_gpu_tuple_key_column_reads_consumed",
3542 )?;
3543 self.trace.accepted_gpu_final_tuple_row_filters_consumed = Self::checked_trace_counter_add(
3544 self.trace.accepted_gpu_final_tuple_row_filters_consumed,
3545 evidence.gpu_final_tuple_row_filters() as u64,
3546 "accepted_gpu_final_tuple_row_filters_consumed",
3547 )?;
3548 self.trace
3549 .accepted_gpu_final_tuple_negated_row_filters_consumed =
3550 Self::checked_trace_counter_add(
3551 self.trace
3552 .accepted_gpu_final_tuple_negated_row_filters_consumed,
3553 evidence.gpu_final_tuple_negated_row_filters() as u64,
3554 "accepted_gpu_final_tuple_negated_row_filters_consumed",
3555 )?;
3556 self.trace
3557 .accepted_gpu_row_specific_membership_row_capacity_consumed =
3558 Self::checked_trace_counter_add(
3559 self.trace
3560 .accepted_gpu_row_specific_membership_row_capacity_consumed,
3561 evidence.gpu_row_specific_membership_row_capacity() as u64,
3562 "accepted_gpu_row_specific_membership_row_capacity_consumed",
3563 )?;
3564 self.trace
3565 .accepted_gpu_row_filter_fallback_row_capacity_consumed =
3566 Self::checked_trace_counter_add(
3567 self.trace
3568 .accepted_gpu_row_filter_fallback_row_capacity_consumed,
3569 evidence.gpu_row_filter_fallback_row_capacity() as u64,
3570 "accepted_gpu_row_filter_fallback_row_capacity_consumed",
3571 )?;
3572 self.trace
3573 .accepted_gpu_constraint_relations_checked_consumed = Self::checked_trace_counter_add(
3574 self.trace
3575 .accepted_gpu_constraint_relations_checked_consumed,
3576 evidence.gpu_checked_constraint_relations() as u64,
3577 "accepted_gpu_constraint_relations_checked_consumed",
3578 )?;
3579 self.trace
3580 .accepted_gpu_constraint_row_count_device_reads_consumed =
3581 Self::checked_trace_counter_add(
3582 self.trace
3583 .accepted_gpu_constraint_row_count_device_reads_consumed,
3584 evidence.gpu_constraint_row_count_device_reads() as u64,
3585 "accepted_gpu_constraint_row_count_device_reads_consumed",
3586 )?;
3587 Ok(())
3588 }
3589
3590 fn encode_program_pir_cnf_with_base_provenance(
3591 &mut self,
3592 program: &Program,
3593 base_provenance: &Provenance,
3594 provider: &Arc<CudaKernelProvider>,
3595 evidence: &AcceptedWorldViewEvidence,
3596 path: EpistemicProbPirCnfPath,
3597 ) -> Result<EpistemicProbPirCnfEvidence> {
3598 self.require_accepted_evidence(evidence)?;
3599 let conditioned_provenance = if evidence.assumptions().is_empty() {
3600 None
3601 } else {
3602 let conditioned_program = condition_program_with_available_evidence_using_provenance(
3603 program,
3604 base_provenance,
3605 evidence,
3606 )?;
3607 Some(extract_from_program(&conditioned_program)?)
3608 };
3609 let provenance = conditioned_provenance.as_ref().unwrap_or(base_provenance);
3610 self.encode_provenance_pir_cnf_with_accepted_world_view(
3611 provenance, provider, evidence, path,
3612 )
3613 }
3614
3615 fn encode_provenance_pir_cnf_with_accepted_world_view(
3616 &mut self,
3617 provenance: &Provenance,
3618 provider: &Arc<CudaKernelProvider>,
3619 evidence: &AcceptedWorldViewEvidence,
3620 path: EpistemicProbPirCnfPath,
3621 ) -> Result<EpistemicProbPirCnfEvidence> {
3622 self.require_accepted_evidence(evidence)?;
3623 let production_events_before = self.trace.checked_gpu_production_path_events()?;
3624 let roots = production_pir_roots(provenance)?;
3625 if roots.is_empty() {
3626 return Err(XlogError::UnsupportedEpistemicConstruct {
3627 construct: "accepted probabilistic PIR/CNF production path".to_string(),
3628 context: "GPU PIR/CNF evidence requires at least one query, evidence, or probabilistic variable root".to_string(),
3629 });
3630 }
3631 let gpu_pir = GpuPirGraph::from_host(&provenance.pir, provider)?;
3632 checked_prob_trace_counter_inc!(self, gpu_pir_graph_uploads);
3633 match path {
3634 EpistemicProbPirCnfPath::Source => {
3635 checked_prob_trace_counter_inc!(self, gpu_source_pir_graph_uploads);
3636 }
3637 EpistemicProbPirCnfPath::Program => {
3638 checked_prob_trace_counter_inc!(self, gpu_program_pir_graph_uploads);
3639 }
3640 }
3641 let gpu_roots = GpuPirRoots::from_host(&roots, provider)?;
3642 let encoding = encode_cnf_gpu(&gpu_pir, &gpu_roots, provider)?;
3643 checked_prob_trace_counter_inc!(self, gpu_cnf_encodes);
3644 match path {
3645 EpistemicProbPirCnfPath::Source => {
3646 checked_prob_trace_counter_inc!(self, gpu_source_cnf_encodes);
3647 }
3648 EpistemicProbPirCnfPath::Program => {
3649 checked_prob_trace_counter_inc!(self, gpu_program_cnf_encodes);
3650 }
3651 }
3652 let pir_cnf_evidence = EpistemicProbPirCnfEvidence {
3653 pir_nodes: provenance.pir.len(),
3654 root_count: roots.len(),
3655 cnf_var_cap: encoding.cnf.var_cap,
3656 cnf_clause_cap: encoding.cnf.clause_cap,
3657 cnf_lit_cap: encoding.cnf.lit_cap,
3658 };
3659 self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3660 self.record_accepted_evidence(evidence)?;
3661 Ok(pir_cnf_evidence)
3662 }
3663}
3664
3665fn require_gpu_exact_backend(program: &ExactDdnnfProgram, construct: &'static str) -> Result<()> {
3666 if !program.uses_gpu_production_backend() {
3667 return Err(XlogError::UnsupportedEpistemicConstruct {
3668 construct: construct.to_string(),
3669 context:
3670 "production probability metrics require a compiled GPU-native Decision-DNNF exact/provenance/PIR/CNF backend; \
3671 empty roots and count-lift-only evaluation cannot satisfy accepted epistemic probability reuse"
3672 .to_string(),
3673 });
3674 }
3675 Ok(())
3676}
3677
3678#[cfg(feature = "host-io")]
3679#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
3680struct EpistemicProbConditionedEvidenceCounts {
3681 total: usize,
3682 nonzero_arity: usize,
3683 max_arity: u32,
3684 negative: usize,
3685 know: usize,
3686 possible: usize,
3687 not_known: usize,
3688 not_possible: usize,
3689}
3690
3691fn condition_program_with_available_evidence_using_provenance(
3692 program: &Program,
3693 base_provenance: &Provenance,
3694 evidence: &AcceptedWorldViewEvidence,
3695) -> Result<Program> {
3696 if evidence.assumptions().is_empty() {
3697 return Ok(program.clone());
3698 }
3699
3700 let mut program = program.clone();
3701 let mut applied = 0usize;
3702 for assumption in evidence.assumptions() {
3703 validate_conditioned_assumption_shape(assumption)?;
3704 let Some(atom) = conditioned_evidence_atom_for_assumption(base_provenance, assumption)
3705 else {
3706 return Err(XlogError::UnsupportedEpistemicConstruct {
3707 construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3708 context: format!(
3709 "accepted {} PIR/CNF evidence for {}/{} has no provenance formula; partial \
3710 world-view evidence cannot satisfy production conditioning metrics",
3711 assumption.evidence_literal(),
3712 assumption.predicate,
3713 assumption.arity
3714 ),
3715 });
3716 };
3717 program.evidence.push(Evidence {
3718 atom,
3719 value: assumption.value,
3720 });
3721 applied += 1;
3722 }
3723
3724 if applied == 0 {
3725 return Err(XlogError::UnsupportedEpistemicConstruct {
3726 construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3727 context: "PIR/CNF encoding requires at least one accepted epistemic assumption to match existing probabilistic provenance"
3728 .to_string(),
3729 });
3730 }
3731
3732 Ok(program)
3733}
3734
3735#[cfg(feature = "host-io")]
3736fn condition_program_with_accepted_evidence_using_provenance(
3737 program: &Program,
3738 provenance: &Provenance,
3739 evidence: &AcceptedWorldViewEvidence,
3740) -> Result<(Program, EpistemicProbConditionedEvidenceCounts)> {
3741 if evidence.assumptions().is_empty() {
3742 return Err(XlogError::UnsupportedEpistemicConstruct {
3743 construct: "accepted probabilistic evidence conditioning".to_string(),
3744 context: "conditioned exact path requires at least one accepted epistemic assumption"
3745 .to_string(),
3746 });
3747 }
3748
3749 let mut counts = EpistemicProbConditionedEvidenceCounts::default();
3750 for assumption in evidence.assumptions() {
3751 validate_conditioned_assumption_shape(assumption)?;
3752 record_conditioned_assumption_counts(&mut counts, assumption);
3753 }
3754 let mut program = program.clone();
3755 for assumption in evidence.assumptions() {
3756 let Some(atom) = conditioned_evidence_atom_for_assumption(provenance, assumption) else {
3757 return Err(XlogError::UnsupportedEpistemicConstruct {
3758 construct: "accepted probabilistic evidence conditioning".to_string(),
3759 context: format!(
3760 "accepted {} exact evidence for {}/{} has no provenance formula; \
3761 vacuous evidence cannot satisfy production conditioning metrics",
3762 assumption.evidence_literal(),
3763 assumption.predicate,
3764 assumption.arity
3765 ),
3766 });
3767 };
3768 program.evidence.push(Evidence {
3769 atom,
3770 value: assumption.value,
3771 });
3772 }
3773
3774 Ok((program, counts))
3775}
3776
3777fn validate_conditioned_assumption_shape(assumption: &EpistemicAssumption) -> Result<()> {
3778 if assumption.arity == 0 {
3779 if !assumption.terms.is_empty() {
3780 return Err(XlogError::UnsupportedEpistemicConstruct {
3781 construct: "accepted probabilistic evidence conditioning".to_string(),
3782 context: format!(
3783 "zero-arity exact evidence must not carry tuple terms, got {}/{}",
3784 assumption.predicate, assumption.arity
3785 ),
3786 });
3787 }
3788 } else if assumption.terms.len() != assumption.arity {
3789 return Err(XlogError::UnsupportedEpistemicConstruct {
3790 construct: "accepted probabilistic evidence conditioning".to_string(),
3791 context: format!(
3792 "nonzero exact evidence conditioning requires {} concrete tuple terms, got {} for {}/{}",
3793 assumption.arity,
3794 assumption.terms.len(),
3795 assumption.predicate,
3796 assumption.arity
3797 ),
3798 });
3799 }
3800 Ok(())
3801}
3802
3803#[cfg(feature = "host-io")]
3804fn record_conditioned_assumption_counts(
3805 counts: &mut EpistemicProbConditionedEvidenceCounts,
3806 assumption: &EpistemicAssumption,
3807) {
3808 counts.total += 1;
3809 if assumption.arity > 0 {
3810 counts.nonzero_arity += 1;
3811 counts.max_arity = counts.max_arity.max(assumption.arity as u32);
3812 }
3813 if !assumption.value {
3814 counts.negative += 1;
3815 }
3816 match (assumption.kind, assumption.value) {
3817 (EpistemicAssumptionKind::Know, true) => counts.know += 1,
3818 (EpistemicAssumptionKind::Possible, true) => counts.possible += 1,
3819 (EpistemicAssumptionKind::Know, false) => counts.not_known += 1,
3820 (EpistemicAssumptionKind::Possible, false) => counts.not_possible += 1,
3821 }
3822}
3823
3824fn evidence_term_variants(term: &EpistemicEvidenceTerm) -> Vec<(Value, Term)> {
3825 match term {
3826 EpistemicEvidenceTerm::Integer(value) => vec![(Value::I64(*value), Term::Integer(*value))],
3827 EpistemicEvidenceTerm::String(value) => {
3828 let symbol_id = symbol::intern(value);
3829 vec![
3830 (Value::String(value.clone()), Term::String(value.clone())),
3831 (Value::Symbol(symbol_id), Term::Symbol(symbol_id)),
3832 ]
3833 }
3834 EpistemicEvidenceTerm::Symbol(value) => {
3835 let string_value = symbol::resolve(*value);
3836 vec![
3837 (Value::Symbol(*value), Term::Symbol(*value)),
3838 (
3839 Value::String(string_value.clone()),
3840 Term::String(string_value),
3841 ),
3842 ]
3843 }
3844 }
3845}
3846
3847fn conditioned_evidence_atom_for_assumption(
3848 provenance: &Provenance,
3849 assumption: &EpistemicAssumption,
3850) -> Option<Atom> {
3851 if assumption.terms.is_empty() {
3852 if provenance
3853 .query_formula(&assumption.predicate, &[])
3854 .is_some()
3855 {
3856 return Some(Atom {
3857 predicate: assumption.predicate.clone(),
3858 terms: Vec::new(),
3859 });
3860 }
3861 return None;
3862 }
3863
3864 let variants = assumption
3865 .terms
3866 .iter()
3867 .map(evidence_term_variants)
3868 .collect::<Vec<_>>();
3869 let mut values = Vec::with_capacity(variants.len());
3870 let mut terms = Vec::with_capacity(variants.len());
3871 conditioned_evidence_atom_from_variants(
3872 provenance,
3873 assumption,
3874 &variants,
3875 0,
3876 &mut values,
3877 &mut terms,
3878 )
3879}
3880
3881fn conditioned_evidence_atom_from_variants(
3882 provenance: &Provenance,
3883 assumption: &EpistemicAssumption,
3884 variants: &[Vec<(Value, Term)>],
3885 index: usize,
3886 values: &mut Vec<Value>,
3887 terms: &mut Vec<Term>,
3888) -> Option<Atom> {
3889 if index == variants.len() {
3890 if provenance
3891 .query_formula(&assumption.predicate, values)
3892 .is_some()
3893 {
3894 return Some(Atom {
3895 predicate: assumption.predicate.clone(),
3896 terms: terms.clone(),
3897 });
3898 }
3899 return None;
3900 }
3901
3902 for (value, term) in &variants[index] {
3903 values.push(value.clone());
3904 terms.push(term.clone());
3905 if let Some(atom) = conditioned_evidence_atom_from_variants(
3906 provenance,
3907 assumption,
3908 variants,
3909 index + 1,
3910 values,
3911 terms,
3912 ) {
3913 return Some(atom);
3914 }
3915 values.pop();
3916 terms.pop();
3917 }
3918 None
3919}
3920
3921fn assumption_has_provenance_formula(
3922 provenance: &Provenance,
3923 assumption: &EpistemicAssumption,
3924) -> bool {
3925 conditioned_evidence_atom_for_assumption(provenance, assumption).is_some()
3926}
3927
3928fn evidence_with_provenance_backed_assumptions(
3929 evidence: &AcceptedWorldViewEvidence,
3930 provenance: &Provenance,
3931) -> Result<AcceptedWorldViewEvidence> {
3932 let assumptions = evidence
3933 .assumptions()
3934 .iter()
3935 .filter(|assumption| assumption_has_provenance_formula(provenance, assumption))
3936 .cloned()
3937 .collect::<Vec<_>>();
3938 if assumptions.is_empty() {
3939 return Err(XlogError::UnsupportedEpistemicConstruct {
3940 construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3941 context: "PIR/CNF encoding requires at least one accepted epistemic assumption to match existing probabilistic provenance"
3942 .to_string(),
3943 });
3944 }
3945 Ok(evidence.with_assumptions(assumptions))
3946}
3947
3948#[cfg(feature = "host-io")]
3949fn accepted_evidence_for_provenance<'a>(
3950 evidence: &'a AcceptedWorldViewEvidence,
3951 provenance: &Provenance,
3952) -> Result<Cow<'a, AcceptedWorldViewEvidence>> {
3953 if evidence.assumptions_auto_derived_from_gpu() {
3954 Ok(Cow::Owned(evidence_with_provenance_backed_assumptions(
3955 evidence, provenance,
3956 )?))
3957 } else {
3958 Ok(Cow::Borrowed(evidence))
3959 }
3960}
3961
3962fn production_pir_roots(provenance: &Provenance) -> Result<Vec<PirNodeId>> {
3963 let mut roots = BTreeSet::new();
3964
3965 for (atom, value) in &provenance.evidence {
3966 if let Some(id) = provenance.query_formula(&atom.predicate, &atom.args) {
3967 roots.insert(id);
3968 } else if *value {
3969 return Err(XlogError::Execution(format!(
3970 "Exact inference error: evidence atom is never derivable: {}",
3971 atom.predicate
3972 )));
3973 }
3974 }
3975
3976 for atom in &provenance.queries {
3977 if let Some(id) = provenance.query_formula(&atom.predicate, &atom.args) {
3978 roots.insert(id);
3979 }
3980 }
3981
3982 for (idx, node) in provenance.pir.nodes().iter().enumerate() {
3983 if matches!(
3984 node,
3985 PirNode::Decision { .. } | PirNode::Lit { .. } | PirNode::NegLit { .. }
3986 ) {
3987 roots.insert(PirNodeId::from_u32(idx as u32));
3988 }
3989 }
3990
3991 Ok(roots.into_iter().collect())
3992}
3993
3994#[cfg(all(test, feature = "host-io"))]
3995mod prepared_conditioned_poison_tests {
3996 use super::*;
3997
3998 #[test]
3999 fn rollback_failure_permanently_invalidates_prepared_state_and_all_clones() {
4000 let _gpu_guard = crate::test_gpu_lock::lock();
4001 match xlog_cuda::CudaDevice::new(0) {
4002 Ok(_) => {}
4003 Err(error) if std::env::var("XLOG_REQUIRE_CUDA").as_deref() == Ok("1") => {
4004 panic!("XLOG_REQUIRE_CUDA=1 but CUDA runtime initialization failed: {error}")
4005 }
4006 Err(error) => {
4007 eprintln!("Skipping test: CUDA runtime unavailable: {error}");
4008 return;
4009 }
4010 }
4011
4012 let exact = ExactDdnnfProgram::compile_source(
4013 "0.5::rain().\n\
4014 query(rain()).\n",
4015 )
4016 .expect("compile prepared exact program");
4017 let prepared =
4018 PreparedConditionedProgram::new(exact, EpistemicProbProductionTrace::default())
4019 .expect("prepare exact circuit");
4020 let rain_var = prepared
4021 .prob_var_map()
4022 .expect("read fact map before injected failure")
4023 .iter()
4024 .enumerate()
4025 .find_map(|(var, info)| {
4026 matches!(info, ProbVarInfo::Fact { atom, .. } if atom.predicate == "rain")
4027 .then_some(var as u32)
4028 })
4029 .expect("rain fact has a CNF variable");
4030 let clone_before_failure = prepared.clone();
4031
4032 let error = prepared
4033 .set_fact_probabilities_with_device_failures(
4034 &BTreeMap::from([(rain_var, 0.9)]),
4035 Some(1),
4036 Some(1),
4037 )
4038 .expect_err("rollback failure must be reported");
4039 let message = error.to_string();
4040 assert!(message.contains("device update failed"), "{message}");
4041 assert!(message.contains("rollback also failed"), "{message}");
4042 assert!(
4043 message.contains("injected fact probability device-write failure"),
4044 "{message}"
4045 );
4046 assert!(
4047 message.contains("injected fact probability rollback failure"),
4048 "{message}"
4049 );
4050
4051 let clone_after_failure = prepared.clone();
4052 for (operation, result) in [
4053 ("evaluate", prepared.evaluate().map(|_| ())),
4054 ("gradient", prepared.evaluate_with_grads().map(|_| ())),
4055 ("prob_var_map", prepared.prob_var_map().map(|_| ())),
4056 (
4057 "set_fact_probabilities",
4058 prepared.set_fact_probabilities(&BTreeMap::from([(rain_var, 0.4)])),
4059 ),
4060 (
4061 "clone-before evaluate",
4062 clone_before_failure.evaluate().map(|_| ()),
4063 ),
4064 (
4065 "clone-before prob_var_map",
4066 clone_before_failure.prob_var_map().map(|_| ()),
4067 ),
4068 (
4069 "clone-after gradient",
4070 clone_after_failure.evaluate_with_grads().map(|_| ()),
4071 ),
4072 (
4073 "clone-after set",
4074 clone_after_failure.set_fact_probabilities(&BTreeMap::from([(rain_var, 0.4)])),
4075 ),
4076 ] {
4077 let later = result
4078 .err()
4079 .unwrap_or_else(|| panic!("{operation} reused poisoned state"));
4080 let later_message = later.to_string();
4081 assert!(
4082 later_message.contains("permanently invalid"),
4083 "{operation}: {later_message}"
4084 );
4085 assert!(
4086 later_message.contains("rollback also failed"),
4087 "{operation}: {later_message}"
4088 );
4089 }
4090 }
4091}