use std::collections::BTreeSet;
use super::func::IFn;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ISubpropertyFunc {
pub parent: Option<usize>,
pub func: IFn,
pub children: Vec<usize>,
pub dependencies: BTreeSet<usize>,
pub display: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ISubpropertyNext {
pub parent: Option<usize>,
pub universal: bool,
pub inner: usize,
pub display: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ISubpropertyFixedPoint {
pub parent: Option<usize>,
pub universal: bool,
pub inner: usize,
pub dependents: Vec<usize>,
pub display: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ISubproperty {
Func(ISubpropertyFunc),
Next(ISubpropertyNext),
FixedPoint(ISubpropertyFixedPoint),
}
impl ISubproperty {
pub fn parent(&self) -> Option<usize> {
match self {
ISubproperty::Func(subproperty) => subproperty.parent,
ISubproperty::Next(subproperty) => subproperty.parent,
ISubproperty::FixedPoint(subproperty) => subproperty.parent,
}
}
pub fn children(&self) -> &[usize] {
match self {
ISubproperty::Func(subproperty) => &subproperty.children,
ISubproperty::Next(subproperty) => std::slice::from_ref(&subproperty.inner),
ISubproperty::FixedPoint(subproperty) => std::slice::from_ref(&subproperty.inner),
}
}
pub fn display_str(&self) -> Option<&str> {
match self {
ISubproperty::Func(subproperty) => subproperty.display.as_ref(),
ISubproperty::Next(subproperty) => subproperty.display.as_ref(),
ISubproperty::FixedPoint(subproperty) => subproperty.display.as_ref(),
}
.map(|v| v.as_str())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IProperty {
pub subproperties: Vec<ISubproperty>,
}
impl IProperty {
pub fn num_subproperties(&self) -> usize {
self.subproperties.len()
}
pub fn subproperty_entry(&self, index: usize) -> &ISubproperty {
&self.subproperties[index]
}
pub fn transition_depth(&self) -> usize {
let (open_number, max_closed_number) = self.subproperty_transition_depth(0);
open_number.max(max_closed_number)
}
fn subproperty_transition_depth(&self, subproperty_index: usize) -> (usize, usize) {
let subproperty = &self.subproperties[subproperty_index];
match subproperty {
ISubproperty::Func(subproperty) => {
let mut open_number = 0;
let mut max_closed_number = 0;
for child_index in subproperty.children.iter().cloned() {
let (candidate_open_number, candidate_max_closed_number) =
self.subproperty_transition_depth(child_index);
open_number = open_number.max(candidate_open_number);
max_closed_number = max_closed_number.max(candidate_max_closed_number);
}
(open_number, max_closed_number)
}
ISubproperty::Next(subproperty) => {
let (mut open_number, max_closed_number) =
self.subproperty_transition_depth(subproperty.inner);
open_number += 1;
(open_number, max_closed_number)
}
ISubproperty::FixedPoint(subproperty) => {
let (open_number, max_closed_number) =
self.subproperty_transition_depth(subproperty.inner);
let max_closed_number = max_closed_number.max(open_number);
(0, max_closed_number)
}
}
}
pub fn is_subproperty_closed_form(&self, subproperty_index: usize) -> bool {
let mut self_descendants = BTreeSet::new();
let mut dependencies = BTreeSet::new();
self.compute_self_descendants_and_dependencies(
subproperty_index,
&mut self_descendants,
&mut dependencies,
);
self_descendants == dependencies
}
fn compute_self_descendants_and_dependencies(
&self,
subproperty_index: usize,
self_descendants: &mut BTreeSet<usize>,
dependencies: &mut BTreeSet<usize>,
) {
self_descendants.insert(subproperty_index);
dependencies.insert(subproperty_index);
let subproperty = &self.subproperties[subproperty_index];
match subproperty {
ISubproperty::Func(subproperty) => {
dependencies.extend(subproperty.dependencies.iter().cloned());
for child_index in subproperty.children.iter().cloned() {
self.compute_self_descendants_and_dependencies(
child_index,
self_descendants,
dependencies,
);
}
}
ISubproperty::Next(subproperty) => {
self.compute_self_descendants_and_dependencies(
subproperty.inner,
self_descendants,
dependencies,
);
}
ISubproperty::FixedPoint(subproperty) => {
self.compute_self_descendants_and_dependencies(
subproperty.inner,
self_descendants,
dependencies,
);
}
};
}
}