1use karpal_proof::rewrite::Justifies;
14#[cfg(any(feature = "std", feature = "alloc"))]
15use karpal_proof::rewrite::Rewrite;
16
17pub struct PentagonIdentity;
26
27impl<A, B, C, D> Justifies<(((A, B), C), D), (A, (B, (C, D)))> for PentagonIdentity {}
28
29#[cfg(any(feature = "std", feature = "alloc"))]
33#[allow(clippy::type_complexity)]
34pub fn verify_pentagon<A, B, C, D>() -> Rewrite<(((A, B), C), D), (A, (B, (C, D))), PentagonIdentity>
35{
36 Rewrite::witness()
37}
38
39pub struct TriangleIdentity;
48
49impl<A, B> Justifies<((A, ()), B), (A, B)> for TriangleIdentity {}
50
51#[cfg(any(feature = "std", feature = "alloc"))]
55#[allow(clippy::type_complexity)]
56pub fn verify_triangle<A, B>() -> Rewrite<((A, ()), B), (A, B), TriangleIdentity> {
57 Rewrite::witness()
58}
59
60pub struct HexagonIdentity;
69
70impl<A, B, C> Justifies<((A, B), C), ((B, C), A)> for HexagonIdentity {}
71
72#[cfg(any(feature = "std", feature = "alloc"))]
76#[allow(clippy::type_complexity)]
77pub fn verify_hexagon<A, B, C>() -> Rewrite<((A, B), C), ((B, C), A), HexagonIdentity> {
78 Rewrite::witness()
79}
80
81pub struct ByNormalization;
92
93impl<A, B> Justifies<A, B> for ByNormalization {}
94
95#[cfg(any(feature = "std", feature = "alloc"))]
103pub fn equivalent_proved<A, B>(
104 a: &crate::Diagram,
105 b: &crate::Diagram,
106) -> Option<Rewrite<A, B, ByNormalization>> {
107 if a.equivalent_to(b) {
108 Some(Rewrite::witness())
109 } else {
110 None
111 }
112}
113
114pub struct ByYanking;
124
125impl<A, B> Justifies<A, B> for ByYanking {}
126
127#[cfg(any(feature = "std", feature = "alloc"))]
137pub fn prove_yanking<A, B>(arity: usize) -> Rewrite<A, B, ByYanking> {
138 let left_yank = crate::Diagram::cup(arity)
139 .parallel(crate::Diagram::identity(arity))
140 .then(crate::Diagram::identity(arity).parallel(crate::Diagram::cap(arity)));
141
142 let right_yank = crate::Diagram::identity(arity)
143 .parallel(crate::Diagram::cup(arity))
144 .then(crate::Diagram::cap(arity).parallel(crate::Diagram::identity(arity)));
145
146 assert!(
147 left_yank.equivalent_to(&crate::Diagram::identity(arity)),
148 "left yanking equation failed for arity {arity}"
149 );
150 assert!(
151 right_yank.equivalent_to(&crate::Diagram::identity(arity)),
152 "right yanking equation failed for arity {arity}"
153 );
154
155 Rewrite::witness()
156}
157
158#[cfg(any(feature = "std", feature = "alloc"))]
164pub struct CoherenceCertificate;
165
166#[cfg(any(feature = "std", feature = "alloc"))]
167impl karpal_verify::VerificationBackend for CoherenceCertificate {
168 const NAME: &'static str = "karpal-diagram-coherence";
169}
170
171#[cfg(any(feature = "std", feature = "alloc"))]
176pub fn coherence_certificates() -> alloc::vec::Vec<karpal_verify::Certificate> {
177 use karpal_verify::{Obligation, Origin, ProofBridge, ProofEvidence, Term, VerificationTier};
178
179 let pentagon = Obligation {
180 name: "pentagon_coherence".into(),
181 property: "coherence",
182 declarations: alloc::vec![],
183 assumptions: alloc::vec![],
184 conclusion: Term::bool(true),
185 origin: Origin::new("karpal-diagram", "coherence::PentagonIdentity"),
186 tier: VerificationTier::Emergent,
187 };
188
189 let triangle = Obligation {
190 name: "triangle_coherence".into(),
191 property: "coherence",
192 declarations: alloc::vec![],
193 assumptions: alloc::vec![],
194 conclusion: Term::bool(true),
195 origin: Origin::new("karpal-diagram", "coherence::TriangleIdentity"),
196 tier: VerificationTier::Emergent,
197 };
198
199 let hexagon = Obligation {
200 name: "hexagon_coherence".into(),
201 property: "coherence",
202 declarations: alloc::vec![],
203 assumptions: alloc::vec![],
204 conclusion: Term::bool(true),
205 origin: Origin::new("karpal-diagram", "coherence::HexagonIdentity"),
206 tier: VerificationTier::Emergent,
207 };
208
209 let evidence = ProofEvidence::passed_tests("karpal-diagram::coherence::all", 1)
210 .with_notes("runtime coherence verification via crate test suite");
211
212 alloc::vec![
213 ProofBridge::certificate::<CoherenceCertificate>(&pentagon, evidence.clone()),
214 ProofBridge::certificate::<CoherenceCertificate>(&triangle, evidence.clone()),
215 ProofBridge::certificate::<CoherenceCertificate>(&hexagon, evidence),
216 ]
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 use crate::Tensor;
223 use karpal_arrow::{Category, FnA, Semigroupoid};
224
225 #[test]
226 fn pentagon_produces_witness() {
227 let _: Rewrite<(((i32, u8), bool), String), (i32, (u8, (bool, String))), PentagonIdentity> =
228 verify_pentagon::<i32, u8, bool, String>();
229 }
230
231 #[test]
232 fn triangle_produces_witness() {
233 let _: Rewrite<((i32, ()), String), (i32, String), TriangleIdentity> =
234 verify_triangle::<i32, String>();
235 }
236
237 #[test]
238 fn pentagon_paths_agree() {
239 let input = (((1_i32, 2_u8), true), "end".to_string());
240
241 let upper_step1 = FnA::tensor(FnA::associate::<i32, u8, bool>(), FnA::id::<String>());
243 let upper_step2 = FnA::associate::<i32, (u8, bool), String>();
244 let upper_step3 = FnA::tensor(FnA::id::<i32>(), FnA::associate::<u8, bool, String>());
245 let upper = FnA::compose(upper_step3, FnA::compose(upper_step2, upper_step1));
246
247 let lower_step1 = FnA::associate::<(i32, u8), bool, String>();
249 let lower_step2 = FnA::associate::<i32, u8, (bool, String)>();
250 let lower = FnA::compose(lower_step2, lower_step1);
251
252 assert_eq!(upper(input.clone()), lower(input));
253 }
254
255 #[test]
256 fn triangle_paths_agree() {
257 let input = ((42_i32, ()), "hello".to_string());
258
259 let left = FnA::tensor(FnA::right_unitor::<i32>(), FnA::id::<String>());
261
262 let alpha = FnA::associate::<i32, (), String>();
264 let right_step2 = FnA::tensor(FnA::id::<i32>(), FnA::left_unitor::<String>());
265 let right = FnA::compose(right_step2, alpha);
266
267 assert_eq!(left(input.clone()), right(input.clone()));
268 }
269
270 #[test]
271 fn hexagon_produces_witness() {
272 let _: Rewrite<((i32, u8), bool), ((u8, bool), i32), HexagonIdentity> =
273 verify_hexagon::<i32, u8, bool>();
274 }
275
276 #[test]
277 fn hexagon_paths_agree() {
278 use crate::Braiding;
279
280 let input = ((1_i32, 2_u8), true);
281
282 let braid_ab_c = FnA::braid::<(i32, u8), bool>();
284 let assoc_inv_c_a_b = FnA::associate_inv::<bool, i32, u8>();
285 let braid_ca_b = FnA::braid::<(bool, i32), u8>();
286 let assoc_inv_b_c_a = FnA::associate_inv::<u8, bool, i32>();
287 let upper = FnA::compose(
288 assoc_inv_b_c_a,
289 FnA::compose(braid_ca_b, FnA::compose(assoc_inv_c_a_b, braid_ab_c)),
290 );
291
292 let assoc_a_b_c = FnA::associate::<i32, u8, bool>();
294 let braid_a_bc = FnA::braid::<i32, (u8, bool)>();
295 let lower = FnA::compose(braid_a_bc, assoc_a_b_c);
296
297 assert_eq!(upper(input.clone()), lower(input));
298 }
299}