///|
/// Keep members whose cardinality lies in the inclusive interval.
pub fn Family::cardinality(
self : Family,
minimum : Int32,
maximum : Int32,
limits~ : Limits = Limits::default(),
) -> Family raise ZddError {
if minimum < 0 || maximum < minimum {
raise Invalid("invalid cardinality interval")
}
let e = engine(self.universe, limits)
let root = e.load(self)
let cache : Map[(Int32, Int32, Int32), Int32] = Map([])
fn visit(id : Int32, lo : Int32, hi : Int32) -> Int32 raise ZddError {
e.tick()
if id == 0 || hi < 0 {
return 0
}
if id == 1 {
return if lo == 0 { 1 } else { 0 }
}
let key = (id, lo, hi)
if cache.get(key) is Some(found) {
return found
}
let node = e.nodes[id]
if lo > self.universe - node.variable {
return 0
}
let low = visit(node.low, lo, hi)
let high = visit(node.high, (lo - 1).max(0), hi - 1)
let out = e.make(node.variable, low, high)
cache[key] = out
out
}
e.finish(visit(root, minimum, maximum.min(self.universe)))
}
///|
/// Exact count per cardinality. Intermediate storage is bounded to 2 million counters.
/// A coefficient overflow raises CountOverflow even if other coefficients fit.
pub fn Family::cardinality_spectrum(
self : Family,
) -> Array[UInt64] raise ZddError {
let spectra : Array[Array[UInt64]] = [[0], [1]]
let mut stored = 2
for id in 2.. 2000000 {
raise BudgetExceeded
}
let row : Array[UInt64] = Array::make(width, 0)
for i in 0..