1use karpal_proof::rewrite::Justifies;
11#[cfg(any(feature = "std", feature = "alloc"))]
12use karpal_proof::rewrite::Rewrite;
13
14pub struct PentagonIdentity;
23
24impl<A, B, C, D> Justifies<(((A, B), C), D), (A, (B, (C, D)))> for PentagonIdentity {}
25
26#[cfg(any(feature = "std", feature = "alloc"))]
30#[allow(clippy::type_complexity)]
31pub fn verify_pentagon<A, B, C, D>() -> Rewrite<(((A, B), C), D), (A, (B, (C, D))), PentagonIdentity>
32{
33 Rewrite::witness()
34}
35
36pub struct TriangleIdentity;
45
46impl<A, B> Justifies<((A, ()), B), (A, B)> for TriangleIdentity {}
47
48#[cfg(any(feature = "std", feature = "alloc"))]
52#[allow(clippy::type_complexity)]
53pub fn verify_triangle<A, B>() -> Rewrite<((A, ()), B), (A, B), TriangleIdentity> {
54 Rewrite::witness()
55}
56
57pub struct HexagonIdentity;
66
67impl<A, B, C> Justifies<((A, B), C), ((B, C), A)> for HexagonIdentity {}
68
69#[cfg(any(feature = "std", feature = "alloc"))]
73#[allow(clippy::type_complexity)]
74pub fn verify_hexagon<A, B, C>() -> Rewrite<((A, B), C), ((B, C), A), HexagonIdentity> {
75 Rewrite::witness()
76}
77
78pub struct ByNormalization;
89
90impl<A, B> Justifies<A, B> for ByNormalization {}
91
92#[cfg(any(feature = "std", feature = "alloc"))]
100pub fn equivalent_proved<A, B>(
101 a: &crate::Diagram,
102 b: &crate::Diagram,
103) -> Option<Rewrite<A, B, ByNormalization>> {
104 if a.equivalent_to(b) {
105 Some(Rewrite::witness())
106 } else {
107 None
108 }
109}
110
111pub struct ByYanking;
121
122impl<A, B> Justifies<A, B> for ByYanking {}
123
124#[cfg(any(feature = "std", feature = "alloc"))]
134pub fn prove_yanking<A, B>(arity: usize) -> Rewrite<A, B, ByYanking> {
135 let left_yank = crate::Diagram::cup(arity)
136 .parallel(crate::Diagram::identity(arity))
137 .then(crate::Diagram::identity(arity).parallel(crate::Diagram::cap(arity)));
138
139 let right_yank = crate::Diagram::identity(arity)
140 .parallel(crate::Diagram::cup(arity))
141 .then(crate::Diagram::cap(arity).parallel(crate::Diagram::identity(arity)));
142
143 assert!(
144 left_yank.equivalent_to(&crate::Diagram::identity(arity)),
145 "left yanking equation failed for arity {arity}"
146 );
147 assert!(
148 right_yank.equivalent_to(&crate::Diagram::identity(arity)),
149 "right yanking equation failed for arity {arity}"
150 );
151
152 Rewrite::witness()
153}
154
155#[cfg(any(feature = "std", feature = "alloc"))]
161pub struct CoherenceCertificate;
162
163#[cfg(any(feature = "std", feature = "alloc"))]
164impl karpal_verify::VerificationBackend for CoherenceCertificate {
165 const NAME: &'static str = "karpal-diagram-coherence";
166}
167
168#[cfg(any(feature = "std", feature = "alloc"))]
173pub fn coherence_certificates() -> alloc::vec::Vec<karpal_verify::Certificate> {
174 use karpal_verify::{Obligation, Origin, ProofBridge, ProofEvidence, Term, VerificationTier};
175
176 let pentagon = Obligation {
177 name: "pentagon_coherence".into(),
178 property: "coherence",
179 declarations: alloc::vec![],
180 assumptions: alloc::vec![],
181 conclusion: Term::bool(true),
182 origin: Origin::new("karpal-diagram", "coherence::PentagonIdentity"),
183 tier: VerificationTier::Emergent,
184 };
185
186 let triangle = Obligation {
187 name: "triangle_coherence".into(),
188 property: "coherence",
189 declarations: alloc::vec![],
190 assumptions: alloc::vec![],
191 conclusion: Term::bool(true),
192 origin: Origin::new("karpal-diagram", "coherence::TriangleIdentity"),
193 tier: VerificationTier::Emergent,
194 };
195
196 let hexagon = Obligation {
197 name: "hexagon_coherence".into(),
198 property: "coherence",
199 declarations: alloc::vec![],
200 assumptions: alloc::vec![],
201 conclusion: Term::bool(true),
202 origin: Origin::new("karpal-diagram", "coherence::HexagonIdentity"),
203 tier: VerificationTier::Emergent,
204 };
205
206 let evidence = ProofEvidence::passed_tests("karpal-diagram::coherence::all", 1)
207 .with_notes("runtime coherence verification via crate test suite");
208
209 alloc::vec![
210 ProofBridge::certificate::<CoherenceCertificate>(&pentagon, evidence.clone()),
211 ProofBridge::certificate::<CoherenceCertificate>(&triangle, evidence.clone()),
212 ProofBridge::certificate::<CoherenceCertificate>(&hexagon, evidence),
213 ]
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219 use crate::Tensor;
220 use karpal_arrow::{Category, FnA, Semigroupoid};
221
222 #[test]
223 fn pentagon_produces_witness() {
224 let _: Rewrite<(((i32, u8), bool), String), (i32, (u8, (bool, String))), PentagonIdentity> =
225 verify_pentagon::<i32, u8, bool, String>();
226 }
227
228 #[test]
229 fn triangle_produces_witness() {
230 let _: Rewrite<((i32, ()), String), (i32, String), TriangleIdentity> =
231 verify_triangle::<i32, String>();
232 }
233
234 #[test]
235 fn pentagon_paths_agree() {
236 let input = (((1_i32, 2_u8), true), "end".to_string());
237
238 let upper_step1 = FnA::tensor(FnA::associate::<i32, u8, bool>(), FnA::id::<String>());
240 let upper_step2 = FnA::associate::<i32, (u8, bool), String>();
241 let upper_step3 = FnA::tensor(FnA::id::<i32>(), FnA::associate::<u8, bool, String>());
242 let upper = FnA::compose(upper_step3, FnA::compose(upper_step2, upper_step1));
243
244 let lower_step1 = FnA::associate::<(i32, u8), bool, String>();
246 let lower_step2 = FnA::associate::<i32, u8, (bool, String)>();
247 let lower = FnA::compose(lower_step2, lower_step1);
248
249 assert_eq!(upper(input.clone()), lower(input));
250 }
251
252 #[test]
253 fn triangle_paths_agree() {
254 let input = ((42_i32, ()), "hello".to_string());
255
256 let left = FnA::tensor(FnA::right_unitor::<i32>(), FnA::id::<String>());
258
259 let alpha = FnA::associate::<i32, (), String>();
261 let right_step2 = FnA::tensor(FnA::id::<i32>(), FnA::left_unitor::<String>());
262 let right = FnA::compose(right_step2, alpha);
263
264 assert_eq!(left(input.clone()), right(input.clone()));
265 }
266
267 #[test]
268 fn hexagon_produces_witness() {
269 let _: Rewrite<((i32, u8), bool), ((u8, bool), i32), HexagonIdentity> =
270 verify_hexagon::<i32, u8, bool>();
271 }
272
273 #[test]
274 fn hexagon_paths_agree() {
275 use crate::Braiding;
276
277 let input = ((1_i32, 2_u8), true);
278
279 let braid_ab_c = FnA::braid::<(i32, u8), bool>();
281 let assoc_inv_c_a_b = FnA::associate_inv::<bool, i32, u8>();
282 let braid_ca_b = FnA::braid::<(bool, i32), u8>();
283 let assoc_inv_b_c_a = FnA::associate_inv::<u8, bool, i32>();
284 let upper = FnA::compose(
285 assoc_inv_b_c_a,
286 FnA::compose(braid_ca_b, FnA::compose(assoc_inv_c_a_b, braid_ab_c)),
287 );
288
289 let assoc_a_b_c = FnA::associate::<i32, u8, bool>();
291 let braid_a_bc = FnA::braid::<i32, (u8, bool)>();
292 let lower = FnA::compose(braid_a_bc, assoc_a_b_c);
293
294 assert_eq!(upper(input.clone()), lower(input));
295 }
296}