///|
/// Zero-based rank in low-before-high traversal order. A missing set raises MissingMember.
/// Requires the complete family count to fit UInt64.
pub fn Family::rank(
self : Family,
elements : Array[Int32],
) -> UInt64 raise ZddError {
check_set(self.universe, elements)
let counts = self.counts()
let mut result = 0UL
let mut id = self.root
let mut pos = 0
while id > 1 {
let node = self.nodes[id]
if pos < elements.length() && elements[pos] < node.variable {
raise MissingMember
}
if pos < elements.length() && elements[pos] == node.variable {
result = checked_count_add(result, counts[node.low])
pos += 1
id = node.high
} else {
id = node.low
}
}
if id != 1 || pos != elements.length() {
raise MissingMember
}
result
}
///|
fn Family::select_rank(
self : Family,
ordinal : UInt64,
counts : Array[UInt64],
) -> Array[Int32] raise ZddError {
if ordinal >= counts[self.root] {
raise Invalid("rank outside family")
}
let out : Array[Int32] = []
let mut remaining = ordinal
let mut id = self.root
while id > 1 {
let node = self.nodes[id]
let low_count = counts[node.low]
if remaining < low_count {
id = node.low
} else {
remaining -= low_count
out.push(node.variable)
id = node.high
}
}
out
}
///|
pub fn Family::unrank(
self : Family,
ordinal : UInt64,
) -> Array[Int32] raise ZddError {
self.select_rank(ordinal, self.counts())
}
///|
/// Skip directly to offset without enumerating earlier members.
pub fn Family::page(
self : Family,
offset : UInt64,
limit : Int32,
) -> Enumeration raise ZddError {
if limit < 0 || limit > 10000 {
raise Invalid("page limit must be 0..10000")
}
let counts = self.counts()
let total = counts[self.root]
if offset > total {
raise Invalid("page offset beyond family")
}
let sets : Array[Array[Int32]] = []
let mut next = offset
while next < total && sets.length() < limit {
sets.push(self.select_rank(next, counts))
next += 1UL
}
{ sets, complete: next == total, }
}