use core::fmt::Debug;
use open_hypergraphs::array::vec::*;
use open_hypergraphs::category::*;
use open_hypergraphs::finite_function::*;
use open_hypergraphs::indexed_coproduct::*;
use open_hypergraphs::semifinite::*;
use open_hypergraphs::strict::hypergraph::{arrow::*, *};
use proptest::collection::vec;
use proptest::prelude::*;
use proptest::strategy::{BoxedStrategy, Strategy};
#[non_exhaustive]
#[derive(Debug, PartialEq, Clone)]
pub struct FiniteFunctionType {
pub source: usize,
pub target: usize,
}
impl FiniteFunctionType {
pub fn new(source: usize, target: usize) -> Option<Self> {
if source > 0 && target == 0 {
None
} else {
Some(Self { source, target })
}
}
}
pub fn arb_finite_function_type(
max_size: usize,
fixed_a: Option<usize>,
fixed_b: Option<usize>,
) -> BoxedStrategy<FiniteFunctionType> {
if let (Some(a), Some(b)) = (fixed_a, fixed_b) {
assert!(
b > 0 || a == 0,
"Impossible FiniteFunction type specified: {:?} → {:?}",
a,
b
);
}
let a_strategy = match fixed_a {
Some(a) => Just(a).boxed(),
None => (0..=max_size).boxed(),
};
let b_strategy = match fixed_b {
Some(b) => Just(b).boxed(),
None => (1..=max_size).boxed(),
};
(a_strategy, b_strategy)
.prop_filter("Domain size must be >= codomain size for n>0", |(a, b)| {
*b > 0 || *a == 0
})
.prop_map(|(a, b)| FiniteFunctionType::new(a, b).unwrap())
.boxed()
}
pub fn arb_finite_function(
FiniteFunctionType { source, target }: FiniteFunctionType,
) -> BoxedStrategy<FiniteFunction<VecKind>> {
assert!(target > 0 || source == 0, "what");
vec((0..target).boxed(), source..=source)
.prop_map(move |values| FiniteFunction::new(VecArray(values), target).unwrap())
.boxed()
}
pub fn arb_semifinite<T: Debug + 'static>(
arb_element: BoxedStrategy<T>,
num_elements: Option<BoxedStrategy<usize>>,
) -> BoxedStrategy<SemifiniteFunction<VecKind, T>> {
let size_strategy = num_elements.unwrap_or_else(|| (0usize..=10).boxed());
size_strategy
.prop_flat_map(move |size| vec(arb_element.clone(), size..=size))
.prop_map(|v| SemifiniteFunction(VecArray(v)))
.boxed()
}
pub fn arb_indexed_coproduct_finite(
len: usize,
target: usize,
) -> BoxedStrategy<IndexedCoproduct<VecKind, FiniteFunction<VecKind>>> {
let max_source: usize = if target == 0 { 0 } else { 10 };
let sources = arb_semifinite((0..=max_source).boxed(), Some(Just(len).boxed()));
sources
.prop_flat_map(move |sources| {
let sources = sources.clone();
let total_size = sources.0.as_ref().iter().sum();
let ff = arb_finite_function_type(1, Some(total_size), Some(target))
.prop_flat_map(arb_finite_function)
.boxed();
ff.prop_map(move |values| {
let sources = sources.clone();
IndexedCoproduct::from_semifinite(sources, values).unwrap()
})
})
.boxed()
}
#[derive(Clone, Debug)]
pub struct Labels<O, A> {
pub w: SemifiniteFunction<VecKind, O>,
pub x: SemifiniteFunction<VecKind, A>,
}
pub fn arb_labels<
O: PartialEq + Clone + Debug + 'static,
A: PartialEq + Clone + Debug + 'static,
>(
arb_object: BoxedStrategy<O>,
arb_arrow: BoxedStrategy<A>,
) -> BoxedStrategy<Labels<O, A>> {
let operations = arb_semifinite::<A>(arb_arrow, None);
let objects = arb_semifinite::<O>(arb_object, None);
(objects, operations)
.prop_map(|(w, x)| Labels { w, x })
.boxed()
}
pub fn arb_hypergraph<
O: PartialEq + Clone + Debug + 'static,
A: PartialEq + Clone + Debug + 'static,
>(
Labels { w, x }: Labels<O, A>,
) -> BoxedStrategy<Hypergraph<VecKind, O, A>> {
let num_arr = x.len();
let num_obj = w.len();
let s = arb_indexed_coproduct_finite(num_arr, num_obj);
let t = arb_indexed_coproduct_finite(num_arr, num_obj);
(s, t)
.prop_flat_map(move |(s, t)| {
Just(Hypergraph {
s,
t,
w: w.clone(),
x: x.clone(),
})
})
.boxed()
}
pub fn arb_inclusion<
O: PartialEq + Clone + Debug + 'static,
A: PartialEq + Clone + Debug + 'static,
>(
labels: Labels<O, A>,
g: Hypergraph<VecKind, O, A>,
) -> BoxedStrategy<HypergraphArrow<VecKind, O, A>> {
arb_hypergraph(labels)
.prop_flat_map(move |k| {
let h = g.coproduct(&k);
let w = FiniteFunction::inj0(g.w.len(), k.w.len());
let x = FiniteFunction::inj0(g.x.len(), k.x.len());
Just(HypergraphArrow::new(g.clone(), h, w, x).expect("valid HypergraphArrow"))
})
.boxed()
}
#[derive(Clone, Debug)]
pub struct DiscreteSpan<O: Debug, A: Debug> {
pub l: HypergraphArrow<VecKind, O, A>,
#[allow(dead_code)]
pub h: Hypergraph<VecKind, O, A>,
pub r: HypergraphArrow<VecKind, O, A>,
}
impl<O: PartialEq + Clone + Debug, A: PartialEq + Clone + Debug> DiscreteSpan<O, A> {
pub fn validate(self) -> Self {
let DiscreteSpan { ref l, ref r, .. } = self;
assert_eq!(l.w.target(), l.target.w.len());
assert_eq!(r.w.target(), r.target.w.len());
assert_eq!(l.x.target(), l.target.x.len());
assert_eq!(r.x.target(), r.target.x.len());
self
}
}
pub fn arb_discrete_span<
O: PartialEq + Clone + Debug + 'static,
A: PartialEq + Clone + Debug + 'static,
>(
labels: Labels<O, A>,
) -> BoxedStrategy<DiscreteSpan<O, A>> {
let h = Hypergraph::<VecKind, O, A>::discrete(labels.w.clone());
arb_inclusion(labels.clone(), h.clone())
.prop_flat_map(move |l| {
let l = l.clone();
let h = h.clone();
arb_inclusion(labels.clone(), h.clone()).prop_flat_map(move |r| {
let l = l.clone();
let h = h.clone();
Just(DiscreteSpan { l, h, r }.validate())
})
})
.boxed()
}
pub type LabeledCospan<T> = (
FiniteFunction<VecKind>,
FiniteFunction<VecKind>,
SemifiniteFunction<VecKind, T>,
);
pub fn arb_cospan_type() -> BoxedStrategy<(FiniteFunctionType, FiniteFunctionType)> {
let max_size = 10;
let s = arb_finite_function_type(max_size.clone(), None, None);
s.prop_flat_map(move |s| {
let target = s.target;
(
Just(s),
arb_finite_function_type(max_size, None, Some(target)),
)
})
.boxed()
}
pub fn arb_labeled_cospan<O: Debug + Clone + PartialEq + 'static>(
arb_object: BoxedStrategy<O>,
) -> BoxedStrategy<LabeledCospan<O>> {
arb_cospan_type()
.prop_flat_map(move |(ts, tt)| {
(
arb_finite_function(ts),
arb_finite_function(tt.clone()),
arb_semifinite::<O>(arb_object.clone(), Some(Just(tt.target).boxed())),
)
})
.boxed()
}