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