///|
/// Materialize current pairwise domains as fresh evidence.
/// Original source labels are intentionally not claimed for inferred domains.
pub fn Network::domain_constraints(
self : Network,
label~ : String = "domain",
) -> Array[Constraint] {
let out : Array[Constraint] = []
let n = self.size()
for i = 0; i < n; i = i + 1 {
for j = i; j < n; j = j + 1 {
let set = self.cells[i * n + j]
let default = if i == j { RelSet::single(Equal) } else { RelSet::all() }
if set != default {
out.push({
left: self.names[i],
right: self.names[j],
allowed: set,
label,
})
}
}
}
out
}
///|
/// Induced pairwise view, NOT full existential quantifier elimination.
pub fn Network::induced(
self : Network,
names : Array[String],
) -> Network raise AllenError {
let mut out = Network::new(names)
let positions = names.map(name => self.index(name))
for i = 0; i < names.length(); i = i + 1 {
for j = i; j < names.length(); j = j + 1 {
let allowed = self.cells[positions[i] * self.size() + positions[j]]
let default = if i == j { RelSet::single(Equal) } else { RelSet::all() }
if allowed != default {
out = out.restrict(names[i], names[j], allowed, label="induced-domain")
}
}
}
out
}
///|
/// Positional renaming preserves all matrix domains and source labels.
pub fn Network::rename(
self : Network,
names : Array[String],
) -> Network raise AllenError {
let validated = Network::new(names)
if validated.size() != self.size() {
raise InvalidFormat("rename length mismatch")
}
let sources : Array[Constraint] = []
for source in self.sources {
sources.push({
left: names[self.index(source.left)],
right: names[self.index(source.right)],
allowed: source.allowed,
label: source.label,
})
}
{ names: validated.names, cells: self.cells.copy(), sources, }
}
///|
/// Independent components of the non-universal domain graph, including isolates.
pub fn Network::components(self : Network) -> Array[Array[String]] {
let n = self.size()
let seen = Array::make(n, false)
let out : Array[Array[String]] = []
for seed = 0; seed < n; seed = seed + 1 {
if seen[seed] {
continue
}
let pending = [seed]
let members : Array[String] = []
seen[seed] = true
let mut cursor = 0
while cursor < pending.length() {
let i = pending[cursor]
cursor = cursor + 1
members.push(self.names[i])
for j = 0; j < n; j = j + 1 {
if !seen[j] && self.cells[i * n + j] != RelSet::all() {
seen[j] = true
pending.push(j)
}
}
}
out.push(members)
}
out
}