Skip to main content

oxilean_std/graph/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6use std::collections::{HashSet, VecDeque};
7
8use super::types::{
9    DiGraph, ExpanderChecker, GraphonSampler, SzemerédiRegularityLemma, TreewidthHeuristic,
10    TuttePolynomialEval, UndirectedGraph,
11};
12
13#[allow(dead_code)]
14pub fn app(f: Expr, a: Expr) -> Expr {
15    Expr::App(Box::new(f), Box::new(a))
16}
17#[allow(dead_code)]
18pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
19    app(app(f, a), b)
20}
21#[allow(dead_code)]
22pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
23    app(app2(f, a, b), c)
24}
25pub fn cst(s: &str) -> Expr {
26    Expr::Const(Name::str(s), vec![])
27}
28pub fn prop() -> Expr {
29    Expr::Sort(Level::zero())
30}
31pub fn type0() -> Expr {
32    Expr::Sort(Level::succ(Level::zero()))
33}
34pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
35    Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
36}
37pub fn arrow(a: Expr, b: Expr) -> Expr {
38    pi(BinderInfo::Default, "_", a, b)
39}
40pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
41    pi(BinderInfo::Implicit, name, dom, body)
42}
43pub fn nat_ty() -> Expr {
44    cst("Nat")
45}
46pub fn bool_ty() -> Expr {
47    cst("Bool")
48}
49/// SimpleGraph V = { adj : V → V → Prop // sym, irrefl }
50pub fn simple_graph_ty() -> Expr {
51    pi(BinderInfo::Default, "V", type0(), type0())
52}
53/// SimpleGraph.adj : ∀ {V}, SimpleGraph V → V → V → Prop
54pub fn simple_graph_adj_ty() -> Expr {
55    impl_pi(
56        "V",
57        type0(),
58        arrow(
59            app(cst("SimpleGraph"), bvar(0)),
60            arrow(bvar(0), arrow(bvar(1), prop())),
61        ),
62    )
63}
64pub fn bvar(n: u32) -> Expr {
65    Expr::BVar(n)
66}
67/// SimpleGraph.degree : ∀ {V} [Fintype V] [DecidableEq V], SimpleGraph V → V → Nat
68pub fn simple_graph_degree_ty() -> Expr {
69    impl_pi(
70        "V",
71        type0(),
72        arrow(app(cst("SimpleGraph"), bvar(0)), arrow(bvar(0), nat_ty())),
73    )
74}
75/// Digraph V = { adj : V → V → Bool }
76pub fn digraph_ty() -> Expr {
77    pi(BinderInfo::Default, "V", type0(), type0())
78}
79/// digraph_adj : ∀ {V}, Digraph V → V → V → Bool
80pub fn digraph_adj_ty() -> Expr {
81    impl_pi(
82        "V",
83        type0(),
84        arrow(
85            app(cst("Digraph"), bvar(0)),
86            arrow(bvar(0), arrow(bvar(1), bool_ty())),
87        ),
88    )
89}
90/// Walk G u v = path from u to v in G (list of adjacent vertices)
91pub fn walk_ty() -> Expr {
92    impl_pi(
93        "V",
94        type0(),
95        arrow(
96            app(cst("SimpleGraph"), bvar(0)),
97            arrow(bvar(0), arrow(bvar(1), type0())),
98        ),
99    )
100}
101/// SimpleGraph.Connected : ∀ {V}, SimpleGraph V → Prop
102pub fn simple_graph_connected_ty() -> Expr {
103    impl_pi(
104        "V",
105        type0(),
106        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
107    )
108}
109/// IsTree G ↔ Connected G ∧ acyclic G
110pub fn is_tree_ty() -> Expr {
111    impl_pi(
112        "V",
113        type0(),
114        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
115    )
116}
117/// chromatic_number : ∀ {V} [Fintype V], SimpleGraph V → Nat
118pub fn chromatic_number_ty() -> Expr {
119    impl_pi(
120        "V",
121        type0(),
122        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
123    )
124}
125/// IsEulerian : ∀ {V}, SimpleGraph V → Prop
126/// A graph has an Eulerian circuit iff every vertex has even degree and graph is connected
127pub fn is_eulerian_ty() -> Expr {
128    impl_pi(
129        "V",
130        type0(),
131        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
132    )
133}
134/// IsHamiltonian : ∀ {V}, SimpleGraph V → Prop
135/// A graph has a Hamiltonian cycle visiting each vertex exactly once
136pub fn is_hamiltonian_ty() -> Expr {
137    impl_pi(
138        "V",
139        type0(),
140        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
141    )
142}
143/// IsBipartite : ∀ {V}, SimpleGraph V → Prop
144pub fn is_bipartite_ty() -> Expr {
145    impl_pi(
146        "V",
147        type0(),
148        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
149    )
150}
151/// IsPlanar : ∀ {V}, SimpleGraph V → Prop
152pub fn is_planar_ty() -> Expr {
153    impl_pi(
154        "V",
155        type0(),
156        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
157    )
158}
159/// Matching G = Set of independent edges
160pub fn matching_ty() -> Expr {
161    impl_pi(
162        "V",
163        type0(),
164        arrow(app(cst("SimpleGraph"), bvar(0)), type0()),
165    )
166}
167/// IsPerfectMatching : ∀ {V} [Fintype V], SimpleGraph V → Matching → Prop
168pub fn is_perfect_matching_ty() -> Expr {
169    impl_pi(
170        "V",
171        type0(),
172        arrow(
173            app(cst("SimpleGraph"), bvar(0)),
174            arrow(app2(cst("Matching"), bvar(0), bvar(0)), prop()),
175        ),
176    )
177}
178/// Four Color Theorem: χ(G) ≤ 4 for any planar graph G
179pub fn four_color_theorem_ty() -> Expr {
180    impl_pi(
181        "V",
182        type0(),
183        pi(
184            BinderInfo::Default,
185            "G",
186            app(cst("SimpleGraph"), bvar(0)),
187            arrow(
188                app(cst("IsPlanar"), bvar(0)),
189                app2(
190                    cst("Nat.le"),
191                    app(cst("chromatic_number"), bvar(1)),
192                    Expr::Lit(oxilean_kernel::Literal::Nat(4)),
193                ),
194            ),
195        ),
196    )
197}
198/// Euler's formula: V - E + F = 2 for connected planar graphs
199pub fn euler_formula_ty() -> Expr {
200    pi(
201        BinderInfo::Default,
202        "v",
203        nat_ty(),
204        pi(
205            BinderInfo::Default,
206            "e",
207            nat_ty(),
208            pi(
209                BinderInfo::Default,
210                "f",
211                nat_ty(),
212                arrow(
213                    app3(cst("IsConnectedPlanar"), bvar(2), bvar(1), bvar(0)),
214                    app2(
215                        app(cst("Eq"), nat_ty()),
216                        app2(
217                            cst("Nat.add"),
218                            app2(cst("Nat.sub"), bvar(2), bvar(1)),
219                            bvar(0),
220                        ),
221                        Expr::Lit(oxilean_kernel::Literal::Nat(2)),
222                    ),
223                ),
224            ),
225        ),
226    )
227}
228/// Eulerian circuit theorem: G has Eulerian circuit ↔ G is connected ∧ all degrees even
229pub fn eulerian_circuit_thm_ty() -> Expr {
230    impl_pi(
231        "V",
232        type0(),
233        pi(
234            BinderInfo::Default,
235            "G",
236            app(cst("SimpleGraph"), bvar(0)),
237            app2(
238                cst("Iff"),
239                app(cst("IsEulerian"), bvar(0)),
240                app2(
241                    cst("And"),
242                    app(cst("SimpleGraph.Connected"), bvar(1)),
243                    app(cst("AllDegreesEven"), bvar(1)),
244                ),
245            ),
246        ),
247    )
248}
249/// Hall's theorem: bipartite graph G=(A∪B, E) has perfect matching ↔
250/// for all S ⊆ A, |N(S)| ≥ |S|
251pub fn halls_theorem_ty() -> Expr {
252    impl_pi(
253        "V",
254        type0(),
255        pi(
256            BinderInfo::Default,
257            "G",
258            app(cst("SimpleGraph"), bvar(0)),
259            arrow(
260                app(cst("IsBipartite"), bvar(0)),
261                app2(
262                    cst("Iff"),
263                    app(cst("HasPerfectMatching"), bvar(1)),
264                    app(cst("HallCondition"), bvar(1)),
265                ),
266            ),
267        ),
268    )
269}
270/// Kuratowski's theorem: G is planar ↔ G has no K₅ or K₃₃ subdivision
271pub fn kuratowski_theorem_ty() -> Expr {
272    impl_pi(
273        "V",
274        type0(),
275        pi(
276            BinderInfo::Default,
277            "G",
278            app(cst("SimpleGraph"), bvar(0)),
279            app2(
280                cst("Iff"),
281                app(cst("IsPlanar"), bvar(0)),
282                app(cst("NoK5OrK33Subdivision"), bvar(0)),
283            ),
284        ),
285    )
286}
287pub fn real_ty() -> Expr {
288    cst("Real")
289}
290/// GraphMinor : ∀ {V W}, SimpleGraph V → SimpleGraph W → Prop
291/// H is a minor of G if H can be obtained from a subgraph of G by contracting edges.
292#[allow(dead_code)]
293pub fn graph_minor_ty() -> Expr {
294    impl_pi(
295        "V",
296        type0(),
297        impl_pi(
298            "W",
299            type0(),
300            arrow(
301                app(cst("SimpleGraph"), bvar(1)),
302                arrow(app(cst("SimpleGraph"), bvar(1)), prop()),
303            ),
304        ),
305    )
306}
307/// RobertsonSeymourWQO : ∀ {V} (seq : Nat → SimpleGraph V), ∃ i j, i < j ∧ Minor (seq i) (seq j)
308/// The Robertson-Seymour theorem: graphs are well-quasi-ordered under the minor relation.
309#[allow(dead_code)]
310pub fn robertson_seymour_wqo_ty() -> Expr {
311    impl_pi(
312        "V",
313        type0(),
314        pi(
315            BinderInfo::Default,
316            "seq",
317            arrow(nat_ty(), app(cst("SimpleGraph"), bvar(0))),
318            app(cst("WellQuasiOrdered"), app(cst("GraphMinor"), bvar(0))),
319        ),
320    )
321}
322/// ExcludedMinorCharacterization : ∀ {V}, SimpleGraph V → Type
323/// A graph class is characterized by a finite set of forbidden minors.
324#[allow(dead_code)]
325pub fn excluded_minor_characterization_ty() -> Expr {
326    impl_pi(
327        "V",
328        type0(),
329        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
330    )
331}
332/// VertexExpansion : ∀ {V}, SimpleGraph V → Real → Prop
333/// h-vertex expander: for all S with |S| ≤ |V|/2, |N(S)| ≥ h·|S|.
334#[allow(dead_code)]
335pub fn vertex_expansion_ty() -> Expr {
336    impl_pi(
337        "V",
338        type0(),
339        arrow(app(cst("SimpleGraph"), bvar(0)), arrow(real_ty(), prop())),
340    )
341}
342/// EdgeExpansion : ∀ {V}, SimpleGraph V → Real → Prop
343/// Cheeger constant h(G) = min over S of |∂S|/min(|S|,|V\S|).
344#[allow(dead_code)]
345pub fn edge_expansion_ty() -> Expr {
346    impl_pi(
347        "V",
348        type0(),
349        arrow(app(cst("SimpleGraph"), bvar(0)), arrow(real_ty(), prop())),
350    )
351}
352/// CheegerConstant : ∀ {V} [Fintype V], SimpleGraph V → Real
353/// The Cheeger constant (edge expansion ratio) of a graph.
354#[allow(dead_code)]
355pub fn cheeger_constant_ty() -> Expr {
356    impl_pi(
357        "V",
358        type0(),
359        arrow(app(cst("SimpleGraph"), bvar(0)), real_ty()),
360    )
361}
362/// CheegerInequality : ∀ {V} [Fintype V] (G : SimpleGraph V),
363///   λ₂/2 ≤ h(G) ≤ √(2·d·λ₂)
364/// The Cheeger inequality connecting spectral gap λ₂ to edge expansion h(G).
365#[allow(dead_code)]
366pub fn cheeger_inequality_ty() -> Expr {
367    impl_pi(
368        "V",
369        type0(),
370        pi(
371            BinderInfo::Default,
372            "G",
373            app(cst("SimpleGraph"), bvar(0)),
374            app2(
375                cst("CheegerBounds"),
376                app(cst("SpectralGap"), bvar(0)),
377                app(cst("CheegerConstant"), bvar(0)),
378            ),
379        ),
380    )
381}
382/// SpectralGap : ∀ {V} [Fintype V], SimpleGraph V → Real
383/// The spectral gap λ₂ = second smallest eigenvalue of the normalized Laplacian.
384#[allow(dead_code)]
385pub fn spectral_gap_ty() -> Expr {
386    impl_pi(
387        "V",
388        type0(),
389        arrow(app(cst("SimpleGraph"), bvar(0)), real_ty()),
390    )
391}
392/// ErdosRenyiGraph : Nat → Real → SimpleGraph
393/// The Erdős-Rényi G(n,p) random graph model.
394#[allow(dead_code)]
395pub fn erdos_renyi_graph_ty() -> Expr {
396    arrow(
397        nat_ty(),
398        arrow(real_ty(), app(cst("SimpleGraph"), nat_ty())),
399    )
400}
401/// ConnectivityThreshold : Nat → Real
402/// The threshold probability p_c = ln(n)/n for G(n,p) connectivity.
403#[allow(dead_code)]
404pub fn connectivity_threshold_ty() -> Expr {
405    arrow(nat_ty(), real_ty())
406}
407/// PhaseTransition : ∀ (n : Nat) (p : Real), p > 1/n → GiantComponentExists (ErdosRenyi n p)
408/// Phase transition at p = 1/n: a giant component emerges.
409#[allow(dead_code)]
410pub fn phase_transition_ty() -> Expr {
411    pi(
412        BinderInfo::Default,
413        "n",
414        nat_ty(),
415        pi(
416            BinderInfo::Default,
417            "p",
418            real_ty(),
419            arrow(
420                app2(cst("Real.gt"), bvar(0), app(cst("Real.inv"), bvar(1))),
421                app(
422                    cst("GiantComponentExists"),
423                    app2(cst("ErdosRenyiGraph"), bvar(1), bvar(0)),
424                ),
425            ),
426        ),
427    )
428}
429/// Graphon : Type
430/// A graphon is a symmetric measurable function W : [0,1]² → [0,1].
431#[allow(dead_code)]
432pub fn graphon_ty() -> Expr {
433    type0()
434}
435/// GraphonCutDistance : Graphon → Graphon → Real
436/// The cut distance between two graphons.
437#[allow(dead_code)]
438pub fn graphon_cut_distance_ty() -> Expr {
439    arrow(cst("Graphon"), arrow(cst("Graphon"), real_ty()))
440}
441/// SzemerediRegularity : ∀ {V} [Fintype V] (G : SimpleGraph V) (ε : Real),
442///   ∃ partition, ε-regular and |partition| ≤ M(ε)
443/// Szemerédi regularity lemma: every graph has an ε-regular partition.
444#[allow(dead_code)]
445pub fn szemeredi_regularity_ty() -> Expr {
446    impl_pi(
447        "V",
448        type0(),
449        pi(
450            BinderInfo::Default,
451            "G",
452            app(cst("SimpleGraph"), bvar(0)),
453            pi(
454                BinderInfo::Default,
455                "eps",
456                real_ty(),
457                app2(
458                    cst("Exists"),
459                    cst("Partition"),
460                    app2(cst("IsEpsRegular"), bvar(1), bvar(0)),
461                ),
462            ),
463        ),
464    )
465}
466/// IsPerfectGraph : ∀ {V}, SimpleGraph V → Prop
467/// A graph is perfect if χ(H) = ω(H) for every induced subgraph H.
468#[allow(dead_code)]
469pub fn is_perfect_graph_ty() -> Expr {
470    impl_pi(
471        "V",
472        type0(),
473        arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
474    )
475}
476/// StrongPerfectGraphThm : ∀ {V} (G : SimpleGraph V),
477///   IsPerfect G ↔ (NoOddHole G ∧ NoOddAntihole G)
478/// The strong perfect graph theorem (Chudnovsky-Robertson-Seymour-Thomas 2006).
479#[allow(dead_code)]
480pub fn strong_perfect_graph_thm_ty() -> Expr {
481    impl_pi(
482        "V",
483        type0(),
484        pi(
485            BinderInfo::Default,
486            "G",
487            app(cst("SimpleGraph"), bvar(0)),
488            app2(
489                cst("Iff"),
490                app(cst("IsPerfectGraph"), bvar(0)),
491                app2(
492                    cst("And"),
493                    app(cst("NoOddHole"), bvar(0)),
494                    app(cst("NoOddAntihole"), bvar(0)),
495                ),
496            ),
497        ),
498    )
499}
500/// CliqueCoverNumber : ∀ {V} [Fintype V], SimpleGraph V → Nat
501/// The minimum number of cliques needed to cover all vertices.
502#[allow(dead_code)]
503pub fn clique_cover_number_ty() -> Expr {
504    impl_pi(
505        "V",
506        type0(),
507        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
508    )
509}
510/// VertexConnectivity : ∀ {V} [Fintype V], SimpleGraph V → Nat
511/// κ(G) = minimum number of vertices whose removal disconnects G.
512#[allow(dead_code)]
513pub fn vertex_connectivity_ty() -> Expr {
514    impl_pi(
515        "V",
516        type0(),
517        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
518    )
519}
520/// EdgeConnectivity : ∀ {V} [Fintype V], SimpleGraph V → Nat
521/// λ(G) = minimum number of edges whose removal disconnects G.
522#[allow(dead_code)]
523pub fn edge_connectivity_ty() -> Expr {
524    impl_pi(
525        "V",
526        type0(),
527        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
528    )
529}
530/// MengersThm : ∀ {V} [Fintype V] (G : SimpleGraph V) (s t : V),
531///   MaxDisjointPaths G s t = MinVertexCut G s t
532/// Menger's theorem: max number of vertex-disjoint s-t paths = min vertex cut size.
533#[allow(dead_code)]
534pub fn mengers_theorem_ty() -> Expr {
535    impl_pi(
536        "V",
537        type0(),
538        pi(
539            BinderInfo::Default,
540            "G",
541            app(cst("SimpleGraph"), bvar(0)),
542            pi(
543                BinderInfo::Default,
544                "s",
545                bvar(1),
546                pi(
547                    BinderInfo::Default,
548                    "t",
549                    bvar(2),
550                    app2(
551                        app(cst("Eq"), nat_ty()),
552                        app3(cst("MaxDisjointPaths"), bvar(2), bvar(1), bvar(0)),
553                        app3(cst("MinVertexCut"), bvar(2), bvar(1), bvar(0)),
554                    ),
555                ),
556            ),
557        ),
558    )
559}
560/// MaxFlowMinCut : ∀ (n : Nat) (s t : Nat) (cap : Nat → Nat → Real),
561///   MaxFlow n s t cap = MinCutCapacity n s t cap
562/// Max-flow min-cut theorem for real-valued capacities.
563#[allow(dead_code)]
564pub fn max_flow_min_cut_ty() -> Expr {
565    pi(
566        BinderInfo::Default,
567        "n",
568        nat_ty(),
569        pi(
570            BinderInfo::Default,
571            "s",
572            nat_ty(),
573            pi(
574                BinderInfo::Default,
575                "t",
576                nat_ty(),
577                pi(
578                    BinderInfo::Default,
579                    "cap",
580                    arrow(nat_ty(), arrow(nat_ty(), real_ty())),
581                    app2(
582                        app(cst("Eq"), real_ty()),
583                        app3(app(cst("MaxFlowVal"), bvar(3)), bvar(2), bvar(1), bvar(0)),
584                        app3(
585                            app(cst("MinCutCapacity"), bvar(3)),
586                            bvar(2),
587                            bvar(1),
588                            bvar(0),
589                        ),
590                    ),
591                ),
592            ),
593        ),
594    )
595}
596/// Genus : ∀ {V} [Fintype V], SimpleGraph V → Nat
597/// The genus of a graph: minimum genus of orientable surface for embedding.
598#[allow(dead_code)]
599pub fn genus_ty() -> Expr {
600    impl_pi(
601        "V",
602        type0(),
603        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
604    )
605}
606/// CrossingNumber : ∀ {V} [Fintype V], SimpleGraph V → Nat
607/// The crossing number cr(G): minimum crossings in any planar drawing.
608#[allow(dead_code)]
609pub fn crossing_number_ty() -> Expr {
610    impl_pi(
611        "V",
612        type0(),
613        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
614    )
615}
616/// WagnerThm : ∀ {V} (G : SimpleGraph V),
617///   IsPlanar G ↔ NoK5Minor G ∧ NoK33Minor G
618/// Wagner's theorem: G is planar iff G has no K₅ or K₃,₃ minor.
619#[allow(dead_code)]
620pub fn wagner_theorem_ty() -> Expr {
621    impl_pi(
622        "V",
623        type0(),
624        pi(
625            BinderInfo::Default,
626            "G",
627            app(cst("SimpleGraph"), bvar(0)),
628            app2(
629                cst("Iff"),
630                app(cst("IsPlanar"), bvar(0)),
631                app2(
632                    cst("And"),
633                    app(cst("NoK5Minor"), bvar(0)),
634                    app(cst("NoK33Minor"), bvar(0)),
635                ),
636            ),
637        ),
638    )
639}
640/// Hypergraph : Type → Type
641/// A hypergraph on vertex type V: a collection of hyperedges (subsets of V).
642#[allow(dead_code)]
643pub fn hypergraph_ty() -> Expr {
644    pi(BinderInfo::Default, "V", type0(), type0())
645}
646/// HypergraphColoring : ∀ {V}, Hypergraph V → Nat → Prop
647/// A proper k-coloring of a hypergraph: each hyperedge has at least 2 colors.
648#[allow(dead_code)]
649pub fn hypergraph_coloring_ty() -> Expr {
650    impl_pi(
651        "V",
652        type0(),
653        arrow(app(cst("Hypergraph"), bvar(0)), arrow(nat_ty(), prop())),
654    )
655}
656/// SunflowerLemma : ∀ (p k : Nat) (F : Finset (Finset Nat)),
657///   |F| > (p-1)^k · k! → ∃ sunflower of size p in F
658/// Erdős-Ko-Rado sunflower lemma for set families.
659#[allow(dead_code)]
660pub fn sunflower_lemma_ty() -> Expr {
661    pi(
662        BinderInfo::Default,
663        "p",
664        nat_ty(),
665        pi(
666            BinderInfo::Default,
667            "k",
668            nat_ty(),
669            pi(
670                BinderInfo::Default,
671                "F",
672                app(cst("Finset"), app(cst("Finset"), nat_ty())),
673                arrow(
674                    app2(
675                        cst("SunflowerSizeCondition"),
676                        bvar(2),
677                        app(cst("Finset.card"), bvar(0)),
678                    ),
679                    app2(cst("HasSunflower"), bvar(0), bvar(2)),
680                ),
681            ),
682        ),
683    )
684}
685/// HypergraphTuran : ∀ (r k n : Nat), TuranDensity r k n
686/// Turán-type density results for hypergraphs.
687#[allow(dead_code)]
688pub fn hypergraph_turan_ty() -> Expr {
689    pi(
690        BinderInfo::Default,
691        "r",
692        nat_ty(),
693        pi(
694            BinderInfo::Default,
695            "k",
696            nat_ty(),
697            pi(
698                BinderInfo::Default,
699                "n",
700                nat_ty(),
701                app3(cst("TuranDensity"), bvar(2), bvar(1), bvar(0)),
702            ),
703        ),
704    )
705}
706/// GraphHomomorphism : ∀ {V W}, SimpleGraph V → SimpleGraph W → Type
707/// A graph homomorphism f : V → W preserving adjacency.
708#[allow(dead_code)]
709pub fn graph_homomorphism_ty() -> Expr {
710    impl_pi(
711        "V",
712        type0(),
713        impl_pi(
714            "W",
715            type0(),
716            arrow(
717                app(cst("SimpleGraph"), bvar(1)),
718                arrow(app(cst("SimpleGraph"), bvar(1)), type0()),
719            ),
720        ),
721    )
722}
723/// LovaszThetaFunction : ∀ {V} [Fintype V], SimpleGraph V → Real
724/// The Lovász theta function ϑ(G), sandwiched between ω(G) and χ(G̅).
725#[allow(dead_code)]
726pub fn lovasz_theta_ty() -> Expr {
727    impl_pi(
728        "V",
729        type0(),
730        arrow(app(cst("SimpleGraph"), bvar(0)), real_ty()),
731    )
732}
733/// FractionalChromaticNumber : ∀ {V} [Fintype V], SimpleGraph V → Real
734/// χ_f(G) = inf { k/d : G has a (k:d)-coloring }.
735#[allow(dead_code)]
736pub fn fractional_chromatic_number_ty() -> Expr {
737    impl_pi(
738        "V",
739        type0(),
740        arrow(app(cst("SimpleGraph"), bvar(0)), real_ty()),
741    )
742}
743/// HomomorphismDuality : ∀ {V W} (H : SimpleGraph V) (G : SimpleGraph W),
744///   ¬ (Hom H G) ↔ ∃ (D : Digraph), DualObstruction D G
745/// Homomorphism duality: absence of H-homomorphism characterized by dual.
746#[allow(dead_code)]
747pub fn homomorphism_duality_ty() -> Expr {
748    impl_pi(
749        "V",
750        type0(),
751        impl_pi(
752            "W",
753            type0(),
754            pi(
755                BinderInfo::Default,
756                "H",
757                app(cst("SimpleGraph"), bvar(1)),
758                pi(
759                    BinderInfo::Default,
760                    "G",
761                    app(cst("SimpleGraph"), bvar(1)),
762                    app2(
763                        cst("Iff"),
764                        app(cst("Not"), app2(cst("GraphHom"), bvar(1), bvar(0))),
765                        app2(cst("HasDualObstruction"), cst("Digraph"), bvar(0)),
766                    ),
767                ),
768            ),
769        ),
770    )
771}
772/// TreeDecomposition : ∀ {V}, SimpleGraph V → Type
773/// A tree decomposition of G: a tree T with bags B(t) ⊆ V covering edges.
774#[allow(dead_code)]
775pub fn tree_decomposition_ty() -> Expr {
776    impl_pi(
777        "V",
778        type0(),
779        arrow(app(cst("SimpleGraph"), bvar(0)), type0()),
780    )
781}
782/// Treewidth : ∀ {V} [Fintype V], SimpleGraph V → Nat
783/// tw(G) = min over tree decompositions of (max bag size - 1).
784#[allow(dead_code)]
785pub fn treewidth_ty() -> Expr {
786    impl_pi(
787        "V",
788        type0(),
789        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
790    )
791}
792/// Pathwidth : ∀ {V} [Fintype V], SimpleGraph V → Nat
793/// pw(G) = min over path decompositions of (max bag size - 1).
794#[allow(dead_code)]
795pub fn pathwidth_ty() -> Expr {
796    impl_pi(
797        "V",
798        type0(),
799        arrow(app(cst("SimpleGraph"), bvar(0)), nat_ty()),
800    )
801}
802/// TreewidthDuality : ∀ {V} [Fintype V] (G : SimpleGraph V) (k : Nat),
803///   Treewidth G ≤ k ↔ ¬ HasBranchDecompositionObstruction G k
804/// Treewidth duality via brambles/haven obstructions.
805#[allow(dead_code)]
806pub fn treewidth_duality_ty() -> Expr {
807    impl_pi(
808        "V",
809        type0(),
810        pi(
811            BinderInfo::Default,
812            "G",
813            app(cst("SimpleGraph"), bvar(0)),
814            pi(
815                BinderInfo::Default,
816                "k",
817                nat_ty(),
818                app2(
819                    cst("Iff"),
820                    app2(cst("Nat.le"), app(cst("Treewidth"), bvar(1)), bvar(0)),
821                    app(
822                        cst("Not"),
823                        app2(cst("HasBranchDecompositionObstruction"), bvar(1), bvar(0)),
824                    ),
825                ),
826            ),
827        ),
828    )
829}
830/// AdjacencyMatrix : ∀ {V} [Fintype V], SimpleGraph V → Matrix V V Real
831/// The adjacency matrix of a graph.
832#[allow(dead_code)]
833pub fn adjacency_matrix_ty() -> Expr {
834    impl_pi(
835        "V",
836        type0(),
837        arrow(
838            app(cst("SimpleGraph"), bvar(0)),
839            app3(cst("Matrix"), bvar(0), bvar(0), real_ty()),
840        ),
841    )
842}
843/// GraphLaplacian : ∀ {V} [Fintype V], SimpleGraph V → Matrix V V Real
844/// L = D - A where D is degree matrix, A is adjacency matrix.
845#[allow(dead_code)]
846pub fn graph_laplacian_ty() -> Expr {
847    impl_pi(
848        "V",
849        type0(),
850        arrow(
851            app(cst("SimpleGraph"), bvar(0)),
852            app3(cst("Matrix"), bvar(0), bvar(0), real_ty()),
853        ),
854    )
855}
856/// EigenvalueInterlacing : ∀ {V} [Fintype V] (G H : SimpleGraph V),
857///   IsInducedSubgraph H G → InterlacesEigenvalues (Laplacian G) (Laplacian H)
858/// Cauchy's eigenvalue interlacing theorem for graph Laplacians.
859#[allow(dead_code)]
860pub fn eigenvalue_interlacing_ty() -> Expr {
861    impl_pi(
862        "V",
863        type0(),
864        pi(
865            BinderInfo::Default,
866            "G",
867            app(cst("SimpleGraph"), bvar(0)),
868            pi(
869                BinderInfo::Default,
870                "H",
871                app(cst("SimpleGraph"), bvar(1)),
872                arrow(
873                    app2(cst("IsInducedSubgraph"), bvar(0), bvar(1)),
874                    app2(
875                        cst("InterlacesEigenvalues"),
876                        app(cst("GraphLaplacian"), bvar(1)),
877                        app(cst("GraphLaplacian"), bvar(0)),
878                    ),
879                ),
880            ),
881        ),
882    )
883}
884/// IharaZetaFunction : ∀ {V} [Fintype V], SimpleGraph V → (Complex → Complex)
885/// The Ihara zeta function Z_G(u) = ∏_p (1 - u^{|p|})^{-1} over prime cycles p.
886#[allow(dead_code)]
887pub fn ihara_zeta_function_ty() -> Expr {
888    impl_pi(
889        "V",
890        type0(),
891        arrow(
892            app(cst("SimpleGraph"), bvar(0)),
893            arrow(cst("Complex"), cst("Complex")),
894        ),
895    )
896}
897/// ChromaticPolynomial : ∀ {V} [Fintype V], SimpleGraph V → (Nat → Int)
898/// P(G, k) = number of proper k-colorings of G.
899#[allow(dead_code)]
900pub fn chromatic_polynomial_ty() -> Expr {
901    impl_pi(
902        "V",
903        type0(),
904        arrow(
905            app(cst("SimpleGraph"), bvar(0)),
906            arrow(nat_ty(), cst("Int")),
907        ),
908    )
909}
910/// TuttePolynomial : ∀ {V} [Fintype V], SimpleGraph V → (Real → Real → Real)
911/// T(G; x, y) = universal graph polynomial encoding many graph invariants.
912#[allow(dead_code)]
913pub fn tutte_polynomial_ty() -> Expr {
914    impl_pi(
915        "V",
916        type0(),
917        arrow(
918            app(cst("SimpleGraph"), bvar(0)),
919            arrow(real_ty(), arrow(real_ty(), real_ty())),
920        ),
921    )
922}
923/// MatchingPolynomial : ∀ {V} [Fintype V], SimpleGraph V → (Real → Real)
924/// μ(G, x) = ∑_k (-1)^k m_k(G) x^{n-2k} where m_k = number of k-matchings.
925#[allow(dead_code)]
926pub fn matching_polynomial_ty() -> Expr {
927    impl_pi(
928        "V",
929        type0(),
930        arrow(
931            app(cst("SimpleGraph"), bvar(0)),
932            arrow(real_ty(), real_ty()),
933        ),
934    )
935}
936/// DeletionContractionTutte : ∀ {V} [Fintype V] (G : SimpleGraph V) (e : Edge V),
937///   TuttePolynomial G = TuttePolynomial (Delete G e) + TuttePolynomial (Contract G e)
938/// Deletion-contraction recurrence for the Tutte polynomial.
939#[allow(dead_code)]
940pub fn deletion_contraction_tutte_ty() -> Expr {
941    impl_pi(
942        "V",
943        type0(),
944        pi(
945            BinderInfo::Default,
946            "G",
947            app(cst("SimpleGraph"), bvar(0)),
948            pi(
949                BinderInfo::Default,
950                "e",
951                app(cst("Edge"), bvar(1)),
952                app2(
953                    app(cst("Eq"), arrow(real_ty(), arrow(real_ty(), real_ty()))),
954                    app(cst("TuttePolynomial"), bvar(1)),
955                    app2(
956                        cst("TutteSum"),
957                        app(
958                            cst("TuttePolynomial"),
959                            app2(cst("Delete"), bvar(1), bvar(0)),
960                        ),
961                        app(
962                            cst("TuttePolynomial"),
963                            app2(cst("Contract"), bvar(1), bvar(0)),
964                        ),
965                    ),
966                ),
967            ),
968        ),
969    )
970}
971/// CayleyGraph : ∀ (G : Group) (S : Finset G), SimpleGraph G
972/// The Cayley graph Cay(G, S) with vertex set G and edges from S-generating set.
973#[allow(dead_code)]
974pub fn cayley_graph_ty() -> Expr {
975    pi(
976        BinderInfo::Default,
977        "G",
978        cst("Group"),
979        pi(
980            BinderInfo::Default,
981            "S",
982            app(cst("Finset"), bvar(0)),
983            app(cst("SimpleGraph"), bvar(1)),
984        ),
985    )
986}
987/// StronglyRegularGraph : ∀ {V} [Fintype V] (G : SimpleGraph V) (k λ μ : Nat), Prop
988/// srg(n, k, λ, μ): k-regular, adjacent pairs have λ common neighbors,
989/// non-adjacent pairs have μ common neighbors.
990#[allow(dead_code)]
991pub fn strongly_regular_graph_ty() -> Expr {
992    impl_pi(
993        "V",
994        type0(),
995        pi(
996            BinderInfo::Default,
997            "G",
998            app(cst("SimpleGraph"), bvar(0)),
999            pi(
1000                BinderInfo::Default,
1001                "k",
1002                nat_ty(),
1003                pi(
1004                    BinderInfo::Default,
1005                    "lam",
1006                    nat_ty(),
1007                    pi(BinderInfo::Default, "mu", nat_ty(), prop()),
1008                ),
1009            ),
1010        ),
1011    )
1012}
1013/// DynamicGraph : Type → Type
1014/// A dynamic graph supporting incremental/decremental edge updates.
1015#[allow(dead_code)]
1016pub fn dynamic_graph_ty() -> Expr {
1017    pi(BinderInfo::Default, "V", type0(), type0())
1018}
1019/// FullyDynamicConnectivity : ∀ {V} [Fintype V], DynamicGraph V → Prop
1020/// A data structure supporting edge insertions, deletions, and connectivity queries.
1021#[allow(dead_code)]
1022pub fn fully_dynamic_connectivity_ty() -> Expr {
1023    impl_pi(
1024        "V",
1025        type0(),
1026        arrow(app(cst("DynamicGraph"), bvar(0)), prop()),
1027    )
1028}
1029/// IncrementalConnectivity : ∀ {V} [Fintype V], DynamicGraph V → Prop
1030/// An online connectivity structure supporting only edge insertions.
1031#[allow(dead_code)]
1032pub fn incremental_connectivity_ty() -> Expr {
1033    impl_pi(
1034        "V",
1035        type0(),
1036        arrow(app(cst("DynamicGraph"), bvar(0)), prop()),
1037    )
1038}
1039/// SemiStreamingSketch : ∀ {V} [Fintype V], SimpleGraph V → Type
1040/// A semi-streaming sketch using O(n · polylog n) space for n = |V|.
1041#[allow(dead_code)]
1042pub fn semi_streaming_sketch_ty() -> Expr {
1043    impl_pi(
1044        "V",
1045        type0(),
1046        arrow(app(cst("SimpleGraph"), bvar(0)), type0()),
1047    )
1048}
1049/// SketchedConnectivity : ∀ {V} [Fintype V], SemiStreamingSketch → Prop
1050/// Determine connectivity from a semi-streaming sketch.
1051#[allow(dead_code)]
1052pub fn sketched_connectivity_ty() -> Expr {
1053    impl_pi(
1054        "V",
1055        type0(),
1056        arrow(app(cst("SemiStreamingSketch"), bvar(0)), prop()),
1057    )
1058}
1059/// Build the graph theory environment, registering all axioms and theorems.
1060#[allow(dead_code)]
1061pub fn build_graph_theory_env(env: &mut Environment) -> Result<(), String> {
1062    let _ = env.add(Declaration::Axiom {
1063        name: Name::str("SimpleGraph"),
1064        univ_params: vec![],
1065        ty: simple_graph_ty(),
1066    });
1067    let _ = env.add(Declaration::Axiom {
1068        name: Name::str("SimpleGraph.adj"),
1069        univ_params: vec![],
1070        ty: simple_graph_adj_ty(),
1071    });
1072    let _ = env.add(Declaration::Axiom {
1073        name: Name::str("SimpleGraph.degree"),
1074        univ_params: vec![],
1075        ty: simple_graph_degree_ty(),
1076    });
1077    let _ = env.add(Declaration::Axiom {
1078        name: Name::str("Digraph"),
1079        univ_params: vec![],
1080        ty: digraph_ty(),
1081    });
1082    let _ = env.add(Declaration::Axiom {
1083        name: Name::str("Digraph.adj"),
1084        univ_params: vec![],
1085        ty: digraph_adj_ty(),
1086    });
1087    let _ = env.add(Declaration::Axiom {
1088        name: Name::str("Walk"),
1089        univ_params: vec![],
1090        ty: walk_ty(),
1091    });
1092    let _ = env.add(Declaration::Axiom {
1093        name: Name::str("SimpleGraph.Connected"),
1094        univ_params: vec![],
1095        ty: simple_graph_connected_ty(),
1096    });
1097    let _ = env.add(Declaration::Axiom {
1098        name: Name::str("IsTree"),
1099        univ_params: vec![],
1100        ty: is_tree_ty(),
1101    });
1102    let _ = env.add(Declaration::Axiom {
1103        name: Name::str("chromatic_number"),
1104        univ_params: vec![],
1105        ty: chromatic_number_ty(),
1106    });
1107    let _ = env.add(Declaration::Axiom {
1108        name: Name::str("IsEulerian"),
1109        univ_params: vec![],
1110        ty: is_eulerian_ty(),
1111    });
1112    let _ = env.add(Declaration::Axiom {
1113        name: Name::str("IsHamiltonian"),
1114        univ_params: vec![],
1115        ty: is_hamiltonian_ty(),
1116    });
1117    let _ = env.add(Declaration::Axiom {
1118        name: Name::str("IsBipartite"),
1119        univ_params: vec![],
1120        ty: is_bipartite_ty(),
1121    });
1122    let _ = env.add(Declaration::Axiom {
1123        name: Name::str("IsPlanar"),
1124        univ_params: vec![],
1125        ty: is_planar_ty(),
1126    });
1127    let _ = env.add(Declaration::Axiom {
1128        name: Name::str("four_color_theorem"),
1129        univ_params: vec![],
1130        ty: four_color_theorem_ty(),
1131    });
1132    let _ = env.add(Declaration::Axiom {
1133        name: Name::str("eulerian_circuit_theorem"),
1134        univ_params: vec![],
1135        ty: eulerian_circuit_thm_ty(),
1136    });
1137    let _ = env.add(Declaration::Axiom {
1138        name: Name::str("halls_theorem"),
1139        univ_params: vec![],
1140        ty: halls_theorem_ty(),
1141    });
1142    let _ = env.add(Declaration::Axiom {
1143        name: Name::str("kuratowski_theorem"),
1144        univ_params: vec![],
1145        ty: kuratowski_theorem_ty(),
1146    });
1147    let _ = env.add(Declaration::Axiom {
1148        name: Name::str("GraphMinor"),
1149        univ_params: vec![],
1150        ty: graph_minor_ty(),
1151    });
1152    let _ = env.add(Declaration::Axiom {
1153        name: Name::str("robertson_seymour_wqo"),
1154        univ_params: vec![],
1155        ty: robertson_seymour_wqo_ty(),
1156    });
1157    let _ = env.add(Declaration::Axiom {
1158        name: Name::str("VertexExpansion"),
1159        univ_params: vec![],
1160        ty: vertex_expansion_ty(),
1161    });
1162    let _ = env.add(Declaration::Axiom {
1163        name: Name::str("EdgeExpansion"),
1164        univ_params: vec![],
1165        ty: edge_expansion_ty(),
1166    });
1167    let _ = env.add(Declaration::Axiom {
1168        name: Name::str("CheegerConstant"),
1169        univ_params: vec![],
1170        ty: cheeger_constant_ty(),
1171    });
1172    let _ = env.add(Declaration::Axiom {
1173        name: Name::str("SpectralGap"),
1174        univ_params: vec![],
1175        ty: spectral_gap_ty(),
1176    });
1177    let _ = env.add(Declaration::Axiom {
1178        name: Name::str("Graphon"),
1179        univ_params: vec![],
1180        ty: graphon_ty(),
1181    });
1182    let _ = env.add(Declaration::Axiom {
1183        name: Name::str("GraphonCutDistance"),
1184        univ_params: vec![],
1185        ty: graphon_cut_distance_ty(),
1186    });
1187    let _ = env.add(Declaration::Axiom {
1188        name: Name::str("IsPerfectGraph"),
1189        univ_params: vec![],
1190        ty: is_perfect_graph_ty(),
1191    });
1192    let _ = env.add(Declaration::Axiom {
1193        name: Name::str("strong_perfect_graph_theorem"),
1194        univ_params: vec![],
1195        ty: strong_perfect_graph_thm_ty(),
1196    });
1197    let _ = env.add(Declaration::Axiom {
1198        name: Name::str("VertexConnectivity"),
1199        univ_params: vec![],
1200        ty: vertex_connectivity_ty(),
1201    });
1202    let _ = env.add(Declaration::Axiom {
1203        name: Name::str("EdgeConnectivity"),
1204        univ_params: vec![],
1205        ty: edge_connectivity_ty(),
1206    });
1207    let _ = env.add(Declaration::Axiom {
1208        name: Name::str("Genus"),
1209        univ_params: vec![],
1210        ty: genus_ty(),
1211    });
1212    let _ = env.add(Declaration::Axiom {
1213        name: Name::str("CrossingNumber"),
1214        univ_params: vec![],
1215        ty: crossing_number_ty(),
1216    });
1217    let _ = env.add(Declaration::Axiom {
1218        name: Name::str("Hypergraph"),
1219        univ_params: vec![],
1220        ty: hypergraph_ty(),
1221    });
1222    let _ = env.add(Declaration::Axiom {
1223        name: Name::str("HypergraphColoring"),
1224        univ_params: vec![],
1225        ty: hypergraph_coloring_ty(),
1226    });
1227    let _ = env.add(Declaration::Axiom {
1228        name: Name::str("GraphHomomorphism"),
1229        univ_params: vec![],
1230        ty: graph_homomorphism_ty(),
1231    });
1232    let _ = env.add(Declaration::Axiom {
1233        name: Name::str("LovaszTheta"),
1234        univ_params: vec![],
1235        ty: lovasz_theta_ty(),
1236    });
1237    let _ = env.add(Declaration::Axiom {
1238        name: Name::str("FractionalChromaticNumber"),
1239        univ_params: vec![],
1240        ty: fractional_chromatic_number_ty(),
1241    });
1242    let _ = env.add(Declaration::Axiom {
1243        name: Name::str("TreeDecomposition"),
1244        univ_params: vec![],
1245        ty: tree_decomposition_ty(),
1246    });
1247    let _ = env.add(Declaration::Axiom {
1248        name: Name::str("Treewidth"),
1249        univ_params: vec![],
1250        ty: treewidth_ty(),
1251    });
1252    let _ = env.add(Declaration::Axiom {
1253        name: Name::str("Pathwidth"),
1254        univ_params: vec![],
1255        ty: pathwidth_ty(),
1256    });
1257    let _ = env.add(Declaration::Axiom {
1258        name: Name::str("AdjacencyMatrix"),
1259        univ_params: vec![],
1260        ty: adjacency_matrix_ty(),
1261    });
1262    let _ = env.add(Declaration::Axiom {
1263        name: Name::str("GraphLaplacian"),
1264        univ_params: vec![],
1265        ty: graph_laplacian_ty(),
1266    });
1267    let _ = env.add(Declaration::Axiom {
1268        name: Name::str("IharaZetaFunction"),
1269        univ_params: vec![],
1270        ty: ihara_zeta_function_ty(),
1271    });
1272    let _ = env.add(Declaration::Axiom {
1273        name: Name::str("ChromaticPolynomial"),
1274        univ_params: vec![],
1275        ty: chromatic_polynomial_ty(),
1276    });
1277    let _ = env.add(Declaration::Axiom {
1278        name: Name::str("TuttePolynomial"),
1279        univ_params: vec![],
1280        ty: tutte_polynomial_ty(),
1281    });
1282    let _ = env.add(Declaration::Axiom {
1283        name: Name::str("MatchingPolynomial"),
1284        univ_params: vec![],
1285        ty: matching_polynomial_ty(),
1286    });
1287    let _ = env.add(Declaration::Axiom {
1288        name: Name::str("CayleyGraph"),
1289        univ_params: vec![],
1290        ty: cayley_graph_ty(),
1291    });
1292    let _ = env.add(Declaration::Axiom {
1293        name: Name::str("StronglyRegularGraph"),
1294        univ_params: vec![],
1295        ty: strongly_regular_graph_ty(),
1296    });
1297    let _ = env.add(Declaration::Axiom {
1298        name: Name::str("DynamicGraph"),
1299        univ_params: vec![],
1300        ty: dynamic_graph_ty(),
1301    });
1302    let _ = env.add(Declaration::Axiom {
1303        name: Name::str("FullyDynamicConnectivity"),
1304        univ_params: vec![],
1305        ty: fully_dynamic_connectivity_ty(),
1306    });
1307    let _ = env.add(Declaration::Axiom {
1308        name: Name::str("SemiStreamingSketch"),
1309        univ_params: vec![],
1310        ty: semi_streaming_sketch_ty(),
1311    });
1312    Ok(())
1313}
1314/// Minimum spanning tree via Kruskal's algorithm (weighted undirected graph).
1315pub fn kruskal_mst(n: usize, mut edges: Vec<(usize, usize, i64)>) -> Vec<(usize, usize, i64)> {
1316    edges.sort_by_key(|&(_, _, w)| w);
1317    let mut parent: Vec<usize> = (0..n).collect();
1318    let mut rank = vec![0usize; n];
1319    fn find(parent: &mut Vec<usize>, x: usize) -> usize {
1320        if parent[x] != x {
1321            parent[x] = find(parent, parent[x]);
1322        }
1323        parent[x]
1324    }
1325    fn union(parent: &mut Vec<usize>, rank: &mut Vec<usize>, x: usize, y: usize) -> bool {
1326        let rx = find(parent, x);
1327        let ry = find(parent, y);
1328        if rx == ry {
1329            return false;
1330        }
1331        if rank[rx] < rank[ry] {
1332            parent[rx] = ry;
1333        } else if rank[rx] > rank[ry] {
1334            parent[ry] = rx;
1335        } else {
1336            parent[ry] = rx;
1337            rank[rx] += 1;
1338        }
1339        true
1340    }
1341    let mut mst = Vec::new();
1342    for (u, v, w) in edges {
1343        if union(&mut parent, &mut rank, u, v) {
1344            mst.push((u, v, w));
1345            if mst.len() == n - 1 {
1346                break;
1347            }
1348        }
1349    }
1350    mst
1351}
1352/// Max-flow via Ford-Fulkerson with BFS (Edmonds-Karp).
1353pub fn max_flow(n: usize, source: usize, sink: usize, capacity: &[Vec<i64>]) -> i64 {
1354    let mut flow_matrix = vec![vec![0i64; n]; n];
1355    let mut total_flow = 0i64;
1356    loop {
1357        let mut parent = vec![usize::MAX; n];
1358        parent[source] = source;
1359        let mut queue = VecDeque::new();
1360        queue.push_back(source);
1361        while let Some(u) = queue.pop_front() {
1362            if u == sink {
1363                break;
1364            }
1365            for v in 0..n {
1366                let residual = capacity[u][v] - flow_matrix[u][v];
1367                if parent[v] == usize::MAX && residual > 0 {
1368                    parent[v] = u;
1369                    queue.push_back(v);
1370                }
1371            }
1372        }
1373        if parent[sink] == usize::MAX {
1374            break;
1375        }
1376        let mut bottleneck = i64::MAX;
1377        let mut v = sink;
1378        while v != source {
1379            let u = parent[v];
1380            bottleneck = bottleneck.min(capacity[u][v] - flow_matrix[u][v]);
1381            v = u;
1382        }
1383        v = sink;
1384        while v != source {
1385            let u = parent[v];
1386            flow_matrix[u][v] += bottleneck;
1387            flow_matrix[v][u] -= bottleneck;
1388            v = u;
1389        }
1390        total_flow += bottleneck;
1391    }
1392    total_flow
1393}
1394#[cfg(test)]
1395mod tests {
1396    use super::*;
1397    #[test]
1398    fn test_bfs_connected() {
1399        let mut g = UndirectedGraph::new(4);
1400        g.add_edge(0, 1);
1401        g.add_edge(1, 2);
1402        g.add_edge(2, 3);
1403        assert!(g.is_connected());
1404        let dist = g.bfs(0);
1405        assert_eq!(dist, vec![0, 1, 2, 3]);
1406    }
1407    #[test]
1408    fn test_bfs_disconnected() {
1409        let mut g = UndirectedGraph::new(4);
1410        g.add_edge(0, 1);
1411        g.add_edge(2, 3);
1412        assert!(!g.is_connected());
1413        assert_eq!(g.num_components(), 2);
1414    }
1415    #[test]
1416    fn test_bipartite() {
1417        let k33 = UndirectedGraph::complete_bipartite(3, 3);
1418        assert!(k33.is_bipartite());
1419        let k3 = UndirectedGraph::complete(3);
1420        assert!(!k3.is_bipartite());
1421    }
1422    #[test]
1423    fn test_eulerian_even_cycle() {
1424        let c4 = UndirectedGraph::cycle(4);
1425        assert!(c4.all_degrees_even());
1426        assert!(c4.has_eulerian_circuit());
1427    }
1428    #[test]
1429    fn test_eulerian_odd_cycle_fails() {
1430        let p4 = UndirectedGraph::path(4);
1431        assert!(!p4.all_degrees_even());
1432        assert!(!p4.has_eulerian_circuit());
1433    }
1434    #[test]
1435    fn test_greedy_coloring_path() {
1436        let p4 = UndirectedGraph::path(4);
1437        let (k, coloring) = p4.greedy_coloring();
1438        assert!(k <= 2);
1439        assert!(p4.is_proper_coloring(&coloring));
1440    }
1441    #[test]
1442    fn test_greedy_coloring_complete() {
1443        let k4 = UndirectedGraph::complete(4);
1444        let (k, coloring) = k4.greedy_coloring();
1445        assert_eq!(k, 4);
1446        assert!(k4.is_proper_coloring(&coloring));
1447    }
1448    #[test]
1449    fn test_spanning_tree() {
1450        let k4 = UndirectedGraph::complete(4);
1451        let tree = k4.spanning_tree();
1452        assert_eq!(tree.len(), 3);
1453    }
1454    #[test]
1455    fn test_digraph_bfs() {
1456        let mut g = DiGraph::new(5);
1457        g.add_edge(0, 1, 1);
1458        g.add_edge(1, 2, 1);
1459        g.add_edge(2, 3, 1);
1460        g.add_edge(3, 4, 1);
1461        let dist = g.bfs(0);
1462        assert_eq!(dist, vec![0, 1, 2, 3, 4]);
1463    }
1464    #[test]
1465    fn test_topo_sort_dag() {
1466        let mut g = DiGraph::new(4);
1467        g.add_edge(0, 1, 0);
1468        g.add_edge(0, 2, 0);
1469        g.add_edge(1, 3, 0);
1470        g.add_edge(2, 3, 0);
1471        let order = g.topo_sort().expect("topo_sort should succeed");
1472        assert_eq!(order.len(), 4);
1473    }
1474    #[test]
1475    fn test_topo_sort_cycle() {
1476        let mut g = DiGraph::new(3);
1477        g.add_edge(0, 1, 0);
1478        g.add_edge(1, 2, 0);
1479        g.add_edge(2, 0, 0);
1480        assert!(g.topo_sort().is_none());
1481    }
1482    #[test]
1483    fn test_scc() {
1484        let mut g = DiGraph::new(4);
1485        g.add_edge(0, 1, 0);
1486        g.add_edge(1, 0, 0);
1487        g.add_edge(2, 3, 0);
1488        let sccs = g.scc();
1489        assert_eq!(sccs.len(), 3);
1490    }
1491    #[test]
1492    fn test_dijkstra() {
1493        let mut g = DiGraph::new(4);
1494        g.add_edge(0, 1, 1);
1495        g.add_edge(0, 2, 4);
1496        g.add_edge(1, 2, 2);
1497        g.add_edge(1, 3, 5);
1498        g.add_edge(2, 3, 1);
1499        let (dist, _) = g.dijkstra(0);
1500        assert_eq!(dist[3], 4);
1501    }
1502    #[test]
1503    fn test_bellman_ford() {
1504        let mut g = DiGraph::new(3);
1505        g.add_edge(0, 1, -1);
1506        g.add_edge(1, 2, 3);
1507        let dist = g.bellman_ford(0).expect("bellman_ford should succeed");
1508        assert_eq!(dist[2], 2);
1509    }
1510    #[test]
1511    fn test_floyd_warshall() {
1512        let mut g = DiGraph::new(3);
1513        g.add_edge(0, 1, 5);
1514        g.add_edge(1, 2, 3);
1515        g.add_edge(0, 2, 10);
1516        let d = g.floyd_warshall();
1517        assert_eq!(d[0][2], 8);
1518    }
1519    #[test]
1520    fn test_kruskal_mst() {
1521        let edges = vec![(0, 1, 1), (1, 2, 2), (0, 2, 10), (2, 3, 3)];
1522        let mst = kruskal_mst(4, edges);
1523        assert_eq!(mst.len(), 3);
1524        let total: i64 = mst.iter().map(|&(_, _, w)| w).sum();
1525        assert_eq!(total, 6);
1526    }
1527    #[test]
1528    fn test_max_flow() {
1529        let n = 4;
1530        let mut cap = vec![vec![0i64; n]; n];
1531        cap[0][1] = 3;
1532        cap[0][2] = 2;
1533        cap[1][3] = 2;
1534        cap[2][3] = 3;
1535        cap[1][2] = 1;
1536        let flow = max_flow(n, 0, 3, &cap);
1537        assert_eq!(flow, 5);
1538    }
1539    #[test]
1540    fn test_build_graph_theory_env() {
1541        let mut env = Environment::new();
1542        let _ = env.add(Declaration::Axiom {
1543            name: Name::str("Nat"),
1544            univ_params: vec![],
1545            ty: type0(),
1546        });
1547        let _ = env.add(Declaration::Axiom {
1548            name: Name::str("Bool"),
1549            univ_params: vec![],
1550            ty: type0(),
1551        });
1552        let _ = env.add(Declaration::Axiom {
1553            name: Name::str("Nat.le"),
1554            univ_params: vec![],
1555            ty: arrow(nat_ty(), arrow(nat_ty(), prop())),
1556        });
1557        let _ = env.add(Declaration::Axiom {
1558            name: Name::str("AllDegreesEven"),
1559            univ_params: vec![],
1560            ty: impl_pi(
1561                "V",
1562                type0(),
1563                arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
1564            ),
1565        });
1566        let _ = env.add(Declaration::Axiom {
1567            name: Name::str("HasPerfectMatching"),
1568            univ_params: vec![],
1569            ty: impl_pi(
1570                "V",
1571                type0(),
1572                arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
1573            ),
1574        });
1575        let _ = env.add(Declaration::Axiom {
1576            name: Name::str("HallCondition"),
1577            univ_params: vec![],
1578            ty: impl_pi(
1579                "V",
1580                type0(),
1581                arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
1582            ),
1583        });
1584        let _ = env.add(Declaration::Axiom {
1585            name: Name::str("NoK5OrK33Subdivision"),
1586            univ_params: vec![],
1587            ty: impl_pi(
1588                "V",
1589                type0(),
1590                arrow(app(cst("SimpleGraph"), bvar(0)), prop()),
1591            ),
1592        });
1593        let _ = env.add(Declaration::Axiom {
1594            name: Name::str("IsConnectedPlanar"),
1595            univ_params: vec![],
1596            ty: arrow(nat_ty(), arrow(nat_ty(), arrow(nat_ty(), prop()))),
1597        });
1598        let result = build_graph_theory_env(&mut env);
1599        assert!(result.is_ok());
1600    }
1601    #[test]
1602    fn test_expander_checker_complete_graph() {
1603        let k4 = UndirectedGraph::complete(4);
1604        let checker = ExpanderChecker::new(k4);
1605        let h = checker.approximate_cheeger();
1606        assert!(h >= 1.0, "K_4 should have good expansion: h = {}", h);
1607        assert!(checker.is_expander(1.0));
1608    }
1609    #[test]
1610    fn test_expander_checker_path_graph() {
1611        let p4 = UndirectedGraph::path(4);
1612        let checker = ExpanderChecker::new(p4);
1613        let h = checker.approximate_cheeger();
1614        assert!(
1615            h < 2.0,
1616            "Path graph should have limited expansion: h = {}",
1617            h
1618        );
1619    }
1620    #[test]
1621    fn test_graphon_sampler_constant() {
1622        let sampler = GraphonSampler::new(5, Box::new(|_x, _y| 0.8));
1623        let g = sampler.sample_deterministic();
1624        assert_eq!(g.edge_count(), 10);
1625    }
1626    #[test]
1627    fn test_graphon_sampler_zero() {
1628        let sampler = GraphonSampler::new(5, Box::new(|_x, _y| 0.3));
1629        let g = sampler.sample_deterministic();
1630        assert_eq!(g.edge_count(), 0);
1631    }
1632    #[test]
1633    fn test_graphon_sampler_threshold() {
1634        let n = 6usize;
1635        let sampler = GraphonSampler::new(
1636            n,
1637            Box::new(move |x, y| {
1638                let half = 0.5f64;
1639                if (x < half) != (y < half) {
1640                    0.9
1641                } else {
1642                    0.1
1643                }
1644            }),
1645        );
1646        let g = sampler.sample_at_threshold(0.5);
1647        assert!(g.edge_count() > 0);
1648        assert!(g.is_bipartite());
1649    }
1650    #[test]
1651    fn test_treewidth_heuristic_tree() {
1652        let p5 = UndirectedGraph::path(5);
1653        let mut h = TreewidthHeuristic::new(&p5);
1654        let (_order, tw) = h.run();
1655        assert_eq!(tw, 1, "Path graph has treewidth 1");
1656    }
1657    #[test]
1658    fn test_treewidth_heuristic_complete() {
1659        let k4 = UndirectedGraph::complete(4);
1660        let mut h = TreewidthHeuristic::new(&k4);
1661        let (_order, tw) = h.run();
1662        assert!(tw >= 3, "K_4 treewidth should be at least 3, got {}", tw);
1663    }
1664    #[test]
1665    fn test_tutte_polynomial_tree() {
1666        let p3 = UndirectedGraph::path(3);
1667        let eval = TuttePolynomialEval::from_graph(&p3);
1668        let val = eval.evaluate(2.0, 2.0);
1669        assert!((val - 4.0).abs() < 1e-9, "T(path3; 2,2) = {}", val);
1670    }
1671    #[test]
1672    fn test_tutte_polynomial_single_edge() {
1673        let mut g = UndirectedGraph::new(2);
1674        g.add_edge(0, 1);
1675        let eval = TuttePolynomialEval::from_graph(&g);
1676        let val = eval.evaluate(2.0, 2.0);
1677        assert!(
1678            (val - 2.0).abs() < 1e-9,
1679            "T(K2; 2,2) = {} (expected 2.0)",
1680            val
1681        );
1682    }
1683    #[test]
1684    fn test_szemeredi_regularity_complete() {
1685        let k5 = UndirectedGraph::complete(5);
1686        let rl = SzemerédiRegularityLemma::new(k5, 0.5);
1687        let (parts, regular_pairs) = rl.run(2);
1688        assert_eq!(parts.len(), 2);
1689        let _ = regular_pairs;
1690    }
1691    #[test]
1692    fn test_szemeredi_density_bipartite() {
1693        let k33 = UndirectedGraph::complete_bipartite(3, 3);
1694        let rl = SzemerédiRegularityLemma::new(k33, 0.5);
1695        let part_a: Vec<usize> = (0..3).collect();
1696        let part_b: Vec<usize> = (3..6).collect();
1697        let d = rl.density(&part_a, &part_b);
1698        assert!((d - 1.0).abs() < 1e-9, "K_3,3 density = {}", d);
1699        assert!(rl.is_regular_pair(&part_a, &part_b));
1700    }
1701    #[test]
1702    fn test_new_axiom_types_build() {
1703        let _ = graph_minor_ty();
1704        let _ = vertex_expansion_ty();
1705        let _ = edge_expansion_ty();
1706        let _ = cheeger_constant_ty();
1707        let _ = spectral_gap_ty();
1708        let _ = graphon_ty();
1709        let _ = graphon_cut_distance_ty();
1710        let _ = is_perfect_graph_ty();
1711        let _ = strong_perfect_graph_thm_ty();
1712        let _ = vertex_connectivity_ty();
1713        let _ = edge_connectivity_ty();
1714        let _ = genus_ty();
1715        let _ = crossing_number_ty();
1716        let _ = hypergraph_ty();
1717        let _ = hypergraph_coloring_ty();
1718        let _ = graph_homomorphism_ty();
1719        let _ = lovasz_theta_ty();
1720        let _ = fractional_chromatic_number_ty();
1721        let _ = tree_decomposition_ty();
1722        let _ = treewidth_ty();
1723        let _ = pathwidth_ty();
1724        let _ = adjacency_matrix_ty();
1725        let _ = graph_laplacian_ty();
1726        let _ = ihara_zeta_function_ty();
1727        let _ = chromatic_polynomial_ty();
1728        let _ = tutte_polynomial_ty();
1729        let _ = matching_polynomial_ty();
1730        let _ = cayley_graph_ty();
1731        let _ = strongly_regular_graph_ty();
1732        let _ = dynamic_graph_ty();
1733        let _ = fully_dynamic_connectivity_ty();
1734        let _ = semi_streaming_sketch_ty();
1735    }
1736}