///|
/// Conditioning by certain event evidence. Incompatible mass stays empty.
/// An impossible/empty observation is rejected rather than fabricated.
pub fn Mass::condition_open(
self : Mass,
event : Int32,
budget~ : Limits = default_limits(),
) -> Mass raise BeliefError {
self.domain.check_mask(event)
if event == 0 {
raise Invalid("conditioning event must be nonempty")
}
budget.check_dense(self.domain)
let bins = Array::make(self.domain.universe() + 1, 0.0)
let corrections = Array::make(bins.length(), 0.0)
for (mask, value) in self.focals {
let target = mask & event
let adjusted = value - corrections[target]
let next = bins[target] + adjusted
corrections[target] = next - bins[target] - adjusted
bins[target] = next
}
from_bins(self.domain, bins, budget)
}
///|
/// Closed-world conditioning uses the same near-total-conflict gate as Dempster.
pub fn Mass::condition(
self : Mass,
event : Int32,
min_survival~ : Double = 1.0e-12,
budget~ : Limits = default_limits(),
) -> Mass raise BeliefError {
check_survival_threshold(min_survival)
self.condition_open(event, budget~).normalize(min_survival~, budget~)
}
///|
/// Conditional belief/plausibility bounds, not a posterior probability vector.
pub fn Mass::conditional_interval(
self : Mass,
query : Int32,
given : Int32,
min_survival~ : Double = 1.0e-12,
budget~ : Limits = default_limits(),
) -> (Double, Double) raise BeliefError {
self.domain.check_mask(query)
self.condition(given, min_survival~, budget~).interval(query)
}