///|
/// Disjunctive fusion transfers each focal pair to its union.
/// This is an alternative source model, not interchangeable with conjunction.
pub fn disjunctive(
a : Mass,
b : Mass,
budget~ : Limits = default_limits(),
) -> Mass raise BeliefError {
pair_budget(a, b, budget)
let bins = Array::make(a.domain.universe() + 1, 0.0)
let corrections = Array::make(bins.length(), 0.0)
for (left, x) in a.focals {
for (right, y) in b.focals {
let target = left | right
let adjusted = x * y - corrections[target]
let next = bins[target] + adjusted
corrections[target] = next - bins[target] - adjusted
bins[target] = next
}
}
from_bins(a.domain, bins, budget)
}
///|
/// Yager transfers all conjunctive conflict to the full frame.
pub fn yager(
a : Mass,
b : Mass,
budget~ : Limits = default_limits(),
) -> Mass raise BeliefError {
let c = conjunctive(a, b, budget~)
let bins = Array::make(a.domain.universe() + 1, 0.0)
for (mask, value) in c.focals {
if mask == 0 {
bins[a.domain.universe()] = bins[a.domain.universe()] + value
} else {
bins[mask] = bins[mask] + value
}
}
from_bins(a.domain, bins, budget)
}
///|
/// Dubois-Prade transfers each incompatible pair to its union.
/// Both-empty pairs stay empty; open-world inputs are not silently normalized.
pub fn dubois_prade(
a : Mass,
b : Mass,
budget~ : Limits = default_limits(),
) -> Mass raise BeliefError {
pair_budget(a, b, budget)
let bins = Array::make(a.domain.universe() + 1, 0.0)
let corrections = Array::make(bins.length(), 0.0)
for (left, x) in a.focals {
for (right, y) in b.focals {
let intersection = left & right
let target = if intersection == 0 { left | right } else { intersection }
let adjusted = x * y - corrections[target]
let next = bins[target] + adjusted
corrections[target] = next - bins[target] - adjusted
bins[target] = next
}
}
from_bins(a.domain, bins, budget)
}