///|
fn check_item(universe : Int32, item : Int32) -> Unit raise ZddError {
if item < 0 || item >= universe {
raise Invalid("item outside universe")
}
}
// 0 exclude, 1 take cofactor, 2 retain containing sets, 3 toggle.
///|
fn Engine::element_nodes(
self : Engine,
id : Int32,
item : Int32,
mode : Int32,
cache : Map[Int32, Int32],
) -> Int32 raise ZddError {
self.tick()
if id == 0 {
return 0
}
if cache.get(id) is Some(found) {
return found
}
let node = self.nodes[id]
let out = if id <= 1 || node.variable > item {
match mode {
0 => id
3 => self.make(item, 0, id)
_ => 0
}
} else if node.variable == item {
match mode {
0 => node.low
1 => node.high
2 => self.make(item, 0, node.high)
_ => self.make(item, node.high, node.low)
}
} else {
let low = self.element_nodes(node.low, item, mode, cache)
let high = self.element_nodes(node.high, item, mode, cache)
self.make(node.variable, low, high)
}
cache[id] = out
out
}
///|
fn Family::element_transform(
self : Family,
item : Int32,
mode : Int32,
limits : Limits,
) -> Family raise ZddError {
check_item(self.universe, item)
let e = engine(self.universe, limits)
let root = e.load(self)
e.finish(e.element_nodes(root, item, mode, Map([])))
}
///|
pub fn Family::excluding(
self : Family,
item : Int32,
limits~ : Limits = Limits::default(),
) -> Family raise ZddError {
self.element_transform(item, 0, limits)
}
///|
/// Keep sets containing item and REMOVE that item from the returned members.
pub fn Family::cofactor(
self : Family,
item : Int32,
limits~ : Limits = Limits::default(),
) -> Family raise ZddError {
self.element_transform(item, 1, limits)
}
///|
/// Keep sets containing item without changing them.
pub fn Family::containing(
self : Family,
item : Int32,
limits~ : Limits = Limits::default(),
) -> Family raise ZddError {
self.element_transform(item, 2, limits)
}
///|
pub fn Family::toggle(
self : Family,
item : Int32,
limits~ : Limits = Limits::default(),
) -> Family raise ZddError {
self.element_transform(item, 3, limits)
}