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