///|
pub(all) struct Constraint {
left : String
right : String
allowed : RelSet
label : String
} derive(Eq, Debug)
///|
pub extend Constraint with Eq::{equal, not_equal}
///|
pub extend Constraint with @debug.Debug::{to_repr}
///|
/// Immutable named matrix. Accessors copy arrays, and constraints intersect.
pub struct Network {
priv names : Array[String]
priv cells : Array[RelSet]
priv sources : Array[Constraint]
}
///|
fn valid_name(name : String) -> Bool {
if name.length() == 0 || name.length() > 128 {
return false
}
for c in name.iter() {
if !(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z') &&
!(c >= '0' && c <= '9') &&
c != '_' &&
c != '-' &&
c != '.' {
return false
}
}
true
}
///|
pub fn Network::new(names : Array[String]) -> Network raise AllenError {
let n = names.length()
if n > 64 {
raise TooLarge(n)
}
for i = 0; i < n; i = i + 1 {
if !valid_name(names[i]) {
raise InvalidName(names[i])
}
for j = 0; j < i; j = j + 1 {
if names[i] == names[j] {
raise DuplicateName(names[i])
}
}
}
let cells = Array::make(n * n, RelSet::all())
for i = 0; i < n; i = i + 1 {
cells[i * n + i] = RelSet::single(Equal)
}
{ names: names.copy(), cells, sources: [], }
}
///|
pub fn Network::size(self : Network) -> Int32 {
self.names.length()
}
///|
pub fn Network::names(self : Network) -> Array[String] {
self.names.copy()
}
///|
pub fn Network::constraints(self : Network) -> Array[Constraint] {
self.sources.copy()
}
///|
pub fn Network::index(self : Network, name : String) -> Int32 raise AllenError {
for i = 0; i < self.size(); i = i + 1 {
if self.names[i] == name {
return i
}
}
raise UnknownName(name)
}
///|
pub fn Network::at(
self : Network,
i : Int32,
j : Int32,
) -> RelSet raise AllenError {
if i < 0 || i >= self.size() {
raise InvalidIndex(i)
}
if j < 0 || j >= self.size() {
raise InvalidIndex(j)
}
self.cells[i * self.size() + j]
}
///|
pub fn Network::get(
self : Network,
left : String,
right : String,
) -> RelSet raise AllenError {
self.at(self.index(left), self.index(right))
}
///|
pub fn Network::constrain(
self : Network,
constraint : Constraint,
) -> Network raise AllenError {
if constraint.label.length() > 256 {
raise InvalidFormat("label too long")
}
if self.sources.length() >= 4096 {
raise TooLarge(self.sources.length() + 1)
}
let i = self.index(constraint.left)
let j = self.index(constraint.right)
let cells = self.cells.copy()
let n = self.size()
let narrowed = cells[i * n + j].intersect(constraint.allowed)
if i == j {
cells[i * n + j] = narrowed.intersect(RelSet::single(Equal))
} else {
cells[i * n + j] = narrowed
cells[j * n + i] = narrowed.converse()
}
let sources = self.sources.copy()
sources.push(constraint)
{ names: self.names.copy(), cells, sources, }
}
///|
pub fn Network::restrict(
self : Network,
left : String,
right : String,
allowed : RelSet,
label~ : String = "",
) -> Network raise AllenError {
self.constrain({ left, right, allowed, label, })
}
///|
pub fn Network::from_constraints(
names : Array[String],
constraints : Array[Constraint],
) -> Network raise AllenError {
let mut net = Network::new(names)
for constraint in constraints {
net = net.constrain(constraint)
}
net
}
///|
pub fn Network::is_atomic(self : Network) -> Bool {
for set in self.cells {
if set.size() != 1 {
return false
}
}
true
}
///|
pub fn Network::same_domains(self : Network, other : Network) -> Bool {
self.names == other.names && self.cells == other.cells
}
///|
pub fn Network::is_refinement_of(self : Network, other : Network) -> Bool {
if self.names != other.names {
return false
}
for i = 0; i < self.cells.length(); i = i + 1 {
if !self.cells[i].subset_of(other.cells[i]) {
return false
}
}
true
}