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}