1use std::fmt::Debug;
9
10use crate::lax::functor::{to_dyn_functor, DynFunctor, Functor};
11use crate::operations::Operations;
12use crate::strict::vec::VecArray;
13use crate::strict::vec::VecKind;
14use crate::strict::IndexedCoproduct;
15use crate::strict::SemifiniteFunction;
16use crate::{lax, lax::OpenHypergraph, strict::functor::optic::Optic as StrictOptic};
17
18pub trait Optic<
22 O1: Clone + PartialEq,
23 A1: Clone,
24 O2: Clone + PartialEq + std::fmt::Debug,
25 A2: Clone,
26>: Clone + 'static
27{
28 fn fwd_object(&self, o: &O1) -> Vec<O2>;
29 fn fwd_operation(&self, a: &A1, source: &[O1], target: &[O1]) -> OpenHypergraph<O2, A2>;
30 fn rev_object(&self, o: &O1) -> Vec<O2>;
31 fn rev_operation(&self, a: &A1, source: &[O1], target: &[O1]) -> OpenHypergraph<O2, A2>;
32 fn residual(&self, a: &A1) -> Vec<O2>;
33
34 fn map_arrow(&self, term: OpenHypergraph<O1, A1>) -> OpenHypergraph<O2, A2> {
35 let optic = to_strict_optic(self);
36 let strict = term.to_strict();
37 lax::OpenHypergraph::from_strict({
38 use crate::strict::functor::Functor;
40 optic.map_arrow(&strict)
41 })
42 }
43
44 fn map_adapted(&self, term: OpenHypergraph<O1, A1>) -> OpenHypergraph<O2, A2> {
45 let optic = to_strict_optic(self);
46 let strict = term.to_strict();
47 lax::OpenHypergraph::from_strict({
48 use crate::strict::functor::Functor;
49 let optic_term = optic.map_arrow(&strict);
50 optic.adapt(&optic_term, &strict.source(), &strict.target())
52 })
53 }
54}
55
56fn to_strict_optic<
57 T: Optic<O1, A1, O2, A2> + 'static,
58 O1: Clone + PartialEq,
59 A1: Clone,
60 O2: Clone + PartialEq + Debug,
61 A2: Clone,
62>(
63 this: &T,
64) -> StrictOptic<
65 DynFunctor<Fwd<T, O1, A1, O2, A2>, O1, A1, O2, A2>,
66 DynFunctor<Rev<T, O1, A1, O2, A2>, O1, A1, O2, A2>,
67 VecKind,
68 O1,
69 A1,
70 O2,
71 A2,
72> {
73 let fwd = to_dyn_functor(Fwd::new(this.clone()));
74 let rev = to_dyn_functor(Rev::new(this.clone()));
75
76 let self_clone = this.clone();
78
79 StrictOptic::new(
80 fwd,
81 rev,
82 Box::new(move |ops: &Operations<VecKind, O1, A1>| {
83 let mut sources_vec = Vec::new();
84 let mut residuals = Vec::new();
85
86 for (op, _, _) in ops.iter() {
87 let m = self_clone.residual(op);
88 sources_vec.push(m.len());
89 residuals.extend(m);
90 }
91
92 let sources = SemifiniteFunction::<VecKind, usize>(VecArray(sources_vec));
93 let values = SemifiniteFunction(VecArray(residuals));
94 IndexedCoproduct::from_semifinite(sources, values).unwrap()
95 }),
96 )
97}
98
99#[derive(Clone, PartialEq)]
105struct Fwd<T, O1, A1, O2, A2> {
106 _phantom: std::marker::PhantomData<(O1, A1, O2, A2)>,
107 optic: Box<T>,
108}
109
110impl<
111 T: Optic<O1, A1, O2, A2>,
112 O1: Clone + PartialEq,
113 A1: Clone,
114 O2: Clone + PartialEq + Debug,
115 A2: Clone,
116 > Functor<O1, A1, O2, A2> for Fwd<T, O1, A1, O2, A2>
117{
118 fn map_object(&self, o: &O1) -> impl ExactSizeIterator<Item = O2> {
119 self.optic.fwd_object(o).into_iter()
120 }
121
122 fn map_operation(&self, a: &A1, source: &[O1], target: &[O1]) -> OpenHypergraph<O2, A2> {
123 self.optic.fwd_operation(a, source, target)
124 }
125
126 fn map_arrow(&self, _f: &OpenHypergraph<O1, A1>) -> OpenHypergraph<O2, A2> {
128 panic!("Fwd is not a functor!");
129 }
130}
131
132impl<
133 T: Optic<O1, A1, O2, A2>,
134 O1: Clone + PartialEq,
135 A1: Clone,
136 O2: Clone + PartialEq + Debug,
137 A2: Clone,
138 > Fwd<T, O1, A1, O2, A2>
139{
140 fn new(t: T) -> Self {
141 Self {
142 _phantom: std::marker::PhantomData,
143 optic: Box::new(t),
144 }
145 }
146}
147
148#[derive(Clone, PartialEq)]
149struct Rev<T, O1, A1, O2, A2> {
150 _phantom: std::marker::PhantomData<(O1, A1, O2, A2)>,
151 optic: Box<T>,
152}
153
154impl<
155 T: Optic<O1, A1, O2, A2>,
156 O1: Clone + PartialEq,
157 A1: Clone,
158 O2: Clone + PartialEq + Debug,
159 A2: Clone,
160 > Functor<O1, A1, O2, A2> for Rev<T, O1, A1, O2, A2>
161{
162 fn map_object(&self, o: &O1) -> impl ExactSizeIterator<Item = O2> {
163 self.optic.rev_object(o).into_iter()
164 }
165
166 fn map_operation(&self, a: &A1, source: &[O1], target: &[O1]) -> OpenHypergraph<O2, A2> {
167 self.optic.rev_operation(a, source, target)
168 }
169
170 fn map_arrow(&self, _f: &OpenHypergraph<O1, A1>) -> OpenHypergraph<O2, A2> {
172 panic!("Rev is not a functor!");
173 }
174}
175
176impl<
177 T: Optic<O1, A1, O2, A2>,
178 O1: Clone + PartialEq,
179 A1: Clone,
180 O2: Clone + PartialEq + Debug,
181 A2: Clone,
182 > Rev<T, O1, A1, O2, A2>
183{
184 fn new(t: T) -> Self {
185 Self {
186 _phantom: std::marker::PhantomData,
187 optic: Box::new(t),
188 }
189 }
190}