open_hypergraphs/indexed_coproduct/
arrow.rs1use crate::array::*;
2use crate::category::*;
3use crate::finite_function::*;
4use crate::semifinite::*;
5
6use core::fmt::Debug;
7use core::ops::{Add, Shr};
8use num_traits::{One, Zero};
9
10pub trait HasLen<K: ArrayKind> {
13 fn len(&self) -> K::I;
14 fn is_empty(&self) -> bool {
15 self.len() == K::I::zero()
16 }
17}
18
19impl<K: ArrayKind> HasLen<K> for FiniteFunction<K> {
20 fn len(&self) -> K::I {
21 self.source()
22 }
23}
24
25impl<K: ArrayKind, T> HasLen<K> for SemifiniteFunction<K, T>
26where
27 K::Type<T>: Array<K, T>,
28{
29 fn len(&self) -> K::I {
30 self.0.len()
31 }
32}
33
34#[non_exhaustive] pub struct IndexedCoproduct<K: ArrayKind, F> {
40 pub sources: FiniteFunction<K>,
42
43 pub values: F,
45}
46
47impl<K: ArrayKind, F: Clone> Clone for IndexedCoproduct<K, F>
48where
49 K::Type<K::I>: Clone,
50{
51 fn clone(&self) -> Self {
52 Self {
53 sources: self.sources.clone(),
54 values: self.values.clone(),
55 }
56 }
57}
58
59impl<K: ArrayKind, F: PartialEq> PartialEq for IndexedCoproduct<K, F> {
60 fn eq(&self, other: &Self) -> bool {
61 self.sources == other.sources && self.values == other.values
62 }
63}
64
65impl<K: ArrayKind, F: Clone + HasLen<K>> IndexedCoproduct<K, F>
66where
67 K::Type<K::I>: NaturalArray<K>,
68{
69 pub fn new(sources: FiniteFunction<K>, values: F) -> Option<Self> {
72 IndexedCoproduct { sources, values }.validate()
73 }
74
75 pub fn from_semifinite(sources: SemifiniteFunction<K, K::I>, values: F) -> Option<Self> {
78 let sources = FiniteFunction::new(sources.0.into(), values.len() + K::I::one())?;
79 IndexedCoproduct { sources, values }.validate()
80 }
81
82 fn validate(self) -> Option<Self> {
83 let sum = self.sources.table.sum();
84
85 if self.sources.target != sum.clone() + K::I::one() {
87 return None;
88 }
89
90 if sum != self.values.len() {
91 return None;
92 }
93
94 Some(self)
95 }
96}
97
98impl<K: ArrayKind, F: Clone + HasLen<K>> IndexedCoproduct<K, F>
99where
100 K::Type<K::I>: NaturalArray<K>,
101{
102 pub fn singleton(values: F) -> Self {
104 let n = values.len();
105 let sources = FiniteFunction::constant(K::I::one(), n, K::I::zero());
106 IndexedCoproduct { sources, values }
107 }
108
109 pub fn elements(values: F) -> Self {
111 let n = values.len();
112
113 let sources =
115 FiniteFunction::new(K::Index::fill(K::I::one(), n.clone()), n + K::I::one()).unwrap();
116
117 IndexedCoproduct::new(sources, values).expect("by construction")
119 }
120
121 pub fn len(&self) -> K::I {
122 self.sources.source()
123 }
124
125 pub fn flatmap_sources<G: Clone>(
137 &self,
138 other: &IndexedCoproduct<K, G>,
139 ) -> IndexedCoproduct<K, G> {
140 assert_eq!(self.values.len(), other.len());
143
144 let sources = FiniteFunction {
145 table: self.sources.table.segmented_sum(&other.sources.table),
146 target: other.sources.target.clone(), };
148 let values = other.values.clone();
149 IndexedCoproduct { sources, values }
150 }
151}
152
153impl<K: ArrayKind, F> HasLen<K> for IndexedCoproduct<K, F>
154where
155 K::Type<K::I>: NaturalArray<K>,
156{
157 fn len(&self) -> K::I {
158 self.sources.len()
159 }
160}
161
162impl<K: ArrayKind> IndexedCoproduct<K, FiniteFunction<K>>
164where
165 K::Type<K::I>: NaturalArray<K>,
166{
167 pub fn initial(target: K::I) -> Self {
170 let sources = FiniteFunction::initial(K::I::one());
171 let values = FiniteFunction::initial(target);
172 IndexedCoproduct { sources, values }
173 }
174
175 pub fn tensor(
177 &self,
178 other: &IndexedCoproduct<K, FiniteFunction<K>>,
179 ) -> IndexedCoproduct<K, FiniteFunction<K>> {
180 let table = self.sources.table.concatenate(&other.sources.table);
184 let target = (self.sources.target.clone() + other.sources.target.clone()) - K::I::one();
185
186 IndexedCoproduct {
187 sources: FiniteFunction { table, target },
188 values: &self.values | &other.values,
189 }
190 }
191
192 pub fn map_values(&self, x: &FiniteFunction<K>) -> Option<Self> {
209 Some(Self {
210 sources: self.sources.clone(),
211 values: (&self.values >> x)?,
212 })
213 }
214
215 pub fn map_semifinite<T>(
219 &self,
220 x: &SemifiniteFunction<K, T>,
221 ) -> Option<IndexedCoproduct<K, SemifiniteFunction<K, T>>>
222 where
223 K::Type<T>: Array<K, T>,
224 {
225 Some(IndexedCoproduct::<K, SemifiniteFunction<K, T>> {
226 sources: self.sources.clone(),
227 values: (&self.values >> x)?,
228 })
229 }
230
231 pub fn flatmap(&self, other: &Self) -> Self {
245 assert_eq!(self.values.target(), other.len());
246
247 let sources_table = self
248 .sources
249 .table
250 .segmented_sum(&(&self.values >> &other.sources).unwrap().table);
251
252 let values = &other.sources.injections(&self.values).unwrap() >> &other.values;
253 let values = values.unwrap();
254
255 IndexedCoproduct::from_semifinite(SemifiniteFunction(sources_table.into()), values).unwrap()
256 }
257}
258
259impl<K: ArrayKind, F> IndexedCoproduct<K, F>
263where
264 K::Type<K::I>: NaturalArray<K>,
265 F: HasLen<K> + Clone,
266 for<'a, 'b> &'a FiniteFunction<K>: Shr<&'b F, Output = Option<F>>, for<'a, 'b> &'a F: Add<&'b F, Output = Option<F>>, {
269 pub fn coproduct(&self, other: &Self) -> Option<Self> {
270 let table = self.sources.table.concatenate(&other.sources.table);
274 let target = (self.sources.target.clone() + other.sources.target.clone()) - K::I::one();
275
276 Some(IndexedCoproduct {
278 sources: FiniteFunction { table, target },
279 values: (&self.values + &other.values)?,
280 })
281 }
282
283 pub fn map_indexes(&self, x: &FiniteFunction<K>) -> Option<Self> {
297 let sources = x.compose(&self.sources)?;
298 let values = self.indexed_values(x)?;
299 IndexedCoproduct::from_semifinite(SemifiniteFunction(sources.table.into()), values)
300 }
301
302 pub fn indexed_values(&self, x: &FiniteFunction<K>) -> Option<F> {
304 &self.sources.injections(x)? >> &self.values
305 }
306}
307
308impl<K: ArrayKind, F: Debug> Debug for IndexedCoproduct<K, F>
309where
310 K::Index: Debug,
311{
312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313 f.debug_struct("IndexedCoproduct")
314 .field("sources", &self.sources)
315 .field("values", &self.values)
316 .finish()
317 }
318}