ruut_functions/
display.rs

1use std::fmt::Display;
2
3use crate::{FType, Func, F1D, F2D, F3D};
4
5impl Display for Func {
6    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7        match self {
8            Self::E => write!(f, "e"),
9            Self::PI => write!(f, "\u{1D70B}"),
10            Self::Var(char) => write!(f, "{}", char),
11            Self::Num(num) => write!(f, "{}", num),
12            Self::Param(par, _) => write!(f, "[{}]", par),
13            Self::S(kind, arg) => match kind {
14                FType::Sin => write!(f, "sin({})", arg),
15                FType::Cos => write!(f, "cos({})", arg),
16                FType::Tan => write!(f, "tan({})", arg),
17                FType::Cot => write!(f, "cot({})", arg),
18                FType::Sec => write!(f, "sec({})", arg),
19                FType::Csc => write!(f, "csc({})", arg),
20                FType::ASin => write!(f, "asin({})", arg),
21                FType::ACos => write!(f, "acos({})", arg),
22                FType::ATan => write!(f, "atan({})", arg),
23                FType::Sinh => write!(f, "sinh({})", arg),
24                FType::Cosh => write!(f, "cosh({})", arg),
25                FType::Tanh => write!(f, "tanh({})", arg),
26                FType::Coth => write!(f, "coth({})", arg),
27                FType::Sech => write!(f, "sech({})", arg),
28                FType::Csch => write!(f, "csch({})", arg),
29                FType::ASinh => write!(f, "asinh({})", arg),
30                FType::ACosh => write!(f, "acosh({})", arg),
31                FType::ATanh => write!(f, "atanh({})", arg),
32                FType::Abs => write!(f, "|{}|", arg),
33                FType::Ln => write!(f, "ln({})", arg),
34            },
35            Self::Add(add) => {
36                let mut output = String::from("");
37                for (i, el) in add.iter().enumerate() {
38                    if i != 0 {
39                        if let Func::Mul(mul) = el {
40                            if !mul.is_empty() {
41                                if let Func::Num(val) = mul[0] {
42                                    if val < 0 {
43                                        output += &format!("{}", el);
44                                        continue;
45                                    }
46                                }
47                            }
48                        }
49                        output += &format!("+{}", el);
50                    } else {
51                        output += &format!("{}", el);
52                    }
53                }
54                write!(f, "{}", output)
55            }
56            Self::Mul(mul) => {
57                let mut output = String::from("");
58                let mut found_div = false;
59                let mut has_divs = false;
60
61                for (i, el) in mul.iter().enumerate() {
62                    if let Func::Num(val) = el {
63                        if *val == -1 {
64                            output += "-";
65                            continue;
66                        }
67                    }
68                    if let Func::Pow(base, exp) = el {
69                        if let Func::Num(e) = **exp {
70                            if e < 0 {
71                                if !found_div {
72                                    output += "/";
73                                    if i != mul.len() - 1 {
74                                        has_divs = true;
75                                        output += "(";
76                                    }
77                                }
78
79                                match **base {
80                                    Func::Add(_) | Func::Mul(_) => output += &format!("({})", base),
81                                    _ => output += &format!("{}", base),
82                                };
83                                if e != -1 {
84                                    output += &format!("^{}", -e);
85                                }
86
87                                found_div = true;
88                                continue;
89                            }
90                        }
91                    }
92                    output += &format!("{}", el);
93                }
94                if has_divs {
95                    output += ")";
96                }
97                write!(f, "{}", output)
98            }
99            Func::Pow(base, exp) => {
100                let mut output = String::new();
101
102                match **base {
103                    Func::Add(_) | Func::Mul(_) => output += &format!("({})^", base),
104                    _ => output += &format!("{}^", base),
105                };
106                match **exp {
107                    Func::Add(_) | Func::Mul(_) => output += &format!("({})", exp),
108                    _ => output += &format!("{}", exp),
109                };
110
111                write!(f, "{}", output)
112            }
113        }
114    }
115}
116
117impl Display for F1D {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        write!(f, "{}", self.0)
120    }
121}
122impl Display for F2D {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        write!(f, "{}", self.0)
125    }
126}
127impl Display for F3D {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        write!(f, "{}", self.0)
130    }
131}
132
133impl Func {
134    pub(crate) fn latex(&self) -> String {
135        match self {
136            Func::Var(char) => char.to_string(),
137            Func::PI => String::from(r"\pi"),
138            Func::E => String::from("e"),
139            Func::Num(val) => format!("{}", val),
140            Func::Param(par, _) => format!(r"\text{{{par}}}"),
141            Func::Add(add) => {
142                let mut output = String::from("");
143
144                for (i, el) in add.iter().enumerate() {
145                    if i != 0 {
146                        if let Func::Mul(mul) = el {
147                            if !mul.is_empty() {
148                                if let Func::Num(val) = mul[0] {
149                                    if val < 0 {
150                                        output += &format!("{}", el);
151                                        continue;
152                                    }
153                                }
154                            }
155                        }
156                        output += &format!("+{}", el.latex());
157                    } else {
158                        output += &el.latex();
159                    }
160                }
161                output
162            }
163            Func::Mul(mul) => {
164                let mut output = String::from("");
165                let mut found_div = false;
166
167                for el in mul {
168                    if let Func::Pow(base, exp) = el {
169                        if **exp < 0 {
170                            if !found_div {
171                                output = format!(r"\frac{{{}}}{{", output);
172                            }
173                            found_div = true;
174                            let div = Func::Pow(base.clone(), Box::new(-1 * *exp.clone()));
175                            output += &div.latex();
176                            continue;
177                        }
178                    }
179
180                    output += &el.latex();
181                }
182
183                if found_div {
184                    output += "}";
185                }
186                output
187            }
188            Func::Pow(base, exp) => {
189                let mut output = String::new();
190
191                match **base {
192                    Func::Add(_) | Func::Mul(_) | Func::Pow(..) => {
193                        output += &format!("({})", base.latex())
194                    }
195                    _ => output += &base.latex(),
196                };
197                match **exp {
198                    Func::Add(_) | Func::Mul(_) | Func::Pow(..) => {
199                        output += &format!("^{{{}}}", exp.latex())
200                    }
201                    Func::Num(1) => (),
202                    _ => output += &format!("^{}", exp.latex()),
203                };
204
205                output
206            }
207            Func::S(kind, arg) => match kind {
208                FType::Ln => format!("ln({})", arg.latex()),
209                FType::Sin => format!("sin({})", arg.latex()),
210                FType::Cos => format!("cos({})", arg.latex()),
211                FType::Tan => format!("tan({})", arg.latex()),
212                FType::Cot => format!("cot({})", arg.latex()),
213                FType::Sec => format!("sec({})", arg.latex()),
214                FType::Csc => format!("csc({})", arg.latex()),
215                FType::ACos => format!("acos({})", arg.latex()),
216                FType::ASin => format!("asin({})", arg.latex()),
217                FType::ATan => format!("atan({})", arg.latex()),
218                FType::Sinh => format!("sinh({})", arg.latex()),
219                FType::Cosh => format!("cosh({})", arg.latex()),
220                FType::Tanh => format!("tanh({})", arg.latex()),
221                FType::Coth => format!("coth({})", arg.latex()),
222                FType::Sech => format!("sech({})", arg.latex()),
223                FType::Csch => format!("csch({})", arg.latex()),
224                FType::ASinh => format!("asinh({})", arg.latex()),
225                FType::ACosh => format!("acosh({})", arg.latex()),
226                FType::ATanh => format!("atanh({})", arg.latex()),
227                FType::Abs => format!("|{}|", arg.latex()),
228            },
229        }
230    }
231}
232
233#[test]
234fn test_display() {
235    use crate::{f1d, f2d, f3d};
236    assert_eq!(
237        format!("{}", f1d!("x+1+cos(x)/ln(x)/ln(15)*sinh(x)^2/7-2+e*pi")),
238        "-1+x+cos(x)sinh(x)^2/(7ln(x)ln(15))+𝜋e",
239    );
240
241    assert_eq!(
242        format!("{}", f1d!("[eta]*sin(x)+cosh(x)/tan(x^2)")),
243        "[eta]sin(x)+cosh(x)/tan(x^2)"
244    );
245    assert_eq!(
246        format!("{}", f1d!("cot(x)+sec(x)^2+csc(e)/acos(x)")),
247        "csc(e)/acos(x)+cot(x)+sec(x)^2"
248    );
249
250    assert_eq!(format!("{}", f2d!("x+(-5y)")), "x-5y");
251    assert_eq!(format!("{}", f2d!("-xy")), "-xy");
252    assert_eq!(format!("{}", f2d!("x/(x+y)^2")), "x/(x+y)^2");
253    assert_eq!(format!("{}", f2d!("(x+y)^(e+2)")), "(x+y)^(2+e)");
254    assert_eq!(
255        format!(
256            "{}",
257            f2d!(
258                "asin(x)+atan(x)+tanh(x)+coth(x)+sech(x)+csch(x)+asinh(x)+acosh(x)+atanh(x)+abs(x)"
259            )
260        ),
261        "|x|+asin(x)+atan(x)+tanh(x)+coth(x)+sech(x)+csch(x)+asinh(x)+acosh(x)+atanh(x)"
262    );
263    assert_eq!(format!("{}", f3d!("xyz")), "xyz");
264}
265
266#[test]
267fn test_latex() {
268    use crate::{f1d, f2d, f3d};
269
270    assert_eq!(
271        format!("{}", f3d!("x^(y^3)+sin(x)+e+pi").latex()),
272        r"\pi+e+sin(x)+x^{y^3}"
273    );
274
275    assert_eq!(
276        format!("{}", f3d!("z+3ln(x)/(xy)").latex()),
277        r"z+\frac{3ln(x)}{xy}"
278    );
279
280    assert_eq!(f3d!("(x+2)^3").latex(), "(2+x)^3");
281    assert_eq!(f3d!("(x+2)^(3+y)").latex(), "(2+x)^{3+y}");
282    assert_eq!(f3d!("x^(3+y)").latex(), "x^{3+y}");
283    assert_eq!(f3d!("-x+[eta]").latex(), r"\text{eta}-x");
284    assert_eq!(
285        format!(
286            "{}",
287            f2d!(
288                "asin(x)+atan(x)+tanh(x)+coth(x)+sech(x)+csch(x)+asinh(x)+acosh(x)+atanh(x)+abs(x)"
289            )
290            .latex()
291        ),
292        "|x|+asin(x)+atan(x)+tanh(x)+coth(x)+sech(x)+csch(x)+asinh(x)+acosh(x)+atanh(x)"
293    );
294
295    assert_eq!(
296        format!(
297            "{}",
298            f1d!("cot(x)+sec(x)^2+csc(e)/acos(x)+cos(x)+tan(x)+sinh(x)cosh(x)").latex()
299        ),
300        r"\frac{csc(e)}{acos(x)}+sinh(x)cosh(x)+cos(x)+tan(x)+cot(x)+sec(x)^2"
301    );
302}