use std::{
borrow::Borrow,
fmt::Display,
ops::{Deref, Rem},
};
use crate::Id;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct StateConjunction(pub(crate) Vec<crate::Id>);
impl StateConjunction {
pub fn get_singleton(&self) -> Option<Id> {
if self.0.len() == 1 {
Some(self.0[0])
} else {
None
}
}
pub fn singleton(id: Id) -> Self {
Self(vec![id])
}
}
pub type AtomicProposition = String;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct AliasName(pub(crate) String);
#[derive(Debug, PartialEq, Eq, Clone)]
#[allow(missing_docs)]
pub enum AcceptanceAtom {
Positive(Id),
Negative(Id),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct AcceptanceSignature(pub(crate) Vec<crate::Id>);
impl AcceptanceSignature {
pub fn get_singleton(&self) -> Option<Option<Id>> {
if self.len() == 0 {
Some(None)
} else if self.len() == 1 {
Some(Some(self[0]))
} else {
None
}
}
pub fn from_singleton(singleton: Id) -> Self {
Self(vec![singleton])
}
pub fn empty() -> Self {
Self(vec![])
}
}
impl Deref for AcceptanceSignature {
type Target = Vec<crate::Id>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, PartialEq, Eq, Clone, Hash, Ord, PartialOrd)]
pub struct HoaBool(pub bool);
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AcceptanceCondition {
Fin(AcceptanceAtom),
Inf(AcceptanceAtom),
And(Box<AcceptanceCondition>, Box<AcceptanceCondition>),
Or(Box<AcceptanceCondition>, Box<AcceptanceCondition>),
Boolean(HoaBool),
}
impl AcceptanceCondition {
fn parity_rec(current: u32, total: u32) -> Self {
if current + 1 >= total {
if current.rem(2) == 0 {
AcceptanceCondition::id_inf(current)
} else {
AcceptanceCondition::id_fin(current)
}
} else if current.rem(2) == 0 {
AcceptanceCondition::Or(
Box::new(AcceptanceCondition::Inf(AcceptanceAtom::Positive(current))),
Box::new(Self::parity_rec(current + 1, total)),
)
} else {
AcceptanceCondition::And(
Box::new(AcceptanceCondition::Fin(AcceptanceAtom::Positive(current))),
Box::new(Self::parity_rec(current + 1, total)),
)
}
}
pub fn parity(priorities: u32) -> Self {
Self::parity_rec(0, priorities)
}
pub fn buchi() -> Self {
AcceptanceCondition::Inf(AcceptanceAtom::Positive(0))
}
pub fn and<C: Borrow<AcceptanceCondition>>(&self, other: C) -> Self {
AcceptanceCondition::And(Box::new(self.clone()), Box::new(other.borrow().clone()))
}
pub fn or<C: Borrow<AcceptanceCondition>>(&self, other: C) -> Self {
AcceptanceCondition::Or(Box::new(self.clone()), Box::new(other.borrow().clone()))
}
pub fn atom<A: Borrow<AcceptanceAtom>>(atom: A) -> Self {
AcceptanceCondition::Fin(atom.borrow().clone())
}
pub fn id_fin(id: Id) -> Self {
Self::Fin(AcceptanceAtom::Positive(id))
}
pub fn id_inf(id: Id) -> Self {
Self::Inf(AcceptanceAtom::Positive(id))
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AcceptanceName {
Buchi,
GeneralizedBuchi,
CoBuchi,
GeneralizedCoBuchi,
Streett,
Rabin,
GeneralizedRabin,
Parity,
All,
None,
}
impl AcceptanceName {
pub fn is_parity(&self) -> bool {
matches!(self, AcceptanceName::Parity)
}
}
impl TryFrom<String> for AcceptanceName {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
match value.as_str() {
"Buchi" => Ok(AcceptanceName::Buchi),
"generalized-Buchi" => Ok(AcceptanceName::GeneralizedBuchi),
"co-Buchi" => Ok(AcceptanceName::CoBuchi),
"generalized-co-Buchi" => Ok(AcceptanceName::GeneralizedCoBuchi),
"Streett" => Ok(AcceptanceName::Streett),
"Rabin" => Ok(AcceptanceName::Rabin),
"generalized-Rabin" => Ok(AcceptanceName::GeneralizedRabin),
"parity" => Ok(AcceptanceName::Parity),
"all" => Ok(AcceptanceName::All),
"none" => Ok(AcceptanceName::None),
val => Err(format!("Unknown acceptance type: {}", val)),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[allow(missing_docs)]
pub enum Property {
StateLabels,
TransLabels,
ImplicitLabels,
ExplicitLabels,
StateAcceptance,
TransitionAcceptance,
UniversalBranching,
NoUniversalBranching,
Deterministic,
Complete,
Unambiguous,
StutterInvariant,
Weak,
VeryWeak,
InherentlyWeak,
Terminal,
Tight,
Colored,
}
impl TryFrom<String> for Property {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
match value.as_str() {
"state-labels" => Ok(Property::StateLabels),
"trans-labels" => Ok(Property::TransLabels),
"implicit-labels" => Ok(Property::ImplicitLabels),
"explicit-labels" => Ok(Property::ExplicitLabels),
"state-acc" => Ok(Property::StateAcceptance),
"trans-acc" => Ok(Property::TransitionAcceptance),
"univ-branch" => Ok(Property::UniversalBranching),
"no-univ-branch" => Ok(Property::NoUniversalBranching),
"deterministic" => Ok(Property::Deterministic),
"complete" => Ok(Property::Complete),
"unambiguous" => Ok(Property::Unambiguous),
"stutter-invariant" => Ok(Property::StutterInvariant),
"weak" => Ok(Property::Weak),
"very-weak" => Ok(Property::VeryWeak),
"inherently-weak" => Ok(Property::InherentlyWeak),
"terminatl" => Ok(Property::Terminal),
"tight" => Ok(Property::Tight),
"colored" => Ok(Property::Colored),
unknown => Err(format!("{} is not a valid property", unknown)),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[allow(missing_docs)]
pub enum AcceptanceInfo {
Int(crate::Id),
Identifier(String),
}
impl AcceptanceInfo {
pub fn identifier<D: Display>(id: D) -> Self {
AcceptanceInfo::Identifier(id.to_string())
}
pub fn integer(id: Id) -> Self {
AcceptanceInfo::Int(id)
}
}
#[cfg(test)]
mod tests {
use crate::AcceptanceCondition;
#[test]
fn parity_acceptance_creator() {
let parity_condition = super::AcceptanceCondition::parity(3);
assert_eq!(
parity_condition,
AcceptanceCondition::id_inf(0)
.or(AcceptanceCondition::id_fin(1).and(AcceptanceCondition::id_inf(2)))
);
}
}