use std::collections::HashMap;
use std::marker::PhantomData;
use crate::category::entity::Entity;
pub trait OppositionDef {
type Entity: Entity;
fn pairs() -> Vec<(Self::Entity, Self::Entity)>;
}
fn symmetric_adj<E: Entity>(pairs: &[(E, E)]) -> HashMap<E, Vec<E>> {
let mut adj: HashMap<E, Vec<E>> = HashMap::new();
for (a, b) in pairs {
adj.entry(a.clone()).or_default().push(b.clone());
adj.entry(b.clone()).or_default().push(a.clone());
}
adj
}
pub fn opposites<T: OppositionDef>(entity: &T::Entity) -> Vec<T::Entity> {
let adj = symmetric_adj(&T::pairs());
adj.get(entity).cloned().unwrap_or_default()
}
pub fn are_opposed<T: OppositionDef>(a: &T::Entity, b: &T::Entity) -> bool {
opposites::<T>(a).contains(b)
}
pub struct Symmetric<T: OppositionDef> {
_marker: PhantomData<T>,
}
impl<T: OppositionDef> Symmetric<T> {
pub fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<T: OppositionDef> Default for Symmetric<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: OppositionDef> crate::logic::Axiom for Symmetric<T> {
fn description(&self) -> &str {
"opposition is symmetric: if A opposes B then B opposes A"
}
fn holds(&self) -> bool {
for (a, b) in &T::pairs() {
if !are_opposed::<T>(b, a) {
return false;
}
}
true
}
}
pub struct Irreflexive<T: OppositionDef> {
_marker: PhantomData<T>,
}
impl<T: OppositionDef> Irreflexive<T> {
pub fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<T: OppositionDef> Default for Irreflexive<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: OppositionDef> crate::logic::Axiom for Irreflexive<T> {
fn description(&self) -> &str {
"opposition is irreflexive: nothing opposes itself"
}
fn holds(&self) -> bool {
T::pairs().iter().all(|(a, b)| a != b)
}
}
pub struct ExclusiveWithEquivalence<T: OppositionDef, F: Fn(&T::Entity, &T::Entity) -> bool> {
are_equivalent: F,
_marker: PhantomData<T>,
}
impl<T: OppositionDef, F: Fn(&T::Entity, &T::Entity) -> bool> ExclusiveWithEquivalence<T, F> {
pub fn new(are_equivalent: F) -> Self {
Self {
are_equivalent,
_marker: PhantomData,
}
}
}
impl<T: OppositionDef, F: Fn(&T::Entity, &T::Entity) -> bool> crate::logic::Axiom
for ExclusiveWithEquivalence<T, F>
{
fn description(&self) -> &str {
"opposites cannot be equivalent (A opposes B implies A ≢ B)"
}
fn holds(&self) -> bool {
for (a, b) in &T::pairs() {
if (self.are_equivalent)(a, b) {
return false;
}
}
true
}
}