use open_hypergraphs::array::vec::VecArray;
use open_hypergraphs::category::*;
use open_hypergraphs::lax::functor::{map_arrow_witness, Functor};
use open_hypergraphs::lax::{NodeId, OpenHypergraph};
use open_hypergraphs::strict::vec::FiniteFunction;
use crate::open_hypergraph::equality::*;
use crate::theory::meaningless::*;
use proptest::proptest;
#[derive(Clone)]
struct LaxIdentity;
impl<O: PartialEq + Clone, A: Clone + PartialEq> Functor<O, A, O, A> for LaxIdentity {
fn map_object(&self, o: &O) -> impl ExactSizeIterator<Item = O> {
std::iter::once(o.clone())
}
fn map_operation(&self, a: &A, source: &[O], target: &[O]) -> OpenHypergraph<O, A> {
OpenHypergraph::singleton(a.clone(), source.to_vec(), target.to_vec())
}
fn map_arrow(&self, f: &OpenHypergraph<O, A>) -> OpenHypergraph<O, A> {
let f_strict;
let f = if f.hypergraph.is_strict() {
f
} else {
f_strict = {
let mut c = f.clone();
c.quotient().unwrap();
c
};
&f_strict
};
let (mut result, _witness) = map_arrow_witness(self, f).unwrap();
result.quotient().unwrap();
result
}
}
proptest! {
#[test]
fn test_lax_identity_functor_reflexive(f in arb_open_hypergraph()) {
let lax_f = OpenHypergraph::from_strict(f.clone());
let g = LaxIdentity.map_arrow(&lax_f);
assert_open_hypergraph_equality_invariants(&f, &g.to_strict());
}
#[test]
fn test_lax_identity_functor_preserves_composition(v in arb_composite_open_hypergraph(2)) {
let [f, g] = v.as_slice() else { panic!("arb_composite_open_hypergraph returned unexpected size result") };
let lax_f = OpenHypergraph::from_strict(f.clone());
let lax_g = OpenHypergraph::from_strict(g.clone());
let identity_composed = LaxIdentity.map_arrow(&lax_f.compose(&lax_g).unwrap());
let mapped_f = LaxIdentity.map_arrow(&lax_f);
let mapped_g = LaxIdentity.map_arrow(&lax_g);
let composed_identity = mapped_f.compose(&mapped_g).unwrap();
assert_open_hypergraph_equality_invariants(
&identity_composed.to_strict(),
&composed_identity.to_strict(),
);
}
}
#[derive(Clone, PartialEq, Debug)]
pub enum Arr {
Add, Neg, Sub, }
#[derive(Clone)]
struct ExpandDefinitions;
impl Functor<(), Arr, (), Arr> for ExpandDefinitions {
fn map_object(&self, _o: &()) -> impl ExactSizeIterator<Item = ()> {
std::iter::once(())
}
fn map_operation(&self, a: &Arr, source: &[()], target: &[()]) -> OpenHypergraph<(), Arr> {
match a {
Arr::Add | Arr::Neg => {
OpenHypergraph::singleton(a.clone(), source.to_vec(), target.to_vec())
}
Arr::Sub => {
let id = OpenHypergraph::identity(vec![()]);
let neg = OpenHypergraph::singleton(Arr::Neg, vec![()], vec![()]);
let add = OpenHypergraph::singleton(Arr::Add, vec![(), ()], vec![()]);
id.tensor(&neg).compose(&add).unwrap()
}
}
}
fn map_arrow(&self, f: &OpenHypergraph<(), Arr>) -> OpenHypergraph<(), Arr> {
let f_strict;
let f = if f.hypergraph.is_strict() {
f
} else {
f_strict = {
let mut c = f.clone();
c.quotient().unwrap();
c
};
&f_strict
};
let (mut result, _witness) = map_arrow_witness(self, f).unwrap();
result.quotient().unwrap();
result
}
}
fn node_ids_to_ff(ids: &[NodeId], n: usize) -> FiniteFunction {
FiniteFunction::new(VecArray(ids.iter().map(|x| x.0).collect()), n).unwrap()
}
#[test]
fn test_sub_expand() {
let sub = OpenHypergraph::singleton(Arr::Sub, vec![(), ()], vec![()]);
let (mut result, witness) = map_arrow_witness(&ExpandDefinitions, &sub).unwrap();
assert_eq!(witness.sources.table.0, vec![1, 1, 1]);
let q = result.quotient().unwrap();
let witness = witness.map_values(&q).unwrap();
assert_eq!(result.source(), vec![(), ()]);
assert_eq!(result.target(), vec![()]);
assert_eq!(result.hypergraph.edges.len(), 2);
assert!(result.hypergraph.edges.contains(&Arr::Neg));
assert!(result.hypergraph.edges.contains(&Arr::Add));
let n_in = sub.hypergraph.nodes.len();
let n_out = result.hypergraph.nodes.len();
let sub_s = node_ids_to_ff(&sub.sources, n_in);
let sub_t = node_ids_to_ff(&sub.targets, n_in);
assert_eq!(
(&sub_s >> &witness.values).unwrap(),
node_ids_to_ff(&result.sources, n_out)
);
assert_eq!(
(&sub_t >> &witness.values).unwrap(),
node_ids_to_ff(&result.targets, n_out)
);
}