use std::fmt::Debug;
use std::hash::Hash;
use crate::category::{Arrow, Category};
use crate::logic::Axiom;
use super::structural::{
AntisymmetricOnKind, AsymmetricOnKind, IrreflexiveOnKind, NoCyclesOnKind, SymmetricOnKind,
};
pub fn structural_axioms_for<C>() -> Vec<Box<dyn Axiom>>
where
C: Category + 'static,
C::Object: Clone + Eq + Hash + 'static,
C::Morphism: Arrow<Object = C::Object>,
<C::Morphism as Arrow>::Kind: Debug + PartialEq + Clone + 'static,
{
let mut distinct: Vec<<C::Morphism as Arrow>::Kind> = Vec::new();
for m in C::morphisms() {
let k = m.kind();
if !distinct.iter().any(|existing| existing == &k) {
distinct.push(k);
}
}
let mut axioms: Vec<Box<dyn Axiom>> = Vec::new();
for kind in distinct {
let name = format!("{kind:?}");
match name.as_str() {
"Subsumption" => {
axioms.push(Box::new(NoCyclesOnKind::<C>::new(kind)));
axioms.push(Box::new(AntisymmetricOnKind::<C>::new(kind)));
}
"Parthood" => {
axioms.push(Box::new(NoCyclesOnKind::<C>::new(kind)));
}
"Causation" => {
axioms.push(Box::new(AsymmetricOnKind::<C>::new(kind)));
axioms.push(Box::new(IrreflexiveOnKind::<C>::new(kind)));
}
"Opposition" => {
axioms.push(Box::new(SymmetricOnKind::<C>::new(kind)));
axioms.push(Box::new(IrreflexiveOnKind::<C>::new(kind)));
}
_ => {}
}
}
axioms
}
#[cfg(test)]
mod tests {
use super::*;
use crate::category::Concept;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Obj {
X,
Y,
Z,
}
impl Concept for Obj {
fn variants() -> Vec<Self> {
vec![Obj::X, Obj::Y, Obj::Z]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Kind {
Identity,
Subsumption,
Parthood,
Causation,
Opposition,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct M {
from: Obj,
to: Obj,
kind: Kind,
}
impl Arrow for M {
type Object = Obj;
type Kind = Kind;
fn source(&self) -> Obj {
self.from
}
fn target(&self) -> Obj {
self.to
}
fn kind(&self) -> Kind {
self.kind
}
}
struct Cat;
impl Category for Cat {
type Object = Obj;
type Morphism = M;
fn identity(o: &Obj) -> M {
M {
from: *o,
to: *o,
kind: Kind::Identity,
}
}
fn compose(f: &M, g: &M) -> Option<M> {
if f.to != g.from {
return None;
}
Some(M {
from: f.from,
to: g.to,
kind: Kind::Identity,
})
}
fn morphisms() -> Vec<M> {
vec![
M {
from: Obj::X,
to: Obj::X,
kind: Kind::Identity,
},
M {
from: Obj::Y,
to: Obj::Y,
kind: Kind::Identity,
},
M {
from: Obj::Z,
to: Obj::Z,
kind: Kind::Identity,
},
M {
from: Obj::X,
to: Obj::Y,
kind: Kind::Subsumption,
},
M {
from: Obj::Y,
to: Obj::Z,
kind: Kind::Subsumption,
},
M {
from: Obj::X,
to: Obj::Y,
kind: Kind::Parthood,
},
M {
from: Obj::X,
to: Obj::Y,
kind: Kind::Causation,
},
M {
from: Obj::X,
to: Obj::Y,
kind: Kind::Opposition,
},
M {
from: Obj::Y,
to: Obj::X,
kind: Kind::Opposition,
},
]
}
}
#[test]
fn inherits_expected_count() {
let axioms = structural_axioms_for::<Cat>();
assert_eq!(axioms.len(), 7);
}
#[test]
fn all_inherited_axioms_verify() {
for a in structural_axioms_for::<Cat>() {
a.verify().unwrap_or_else(|c| {
panic!(
"inherited structural axiom failed: {}",
c.meta().name.as_str()
)
});
}
}
}