Skip to main content

litex/to_latex/
to_latex_string.rs

1use crate::prelude::*;
2
3fn chain_link_infix_latex(prop: &str) -> Option<&'static str> {
4    if prop == EQUAL {
5        Some("=")
6    } else if prop == NOT_EQUAL {
7        Some(r"\neq")
8    } else if prop == LESS {
9        Some("<")
10    } else if prop == GREATER {
11        Some(">")
12    } else if prop == LESS_EQUAL {
13        Some(r"\leq")
14    } else if prop == GREATER_EQUAL {
15        Some(r"\geq")
16    } else if prop == IN {
17        Some(r"\in")
18    } else {
19        None
20    }
21}
22
23fn latex_escape_underscore(s: &str) -> String {
24    s.replace('_', r"\_")
25}
26
27fn latex_local_ident(name: &str) -> String {
28    format!(r"\mathit{{{}}}", latex_escape_underscore(name))
29}
30
31fn latex_texttt_escape(s: &str) -> String {
32    let mut out = String::new();
33    for ch in s.chars() {
34        match ch {
35            '_' | '%' | '#' | '&' | '$' => {
36                out.push('\\');
37                out.push(ch);
38            }
39            '{' => out.push_str(r"\{"),
40            '}' => out.push_str(r"\}"),
41            '\\' => out.push_str(r"\textbackslash{}"),
42            '^' => out.push_str(r"\textasciicircum{}"),
43            '~' => out.push_str(r"\textasciitilde{}"),
44            _ => out.push(ch),
45        }
46    }
47    out
48}
49
50fn fn_set_clause_latex(clause: &FnSetClause) -> String {
51    let mut slots: Vec<String> = Vec::new();
52    for g in &clause.params_def_with_set {
53        let set = fn_param_group_type_to_latex(g);
54        for p in &g.params {
55            slots.push(format!(r"{} \in {}", latex_local_ident(p), set));
56        }
57    }
58    let dom = clause
59        .dom_facts
60        .iter()
61        .map(|f| f.to_latex_string())
62        .collect::<Vec<_>>()
63        .join(r", ");
64    let ret = clause.ret_set.to_latex_string();
65    if dom.is_empty() {
66        format!(
67            r"\mathrm{{fn}}\left({}\right)\to {}",
68            slots.join(r", "),
69            ret
70        )
71    } else {
72        format!(
73            r"\mathrm{{fn}}\left({} \,\middle|\, {}\right)\to {}",
74            slots.join(r", "),
75            dom,
76            ret
77        )
78    }
79}
80
81fn fn_param_group_type_to_latex(g: &ParamGroupWithSet) -> String {
82    g.set_obj().to_latex_string()
83}
84
85impl AndChainAtomicFact {
86    pub fn to_latex_string(&self) -> String {
87        match self {
88            AndChainAtomicFact::AtomicFact(x) => x.to_latex_string(),
89            AndChainAtomicFact::AndFact(x) => x.to_latex_string(),
90            AndChainAtomicFact::ChainFact(x) => x.to_latex_string(),
91        }
92    }
93}
94
95impl OrAndChainAtomicFact {
96    pub fn to_latex_string(&self) -> String {
97        match self {
98            OrAndChainAtomicFact::AtomicFact(x) => x.to_latex_string(),
99            OrAndChainAtomicFact::AndFact(x) => x.to_latex_string(),
100            OrAndChainAtomicFact::ChainFact(x) => x.to_latex_string(),
101            OrAndChainAtomicFact::OrFact(x) => x.to_latex_string(),
102        }
103    }
104}
105
106impl AndFact {
107    pub fn to_latex_string(&self) -> String {
108        self.facts
109            .iter()
110            .map(|a| a.to_latex_string())
111            .collect::<Vec<_>>()
112            .join(r" \land ")
113    }
114}
115
116impl ChainFact {
117    pub fn to_latex_string(&self) -> String {
118        if self.objs.is_empty() {
119            return String::new();
120        }
121        let mut s = self.objs[0].to_latex_string();
122        for (i, obj) in self.objs[1..].iter().enumerate() {
123            let pname = self.prop_names[i].to_string();
124            let rhs = obj.to_latex_string();
125            if let Some(op) = chain_link_infix_latex(&pname) {
126                s.push(' ');
127                s.push_str(op);
128                s.push(' ');
129                s.push_str(&rhs);
130            } else if is_comparison_str(&pname) {
131                s.push(' ');
132                s.push_str(&pname);
133                s.push(' ');
134                s.push_str(&rhs);
135            } else {
136                s.push_str(&format!(r" \mathrel{{\mathrm{{{}}}}} {}", pname, rhs));
137            }
138        }
139        s
140    }
141}
142
143impl Abs {
144    pub fn to_latex_string(&self) -> String {
145        format!(r"\left| {} \right|", self.arg.to_latex_string())
146    }
147}
148
149impl Sqrt {
150    pub fn to_latex_string(&self) -> String {
151        format!(r"\sqrt{{{}}}", self.arg.to_latex_string())
152    }
153}
154
155impl Add {
156    pub fn to_latex_string(&self) -> String {
157        format!(
158            "{} + {}",
159            self.left.to_latex_string(),
160            self.right.to_latex_string()
161        )
162    }
163}
164
165impl ByCasesStmt {
166    pub fn to_latex_string(&self) -> String {
167        let goal = self
168            .then_facts
169            .iter()
170            .map(|f| f.to_latex_string())
171            .collect::<Vec<_>>()
172            .join(r" \land ");
173        let mut rows: Vec<String> = Vec::new();
174        rows.push(format!(r"\text{{Proof by cases. Goal:}} & {}", goal));
175        for (i, ((case, proof), imposs)) in self
176            .cases
177            .iter()
178            .zip(self.proofs.iter())
179            .zip(self.impossible_facts.iter())
180            .enumerate()
181        {
182            rows.push(format!(
183                r"\textbf{{\text{{Case {}.}}}} & {}",
184                i + 1,
185                case.to_latex_string()
186            ));
187            for st in proof {
188                rows.push(format!(r"& \quad {}", st.to_latex_string()));
189            }
190            if let Some(atom) = imposs {
191                rows.push(format!(
192                    r"\textbf{{\text{{Impossible.}}}} & {}",
193                    atom.to_latex_string()
194                ));
195            }
196        }
197        format!(
198            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
199            rows.join(" \\\\\n")
200        )
201    }
202}
203
204impl ByContraStmt {
205    pub fn to_latex_string(&self) -> String {
206        let goal = self.to_prove.to_latex_string();
207        let mut rows = vec![format!(
208            r"\text{{Proof by contradiction. Goal:}} & {}",
209            goal
210        )];
211        for st in &self.proof {
212            rows.push(format!(r"& \quad {}", st.to_latex_string()));
213        }
214        rows.push(format!(
215            r"\textbf{{\text{{Contradiction.}}}} & {}",
216            self.impossible_fact.to_latex_string()
217        ));
218        format!(
219            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
220            rows.join(" \\\\\n")
221        )
222    }
223}
224
225impl ByClosedRangeAsCasesStmt {
226    pub fn to_latex_string(&self) -> String {
227        let a = self.closed_range.start.to_latex_string();
228        let b = self.closed_range.end.to_latex_string();
229        let x = self.element.to_latex_string();
230        let row1 = format!(
231            r"&\text{{\textbf{{By closed range as cases}} on }} [\![ {0},{1}]\!]\text{{.}}",
232            a, b
233        );
234        let row2 = format!(
235            r"&\text{{Equivalently }} {0} \in \{{{1},\, {1}+1,\, \ldots,\, {2}\}}\text{{ (segment {1}\ldots {2}).}}",
236            x, a, b
237        );
238        let row3 = format!(
239            r"&\text{{So }} {0}={1}\lor {0}={1}+1\lor\cdots\lor {0}={2}\text{{.}}",
240            x, a, b
241        );
242        format!("\\begin{{aligned}}\n{row1} \\\\\n{row2} \\\\\n{row3} \n\\end{{aligned}}")
243    }
244}
245
246impl ByEnumerateFiniteSetStmt {
247    pub fn to_latex_string(&self) -> String {
248        let mut rows = vec![format!(
249            r"\text{{Proof by exhaustive enumeration (finite cases).}} & {}",
250            self.forall_fact.to_latex_string()
251        )];
252        for st in &self.proof {
253            rows.push(format!(r"& \quad {}", st.to_latex_string()));
254        }
255        format!(
256            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
257            rows.join(" \\\\\n")
258        )
259    }
260}
261
262impl ByExtensionStmt {
263    pub fn to_latex_string(&self) -> String {
264        let l = self.left.to_latex_string();
265        let r = self.right.to_latex_string();
266        let mut rows = vec![format!(
267            r"\text{{\textbf{{By extensionality}}:}} & {}={} \Longleftrightarrow \bigl({}\subseteq {}\land {}\subseteq {}\bigr)\text{{.}}",
268            l, r, l, r, r, l
269        )];
270        for st in &self.proof {
271            rows.push(format!(r"& \quad {}", st.to_latex_string()));
272        }
273        format!(
274            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
275            rows.join(" \\\\\n")
276        )
277    }
278}
279
280impl ByFnSetAsSetStmt {
281    pub fn to_latex_string(&self) -> String {
282        format!(
283            "\\begin{{aligned}}\n\\text{{\\textbf{{By fn set as set}}:}} & {} \\in {}\\\\\n& \\quad \\text{{Unfold this membership via the set-theoretic definition of the function space; obtain the corresponding facts.}}\n\\end{{aligned}}",
284            self.func.to_latex_string(),
285            self.fn_set.to_latex_string()
286        )
287    }
288}
289
290impl ByFnAsSetStmt {
291    pub fn to_latex_string(&self) -> String {
292        format!(
293            "\\begin{{aligned}}\n\\text{{\\textbf{{By fn as set}}:}} & \\text{{Use the graph / function definition of }} {}\\text{{.}}\n\\end{{aligned}}",
294            self.function.to_latex_string()
295        )
296    }
297}
298
299impl ByForStmt {
300    pub fn to_latex_string(&self) -> String {
301        let mut rows = vec![format!(
302            r"\text{{\textbf{{by for}}:}} & {}",
303            self.forall_fact.to_latex_string()
304        )];
305        for st in &self.proof {
306            rows.push(format!(r"& \quad {}", st.to_latex_string()));
307        }
308        format!(
309            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
310            rows.join(" \\\\\n")
311        )
312    }
313}
314
315impl ByTransitivePropStmt {
316    pub fn to_latex_string(&self) -> String {
317        let mut rows = vec![format!(
318            r"\text{{\textbf{{by transitive_prop}}:}} & {}",
319            self.forall_fact.to_latex_string()
320        )];
321        for st in &self.proof {
322            rows.push(format!(r"& \quad {}", st.to_latex_string()));
323        }
324        format!(
325            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
326            rows.join(" \\\\\n")
327        )
328    }
329}
330
331impl BySymmetricPropStmt {
332    pub fn to_latex_string(&self) -> String {
333        let mut rows = vec![format!(
334            r"\text{{\textbf{{by symmetric_prop}}:}} & {}",
335            self.forall_fact.to_latex_string()
336        )];
337        for st in &self.proof {
338            rows.push(format!(r"& \quad {}", st.to_latex_string()));
339        }
340        format!(
341            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
342            rows.join(" \\\\\n")
343        )
344    }
345}
346
347impl ByReflexivePropStmt {
348    pub fn to_latex_string(&self) -> String {
349        let mut rows = vec![format!(
350            r"\text{{\textbf{{by reflexive_prop}}:}} & {}",
351            self.forall_fact.to_latex_string()
352        )];
353        for st in &self.proof {
354            rows.push(format!(r"& \quad {}", st.to_latex_string()));
355        }
356        format!(
357            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
358            rows.join(" \\\\\n")
359        )
360    }
361}
362
363impl ByAntisymmetricPropStmt {
364    pub fn to_latex_string(&self) -> String {
365        let mut rows = vec![format!(
366            r"\text{{\textbf{{by antisymmetric_prop}}:}} & {}",
367            self.forall_fact.to_latex_string()
368        )];
369        for st in &self.proof {
370            rows.push(format!(r"& \quad {}", st.to_latex_string()));
371        }
372        format!(
373            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
374            rows.join(" \\\\\n")
375        )
376    }
377}
378
379impl ByInducStmt {
380    pub fn to_latex_string(&self) -> String {
381        let goals = self
382            .to_prove
383            .iter()
384            .map(|f| f.to_latex_string())
385            .collect::<Vec<_>>()
386            .join(r" \land ");
387        let induc_label = if self.strong {
388            r"\text{\textbf{strong induc} on }"
389        } else {
390            r"\text{\textbf{by induc} on }"
391        };
392        let mut rows = vec![format!(
393            r"{} {} \text{{ from }} {} \texttt{{:}} & {}",
394            induc_label,
395            latex_local_ident(&self.param),
396            self.induc_from.to_latex_string(),
397            goals
398        )];
399        rows.push(r"\text{prove:} &".to_string());
400        for st in &self.proof {
401            rows.push(format!(r"& \quad {}", st.to_latex_string()));
402        }
403        format!(
404            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
405            rows.join(" \\\\\n")
406        )
407    }
408}
409
410impl ByTupleAsSetStmt {
411    pub fn to_latex_string(&self) -> String {
412        format!(
413            "\\begin{{aligned}}\n\\text{{\\textbf{{By tuple as set}}:}} & \\text{{Use the set-theoretic ordered-pair / tuple encoding for }} {}\\text{{; obtain the corresponding set-theoretic facts.}}\n\\end{{aligned}}",
414            self.obj.to_latex_string()
415        )
416    }
417}
418
419impl Cap {
420    pub fn to_latex_string(&self) -> String {
421        format!(
422            r"\operatorname{{{}}}\left( {}\right)",
423            CAP,
424            self.left.to_latex_string()
425        )
426    }
427}
428
429impl Cart {
430    pub fn to_latex_string(&self) -> String {
431        let inner = self
432            .args
433            .iter()
434            .map(|o| o.to_latex_string())
435            .collect::<Vec<_>>()
436            .join(", ");
437        format!(r"\operatorname{{{}}}\left( {}\right)", CART, inner)
438    }
439}
440
441impl CartDim {
442    pub fn to_latex_string(&self) -> String {
443        format!(
444            r"\operatorname{{{}}}\left( {}\right)",
445            CART_DIM,
446            self.set.to_latex_string()
447        )
448    }
449}
450
451impl ClaimStmt {
452    pub fn to_latex_string(&self) -> String {
453        let mut rows = vec![
454            format!(
455                r"\text{{\textbf{{claim}}:}} & {}",
456                self.fact.to_latex_string()
457            ),
458            r"\text{\textbf{prove}:} &".to_string(),
459        ];
460        for st in &self.proof {
461            rows.push(format!(r"& \quad {}", st.to_latex_string()));
462        }
463        format!(
464            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
465            rows.join(" \\\\\n")
466        )
467    }
468}
469
470impl ClosedRange {
471    pub fn to_latex_string(&self) -> String {
472        format!(
473            r"\operatorname{{{}}}\left( {}, {} \right)",
474            CLOSED_RANGE,
475            self.start.to_latex_string(),
476            self.end.to_latex_string()
477        )
478    }
479}
480
481impl Count {
482    pub fn to_latex_string(&self) -> String {
483        format!(
484            r"\operatorname{{{}}}\left( {}\right)",
485            COUNT,
486            self.set.to_latex_string()
487        )
488    }
489}
490
491impl Sum {
492    pub fn to_latex_string(&self) -> String {
493        format!(
494            r"\operatorname{{{}}}\left( {}, {}, {} \right)",
495            SUM,
496            self.start.to_latex_string(),
497            self.end.to_latex_string(),
498            self.func.to_latex_string()
499        )
500    }
501}
502
503impl Product {
504    pub fn to_latex_string(&self) -> String {
505        format!(
506            r"\operatorname{{{}}}\left( {}, {}, {} \right)",
507            PRODUCT,
508            self.start.to_latex_string(),
509            self.end.to_latex_string(),
510            self.func.to_latex_string()
511        )
512    }
513}
514
515impl Cup {
516    pub fn to_latex_string(&self) -> String {
517        format!(
518            r"\operatorname{{{}}}\left( {}\right)",
519            CUP,
520            self.left.to_latex_string()
521        )
522    }
523}
524
525impl Choose {
526    pub fn to_latex_string(&self) -> String {
527        format!(
528            r"\operatorname{{{}}}\left( {}\right)",
529            CHOOSE,
530            self.set.to_latex_string()
531        )
532    }
533}
534
535impl DefAbstractPropStmt {
536    pub fn to_latex_string(&self) -> String {
537        let ps = self
538            .params
539            .iter()
540            .map(|p| latex_local_ident(p))
541            .collect::<Vec<_>>()
542            .join(", ");
543        format!(
544            r"\operatorname{{{}}}\, {}\left\{{ {} \right\}}",
545            ABSTRACT_PROP,
546            latex_local_ident(&self.name),
547            ps
548        )
549    }
550}
551
552impl DefAlgoStmt {
553    pub fn to_latex_string(&self) -> String {
554        let ps = self
555            .params
556            .iter()
557            .map(|p| latex_local_ident(p))
558            .collect::<Vec<_>>()
559            .join(", ");
560        let mut rows = vec![format!(
561            r"\operatorname{{{}}}\, {}\left( {}\right) \texttt{{:}}",
562            ALGO,
563            latex_local_ident(&self.name),
564            ps
565        )];
566        for c in &self.cases {
567            rows.push(format!(
568                r"& \quad \mathrm{{case}}\ {} \texttt{{:}}\ {}",
569                c.condition.to_latex_string(),
570                c.return_stmt.value.to_latex_string()
571            ));
572        }
573        if let Some(dr) = &self.default_return {
574            rows.push(format!(
575                r"& \quad \mathrm{{default}}\ \texttt{{:}}\ {}",
576                dr.value.to_latex_string()
577            ));
578        }
579        format!(
580            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
581            rows.join(" \\\\\n")
582        )
583    }
584}
585
586impl DefLetStmt {
587    pub fn to_latex_string(&self) -> String {
588        match self.facts.len() {
589            0 => format!(
590                r"\operatorname{{{}}}\, {}",
591                LET,
592                self.param_def.to_latex_string()
593            ),
594            _ => {
595                let mut rows = vec![format!(
596                    r"\operatorname{{{}}}\, {}",
597                    LET,
598                    self.param_def.to_latex_string()
599                )];
600                for fact in &self.facts {
601                    rows.push(format!(r"& \quad {}", fact.to_latex_string()));
602                }
603                format!(
604                    "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
605                    rows.join(" \\\\\n")
606                )
607            }
608        }
609    }
610}
611
612impl DefPropStmt {
613    pub fn to_latex_string(&self) -> String {
614        match self.iff_facts.len() {
615            0 => format!(
616                r"\operatorname{{{}}}\, {}\left\{{ {} \right\}}",
617                PROP,
618                latex_local_ident(&self.name),
619                self.params_def_with_type.to_latex_string()
620            ),
621            _ => {
622                let mut rows = vec![format!(
623                    r"\operatorname{{{}}}\, {}\left\{{ {} \right\}} \texttt{{:}}",
624                    PROP,
625                    latex_local_ident(&self.name),
626                    self.params_def_with_type.to_latex_string()
627                )];
628                for fact in &self.iff_facts {
629                    rows.push(format!(r"& \quad {}", fact.to_latex_string()));
630                }
631                format!(
632                    "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
633                    rows.join(" \\\\\n")
634                )
635            }
636        }
637    }
638}
639
640impl Div {
641    pub fn to_latex_string(&self) -> String {
642        format!(
643            r"\frac{{{}}}{{{}}}",
644            self.left.to_latex_string(),
645            self.right.to_latex_string()
646        )
647    }
648}
649
650impl DoNothingStmt {
651    pub fn to_latex_string(&self) -> String {
652        format!(r"\mathrm{{{}}}", DO_NOTHING)
653    }
654}
655
656impl ClearStmt {
657    pub fn to_latex_string(&self) -> String {
658        format!(r"\mathrm{{{}}}", CLEAR)
659    }
660}
661
662impl EqualFact {
663    pub fn to_latex_string(&self) -> String {
664        format!(
665            "{} = {}",
666            self.left.to_latex_string(),
667            self.right.to_latex_string()
668        )
669    }
670}
671
672impl EvalStmt {
673    pub fn to_latex_string(&self) -> String {
674        format!(
675            r"\operatorname{{{}}}\, {}",
676            EVAL,
677            self.obj_to_eval.to_latex_string()
678        )
679    }
680}
681
682impl EvalByStmt {
683    pub fn to_latex_string(&self) -> String {
684        format!(
685            r"\operatorname{{{}}}\, {} \operatorname{{{}}} {}",
686            EVAL,
687            self.lhs.to_latex_string(),
688            FROM,
689            self.rhs.to_latex_string()
690        )
691    }
692}
693
694impl ExistFactEnum {
695    pub fn to_latex_string(&self) -> String {
696        let head = if self.is_not_exist() {
697            r"\nexists"
698        } else if self.is_exist_unique() {
699            r"\exists!"
700        } else {
701            r"\exists"
702        };
703        let params = self.params_def_with_type().to_latex_string();
704        let facts = self
705            .facts()
706            .iter()
707            .map(|f| f.to_latex_string())
708            .collect::<Vec<_>>()
709            .join(r", ");
710        format!(
711            r"{}\, \left( {}\right)\, \mathrm{{st}}\, \left\{{ {} \right\}}",
712            head, params, facts
713        )
714    }
715}
716
717impl ExistBodyFact {
718    pub fn to_latex_string(&self) -> String {
719        match self {
720            ExistBodyFact::AtomicFact(x) => x.to_latex_string(),
721            ExistBodyFact::AndFact(x) => x.to_latex_string(),
722            ExistBodyFact::ChainFact(x) => x.to_latex_string(),
723            ExistBodyFact::OrFact(x) => x.to_latex_string(),
724            ExistBodyFact::InlineForall(x) => x.to_latex_string(),
725        }
726    }
727}
728
729impl ExistOrAndChainAtomicFact {
730    pub fn to_latex_string(&self) -> String {
731        match self {
732            ExistOrAndChainAtomicFact::AtomicFact(x) => x.to_latex_string(),
733            ExistOrAndChainAtomicFact::AndFact(x) => x.to_latex_string(),
734            ExistOrAndChainAtomicFact::ChainFact(x) => x.to_latex_string(),
735            ExistOrAndChainAtomicFact::OrFact(x) => x.to_latex_string(),
736            ExistOrAndChainAtomicFact::ExistFact(x) => x.to_latex_string(),
737        }
738    }
739}
740
741impl FiniteSeqListObj {
742    pub fn to_latex_string(&self) -> String {
743        let inner = self
744            .objs
745            .iter()
746            .map(|o| o.to_latex_string())
747            .collect::<Vec<_>>()
748            .join(", ");
749        format!(r"\left[ {} \right]", inner)
750    }
751}
752
753impl FiniteSeqSet {
754    pub fn to_latex_string(&self) -> String {
755        format!(
756            r"\operatorname{{{}}}\left( {}, {} \right)",
757            FINITE_SEQ,
758            self.set.to_latex_string(),
759            self.n.to_latex_string()
760        )
761    }
762}
763
764impl FnObj {
765    pub fn to_latex_string(&self) -> String {
766        let head = match self.head.as_ref() {
767            FnObjHead::Identifier(i) => i.to_latex_string(),
768            FnObjHead::IdentifierWithMod(i) => i.to_latex_string(),
769            FnObjHead::Forall(p) => latex_local_ident(&p.name),
770            FnObjHead::DefHeader(p) => latex_local_ident(&p.name),
771            FnObjHead::Exist(p) => latex_local_ident(&p.name),
772            FnObjHead::SetBuilder(p) => latex_local_ident(&p.name),
773            FnObjHead::FnSet(p) => latex_local_ident(&p.name),
774            FnObjHead::AnonymousFnLiteral(a) => a.to_latex_string(),
775            FnObjHead::FiniteSeqListObj(v) => v.to_latex_string(),
776            FnObjHead::Induc(p) => latex_local_ident(&p.name),
777            FnObjHead::DefAlgo(p) => latex_local_ident(&p.name),
778            FnObjHead::InstantiatedTemplateObj(t) => latex_texttt_escape(&t.to_string()),
779        };
780        let mut s = head;
781        for group in self.body.iter() {
782            let inner = group
783                .iter()
784                .map(|o| o.to_latex_string())
785                .collect::<Vec<_>>()
786                .join(", ");
787            s.push_str(&format!(r"\left( {} \right)", inner));
788        }
789        s
790    }
791}
792
793impl AnonymousFn {
794    pub fn to_latex_string(&self) -> String {
795        let mut slots: Vec<String> = Vec::new();
796        for g in &self.body.params_def_with_set {
797            let set = fn_param_group_type_to_latex(g);
798            for p in &g.params {
799                slots.push(format!(r"{} \in {}", latex_local_ident(p), set));
800            }
801        }
802        let dom = self
803            .body
804            .dom_facts
805            .iter()
806            .map(|f| f.to_latex_string())
807            .collect::<Vec<_>>()
808            .join(r", ");
809        let ret = self.body.ret_set.to_latex_string();
810        let body = self.equal_to.to_latex_string();
811        let sig = if dom.is_empty() {
812            format!(r"\left({}\right)", slots.join(r", "))
813        } else {
814            format!(r"\left({} \,\middle|\, {}\right)", slots.join(r", "), dom)
815        };
816        format!(
817            r"'\, {} \to {} \mapsto \left\{{ {}\right\}}",
818            sig, ret, body
819        )
820    }
821}
822
823impl FnSet {
824    pub fn to_latex_string(&self) -> String {
825        let mut slots: Vec<String> = Vec::new();
826        for g in &self.body.params_def_with_set {
827            let set = fn_param_group_type_to_latex(g);
828            for p in &g.params {
829                slots.push(format!(r"{} \in {}", latex_local_ident(p), set));
830            }
831        }
832        let dom = self
833            .body
834            .dom_facts
835            .iter()
836            .map(|f| f.to_latex_string())
837            .collect::<Vec<_>>()
838            .join(r", ");
839        let ret = self.body.ret_set.to_latex_string();
840        if dom.is_empty() {
841            format!(
842                r"\mathrm{{fn}}\left({}\right)\to {}",
843                slots.join(r", "),
844                ret
845            )
846        } else {
847            format!(
848                r"\mathrm{{fn}}\left({} \,\middle|\, {}\right)\to {}",
849                slots.join(r", "),
850                dom,
851                ret
852            )
853        }
854    }
855}
856
857impl ForallFact {
858    pub fn to_latex_string(&self) -> String {
859        let params = self.params_def_with_type.to_latex_string();
860        let then = self
861            .then_facts
862            .iter()
863            .map(|f| f.to_latex_string())
864            .collect::<Vec<_>>()
865            .join(r" \land ");
866        if self.dom_facts.is_empty() {
867            format!(r"\forall \left( {}\right),\, {}", params, then)
868        } else {
869            let dom = self
870                .dom_facts
871                .iter()
872                .map(|f| f.to_latex_string())
873                .collect::<Vec<_>>()
874                .join(r" \land ");
875            format!(
876                r"\forall \left( {}\right),\ \left( {}\right) \Rightarrow \left( {}\right)",
877                params, dom, then
878            )
879        }
880    }
881}
882
883impl ForallFactWithIff {
884    pub fn to_latex_string(&self) -> String {
885        let iff = self
886            .iff_facts
887            .iter()
888            .map(|f| f.to_latex_string())
889            .collect::<Vec<_>>()
890            .join(r" \land ");
891        format!(
892            r"{}\, \Longleftrightarrow\, \left( {}\right)",
893            self.forall_fact.to_latex_string(),
894            iff
895        )
896    }
897}
898
899impl NotForallFact {
900    pub fn to_latex_string(&self) -> String {
901        format!(
902            r"\neg\, \left( {}\right)",
903            self.forall_fact.to_latex_string()
904        )
905    }
906}
907
908impl GreaterEqualFact {
909    pub fn to_latex_string(&self) -> String {
910        format!(
911            r"{} \geq {}",
912            self.left.to_latex_string(),
913            self.right.to_latex_string()
914        )
915    }
916}
917
918impl GreaterFact {
919    pub fn to_latex_string(&self) -> String {
920        format!(
921            "{} > {}",
922            self.left.to_latex_string(),
923            self.right.to_latex_string()
924        )
925    }
926}
927
928impl HaveByExistStmt {
929    pub fn to_latex_string(&self) -> String {
930        let names = self
931            .equal_tos
932            .iter()
933            .map(|s| latex_local_ident(s))
934            .collect::<Vec<_>>()
935            .join(", ");
936        format!(
937            r"\mathrm{{have}}\ \mathrm{{by}}\ {} : {}",
938            self.exist_fact_in_have_obj_st.to_latex_string(),
939            names
940        )
941    }
942}
943
944impl HaveFnByInducStmt {
945    pub fn to_latex_string(&self) -> String {
946        let mut rows: Vec<String> = Vec::new();
947        rows.push(format!(
948            r"\mathrm{{have}}\ \mathrm{{fn}}\ {}\ {} \quad \mathrm{{by}}\ \mathrm{{decreasing}}\ {} \ \mathrm{{from}}\ {}",
949            latex_local_ident(&self.name),
950            fn_set_clause_latex(&self.fn_set_clause),
951            self.measure.to_latex_string(),
952            self.lower_bound.to_latex_string(),
953        ));
954        Self::push_case_rows(&mut rows, &self.cases, 1);
955        format!(
956            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
957            rows.join(" \\\\\n")
958        )
959    }
960
961    fn push_case_rows(rows: &mut Vec<String>, cases: &[HaveFnByInducCase], indent: usize) {
962        let pad = r"\quad ".repeat(indent);
963        for c in cases {
964            match &c.body {
965                HaveFnByInducCaseBody::EqualTo(eq) => rows.push(format!(
966                    r"& {} \mathrm{{case}}\ {} : {}",
967                    pad,
968                    c.case_fact.to_latex_string(),
969                    eq.to_latex_string()
970                )),
971                HaveFnByInducCaseBody::NestedCases(nested) => {
972                    rows.push(format!(
973                        r"& {} \mathrm{{case}}\ {} \texttt{{:}}",
974                        pad,
975                        c.case_fact.to_latex_string()
976                    ));
977                    Self::push_case_rows(rows, nested, indent + 1);
978                }
979            }
980        }
981    }
982}
983
984impl HaveFnEqualCaseByCaseStmt {
985    pub fn to_latex_string(&self) -> String {
986        let head = format!(
987            r"\mathrm{{have}}\ \mathrm{{fn}}\ {}\ \mathrm{{by}}\ \mathrm{{cases}}\texttt{{:}}",
988            latex_local_ident(&self.name)
989        );
990        let clause = fn_set_clause_latex(&self.fn_set_clause);
991        let mut rows = vec![format!(r"{} & {}", head, clause)];
992        for (i, case) in self.cases.iter().enumerate() {
993            rows.push(format!(
994                r"& \quad \mathrm{{case}}\ {} \texttt{{:}}\ {}",
995                case.to_latex_string(),
996                self.equal_tos[i].to_latex_string()
997            ));
998        }
999        format!(
1000            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
1001            rows.join(" \\\\\n")
1002        )
1003    }
1004}
1005
1006impl HaveFnEqualStmt {
1007    pub fn to_latex_string(&self) -> String {
1008        let fn_set_clause = FnSetClause::new(
1009            self.equal_to_anonymous_fn.body.params_def_with_set.clone(),
1010            self.equal_to_anonymous_fn.body.dom_facts.clone(),
1011            (*self.equal_to_anonymous_fn.body.ret_set).clone(),
1012        )
1013        .expect("anonymous function signature was already validated");
1014        format!(
1015            r"\mathrm{{have}}\ \mathrm{{fn}}\ {}\ {} {}",
1016            latex_local_ident(&self.name),
1017            fn_set_clause_latex(&fn_set_clause),
1018            self.equal_to_anonymous_fn.equal_to.to_latex_string()
1019        )
1020    }
1021}
1022
1023impl HaveFnByForallExistUniqueStmt {
1024    pub fn to_latex_string(&self) -> String {
1025        format!(
1026            r"\mathrm{{have}}\ \mathrm{{fn}}\ {}\ \mathrm{{as}}\ \mathrm{{set}}:\ {}",
1027            latex_local_ident(&self.fn_name),
1028            self.forall.to_latex_string()
1029        )
1030    }
1031}
1032
1033impl HaveObjEqualStmt {
1034    pub fn to_latex_string(&self) -> String {
1035        let rhs = self
1036            .objs_equal_to
1037            .iter()
1038            .map(|o| o.to_latex_string())
1039            .collect::<Vec<_>>()
1040            .join(", ");
1041        format!(
1042            r"\mathrm{{have}}\ {} = {}",
1043            self.param_def.to_latex_string(),
1044            rhs
1045        )
1046    }
1047}
1048
1049impl HaveObjInNonemptySetOrParamTypeStmt {
1050    pub fn to_latex_string(&self) -> String {
1051        format!(r"\mathrm{{have}}\ {}", self.param_def.to_latex_string())
1052    }
1053}
1054
1055impl Identifier {
1056    pub fn to_latex_string(&self) -> String {
1057        latex_local_ident(&self.name)
1058    }
1059}
1060
1061impl IdentifierWithMod {
1062    pub fn to_latex_string(&self) -> String {
1063        format!(
1064            r"{}\mathbin{{\mathrm{{::}}}}{}",
1065            latex_local_ident(&self.mod_name),
1066            latex_local_ident(&self.name)
1067        )
1068    }
1069}
1070
1071impl AtomicName {
1072    pub fn to_latex_string(&self) -> String {
1073        match self {
1074            AtomicName::WithoutMod(s) => latex_local_ident(s),
1075            AtomicName::WithMod(m, n) => format!(
1076                r"{}\mathbin{{\mathrm{{::}}}}{}",
1077                latex_local_ident(m),
1078                latex_local_ident(n)
1079            ),
1080        }
1081    }
1082}
1083
1084impl InFact {
1085    pub fn to_latex_string(&self) -> String {
1086        format!(
1087            r"{} \in {}",
1088            self.element.to_latex_string(),
1089            self.set.to_latex_string()
1090        )
1091    }
1092}
1093
1094impl Intersect {
1095    pub fn to_latex_string(&self) -> String {
1096        format!(
1097            r"{} \cap {}",
1098            self.left.to_latex_string(),
1099            self.right.to_latex_string()
1100        )
1101    }
1102}
1103
1104impl IsCartFact {
1105    pub fn to_latex_string(&self) -> String {
1106        format!(
1107            r"\$ \mathrm{{{}}}\left( {}\right)",
1108            IS_CART,
1109            self.set.to_latex_string()
1110        )
1111    }
1112}
1113
1114impl IsFiniteSetFact {
1115    pub fn to_latex_string(&self) -> String {
1116        format!(
1117            r"\$ \mathrm{{{}}}\left( {}\right)",
1118            IS_FINITE_SET,
1119            self.set.to_latex_string()
1120        )
1121    }
1122}
1123
1124impl IsNonemptySetFact {
1125    pub fn to_latex_string(&self) -> String {
1126        format!(
1127            r"\$ \mathrm{{{}}}\left( {}\right)",
1128            IS_NONEMPTY_SET,
1129            self.set.to_latex_string()
1130        )
1131    }
1132}
1133
1134impl IsSetFact {
1135    pub fn to_latex_string(&self) -> String {
1136        format!(
1137            r"\$ \mathrm{{{}}}\left( {}\right)",
1138            IS_SET,
1139            self.set.to_latex_string()
1140        )
1141    }
1142}
1143
1144impl IsTupleFact {
1145    pub fn to_latex_string(&self) -> String {
1146        format!(
1147            r"\$ \mathrm{{{}}}\left( {}\right)",
1148            IS_TUPLE,
1149            self.set.to_latex_string()
1150        )
1151    }
1152}
1153
1154impl KnowStmt {
1155    pub fn to_latex_string(&self) -> String {
1156        if self.facts.len() == 1 {
1157            format!(
1158                r"\operatorname{{{}}} {}",
1159                KNOW,
1160                self.facts[0].to_latex_string()
1161            )
1162        } else {
1163            let rows = self
1164                .facts
1165                .iter()
1166                .map(|fact| format!("& {}", fact.to_latex_string()))
1167                .collect::<Vec<_>>()
1168                .join(" \\\\\n");
1169            format!(
1170                r"\operatorname{{{}}}\colon \begin{{aligned}}{}\end{{aligned}}",
1171                KNOW, rows
1172            )
1173        }
1174    }
1175}
1176
1177impl LessEqualFact {
1178    pub fn to_latex_string(&self) -> String {
1179        format!(
1180            r"{} \leq {}",
1181            self.left.to_latex_string(),
1182            self.right.to_latex_string()
1183        )
1184    }
1185}
1186
1187impl LessFact {
1188    pub fn to_latex_string(&self) -> String {
1189        format!(
1190            "{} < {}",
1191            self.left.to_latex_string(),
1192            self.right.to_latex_string()
1193        )
1194    }
1195}
1196
1197impl ListSet {
1198    pub fn to_latex_string(&self) -> String {
1199        let inner = self
1200            .list
1201            .iter()
1202            .map(|o| o.to_latex_string())
1203            .collect::<Vec<_>>()
1204            .join(", ");
1205        format!(r"\left\{{ {} \right\}}", inner)
1206    }
1207}
1208
1209impl Log {
1210    pub fn to_latex_string(&self) -> String {
1211        format!(
1212            r"\log_{{{}}} \left( {} \right)",
1213            self.base.to_latex_string(),
1214            self.arg.to_latex_string()
1215        )
1216    }
1217}
1218
1219impl MatrixAdd {
1220    pub fn to_latex_string(&self) -> String {
1221        format!(
1222            r"{} \mathbin{{\mathrm{{{}}}}} {}",
1223            self.left.to_latex_string(),
1224            latex_escape_underscore(MATRIX_ADD),
1225            self.right.to_latex_string()
1226        )
1227    }
1228}
1229
1230impl MatrixListObj {
1231    pub fn to_latex_string(&self) -> String {
1232        let rows = self
1233            .rows
1234            .iter()
1235            .map(|row| {
1236                let inner = row
1237                    .iter()
1238                    .map(|o| o.to_latex_string())
1239                    .collect::<Vec<_>>()
1240                    .join(", ");
1241                format!(r"\left( {} \right)", inner)
1242            })
1243            .collect::<Vec<_>>()
1244            .join(", ");
1245        format!(r"\left[ {} \right]", rows)
1246    }
1247}
1248
1249impl MatrixMul {
1250    pub fn to_latex_string(&self) -> String {
1251        format!(
1252            r"{} \mathbin{{\mathrm{{{}}}}} {}",
1253            self.left.to_latex_string(),
1254            latex_escape_underscore(MATRIX_MUL),
1255            self.right.to_latex_string()
1256        )
1257    }
1258}
1259
1260impl MatrixPow {
1261    pub fn to_latex_string(&self) -> String {
1262        format!(
1263            r"{} \mathbin{{\mathrm{{{}}}}} {}",
1264            self.base.to_latex_string(),
1265            latex_escape_underscore(MATRIX_POW),
1266            self.exponent.to_latex_string()
1267        )
1268    }
1269}
1270
1271impl MatrixScalarMul {
1272    pub fn to_latex_string(&self) -> String {
1273        format!(
1274            r"{} \mathbin{{\mathrm{{{}}}}} {}",
1275            self.scalar.to_latex_string(),
1276            latex_escape_underscore(MATRIX_SCALAR_MUL),
1277            self.matrix.to_latex_string()
1278        )
1279    }
1280}
1281
1282impl MatrixSet {
1283    pub fn to_latex_string(&self) -> String {
1284        format!(
1285            r"\operatorname{{{}}}\left( {}, {}, {} \right)",
1286            MATRIX,
1287            self.set.to_latex_string(),
1288            self.row_len.to_latex_string(),
1289            self.col_len.to_latex_string()
1290        )
1291    }
1292}
1293
1294impl MatrixSub {
1295    pub fn to_latex_string(&self) -> String {
1296        format!(
1297            r"{} \mathbin{{\mathrm{{{}}}}} {}",
1298            self.left.to_latex_string(),
1299            latex_escape_underscore(MATRIX_SUB),
1300            self.right.to_latex_string()
1301        )
1302    }
1303}
1304
1305impl Max {
1306    pub fn to_latex_string(&self) -> String {
1307        format!(
1308            r"\max \left( {}, {} \right)",
1309            self.left.to_latex_string(),
1310            self.right.to_latex_string()
1311        )
1312    }
1313}
1314
1315impl Min {
1316    pub fn to_latex_string(&self) -> String {
1317        format!(
1318            r"\min \left( {}, {} \right)",
1319            self.left.to_latex_string(),
1320            self.right.to_latex_string()
1321        )
1322    }
1323}
1324
1325impl Mod {
1326    pub fn to_latex_string(&self) -> String {
1327        format!(
1328            r"\left( {} \mathbin{{\mathrm{{mod}}}} {} \right)",
1329            self.left.to_latex_string(),
1330            self.right.to_latex_string()
1331        )
1332    }
1333}
1334
1335impl Mul {
1336    pub fn to_latex_string(&self) -> String {
1337        format!(
1338            r"{0} \cdot {1}",
1339            self.left.to_latex_string(),
1340            self.right.to_latex_string()
1341        )
1342    }
1343}
1344
1345impl NormalAtomicFact {
1346    pub fn to_latex_string(&self) -> String {
1347        let pred = self.predicate.to_latex_string();
1348        let args = self
1349            .body
1350            .iter()
1351            .map(|o| o.to_latex_string())
1352            .collect::<Vec<_>>()
1353            .join(", ");
1354        format!(r"\$ {}\left( {}\right)", pred, args)
1355    }
1356}
1357
1358impl NotEqualFact {
1359    pub fn to_latex_string(&self) -> String {
1360        format!(
1361            r"{} \neq {}",
1362            self.left.to_latex_string(),
1363            self.right.to_latex_string()
1364        )
1365    }
1366}
1367
1368impl NotGreaterEqualFact {
1369    pub fn to_latex_string(&self) -> String {
1370        format!(
1371            r"{} \ngeq {}",
1372            self.left.to_latex_string(),
1373            self.right.to_latex_string()
1374        )
1375    }
1376}
1377
1378impl NotGreaterFact {
1379    pub fn to_latex_string(&self) -> String {
1380        format!(
1381            r"{} \ngtr {}",
1382            self.left.to_latex_string(),
1383            self.right.to_latex_string()
1384        )
1385    }
1386}
1387
1388impl NotInFact {
1389    pub fn to_latex_string(&self) -> String {
1390        format!(
1391            r"{} \notin {}",
1392            self.element.to_latex_string(),
1393            self.set.to_latex_string()
1394        )
1395    }
1396}
1397
1398impl NotIsCartFact {
1399    pub fn to_latex_string(&self) -> String {
1400        format!(
1401            r"\neg \left( \$ \mathrm{{{}}}\left( {}\right) \right)",
1402            IS_CART,
1403            self.set.to_latex_string()
1404        )
1405    }
1406}
1407
1408impl NotIsFiniteSetFact {
1409    pub fn to_latex_string(&self) -> String {
1410        format!(
1411            r"\neg \left( \$ \mathrm{{{}}}\left( {}\right) \right)",
1412            IS_FINITE_SET,
1413            self.set.to_latex_string()
1414        )
1415    }
1416}
1417
1418impl NotIsNonemptySetFact {
1419    pub fn to_latex_string(&self) -> String {
1420        format!(
1421            r"\neg \left( \$ \mathrm{{{}}}\left( {}\right) \right)",
1422            IS_NONEMPTY_SET,
1423            self.set.to_latex_string()
1424        )
1425    }
1426}
1427
1428impl NotIsSetFact {
1429    pub fn to_latex_string(&self) -> String {
1430        format!(
1431            r"\neg \left( \$ \mathrm{{{}}}\left( {}\right) \right)",
1432            IS_SET,
1433            self.set.to_latex_string()
1434        )
1435    }
1436}
1437
1438impl NotIsTupleFact {
1439    pub fn to_latex_string(&self) -> String {
1440        format!(
1441            r"\neg \left( \$ \mathrm{{{}}}\left( {}\right) \right)",
1442            IS_TUPLE,
1443            self.set.to_latex_string()
1444        )
1445    }
1446}
1447
1448impl NotLessEqualFact {
1449    pub fn to_latex_string(&self) -> String {
1450        format!(
1451            r"{} \nleq {}",
1452            self.left.to_latex_string(),
1453            self.right.to_latex_string()
1454        )
1455    }
1456}
1457
1458impl NotLessFact {
1459    pub fn to_latex_string(&self) -> String {
1460        format!(
1461            r"{} \nless {}",
1462            self.left.to_latex_string(),
1463            self.right.to_latex_string()
1464        )
1465    }
1466}
1467
1468impl NotNormalAtomicFact {
1469    pub fn to_latex_string(&self) -> String {
1470        let pred = self.predicate.to_latex_string();
1471        let args = self
1472            .body
1473            .iter()
1474            .map(|o| o.to_latex_string())
1475            .collect::<Vec<_>>()
1476            .join(", ");
1477        format!(r"\neg \left( \$ {}\left( {}\right) \right)", pred, args)
1478    }
1479}
1480
1481impl NotRestrictFact {
1482    pub fn to_latex_string(&self) -> String {
1483        format!(
1484            r"\neg \left( {} \mathrel{{\$}} \mathrm{{{}}}\, {} \right)",
1485            self.obj.to_latex_string(),
1486            RESTRICT_FN_IN,
1487            self.obj_cannot_restrict_to_fn_set.to_latex_string()
1488        )
1489    }
1490}
1491
1492impl NotSubsetFact {
1493    pub fn to_latex_string(&self) -> String {
1494        format!(
1495            r"\neg \left( {} \subseteq {} \right)",
1496            self.left.to_latex_string(),
1497            self.right.to_latex_string()
1498        )
1499    }
1500}
1501
1502impl NotSupersetFact {
1503    pub fn to_latex_string(&self) -> String {
1504        format!(
1505            r"\neg \left( {} \supseteq {} \right)",
1506            self.left.to_latex_string(),
1507            self.right.to_latex_string()
1508        )
1509    }
1510}
1511
1512impl Number {
1513    pub fn to_latex_string(&self) -> String {
1514        self.normalized_value.clone()
1515    }
1516}
1517
1518impl ObjAtIndex {
1519    pub fn to_latex_string(&self) -> String {
1520        format!(
1521            r"{}\left[ {} \right]",
1522            self.obj.to_latex_string(),
1523            self.index.to_latex_string()
1524        )
1525    }
1526}
1527
1528impl OrFact {
1529    pub fn to_latex_string(&self) -> String {
1530        self.facts
1531            .iter()
1532            .map(|f| f.to_latex_string())
1533            .collect::<Vec<_>>()
1534            .join(r" \lor ")
1535    }
1536}
1537
1538impl ParamDefWithType {
1539    pub fn to_latex_string(&self) -> String {
1540        self.groups
1541            .iter()
1542            .map(|g| g.to_latex_string())
1543            .collect::<Vec<_>>()
1544            .join(", ")
1545    }
1546}
1547
1548impl ParamGroupWithParamType {
1549    pub fn to_latex_string(&self) -> String {
1550        let names = self
1551            .params
1552            .iter()
1553            .map(|p| latex_local_ident(p))
1554            .collect::<Vec<_>>()
1555            .join(", ");
1556        format!(r"{}, {}", names, self.param_type.to_latex_string())
1557    }
1558}
1559
1560impl ParamType {
1561    pub fn to_latex_string(&self) -> String {
1562        match self {
1563            ParamType::Set(_) => format!(r"\mathrm{{{}}}", SET),
1564            ParamType::NonemptySet(_) => format!(r"\mathrm{{{}}}", NONEMPTY_SET),
1565            ParamType::FiniteSet(_) => format!(r"\mathrm{{{}}}", FINITE_SET),
1566            ParamType::Obj(o) => o.to_latex_string(),
1567        }
1568    }
1569}
1570
1571impl Pow {
1572    pub fn to_latex_string(&self) -> String {
1573        format!(
1574            "{{{}}}^{{{}}}",
1575            self.base.to_latex_string(),
1576            self.exponent.to_latex_string()
1577        )
1578    }
1579}
1580
1581impl PowerSet {
1582    pub fn to_latex_string(&self) -> String {
1583        format!(r"\mathcal{{P}}\left( {}\right)", self.set.to_latex_string())
1584    }
1585}
1586
1587impl Proj {
1588    pub fn to_latex_string(&self) -> String {
1589        format!(
1590            r"\operatorname{{{}}}\left( {}, {} \right)",
1591            PROJ,
1592            self.set.to_latex_string(),
1593            self.dim.to_latex_string()
1594        )
1595    }
1596}
1597
1598impl ProveStmt {
1599    pub fn to_latex_string(&self) -> String {
1600        if self.proof.is_empty() {
1601            return r"\text{\texttt{(empty proof)}}".to_string();
1602        }
1603        let rows: Vec<String> = self
1604            .proof
1605            .iter()
1606            .map(|st| format!(r"& \quad {}", st.to_latex_string()))
1607            .collect();
1608        format!(
1609            "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
1610            rows.join(" \\\\\n")
1611        )
1612    }
1613}
1614
1615impl Range {
1616    pub fn to_latex_string(&self) -> String {
1617        format!(
1618            r"\operatorname{{{}}}\left( {}, {} \right)",
1619            RANGE,
1620            self.start.to_latex_string(),
1621            self.end.to_latex_string()
1622        )
1623    }
1624}
1625
1626impl RestrictFact {
1627    pub fn to_latex_string(&self) -> String {
1628        format!(
1629            r"{} \mathrel{{\$}} \mathrm{{{}}}\, {}",
1630            self.obj.to_latex_string(),
1631            RESTRICT_FN_IN,
1632            self.obj_can_restrict_to_fn_set.to_latex_string()
1633        )
1634    }
1635}
1636
1637impl RunFileStmt {
1638    pub fn to_latex_string(&self) -> String {
1639        format!(
1640            r"\operatorname{{{}}}\ \texttt{{{}}}",
1641            RUN_FILE,
1642            latex_texttt_escape(&self.file_path)
1643        )
1644    }
1645}
1646
1647impl RunFileInStd {
1648    pub fn to_latex_string(&self) -> String {
1649        format!(
1650            r"\operatorname{{{}}}\ \texttt{{{}}}",
1651            RUN_FILE,
1652            latex_texttt_escape(&self.file_path)
1653        )
1654    }
1655}
1656
1657impl SeqSet {
1658    pub fn to_latex_string(&self) -> String {
1659        format!(
1660            r"\operatorname{{{}}}\left( {}\right)",
1661            SEQ,
1662            self.set.to_latex_string()
1663        )
1664    }
1665}
1666
1667impl SetBuilder {
1668    pub fn to_latex_string(&self) -> String {
1669        let cond = self
1670            .facts
1671            .iter()
1672            .map(|f| f.to_latex_string())
1673            .collect::<Vec<_>>()
1674            .join(r" \land ");
1675        format!(
1676            r"\left\{{ {} \in {} \,\middle|\, {} \right\}}",
1677            latex_local_ident(&self.param),
1678            self.param_set.to_latex_string(),
1679            cond
1680        )
1681    }
1682}
1683
1684impl SetDiff {
1685    pub fn to_latex_string(&self) -> String {
1686        format!(
1687            r"\operatorname{{{}}}\left( {}, {} \right)",
1688            SET_DIFF,
1689            self.left.to_latex_string(),
1690            self.right.to_latex_string()
1691        )
1692    }
1693}
1694
1695impl SetMinus {
1696    pub fn to_latex_string(&self) -> String {
1697        format!(
1698            r"{} \setminus {}",
1699            self.left.to_latex_string(),
1700            self.right.to_latex_string()
1701        )
1702    }
1703}
1704
1705impl Sub {
1706    pub fn to_latex_string(&self) -> String {
1707        format!(
1708            "{} - {}",
1709            self.left.to_latex_string(),
1710            self.right.to_latex_string()
1711        )
1712    }
1713}
1714
1715impl SubsetFact {
1716    pub fn to_latex_string(&self) -> String {
1717        format!(
1718            r"{} \subseteq {}",
1719            self.left.to_latex_string(),
1720            self.right.to_latex_string()
1721        )
1722    }
1723}
1724
1725impl SupersetFact {
1726    pub fn to_latex_string(&self) -> String {
1727        format!(
1728            r"{} \supseteq {}",
1729            self.left.to_latex_string(),
1730            self.right.to_latex_string()
1731        )
1732    }
1733}
1734
1735impl Tuple {
1736    pub fn to_latex_string(&self) -> String {
1737        let inner = self
1738            .args
1739            .iter()
1740            .map(|o| o.to_latex_string())
1741            .collect::<Vec<_>>()
1742            .join(", ");
1743        format!(r"\left( {} \right)", inner)
1744    }
1745}
1746
1747impl TupleDim {
1748    pub fn to_latex_string(&self) -> String {
1749        format!(
1750            r"\operatorname{{{}}}\left( {}\right)",
1751            TUPLE_DIM,
1752            self.arg.to_latex_string()
1753        )
1754    }
1755}
1756
1757impl Union {
1758    pub fn to_latex_string(&self) -> String {
1759        format!(
1760            r"{} \cup {}",
1761            self.left.to_latex_string(),
1762            self.right.to_latex_string()
1763        )
1764    }
1765}
1766
1767impl WitnessExistFact {
1768    pub fn to_latex_string(&self) -> String {
1769        let names = self
1770            .equal_tos
1771            .iter()
1772            .map(|o| o.to_latex_string())
1773            .collect::<Vec<_>>()
1774            .join(", ");
1775        let facts = self
1776            .exist_fact_in_witness
1777            .facts()
1778            .iter()
1779            .map(|f| f.to_latex_string())
1780            .collect::<Vec<_>>()
1781            .join(", ");
1782        let head = format!(
1783            r"\mathrm{{witness}}\ {} : {} \mathrm{{st}} \left\{{ {}\right\}}",
1784            names,
1785            self.exist_fact_in_witness
1786                .params_def_with_type()
1787                .to_latex_string(),
1788            facts
1789        );
1790        if self.proof.is_empty() {
1791            head
1792        } else {
1793            let mut rows = vec![format!(r"{} &", head)];
1794            for st in &self.proof {
1795                rows.push(format!(r"& \quad {}", st.to_latex_string()));
1796            }
1797            format!(
1798                "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
1799                rows.join(" \\\\\n")
1800            )
1801        }
1802    }
1803}
1804
1805impl WitnessNonemptySet {
1806    pub fn to_latex_string(&self) -> String {
1807        let head = format!(
1808            r"\mathrm{{witness}}\ {} {}",
1809            self.obj.to_latex_string(),
1810            self.set.to_latex_string()
1811        );
1812        if self.proof.is_empty() {
1813            head
1814        } else {
1815            let mut rows = vec![format!(r"{} &", head)];
1816            for st in &self.proof {
1817                rows.push(format!(r"& \quad {}", st.to_latex_string()));
1818            }
1819            format!(
1820                "\\begin{{aligned}}\n{}\n\\end{{aligned}}",
1821                rows.join(" \\\\\n")
1822            )
1823        }
1824    }
1825}
1826
1827impl ImportGlobalModuleStmt {
1828    pub fn to_latex_string(&self) -> String {
1829        match &self.as_mod_name {
1830            Some(m) => format!(
1831                r"\operatorname{{{}}}\ {}\ \mathrm{{as}}\ {}",
1832                IMPORT,
1833                latex_local_ident(&self.mod_name),
1834                latex_local_ident(m)
1835            ),
1836            None => format!(
1837                r"\operatorname{{{}}}\ {}",
1838                IMPORT,
1839                latex_local_ident(&self.mod_name)
1840            ),
1841        }
1842    }
1843}
1844
1845impl ImportRelativePathStmt {
1846    pub fn to_latex_string(&self) -> String {
1847        let path = latex_texttt_escape(&self.path);
1848        match &self.as_mod_name {
1849            Some(m) => format!(
1850                r"\operatorname{{{}}}\ \texttt{{{}}}\ \mathrm{{as}}\ {}",
1851                IMPORT,
1852                path,
1853                latex_local_ident(m)
1854            ),
1855            None => format!(r"\operatorname{{{}}}\ \texttt{{{}}}", IMPORT, path),
1856        }
1857    }
1858}
1859
1860impl ImportStmt {
1861    pub fn to_latex_string(&self) -> String {
1862        match self {
1863            ImportStmt::ImportRelativePath(s) => s.to_latex_string(),
1864            ImportStmt::ImportGlobalModule(s) => s.to_latex_string(),
1865        }
1866    }
1867}
1868
1869impl StandardSet {
1870    pub fn to_latex_string(&self) -> String {
1871        match self {
1872            StandardSet::N => r"\mathbb{N}".to_string(),
1873            StandardSet::NPos => r"\mathbb{N}_{>0}".to_string(),
1874            StandardSet::Z => r"\mathbb{Z}".to_string(),
1875            StandardSet::ZNeg => r"\mathbb{Z}_{<0}".to_string(),
1876            StandardSet::ZNz => r"\mathbb{Z}\setminus\{0\}".to_string(),
1877            StandardSet::Q => r"\mathbb{Q}".to_string(),
1878            StandardSet::QPos => r"\mathbb{Q}_{>0}".to_string(),
1879            StandardSet::QNeg => r"\mathbb{Q}_{<0}".to_string(),
1880            StandardSet::QNz => r"\mathbb{Q}\setminus\{0\}".to_string(),
1881            StandardSet::R => r"\mathbb{R}".to_string(),
1882            StandardSet::RPos => r"\mathbb{R}_{>0}".to_string(),
1883            StandardSet::RNeg => r"\mathbb{R}_{<0}".to_string(),
1884            StandardSet::RNz => r"\mathbb{R}\setminus\{0\}".to_string(),
1885        }
1886    }
1887}
1888
1889impl Fact {
1890    pub fn to_latex_string(&self) -> String {
1891        match self {
1892            Fact::AtomicFact(x) => x.to_latex_string(),
1893            Fact::ExistFact(x) => x.to_latex_string(),
1894            Fact::OrFact(x) => x.to_latex_string(),
1895            Fact::AndFact(x) => x.to_latex_string(),
1896            Fact::ChainFact(x) => x.to_latex_string(),
1897            Fact::ForallFact(x) => x.to_latex_string(),
1898            Fact::ForallFactWithIff(x) => x.to_latex_string(),
1899            Fact::NotForall(x) => x.to_latex_string(),
1900        }
1901    }
1902}
1903
1904impl AtomicFact {
1905    pub fn to_latex_string(&self) -> String {
1906        match self {
1907            AtomicFact::NormalAtomicFact(x) => x.to_latex_string(),
1908            AtomicFact::EqualFact(x) => x.to_latex_string(),
1909            AtomicFact::LessFact(x) => x.to_latex_string(),
1910            AtomicFact::GreaterFact(x) => x.to_latex_string(),
1911            AtomicFact::LessEqualFact(x) => x.to_latex_string(),
1912            AtomicFact::GreaterEqualFact(x) => x.to_latex_string(),
1913            AtomicFact::IsSetFact(x) => x.to_latex_string(),
1914            AtomicFact::IsNonemptySetFact(x) => x.to_latex_string(),
1915            AtomicFact::IsFiniteSetFact(x) => x.to_latex_string(),
1916            AtomicFact::InFact(x) => x.to_latex_string(),
1917            AtomicFact::IsCartFact(x) => x.to_latex_string(),
1918            AtomicFact::IsTupleFact(x) => x.to_latex_string(),
1919            AtomicFact::SubsetFact(x) => x.to_latex_string(),
1920            AtomicFact::SupersetFact(x) => x.to_latex_string(),
1921            AtomicFact::RestrictFact(x) => x.to_latex_string(),
1922            AtomicFact::NotRestrictFact(x) => x.to_latex_string(),
1923            AtomicFact::NotNormalAtomicFact(x) => x.to_latex_string(),
1924            AtomicFact::NotEqualFact(x) => x.to_latex_string(),
1925            AtomicFact::NotLessFact(x) => x.to_latex_string(),
1926            AtomicFact::NotGreaterFact(x) => x.to_latex_string(),
1927            AtomicFact::NotLessEqualFact(x) => x.to_latex_string(),
1928            AtomicFact::NotGreaterEqualFact(x) => x.to_latex_string(),
1929            AtomicFact::NotIsSetFact(x) => x.to_latex_string(),
1930            AtomicFact::NotIsNonemptySetFact(x) => x.to_latex_string(),
1931            AtomicFact::NotIsFiniteSetFact(x) => x.to_latex_string(),
1932            AtomicFact::NotInFact(x) => x.to_latex_string(),
1933            AtomicFact::NotIsCartFact(x) => x.to_latex_string(),
1934            AtomicFact::NotIsTupleFact(x) => x.to_latex_string(),
1935            AtomicFact::NotSubsetFact(x) => x.to_latex_string(),
1936            AtomicFact::NotSupersetFact(x) => x.to_latex_string(),
1937            AtomicFact::FnEqualInFact(f) => format!(
1938                r"\mathsf{{fn\_eq\_in}}({},{},{})",
1939                f.left.to_latex_string(),
1940                f.right.to_latex_string(),
1941                f.set.to_latex_string(),
1942            ),
1943            AtomicFact::FnEqualFact(f) => format!(
1944                r"\mathsf{{fn\_eq}}({},{})",
1945                f.left.to_latex_string(),
1946                f.right.to_latex_string(),
1947            ),
1948        }
1949    }
1950}
1951
1952impl Obj {
1953    pub fn to_latex_string(&self) -> String {
1954        match self {
1955            Obj::Atom(AtomObj::Identifier(x)) => x.to_latex_string(),
1956            Obj::Atom(AtomObj::IdentifierWithMod(x)) => x.to_latex_string(),
1957            Obj::FnObj(x) => x.to_latex_string(),
1958            Obj::Number(x) => x.to_latex_string(),
1959            Obj::Add(x) => x.to_latex_string(),
1960            Obj::Sub(x) => x.to_latex_string(),
1961            Obj::Mul(x) => x.to_latex_string(),
1962            Obj::Div(x) => x.to_latex_string(),
1963            Obj::Mod(x) => x.to_latex_string(),
1964            Obj::Pow(x) => x.to_latex_string(),
1965            Obj::Abs(x) => x.to_latex_string(),
1966            Obj::Sqrt(x) => x.to_latex_string(),
1967            Obj::Log(x) => x.to_latex_string(),
1968            Obj::Max(x) => x.to_latex_string(),
1969            Obj::Min(x) => x.to_latex_string(),
1970            Obj::Union(x) => x.to_latex_string(),
1971            Obj::Intersect(x) => x.to_latex_string(),
1972            Obj::SetMinus(x) => x.to_latex_string(),
1973            Obj::SetDiff(x) => x.to_latex_string(),
1974            Obj::Cup(x) => x.to_latex_string(),
1975            Obj::Cap(x) => x.to_latex_string(),
1976            Obj::PowerSet(x) => x.to_latex_string(),
1977            Obj::ListSet(x) => x.to_latex_string(),
1978            Obj::SetBuilder(x) => x.to_latex_string(),
1979            Obj::FnSet(x) => x.to_latex_string(),
1980            Obj::AnonymousFn(x) => x.to_latex_string(),
1981            Obj::Cart(x) => x.to_latex_string(),
1982            Obj::CartDim(x) => x.to_latex_string(),
1983            Obj::Proj(x) => x.to_latex_string(),
1984            Obj::TupleDim(x) => x.to_latex_string(),
1985            Obj::Tuple(x) => x.to_latex_string(),
1986            Obj::Count(x) => x.to_latex_string(),
1987            Obj::Sum(x) => x.to_latex_string(),
1988            Obj::Product(x) => x.to_latex_string(),
1989            Obj::Range(x) => x.to_latex_string(),
1990            Obj::ClosedRange(x) => x.to_latex_string(),
1991            Obj::FiniteSeqSet(x) => x.to_latex_string(),
1992            Obj::SeqSet(x) => x.to_latex_string(),
1993            Obj::FiniteSeqListObj(x) => x.to_latex_string(),
1994            Obj::Choose(x) => x.to_latex_string(),
1995            Obj::ObjAtIndex(x) => x.to_latex_string(),
1996            Obj::StandardSet(x) => x.to_latex_string(),
1997            Obj::StructObj(x) => latex_texttt_escape(&x.to_string()),
1998            Obj::ObjAsStructInstanceWithFieldAccess(x) => latex_texttt_escape(&x.to_string()),
1999            Obj::InstantiatedTemplateObj(x) => latex_texttt_escape(&x.to_string()),
2000            Obj::Atom(AtomObj::Forall(x)) => latex_local_ident(&x.name),
2001            Obj::Atom(AtomObj::Def(x)) => latex_local_ident(&x.name),
2002            Obj::Atom(AtomObj::Exist(x)) => latex_local_ident(&x.name),
2003            Obj::Atom(AtomObj::SetBuilder(x)) => latex_local_ident(&x.name),
2004            Obj::Atom(AtomObj::FnSet(x)) => latex_local_ident(&x.name),
2005            Obj::Atom(AtomObj::Induc(x)) => latex_local_ident(&x.name),
2006            Obj::Atom(AtomObj::DefAlgo(x)) => latex_local_ident(&x.name),
2007            Obj::Atom(AtomObj::DefStructField(x)) => latex_local_ident(&x.name),
2008            Obj::MatrixSet(x) => x.to_latex_string(),
2009            Obj::MatrixListObj(x) => x.to_latex_string(),
2010            Obj::MatrixAdd(x) => x.to_latex_string(),
2011            Obj::MatrixSub(x) => x.to_latex_string(),
2012            Obj::MatrixMul(x) => x.to_latex_string(),
2013            Obj::MatrixScalarMul(x) => x.to_latex_string(),
2014            Obj::MatrixPow(x) => x.to_latex_string(),
2015        }
2016    }
2017}
2018
2019impl Stmt {
2020    pub fn to_latex_string(&self) -> String {
2021        match self {
2022            Stmt::Fact(x) => x.to_latex_string(),
2023            Stmt::DefLetStmt(x) => x.to_latex_string(),
2024            Stmt::DefPropStmt(x) => x.to_latex_string(),
2025            Stmt::DefAbstractPropStmt(x) => x.to_latex_string(),
2026            Stmt::HaveObjInNonemptySetStmt(x) => x.to_latex_string(),
2027            Stmt::HaveObjEqualStmt(x) => x.to_latex_string(),
2028            Stmt::HaveByExistStmt(x) => x.to_latex_string(),
2029            Stmt::HaveFnEqualStmt(x) => x.to_latex_string(),
2030            Stmt::HaveFnEqualCaseByCaseStmt(x) => x.to_latex_string(),
2031            Stmt::HaveFnByInducStmt(x) => x.to_latex_string(),
2032            Stmt::HaveFnByForallExistUniqueStmt(x) => x.to_latex_string(),
2033            Stmt::DefAlgoStmt(x) => x.to_latex_string(),
2034            Stmt::ClaimStmt(x) => x.to_latex_string(),
2035            Stmt::KnowStmt(x) => x.to_latex_string(),
2036            Stmt::ProveStmt(x) => x.to_latex_string(),
2037            Stmt::ImportStmt(x) => x.to_latex_string(),
2038            Stmt::DoNothingStmt(x) => x.to_latex_string(),
2039            Stmt::ClearStmt(x) => x.to_latex_string(),
2040            Stmt::RunFileStmt(x) => x.to_latex_string(),
2041            Stmt::RunFileInStd(x) => x.to_latex_string(),
2042            Stmt::EvalStmt(x) => x.to_latex_string(),
2043            Stmt::EvalByStmt(x) => x.to_latex_string(),
2044            Stmt::WitnessExistFact(x) => x.to_latex_string(),
2045            Stmt::WitnessNonemptySet(x) => x.to_latex_string(),
2046            Stmt::ByCasesStmt(x) => x.to_latex_string(),
2047            Stmt::ByContraStmt(x) => x.to_latex_string(),
2048            Stmt::ByEnumerateFiniteSetStmt(x) => x.to_latex_string(),
2049            Stmt::ByInducStmt(x) => x.to_latex_string(),
2050            Stmt::ByForStmt(x) => x.to_latex_string(),
2051            Stmt::ByExtensionStmt(x) => x.to_latex_string(),
2052            Stmt::ByFnAsSetStmt(x) => x.to_latex_string(),
2053            Stmt::ByTupleAsSetStmt(x) => x.to_latex_string(),
2054            Stmt::ByFnSetAsSetStmt(x) => x.to_latex_string(),
2055            Stmt::ByClosedRangeAsCasesStmt(x) => x.to_latex_string(),
2056            Stmt::ByTransitivePropStmt(x) => x.to_latex_string(),
2057            Stmt::BySymmetricPropStmt(x) => x.to_latex_string(),
2058            Stmt::ByReflexivePropStmt(x) => x.to_latex_string(),
2059            Stmt::ByAntisymmetricPropStmt(x) => x.to_latex_string(),
2060            Stmt::DefStructStmt(x) => latex_texttt_escape(&x.to_string()),
2061            Stmt::DefTemplateStmt(x) => latex_texttt_escape(&x.to_string()),
2062        }
2063    }
2064}