• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 15270397280

27 May 2025 08:28AM CUT coverage: 88.323% (-0.01%) from 88.334%
15270397280

Pull #14455

github

ElePT
Fix black
Pull Request #14455: Fix more spurious complex parts in circuit functions (backport #14431)

1 of 1 new or added line in 1 file covered. (100.0%)

18 existing lines in 4 files now uncovered.

78467 of 88841 relevant lines covered (88.32%)

467711.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.02
/crates/circuit/src/symbol_expr.rs
1
// This code is part of Qiskit.
2
//
3
// (C) Copyright IBM 2023, 2024
4
//
5
// This code is licensed under the Apache License, Version 2.0. You may
6
// obtain a copy of this license in the LICENSE.txt file in the root directory
7
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
//
9
// Any modifications or derivative works of this code must retain this
10
// copyright notice, and modified files need to carry a notice indicating
11
// that they have been altered from the originals.
12

13
/// symbol_expr.rs
14
/// symbolic expression engine for parameter expression
15
use core::f64;
16
use hashbrown::{HashMap, HashSet};
17
use std::cmp::Ordering;
18
use std::cmp::PartialOrd;
19
use std::convert::From;
20
use std::fmt;
21
use std::ops::{Add, Div, Mul, Neg, Sub};
22

23
use num_complex::Complex64;
24

25
// epsilon for SymbolExpr is hearistically defined
26
pub const SYMEXPR_EPSILON: f64 = f64::EPSILON * 8.0;
27

28
/// node types of expression tree
29
#[derive(Debug, Clone)]
30
pub enum SymbolExpr {
31
    Symbol(Box<String>),
32
    Value(Value),
33
    Unary {
34
        op: UnaryOp,
35
        expr: Box<SymbolExpr>,
36
    },
37
    Binary {
38
        op: BinaryOp,
39
        lhs: Box<SymbolExpr>,
40
        rhs: Box<SymbolExpr>,
41
    },
42
}
43

44
/// Value type, can be integer, real or complex number
45
#[derive(Debug, Clone, Copy)]
46
pub enum Value {
47
    Real(f64),
48
    Int(i64),
49
    Complex(Complex64),
50
}
51

52
/// definition of unary operations
53
#[derive(Debug, Clone, PartialEq)]
54
pub enum UnaryOp {
55
    Abs,
56
    Neg,
57
    Sin,
58
    Asin,
59
    Cos,
60
    Acos,
61
    Tan,
62
    Atan,
63
    Exp,
64
    Log,
65
    Sign,
66
    Conj,
67
}
68

69
/// definition of binary operations
70
#[derive(Debug, Clone, PartialEq)]
71
pub enum BinaryOp {
72
    Add,
73
    Sub,
74
    Mul,
75
    Div,
76
    Pow,
77
}
78

79
// functions to make new expr for add
80
#[inline(always)]
81
fn _add(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
134,610✔
82
    if rhs.is_negative() {
134,610✔
83
        match rhs.neg_opt() {
38,794✔
84
            Some(e) => SymbolExpr::Binary {
38,794✔
85
                op: BinaryOp::Sub,
38,794✔
86
                lhs: Box::new(lhs),
38,794✔
87
                rhs: Box::new(e),
38,794✔
88
            },
38,794✔
89
            None => SymbolExpr::Binary {
×
90
                op: BinaryOp::Sub,
×
91
                lhs: Box::new(lhs),
×
92
                rhs: Box::new(_neg(rhs)),
×
93
            },
×
94
        }
95
    } else {
96
        SymbolExpr::Binary {
95,816✔
97
            op: BinaryOp::Add,
95,816✔
98
            lhs: Box::new(lhs),
95,816✔
99
            rhs: Box::new(rhs),
95,816✔
100
        }
95,816✔
101
    }
102
}
134,610✔
103

104
// functions to make new expr for sub
105
#[inline(always)]
106
fn _sub(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
14,724✔
107
    if rhs.is_negative() {
14,724✔
108
        match rhs.neg_opt() {
758✔
109
            Some(e) => SymbolExpr::Binary {
758✔
110
                op: BinaryOp::Add,
758✔
111
                lhs: Box::new(lhs),
758✔
112
                rhs: Box::new(e),
758✔
113
            },
758✔
114
            None => SymbolExpr::Binary {
×
115
                op: BinaryOp::Add,
×
116
                lhs: Box::new(lhs),
×
117
                rhs: Box::new(_neg(rhs)),
×
118
            },
×
119
        }
120
    } else {
121
        SymbolExpr::Binary {
13,966✔
122
            op: BinaryOp::Sub,
13,966✔
123
            lhs: Box::new(lhs),
13,966✔
124
            rhs: Box::new(rhs),
13,966✔
125
        }
13,966✔
126
    }
127
}
14,724✔
128

129
// functions to make new expr for mul
130
#[inline(always)]
131
fn _mul(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
240,956✔
132
    SymbolExpr::Binary {
240,956✔
133
        op: BinaryOp::Mul,
240,956✔
134
        lhs: Box::new(lhs),
240,956✔
135
        rhs: Box::new(rhs),
240,956✔
136
    }
240,956✔
137
}
240,956✔
138

139
// functions to make new expr for div
140
#[inline(always)]
141
fn _div(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
6,096✔
142
    SymbolExpr::Binary {
6,096✔
143
        op: BinaryOp::Div,
6,096✔
144
        lhs: Box::new(lhs),
6,096✔
145
        rhs: Box::new(rhs),
6,096✔
146
    }
6,096✔
147
}
6,096✔
148

149
// functions to make new expr for pow
150
#[inline(always)]
151
fn _pow(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
43,670✔
152
    SymbolExpr::Binary {
43,670✔
153
        op: BinaryOp::Pow,
43,670✔
154
        lhs: Box::new(lhs),
43,670✔
155
        rhs: Box::new(rhs),
43,670✔
156
    }
43,670✔
157
}
43,670✔
158

159
// functions to make new expr for neg
160
#[inline(always)]
161
fn _neg(expr: SymbolExpr) -> SymbolExpr {
28,642✔
162
    match expr.neg_opt() {
28,642✔
163
        Some(e) => e,
192✔
164
        None => SymbolExpr::Unary {
28,450✔
165
            op: UnaryOp::Neg,
28,450✔
166
            expr: Box::new(expr),
28,450✔
167
        },
28,450✔
168
    }
169
}
28,642✔
170

171
impl fmt::Display for SymbolExpr {
172
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48,538,314✔
173
        write!(
48,538,314✔
174
            f,
48,538,314✔
175
            "{}",
48,538,314✔
176
            match self {
48,538,314✔
177
                SymbolExpr::Symbol(e) => e.to_string(),
48,155,462✔
178
                SymbolExpr::Value(e) => e.to_string(),
103,526✔
179
                SymbolExpr::Unary { op, expr } => {
6,230✔
180
                    let s = expr.to_string();
6,230✔
181
                    match op {
6,230✔
182
                        UnaryOp::Abs => format!("abs({})", s),
×
183
                        UnaryOp::Neg => match expr.as_ref() {
1,892✔
184
                            SymbolExpr::Value(e) => (-e).to_string(),
×
185
                            SymbolExpr::Binary {
186
                                op: BinaryOp::Add | BinaryOp::Sub,
187
                                ..
188
                            } => format!("-({})", s),
×
189
                            _ => format!("-{}", s),
1,892✔
190
                        },
191
                        UnaryOp::Sin => format!("sin({})", s),
142✔
192
                        UnaryOp::Asin => format!("asin({})", s),
106✔
193
                        UnaryOp::Cos => format!("cos({})", s),
78✔
194
                        UnaryOp::Acos => format!("acos({})", s),
90✔
195
                        UnaryOp::Tan => format!("tan({})", s),
62✔
196
                        UnaryOp::Atan => format!("atan({})", s),
74✔
197
                        UnaryOp::Exp => format!("exp({})", s),
258✔
198
                        UnaryOp::Log => format!("log({})", s),
×
199
                        UnaryOp::Sign => format!("sign({})", s),
×
200
                        UnaryOp::Conj => format!("conj({})", s),
3,528✔
201
                    }
202
                }
203
                SymbolExpr::Binary { op, lhs, rhs } => {
273,096✔
204
                    let s_lhs = lhs.to_string();
273,096✔
205
                    let s_rhs = rhs.to_string();
273,096✔
206
                    let op_lhs = match lhs.as_ref() {
273,096✔
207
                        SymbolExpr::Binary { op: lop, .. } => {
33,192✔
208
                            matches!(lop, BinaryOp::Add | BinaryOp::Sub)
33,192✔
209
                        }
210
                        SymbolExpr::Value(e) => match e {
51,396✔
211
                            Value::Real(v) => *v < 0.0,
12,282✔
212
                            Value::Int(v) => *v < 0,
510✔
213
                            Value::Complex(_) => true,
38,604✔
214
                        },
215
                        _ => false,
188,508✔
216
                    };
217
                    let op_rhs = match rhs.as_ref() {
273,096✔
218
                        SymbolExpr::Binary { op: rop, .. } => match rop {
28,692✔
219
                            BinaryOp::Add | BinaryOp::Sub => true,
1,684✔
220
                            _ => matches!(op, BinaryOp::Div),
27,008✔
221
                        },
222
                        SymbolExpr::Value(e) => match e {
51,986✔
223
                            Value::Real(v) => *v < 0.0,
34,686✔
224
                            Value::Int(v) => *v < 0,
244✔
225
                            Value::Complex(_) => true,
17,056✔
226
                        },
227
                        _ => false,
192,418✔
228
                    };
229

230
                    match op {
273,096✔
231
                        BinaryOp::Add => match rhs.as_ref() {
3,762✔
232
                            SymbolExpr::Unary {
233
                                op: UnaryOp::Neg,
234
                                expr: _,
235
                            } => {
236
                                if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
237
                                    format!("{} {}", s_lhs, s_rhs)
×
238
                                } else {
239
                                    format!("{} + {}", s_lhs, s_rhs)
×
240
                                }
241
                            }
242
                            _ => format!("{} + {}", s_lhs, s_rhs),
3,762✔
243
                        },
244
                        BinaryOp::Sub => match rhs.as_ref() {
3,594✔
245
                            SymbolExpr::Unary {
246
                                op: UnaryOp::Neg,
247
                                expr: _,
248
                            } => {
249
                                if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
250
                                    let st = s_rhs.char_indices().nth(0).unwrap().0;
×
251
                                    let ed = s_rhs.char_indices().nth(1).unwrap().0;
×
252
                                    let s_rhs_new: &str = &s_rhs.as_str()[st..ed];
×
253
                                    format!("{} + {}", s_lhs, s_rhs_new)
×
254
                                } else if op_rhs {
×
255
                                    format!("{} -({})", s_lhs, s_rhs)
×
256
                                } else {
257
                                    format!("{} - {}", s_lhs, s_rhs)
×
258
                                }
259
                            }
260
                            _ => {
261
                                if op_rhs {
3,594✔
262
                                    format!("{} -({})", s_lhs, s_rhs)
188✔
263
                                } else {
264
                                    format!("{} - {}", s_lhs, s_rhs)
3,406✔
265
                                }
266
                            }
267
                        },
268
                        BinaryOp::Mul => {
269
                            if op_lhs {
230,624✔
270
                                if op_rhs {
45,146✔
271
                                    format!("({})*({})", s_lhs, s_rhs)
636✔
272
                                } else {
273
                                    format!("({})*{}", s_lhs, s_rhs)
44,510✔
274
                                }
275
                            } else if op_rhs {
185,478✔
276
                                format!("{}*({})", s_lhs, s_rhs)
17,852✔
277
                            } else {
278
                                format!("{}*{}", s_lhs, s_rhs)
167,626✔
279
                            }
280
                        }
281
                        BinaryOp::Div => {
282
                            if op_lhs {
276✔
283
                                if op_rhs {
38✔
284
                                    format!("({})/({})", s_lhs, s_rhs)
×
285
                                } else {
286
                                    format!("({})/{}", s_lhs, s_rhs)
38✔
287
                                }
288
                            } else if op_rhs {
238✔
289
                                format!("{}/({})", s_lhs, s_rhs)
×
290
                            } else {
291
                                format!("{}/{}", s_lhs, s_rhs)
238✔
292
                            }
293
                        }
294
                        BinaryOp::Pow => match lhs.as_ref() {
34,840✔
295
                            SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
296
                                match rhs.as_ref() {
4✔
297
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
298
                                        format!("({})**({})", s_lhs, s_rhs)
×
299
                                    }
300
                                    SymbolExpr::Value(r) => {
×
301
                                        if r.as_real() < 0.0 {
×
302
                                            format!("({})**({})", s_lhs, s_rhs)
×
303
                                        } else {
304
                                            format!("({})**{}", s_lhs, s_rhs)
×
305
                                        }
306
                                    }
307
                                    _ => format!("({})**{}", s_lhs, s_rhs),
4✔
308
                                }
309
                            }
310
                            SymbolExpr::Value(l) => {
4✔
311
                                if l.as_real() < 0.0 {
4✔
312
                                    match rhs.as_ref() {
×
313
                                        SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
314
                                            format!("({})**({})", s_lhs, s_rhs)
×
315
                                        }
316
                                        _ => format!("({})**{}", s_lhs, s_rhs),
×
317
                                    }
318
                                } else {
319
                                    match rhs.as_ref() {
4✔
320
                                        SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
321
                                            format!("{}**({})", s_lhs, s_rhs)
×
322
                                        }
323
                                        _ => format!("{}**{}", s_lhs, s_rhs),
4✔
324
                                    }
325
                                }
326
                            }
327
                            _ => match rhs.as_ref() {
34,832✔
328
                                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
329
                                    format!("{}**({})", s_lhs, s_rhs)
×
330
                                }
331
                                SymbolExpr::Value(r) => {
34,832✔
332
                                    if r.as_real() < 0.0 {
34,832✔
333
                                        format!("{}**({})", s_lhs, s_rhs)
×
334
                                    } else {
335
                                        format!("{}**{}", s_lhs, s_rhs)
34,832✔
336
                                    }
337
                                }
338
                                _ => format!("{}**{}", s_lhs, s_rhs),
×
339
                            },
340
                        },
341
                    }
342
                }
343
            },
344
        )
345
    }
48,538,314✔
346
}
347

348
/// ==================================
349
/// SymbolExpr implementation
350
/// ==================================
351
impl SymbolExpr {
352
    /// bind value to symbol node
353
    pub fn bind(&self, maps: &HashMap<String, Value>) -> SymbolExpr {
1,142,964✔
354
        match self {
1,142,964✔
355
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
464,354✔
356
                Some(v) => SymbolExpr::Value(*v),
463,120✔
357
                None => self.clone(),
1,234✔
358
            },
359
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
243,732✔
360
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
22,508✔
361
                op: op.clone(),
22,508✔
362
                expr: Box::new(expr.bind(maps)),
22,508✔
363
            },
22,508✔
364
            SymbolExpr::Binary { op, lhs, rhs } => {
412,370✔
365
                let new_lhs = lhs.bind(maps);
412,370✔
366
                let new_rhs = rhs.bind(maps);
412,370✔
367
                match op {
412,370✔
368
                    BinaryOp::Add => new_lhs + new_rhs,
86,190✔
369
                    BinaryOp::Sub => new_lhs - new_rhs,
61,816✔
370
                    BinaryOp::Mul => new_lhs * new_rhs,
250,642✔
371
                    BinaryOp::Div => new_lhs / new_rhs,
5,500✔
372
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
8,222✔
373
                }
374
            }
375
        }
376
    }
1,142,964✔
377

378
    /// substitute symbol node to other expression
379
    pub fn subs(&self, maps: &HashMap<String, SymbolExpr>) -> SymbolExpr {
51,908✔
380
        match self {
51,908✔
381
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
17,000✔
382
                Some(v) => v.clone(),
14,302✔
383
                None => self.clone(),
2,698✔
384
            },
385
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
15,524✔
386
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
1,156✔
387
                op: op.clone(),
1,156✔
388
                expr: Box::new(expr.subs(maps)),
1,156✔
389
            },
1,156✔
390
            SymbolExpr::Binary { op, lhs, rhs } => {
18,228✔
391
                let new_lhs = lhs.subs(maps);
18,228✔
392
                let new_rhs = rhs.subs(maps);
18,228✔
393
                match op {
18,228✔
394
                    BinaryOp::Add => new_lhs + new_rhs,
3,676✔
395
                    BinaryOp::Sub => new_lhs - new_rhs,
2,316✔
396
                    BinaryOp::Mul => new_lhs * new_rhs,
12,212✔
397
                    BinaryOp::Div => new_lhs / new_rhs,
6✔
398
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
399
                }
400
            }
401
        }
402
    }
51,908✔
403

404
    /// evaluate the equation
405
    /// if recursive is false, only this node will be evaluated
406
    pub fn eval(&self, recurse: bool) -> Option<Value> {
45,759,234✔
407
        match self {
45,759,234✔
408
            SymbolExpr::Symbol(_) => None,
16,625,874✔
409
            SymbolExpr::Value(e) => Some(*e),
12,022,196✔
410
            SymbolExpr::Unary { op, expr } => {
558,582✔
411
                let val: Value;
558,582✔
412
                if recurse {
558,582✔
413
                    match expr.eval(recurse) {
558,582✔
414
                        Some(v) => val = v,
29,706✔
415
                        None => return None,
528,876✔
416
                    }
417
                } else {
418
                    match expr.as_ref() {
×
419
                        SymbolExpr::Value(e) => val = *e,
×
420
                        _ => return None,
×
421
                    }
422
                }
423
                let ret = match op {
29,706✔
424
                    UnaryOp::Abs => val.abs(),
258✔
425
                    UnaryOp::Neg => -val,
27,700✔
426
                    UnaryOp::Sin => val.sin(),
208✔
427
                    UnaryOp::Asin => val.asin(),
54✔
428
                    UnaryOp::Cos => val.cos(),
332✔
429
                    UnaryOp::Acos => val.acos(),
52✔
430
                    UnaryOp::Tan => val.tan(),
196✔
431
                    UnaryOp::Atan => val.atan(),
54✔
432
                    UnaryOp::Exp => val.exp(),
246✔
433
                    UnaryOp::Log => val.log(),
276✔
434
                    UnaryOp::Sign => val.sign(),
6✔
435
                    UnaryOp::Conj => match val {
324✔
436
                        Value::Complex(v) => Value::Complex(v.conj()),
88✔
437
                        _ => val,
236✔
438
                    },
439
                };
440
                match ret {
29,706✔
441
                    Value::Real(_) => Some(ret),
6,552✔
442
                    Value::Int(_) => Some(ret),
22,184✔
443
                    Value::Complex(c) => {
970✔
444
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
970✔
445
                            Some(Value::Real(c.re))
×
446
                        } else {
447
                            Some(ret)
970✔
448
                        }
449
                    }
450
                }
451
            }
452
            SymbolExpr::Binary { op, lhs, rhs } => {
16,552,582✔
453
                let lval: Value;
16,552,582✔
454
                let rval: Value;
16,552,582✔
455
                if recurse {
16,552,582✔
456
                    match (lhs.eval(true), rhs.eval(true)) {
16,552,582✔
457
                        (Some(left), Some(right)) => {
18,864✔
458
                            lval = left;
18,864✔
459
                            rval = right;
18,864✔
460
                        }
18,864✔
461
                        _ => return None,
16,533,718✔
462
                    }
463
                } else {
464
                    match (lhs.as_ref(), rhs.as_ref()) {
×
465
                        (SymbolExpr::Value(l), SymbolExpr::Value(r)) => {
×
466
                            lval = *l;
×
467
                            rval = *r;
×
468
                        }
×
469
                        _ => return None,
×
470
                    }
471
                }
472
                let ret = match op {
18,864✔
473
                    BinaryOp::Add => lval + rval,
1,424✔
474
                    BinaryOp::Sub => lval - rval,
480✔
475
                    BinaryOp::Mul => lval * rval,
864✔
476
                    BinaryOp::Div => lval / rval,
484✔
477
                    BinaryOp::Pow => lval.pow(&rval),
15,612✔
478
                };
479
                match ret {
18,864✔
480
                    Value::Real(_) => Some(ret),
7,356✔
481
                    Value::Int(_) => Some(ret),
5,418✔
482
                    Value::Complex(c) => {
6,090✔
483
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
6,090✔
484
                            Some(Value::Real(c.re))
×
485
                        } else {
486
                            Some(ret)
6,090✔
487
                        }
488
                    }
489
                }
490
            }
491
        }
492
    }
45,759,234✔
493

494
    /// calculate derivative of the equantion for a symbol passed by param
495
    pub fn derivative(&self, param: &SymbolExpr) -> Result<SymbolExpr, String> {
130✔
496
        if self == param {
130✔
497
            Ok(SymbolExpr::Value(Value::Real(1.0)))
42✔
498
        } else {
499
            match self {
88✔
500
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => {
501
                    Ok(SymbolExpr::Value(Value::Real(0.0)))
22✔
502
                }
503
                SymbolExpr::Unary { op, expr } => {
28✔
504
                    let expr_d = expr.derivative(param)?;
28✔
505
                    match op {
28✔
506
                        UnaryOp::Abs => Ok(&(expr.as_ref() * &expr_d)
2✔
507
                            / &SymbolExpr::Unary {
2✔
508
                                op: op.clone(),
2✔
509
                                expr: Box::new(expr.as_ref().clone()),
2✔
510
                            }),
2✔
511
                        UnaryOp::Neg => Ok(SymbolExpr::Unary {
×
512
                            op: UnaryOp::Neg,
×
513
                            expr: Box::new(expr_d),
×
514
                        }),
×
515
                        UnaryOp::Sin => {
516
                            let lhs = SymbolExpr::Unary {
8✔
517
                                op: UnaryOp::Cos,
8✔
518
                                expr: Box::new(expr.as_ref().clone()),
8✔
519
                            };
8✔
520
                            Ok(lhs * expr_d)
8✔
521
                        }
522
                        UnaryOp::Asin => {
523
                            let d = &SymbolExpr::Value(Value::Real(1.0))
2✔
524
                                - &(expr.as_ref() * expr.as_ref());
2✔
525
                            let rhs = match d {
2✔
526
                                SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
527
                                _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
2✔
528
                            };
529
                            Ok(&expr_d / &rhs)
2✔
530
                        }
531
                        UnaryOp::Cos => {
532
                            let lhs = SymbolExpr::Unary {
2✔
533
                                op: UnaryOp::Sin,
2✔
534
                                expr: Box::new(expr.as_ref().clone()),
2✔
535
                            };
2✔
536
                            Ok(&-&lhs * &expr_d)
2✔
537
                        }
538
                        UnaryOp::Acos => {
539
                            let d = &SymbolExpr::Value(Value::Real(1.0))
2✔
540
                                - &(expr.as_ref() * expr.as_ref());
2✔
541
                            let rhs = match d {
2✔
542
                                SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
543
                                _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
2✔
544
                            };
545
                            Ok(&-&expr_d / &rhs)
2✔
546
                        }
547
                        UnaryOp::Tan => {
548
                            let d = SymbolExpr::Unary {
2✔
549
                                op: UnaryOp::Cos,
2✔
550
                                expr: Box::new(expr.as_ref().clone()),
2✔
551
                            };
2✔
552
                            Ok(&(&expr_d / &d) / &d)
2✔
553
                        }
554
                        UnaryOp::Atan => {
555
                            let d = &SymbolExpr::Value(Value::Real(1.0))
2✔
556
                                + &(expr.as_ref() * expr.as_ref());
2✔
557
                            Ok(&expr_d / &d)
2✔
558
                        }
559
                        UnaryOp::Exp => Ok(&SymbolExpr::Unary {
2✔
560
                            op: UnaryOp::Exp,
2✔
561
                            expr: Box::new(expr.as_ref().clone()),
2✔
562
                        } * &expr_d),
2✔
563
                        UnaryOp::Log => Ok(&expr_d / expr.as_ref()),
2✔
564
                        UnaryOp::Sign => {
565
                            Err("SymbolExpr::derivative does not support sign function."
2✔
566
                                .to_string())
2✔
567
                        }
568
                        UnaryOp::Conj => {
569
                            // we assume real parameters, hence Conj acts as identity
570
                            Ok(SymbolExpr::Value(Value::Real(1.0)))
2✔
571
                        }
572
                    }
573
                }
574
                SymbolExpr::Binary { op, lhs, rhs } => match op {
38✔
575
                    BinaryOp::Add => Ok(lhs.derivative(param)? + rhs.derivative(param)?),
10✔
576
                    BinaryOp::Sub => Ok(lhs.derivative(param)? - rhs.derivative(param)?),
×
577
                    BinaryOp::Mul => Ok(&(&lhs.derivative(param)? * rhs.as_ref())
22✔
578
                        + &(lhs.as_ref() * &rhs.derivative(param)?)),
22✔
579
                    BinaryOp::Div => Ok(&(&(&(&lhs.derivative(param)? * rhs.as_ref())
×
580
                        - &(lhs.as_ref() * &rhs.derivative(param)?))
×
581
                        / rhs.as_ref())
×
582
                        / rhs.as_ref()),
×
583
                    BinaryOp::Pow => {
584
                        if !lhs.has_symbol(&param.to_string()) {
6✔
585
                            if !rhs.has_symbol(&param.to_string()) {
6✔
586
                                Ok(SymbolExpr::Value(Value::Real(0.0)))
6✔
587
                            } else {
588
                                Ok(_mul(
×
589
                                    SymbolExpr::Binary {
×
590
                                        op: BinaryOp::Pow,
×
591
                                        lhs: Box::new(lhs.as_ref().clone()),
×
592
                                        rhs: Box::new(rhs.as_ref().clone()),
×
593
                                    },
×
594
                                    SymbolExpr::Unary {
×
595
                                        op: UnaryOp::Log,
×
596
                                        expr: Box::new(lhs.as_ref().clone()),
×
597
                                    },
×
598
                                ))
×
599
                            }
600
                        } else if !rhs.has_symbol(&param.to_string()) {
×
601
                            Ok(rhs.as_ref()
×
602
                                * &SymbolExpr::Binary {
×
603
                                    op: BinaryOp::Pow,
×
604
                                    lhs: Box::new(lhs.as_ref().clone()),
×
605
                                    rhs: Box::new(
×
606
                                        rhs.as_ref() - &SymbolExpr::Value(Value::Real(1.0)),
×
607
                                    ),
×
608
                                })
×
609
                        } else {
610
                            let new_expr = SymbolExpr::Unary {
×
611
                                op: UnaryOp::Exp,
×
612
                                expr: Box::new(_mul(
×
613
                                    SymbolExpr::Unary {
×
614
                                        op: UnaryOp::Log,
×
615
                                        expr: Box::new(lhs.as_ref().clone()),
×
616
                                    },
×
617
                                    rhs.as_ref().clone(),
×
618
                                )),
×
619
                            };
×
620
                            new_expr.derivative(param)
×
621
                        }
622
                    }
623
                },
624
            }
625
        }
626
    }
130✔
627

628
    /// expand the equation
629
    pub fn expand(&self) -> SymbolExpr {
115,248✔
630
        match self {
115,248✔
631
            SymbolExpr::Symbol(_) => self.clone(),
24,688✔
632
            SymbolExpr::Value(_) => self.clone(),
1,826✔
633
            SymbolExpr::Unary { op, expr } => {
2,836✔
634
                let ex = expr.expand();
2,836✔
635
                match op {
2,836✔
636
                    UnaryOp::Neg => match ex.neg_opt() {
346✔
637
                        Some(ne) => ne,
×
638
                        None => _neg(ex),
346✔
639
                    },
640
                    _ => SymbolExpr::Unary {
2,490✔
641
                        op: op.clone(),
2,490✔
642
                        expr: Box::new(ex),
2,490✔
643
                    },
2,490✔
644
                }
645
            }
646
            SymbolExpr::Binary { op, lhs, rhs } => {
85,898✔
647
                match op {
85,898✔
648
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
81,042✔
649
                        Some(e) => e,
1,888✔
650
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
79,154✔
651
                    },
652
                    BinaryOp::Div => match lhs.div_expand(rhs) {
118✔
653
                        Some(e) => e,
4✔
654
                        None => _div(lhs.as_ref().clone(), rhs.as_ref().clone()),
114✔
655
                    },
656
                    BinaryOp::Add => match lhs.add_opt(rhs, true) {
1,010✔
657
                        Some(e) => e,
200✔
658
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
810✔
659
                    },
660
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
2,062✔
661
                        Some(e) => e,
1,400✔
662
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
662✔
663
                    },
664
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
1,666✔
665
                }
666
            }
667
        }
668
    }
115,248✔
669

670
    /// sign operator
671
    pub fn sign(&self) -> SymbolExpr {
6✔
672
        SymbolExpr::Unary {
6✔
673
            op: UnaryOp::Sign,
6✔
674
            expr: Box::new(self.clone()),
6✔
675
        }
6✔
676
    }
6✔
677

678
    /// return real number if equation can be evaluated
679
    pub fn real(&self) -> Option<f64> {
×
680
        match self.eval(true) {
×
681
            Some(v) => match v {
×
682
                Value::Real(r) => Some(r),
×
683
                Value::Int(r) => Some(r as f64),
×
684
                Value::Complex(c) => Some(c.re),
×
685
            },
686
            None => None,
×
687
        }
688
    }
×
689
    /// return imaginary part of the value if equation can be evaluated as complex number
690
    pub fn imag(&self) -> Option<f64> {
×
691
        match self.eval(true) {
×
692
            Some(v) => match v {
×
693
                Value::Real(_) => Some(0.0),
×
694
                Value::Int(_) => Some(0.0),
×
695
                Value::Complex(c) => Some(c.im),
×
696
            },
697
            None => None,
×
698
        }
699
    }
×
700
    /// return complex number if equation can be evaluated as complex
701
    pub fn complex(&self) -> Option<Complex64> {
×
702
        match self.eval(true) {
×
703
            Some(v) => match v {
×
704
                Value::Real(r) => Some(r.into()),
×
705
                Value::Int(i) => Some((i as f64).into()),
×
706
                Value::Complex(c) => Some(c),
×
707
            },
708
            None => None,
×
709
        }
710
    }
×
711

712
    /// return hashset of all symbols this equation contains
713
    pub fn symbols(&self) -> HashSet<String> {
186✔
714
        match self {
186✔
715
            SymbolExpr::Symbol(e) => HashSet::<String>::from([e.as_ref().clone()]),
68✔
716
            SymbolExpr::Value(_) => HashSet::<String>::new(),
46✔
717
            SymbolExpr::Unary { op: _, expr } => expr.symbols(),
14✔
718
            SymbolExpr::Binary { op: _, lhs, rhs } => {
58✔
719
                let mut symbols = HashSet::<String>::new();
58✔
720
                for s in lhs.symbols().union(&rhs.symbols()) {
64✔
721
                    symbols.insert(s.to_string());
64✔
722
                }
64✔
723
                symbols
58✔
724
            }
725
        }
726
    }
186✔
727

728
    /// return all numbers in the equation
729
    pub fn values(&self) -> Vec<Value> {
186✔
730
        match self {
186✔
731
            SymbolExpr::Symbol(_) => Vec::<Value>::new(),
90✔
732
            SymbolExpr::Value(v) => Vec::<Value>::from([*v]),
44✔
733
            SymbolExpr::Unary { op: _, expr } => expr.values(),
×
734
            SymbolExpr::Binary { op: _, lhs, rhs } => {
52✔
735
                let mut l = lhs.values();
52✔
736
                let r = rhs.values();
52✔
737
                l.extend(r);
52✔
738
                l
52✔
739
            }
740
        }
741
    }
186✔
742

743
    /// check if a symbol is in this equation
744
    pub fn has_symbol(&self, param: &String) -> bool {
12✔
745
        match self {
12✔
746
            SymbolExpr::Symbol(e) => e.as_ref() == param,
6✔
747
            SymbolExpr::Value(_) => false,
6✔
748
            SymbolExpr::Unary { op: _, expr } => expr.has_symbol(param),
×
749
            SymbolExpr::Binary { op: _, lhs, rhs } => lhs.has_symbol(param) | rhs.has_symbol(param),
×
750
        }
751
    }
12✔
752

753
    /// return reciprocal of the equation
754
    pub fn rcp(&self) -> SymbolExpr {
×
755
        match self {
×
756
            SymbolExpr::Symbol(e) => _div(
×
757
                SymbolExpr::Value(Value::Real(1.0)),
×
758
                SymbolExpr::Symbol(e.clone()),
×
759
            ),
×
760
            SymbolExpr::Value(e) => SymbolExpr::Value(e.rcp()),
×
761
            SymbolExpr::Unary { .. } => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
762
            SymbolExpr::Binary { op, lhs, rhs } => match op {
×
763
                BinaryOp::Div => SymbolExpr::Binary {
×
764
                    op: op.clone(),
×
765
                    lhs: Box::new(*rhs.clone()),
×
766
                    rhs: Box::new(*lhs.clone()),
×
767
                },
×
768
                _ => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
769
            },
770
        }
771
    }
×
772
    /// return square root of the equation
773
    pub fn sqrt(&self) -> SymbolExpr {
×
774
        match self {
×
775
            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
776
            _ => self.pow(&SymbolExpr::Value(Value::Real(0.5))),
×
777
        }
778
    }
×
779

780
    /// return conjugate of the equation
781
    pub fn conjugate(&self) -> SymbolExpr {
4,452✔
782
        match self {
4,452✔
783
            SymbolExpr::Symbol(_) => SymbolExpr::Unary {
1,716✔
784
                op: UnaryOp::Conj,
1,716✔
785
                expr: Box::new(self.clone()),
1,716✔
786
            },
1,716✔
787
            SymbolExpr::Value(e) => match e {
1,222✔
788
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
614✔
789
                _ => SymbolExpr::Value(*e),
608✔
790
            },
791
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
260✔
792
                op: op.clone(),
260✔
793
                expr: Box::new(expr.conjugate()),
260✔
794
            },
260✔
795
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
1,254✔
796
                op: op.clone(),
1,254✔
797
                lhs: Box::new(lhs.conjugate()),
1,254✔
798
                rhs: Box::new(rhs.conjugate()),
1,254✔
799
            },
1,254✔
800
        }
801
    }
4,452✔
802

803
    /// check if complex number or not
804
    pub fn is_complex(&self) -> Option<bool> {
×
805
        match self.eval(true) {
×
806
            Some(v) => match v {
×
807
                Value::Complex(c) => Some(!(-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
×
808
                _ => Some(false),
×
809
            },
810
            None => None,
×
811
        }
812
    }
×
813

814
    /// check if real number or not
815
    pub fn is_real(&self) -> Option<bool> {
×
816
        match self.eval(true) {
×
817
            Some(v) => match v {
×
818
                Value::Real(_) => Some(true),
×
819
                Value::Int(_) => Some(false),
×
820
                Value::Complex(c) => Some((-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
×
821
            },
822
            None => None,
×
823
        }
824
    }
×
825

826
    /// check if integer or not
827
    pub fn is_int(&self) -> Option<bool> {
3,756✔
828
        match self.eval(true) {
3,756✔
829
            Some(v) => match v {
3,368✔
830
                Value::Int(_) => Some(true),
1,240✔
831
                _ => Some(false),
2,128✔
832
            },
833
            None => None,
388✔
834
        }
835
    }
3,756✔
836

837
    /// check if evaluated result is 0
838
    pub fn is_zero(&self) -> bool {
9,783,690✔
839
        match self.eval(true) {
9,783,690✔
840
            Some(v) => v.is_zero(),
5,675,748✔
841
            None => false,
4,107,942✔
842
        }
843
    }
9,783,690✔
844

845
    /// check if evaluated result is 1
846
    pub fn is_one(&self) -> bool {
767,098✔
847
        match self.eval(true) {
767,098✔
848
            Some(v) => v.is_one(),
544,080✔
849
            None => false,
223,018✔
850
        }
851
    }
767,098✔
852

853
    /// check if evaluated result is -1
854
    pub fn is_minus_one(&self) -> bool {
468,024✔
855
        match self.eval(true) {
468,024✔
856
            Some(v) => v.is_minus_one(),
277,918✔
857
            None => false,
190,106✔
858
        }
859
    }
468,024✔
860

861
    /// check if evaluated result is negative
862
    fn is_negative(&self) -> bool {
417,460✔
863
        match self {
417,460✔
864
            SymbolExpr::Value(v) => v.is_negative(),
61,464✔
865
            SymbolExpr::Symbol(_) => false,
200,356✔
866
            SymbolExpr::Unary { op, expr } => match op {
17,002✔
867
                UnaryOp::Abs => false,
6✔
868
                UnaryOp::Neg => !expr.is_negative(),
14,910✔
869
                _ => false, // TO DO add heuristic determination
2,086✔
870
            },
871
            SymbolExpr::Binary { op, lhs, rhs } => match op {
138,638✔
872
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
119,928✔
873
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
13,360✔
874
                _ => false, // TO DO add heuristic determination for pow
5,350✔
875
            },
876
        }
877
    }
417,460✔
878

879
    /// unary operations
880
    pub fn abs(&self) -> SymbolExpr {
230✔
881
        match self {
4✔
882
            SymbolExpr::Value(l) => SymbolExpr::Value(l.abs()),
6✔
883
            SymbolExpr::Unary {
884
                op: UnaryOp::Abs | UnaryOp::Neg,
885
                expr,
4✔
886
            } => expr.abs(),
4✔
887
            _ => SymbolExpr::Unary {
220✔
888
                op: UnaryOp::Abs,
220✔
889
                expr: Box::new(self.clone()),
220✔
890
            },
220✔
891
        }
892
    }
230✔
893
    pub fn sin(&self) -> SymbolExpr {
214✔
894
        match self {
214✔
895
            SymbolExpr::Value(l) => SymbolExpr::Value(l.sin()),
×
896
            _ => SymbolExpr::Unary {
214✔
897
                op: UnaryOp::Sin,
214✔
898
                expr: Box::new(self.clone()),
214✔
899
            },
214✔
900
        }
901
    }
214✔
902
    pub fn asin(&self) -> SymbolExpr {
60✔
903
        match self {
60✔
904
            SymbolExpr::Value(l) => SymbolExpr::Value(l.asin()),
×
905
            _ => SymbolExpr::Unary {
60✔
906
                op: UnaryOp::Asin,
60✔
907
                expr: Box::new(self.clone()),
60✔
908
            },
60✔
909
        }
910
    }
60✔
911
    pub fn cos(&self) -> SymbolExpr {
206✔
912
        match self {
206✔
913
            SymbolExpr::Value(l) => SymbolExpr::Value(l.cos()),
×
914
            _ => SymbolExpr::Unary {
206✔
915
                op: UnaryOp::Cos,
206✔
916
                expr: Box::new(self.clone()),
206✔
917
            },
206✔
918
        }
919
    }
206✔
920
    pub fn acos(&self) -> SymbolExpr {
60✔
921
        match self {
60✔
922
            SymbolExpr::Value(l) => SymbolExpr::Value(l.acos()),
×
923
            _ => SymbolExpr::Unary {
60✔
924
                op: UnaryOp::Acos,
60✔
925
                expr: Box::new(self.clone()),
60✔
926
            },
60✔
927
        }
928
    }
60✔
929
    pub fn tan(&self) -> SymbolExpr {
204✔
930
        match self {
204✔
931
            SymbolExpr::Value(l) => SymbolExpr::Value(l.tan()),
×
932
            _ => SymbolExpr::Unary {
204✔
933
                op: UnaryOp::Tan,
204✔
934
                expr: Box::new(self.clone()),
204✔
935
            },
204✔
936
        }
937
    }
204✔
938
    pub fn atan(&self) -> SymbolExpr {
60✔
939
        match self {
60✔
940
            SymbolExpr::Value(l) => SymbolExpr::Value(l.atan()),
×
941
            _ => SymbolExpr::Unary {
60✔
942
                op: UnaryOp::Atan,
60✔
943
                expr: Box::new(self.clone()),
60✔
944
            },
60✔
945
        }
946
    }
60✔
947
    pub fn exp(&self) -> SymbolExpr {
202✔
948
        match self {
202✔
949
            SymbolExpr::Value(l) => SymbolExpr::Value(l.exp()),
×
950
            _ => SymbolExpr::Unary {
202✔
951
                op: UnaryOp::Exp,
202✔
952
                expr: Box::new(self.clone()),
202✔
953
            },
202✔
954
        }
955
    }
202✔
956
    pub fn log(&self) -> SymbolExpr {
154✔
957
        match self {
154✔
958
            SymbolExpr::Value(l) => SymbolExpr::Value(l.log()),
×
959
            _ => SymbolExpr::Unary {
154✔
960
                op: UnaryOp::Log,
154✔
961
                expr: Box::new(self.clone()),
154✔
962
            },
154✔
963
        }
964
    }
154✔
965
    pub fn pow(&self, rhs: &SymbolExpr) -> SymbolExpr {
1,804✔
966
        match self {
1,804✔
967
            SymbolExpr::Value(l) => match rhs {
598✔
968
                SymbolExpr::Value(r) => SymbolExpr::Value(l.pow(r)),
×
969
                _ => SymbolExpr::Binary {
598✔
970
                    op: BinaryOp::Pow,
598✔
971
                    lhs: Box::new(SymbolExpr::Value(*l)),
598✔
972
                    rhs: Box::new(rhs.clone()),
598✔
973
                },
598✔
974
            },
975
            _ => SymbolExpr::Binary {
1,206✔
976
                op: BinaryOp::Pow,
1,206✔
977
                lhs: Box::new(self.clone()),
1,206✔
978
                rhs: Box::new(rhs.clone()),
1,206✔
979
            },
1,206✔
980
        }
981
    }
1,804✔
982

983
    // Add with heuristic optimization
984
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,595,476✔
985
        if self.is_zero() {
2,595,476✔
986
            Some(rhs.clone())
1,324,434✔
987
        } else if rhs.is_zero() {
1,271,042✔
988
            Some(self.clone())
1,031,120✔
989
        } else {
990
            // if neg operation, call sub_opt
991
            if let SymbolExpr::Unary { op, expr } = rhs {
239,922✔
992
                if let UnaryOp::Neg = op {
16,090✔
993
                    return self.sub_opt(expr, recursive);
14,340✔
994
                }
1,750✔
995
            } else if recursive {
223,832✔
996
                if let SymbolExpr::Binary {
997
                    op,
33,260✔
998
                    lhs: r_lhs,
33,260✔
999
                    rhs: r_rhs,
33,260✔
1000
                } = rhs
70,688✔
1001
                {
1002
                    // recursive optimization for add and sub
1003
                    if let BinaryOp::Add = &op {
33,260✔
1004
                        if let Some(e) = self.add_opt(r_lhs, true) {
2,776✔
1005
                            return match e.add_opt(r_rhs, true) {
14✔
1006
                                Some(ee) => Some(ee),
6✔
1007
                                None => Some(_add(e, r_rhs.as_ref().clone())),
8✔
1008
                            };
1009
                        }
2,762✔
1010
                        if let Some(e) = self.add_opt(r_rhs, true) {
2,762✔
1011
                            return match e.add_opt(r_lhs, true) {
×
1012
                                Some(ee) => Some(ee),
×
1013
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
1014
                            };
1015
                        }
2,762✔
1016
                    }
30,484✔
1017
                    if let BinaryOp::Sub = &op {
33,246✔
1018
                        if let Some(e) = self.add_opt(r_lhs, true) {
3,016✔
1019
                            return match e.sub_opt(r_rhs, true) {
18✔
1020
                                Some(ee) => Some(ee),
18✔
UNCOV
1021
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
×
1022
                            };
1023
                        }
2,998✔
1024
                        if let Some(e) = self.sub_opt(r_rhs, true) {
2,998✔
1025
                            return match e.add_opt(r_lhs, true) {
×
1026
                                Some(ee) => Some(ee),
×
1027
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
1028
                            };
1029
                        }
2,998✔
1030
                    }
30,230✔
1031
                }
37,428✔
1032
            }
153,144✔
1033

1034
            // optimization for each node type
1035
            match self {
225,550✔
1036
                SymbolExpr::Value(l) => match rhs {
93,828✔
1037
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
70,452✔
1038
                    SymbolExpr::Binary {
1039
                        op,
2,942✔
1040
                        lhs: r_lhs,
2,942✔
1041
                        rhs: r_rhs,
2,942✔
1042
                    } => {
1043
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
2,942✔
1044
                            let t = l + v;
2,278✔
1045
                            match op {
2,278✔
1046
                                BinaryOp::Add => {
1047
                                    if t.is_zero() {
12✔
1048
                                        Some(r_rhs.as_ref().clone())
×
1049
                                    } else {
1050
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
12✔
1051
                                    }
1052
                                }
1053
                                BinaryOp::Sub => {
1054
                                    if t.is_zero() {
×
1055
                                        match r_rhs.neg_opt() {
×
1056
                                            Some(e) => Some(e),
×
1057
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1058
                                        }
1059
                                    } else {
1060
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1061
                                    }
1062
                                }
1063
                                _ => None,
2,266✔
1064
                            }
1065
                        } else {
1066
                            None
664✔
1067
                        }
1068
                    }
1069
                    _ => None,
20,434✔
1070
                },
1071
                SymbolExpr::Symbol(l) => match rhs {
26,848✔
1072
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
1,704✔
1073
                    SymbolExpr::Symbol(r) => {
22,682✔
1074
                        if r == l {
22,682✔
1075
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
144✔
1076
                        } else if r < l {
22,538✔
1077
                            Some(_add(rhs.clone(), self.clone()))
1,728✔
1078
                        } else {
1079
                            None
20,810✔
1080
                        }
1081
                    }
1082
                    SymbolExpr::Binary {
1083
                        op,
2,462✔
1084
                        lhs: r_lhs,
2,462✔
1085
                        rhs: r_rhs,
2,462✔
1086
                    } => {
1087
                        if let (
1088
                            BinaryOp::Mul | BinaryOp::Div,
1089
                            SymbolExpr::Value(v),
1,852✔
1090
                            SymbolExpr::Symbol(s),
1,852✔
1091
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
2,462✔
1092
                        {
1093
                            if l == s {
1,852✔
1094
                                let t = v + &Value::Int(1);
6✔
1095
                                if t.is_zero() {
6✔
1096
                                    Some(SymbolExpr::Value(Value::Int(0)))
2✔
1097
                                } else {
1098
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
4✔
1099
                                }
1100
                            } else {
1101
                                None
1,846✔
1102
                            }
1103
                        } else {
1104
                            None
610✔
1105
                        }
1106
                    }
1107
                    _ => None,
×
1108
                },
1109
                SymbolExpr::Unary { op, expr } => {
11,788✔
1110
                    if let UnaryOp::Neg = op {
11,788✔
1111
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
10,726✔
1112
                            return match e.neg_opt() {
5,446✔
1113
                                Some(ee) => Some(ee),
5,446✔
1114
                                None => Some(_neg(e)),
×
1115
                            };
1116
                        }
5,280✔
1117
                    } else if let SymbolExpr::Unary {
1118
                        op: rop,
644✔
1119
                        expr: rexpr,
644✔
1120
                    } = rhs
1,062✔
1121
                    {
1122
                        if op == rop {
644✔
1123
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
352✔
1124
                                if t.is_zero() {
76✔
1125
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1126
                                }
76✔
1127
                            }
276✔
1128
                        }
292✔
1129
                    }
418✔
1130

1131
                    // swap nodes by sorting rule
1132
                    match rhs {
6,342✔
1133
                        SymbolExpr::Binary { op: rop, .. } => {
4,764✔
1134
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
4,764✔
1135
                                if self > rhs {
4,300✔
1136
                                    Some(_add(rhs.clone(), self.clone()))
×
1137
                                } else {
1138
                                    None
4,300✔
1139
                                }
1140
                            } else {
1141
                                None
464✔
1142
                            }
1143
                        }
1144
                        _ => {
1145
                            if self > rhs {
1,578✔
1146
                                Some(_add(rhs.clone(), self.clone()))
100✔
1147
                            } else {
1148
                                None
1,478✔
1149
                            }
1150
                        }
1151
                    }
1152
                }
1153
                SymbolExpr::Binary {
1154
                    op,
93,086✔
1155
                    lhs: l_lhs,
93,086✔
1156
                    rhs: l_rhs,
93,086✔
1157
                } => {
1158
                    if let SymbolExpr::Binary {
1159
                        op: rop,
86,398✔
1160
                        lhs: r_lhs,
86,398✔
1161
                        rhs: r_rhs,
86,398✔
1162
                    } = rhs
93,086✔
1163
                    {
1164
                        if op == rop {
86,398✔
1165
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
32,692✔
1166
                                if let (SymbolExpr::Value(rv), SymbolExpr::Value(lv)) =
9,664✔
1167
                                    (l_lhs.as_ref(), r_lhs.as_ref())
31,492✔
1168
                                {
1169
                                    if l_rhs.expand().to_string() == r_rhs.expand().to_string() {
9,664✔
1170
                                        return match SymbolExpr::Value(rv + lv)
1,624✔
1171
                                            .mul_opt(l_rhs, recursive)
1,624✔
1172
                                        {
1173
                                            Some(e) => Some(e),
1,288✔
1174
                                            None => Some(_mul(
336✔
1175
                                                SymbolExpr::Value(rv + lv),
336✔
1176
                                                l_rhs.as_ref().clone(),
336✔
1177
                                            )),
336✔
1178
                                        };
1179
                                    }
8,040✔
1180
                                }
21,828✔
1181

1182
                                if let Some(e) = rhs.neg_opt() {
29,868✔
1183
                                    if self.expand().to_string() == e.expand().to_string() {
16,026✔
1184
                                        return Some(SymbolExpr::Value(Value::Int(0)));
4✔
1185
                                    }
16,022✔
1186
                                }
13,842✔
1187
                            }
1,200✔
1188
                        }
53,706✔
1189
                    } else if let SymbolExpr::Symbol(r) = rhs {
6,688✔
1190
                        if let (
1191
                            BinaryOp::Mul | BinaryOp::Div,
1192
                            SymbolExpr::Value(v),
1,418✔
1193
                            SymbolExpr::Symbol(s),
1,418✔
1194
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
4,812✔
1195
                        {
1196
                            if s == r {
1,418✔
1197
                                let t = v + &Value::Int(1);
×
1198
                                if t.is_zero() {
×
1199
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1200
                                } else {
1201
                                    return Some(_mul(
×
1202
                                        SymbolExpr::Value(t),
×
1203
                                        l_rhs.as_ref().clone(),
×
1204
                                    ));
×
1205
                                }
1206
                            }
1,418✔
1207
                        }
3,394✔
1208
                    }
1,876✔
1209
                    if recursive {
91,458✔
1210
                        if let BinaryOp::Add = op {
31,078✔
1211
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
4,356✔
1212
                                return match e.add_opt(l_rhs, true) {
508✔
1213
                                    Some(ee) => Some(ee),
214✔
1214
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
294✔
1215
                                };
1216
                            }
3,848✔
1217
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
3,848✔
1218
                                return match l_lhs.add_opt(&e, true) {
78✔
1219
                                    Some(ee) => Some(ee),
×
1220
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
78✔
1221
                                };
1222
                            }
3,770✔
1223
                        } else if let BinaryOp::Sub = op {
26,722✔
1224
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
4,478✔
1225
                                return match e.sub_opt(l_rhs, true) {
942✔
1226
                                    Some(ee) => Some(ee),
256✔
1227
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
686✔
1228
                                };
1229
                            }
3,536✔
1230
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
3,536✔
1231
                                return match l_lhs.sub_opt(&e, true) {
112✔
1232
                                    Some(ee) => Some(ee),
16✔
1233
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
96✔
1234
                                };
1235
                            }
3,424✔
1236
                        }
22,244✔
1237
                    }
60,380✔
1238
                    // swap nodes by sorting rule
1239
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
89,818✔
1240
                        match rhs {
36,352✔
1241
                            SymbolExpr::Binary { op: rop, .. } => {
34,068✔
1242
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
34,068✔
1243
                                    if self > rhs {
29,962✔
1244
                                        Some(_add(rhs.clone(), self.clone()))
318✔
1245
                                    } else {
1246
                                        None
29,644✔
1247
                                    }
1248
                                } else {
1249
                                    None
4,106✔
1250
                                }
1251
                            }
1252
                            _ => {
1253
                                if self > rhs {
2,284✔
1254
                                    Some(_add(rhs.clone(), self.clone()))
2,284✔
1255
                                } else {
1256
                                    None
×
1257
                                }
1258
                            }
1259
                        }
1260
                    } else {
1261
                        None
53,466✔
1262
                    }
1263
                }
1264
            }
1265
        }
1266
    }
2,595,476✔
1267

1268
    /// Sub with heuristic optimization
1269
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
240,544✔
1270
        if self.is_zero() {
240,544✔
1271
            match rhs.neg_opt() {
6,958✔
1272
                Some(e) => Some(e),
6,038✔
1273
                None => Some(_neg(rhs.clone())),
920✔
1274
            }
1275
        } else if rhs.is_zero() {
233,586✔
1276
            Some(self.clone())
1,874✔
1277
        } else {
1278
            // if neg, call add_opt
1279
            if let SymbolExpr::Unary { op, expr } = rhs {
231,712✔
1280
                if let UnaryOp::Neg = op {
4,710✔
1281
                    return self.add_opt(expr, recursive);
2,612✔
1282
                }
2,098✔
1283
            } else if recursive {
227,002✔
1284
                if let SymbolExpr::Binary {
1285
                    op,
37,116✔
1286
                    lhs: r_lhs,
37,116✔
1287
                    rhs: r_rhs,
37,116✔
1288
                } = rhs
131,424✔
1289
                {
1290
                    // recursive optimization for add and sub
1291
                    if let BinaryOp::Add = &op {
37,116✔
1292
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,596✔
1293
                            return match e.sub_opt(r_rhs, true) {
594✔
1294
                                Some(ee) => Some(ee),
582✔
1295
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
12✔
1296
                            };
1297
                        }
3,002✔
1298
                        if let Some(e) = self.sub_opt(r_rhs, true) {
3,002✔
1299
                            return match e.sub_opt(r_lhs, true) {
4✔
1300
                                Some(ee) => Some(ee),
×
1301
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
4✔
1302
                            };
1303
                        }
2,998✔
1304
                    }
33,520✔
1305
                    if let BinaryOp::Sub = &op {
36,518✔
1306
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,384✔
1307
                            return match e.add_opt(r_rhs, true) {
572✔
1308
                                Some(ee) => Some(ee),
556✔
1309
                                None => Some(_add(e, r_rhs.as_ref().clone())),
16✔
1310
                            };
1311
                        }
2,812✔
1312
                        if let Some(e) = self.add_opt(r_rhs, true) {
2,812✔
1313
                            return match e.sub_opt(r_lhs, true) {
×
1314
                                Some(ee) => Some(ee),
×
1315
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
×
1316
                            };
1317
                        }
2,812✔
1318
                    }
33,134✔
1319
                }
94,308✔
1320
            }
95,578✔
1321

1322
            // optimization for each type
1323
            match self {
227,930✔
1324
                SymbolExpr::Value(l) => match &rhs {
76,872✔
1325
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
70,906✔
1326
                    SymbolExpr::Binary {
1327
                        op,
2,816✔
1328
                        lhs: r_lhs,
2,816✔
1329
                        rhs: r_rhs,
2,816✔
1330
                    } => {
1331
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
2,816✔
1332
                            let t = l - v;
1,466✔
1333
                            match op {
1,466✔
1334
                                BinaryOp::Add => {
1335
                                    if t.is_zero() {
×
1336
                                        match r_rhs.neg_opt() {
×
1337
                                            Some(e) => Some(e),
×
1338
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1339
                                        }
1340
                                    } else {
1341
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1342
                                    }
1343
                                }
1344
                                BinaryOp::Sub => {
1345
                                    if t.is_zero() {
×
1346
                                        Some(r_rhs.as_ref().clone())
×
1347
                                    } else {
1348
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1349
                                    }
1350
                                }
1351
                                _ => None,
1,466✔
1352
                            }
1353
                        } else {
1354
                            None
1,350✔
1355
                        }
1356
                    }
1357
                    _ => None,
3,150✔
1358
                },
1359
                SymbolExpr::Symbol(l) => match &rhs {
55,860✔
1360
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
2,166✔
1361
                    SymbolExpr::Symbol(r) => {
50,790✔
1362
                        if r == l {
50,790✔
1363
                            Some(SymbolExpr::Value(Value::Int(0)))
28,978✔
1364
                        } else if r < l {
21,812✔
1365
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,322✔
1366
                        } else {
1367
                            None
20,490✔
1368
                        }
1369
                    }
1370
                    SymbolExpr::Binary {
1371
                        op,
2,904✔
1372
                        lhs: r_lhs,
2,904✔
1373
                        rhs: r_rhs,
2,904✔
1374
                    } => {
1375
                        if let (
1376
                            BinaryOp::Mul | BinaryOp::Div,
1377
                            SymbolExpr::Value(v),
1,746✔
1378
                            SymbolExpr::Symbol(s),
1,746✔
1379
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
2,904✔
1380
                        {
1381
                            if l == s {
1,746✔
1382
                                let t = &Value::Int(1) - v;
10✔
1383
                                if t.is_zero() {
10✔
1384
                                    Some(SymbolExpr::Value(Value::Int(0)))
×
1385
                                } else {
1386
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
10✔
1387
                                }
1388
                            } else {
1389
                                None
1,736✔
1390
                            }
1391
                        } else {
1392
                            None
1,158✔
1393
                        }
1394
                    }
1395
                    _ => None,
×
1396
                },
1397
                SymbolExpr::Unary { op, expr } => {
11,462✔
1398
                    if let UnaryOp::Neg = op {
11,462✔
1399
                        if let Some(e) = expr.add_opt(rhs, recursive) {
9,570✔
1400
                            return match e.neg_opt() {
5,744✔
1401
                                Some(ee) => Some(ee),
5,744✔
1402
                                None => Some(_neg(e)),
×
1403
                            };
1404
                        }
3,826✔
1405
                    }
1,892✔
1406
                    if let SymbolExpr::Unary {
1407
                        op: rop,
1,528✔
1408
                        expr: rexpr,
1,528✔
1409
                    } = rhs
5,718✔
1410
                    {
1411
                        if op == rop {
1,528✔
1412
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
1,116✔
1413
                                if t.is_zero() {
828✔
1414
                                    return Some(SymbolExpr::Value(Value::Int(0)));
764✔
1415
                                }
64✔
1416
                            }
288✔
1417
                        }
412✔
1418
                    }
4,190✔
1419

1420
                    // swap nodes by sorting rule
1421
                    match rhs {
4,954✔
1422
                        SymbolExpr::Binary { op: rop, .. } => {
3,238✔
1423
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
3,238✔
1424
                                if self > rhs {
2,876✔
1425
                                    match rhs.neg_opt() {
×
1426
                                        Some(e) => Some(_add(e, self.clone())),
×
1427
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
×
1428
                                    }
1429
                                } else {
1430
                                    None
2,876✔
1431
                                }
1432
                            } else {
1433
                                None
362✔
1434
                            }
1435
                        }
1436
                        _ => {
1437
                            if self > rhs {
1,716✔
1438
                                match rhs.neg_opt() {
88✔
1439
                                    Some(e) => Some(_add(e, self.clone())),
×
1440
                                    None => Some(_add(_neg(rhs.clone()), self.clone())),
88✔
1441
                                }
1442
                            } else {
1443
                                None
1,628✔
1444
                            }
1445
                        }
1446
                    }
1447
                }
1448
                SymbolExpr::Binary {
1449
                    op,
83,736✔
1450
                    lhs: l_lhs,
83,736✔
1451
                    rhs: l_rhs,
83,736✔
1452
                } => {
1453
                    if let SymbolExpr::Binary {
1454
                        op: rop,
41,182✔
1455
                        lhs: r_lhs,
41,182✔
1456
                        rhs: r_rhs,
41,182✔
1457
                    } = rhs
83,736✔
1458
                    {
1459
                        if op == rop {
41,182✔
1460
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
22,060✔
1461
                                if let (SymbolExpr::Value(rv), SymbolExpr::Value(lv)) =
3,656✔
1462
                                    (l_lhs.as_ref(), r_lhs.as_ref())
21,208✔
1463
                                {
1464
                                    if l_rhs.expand().to_string() == r_rhs.expand().to_string() {
3,656✔
1465
                                        return match SymbolExpr::Value(rv - lv)
1,098✔
1466
                                            .mul_opt(l_rhs, recursive)
1,098✔
1467
                                        {
1468
                                            Some(e) => Some(e),
1,098✔
1469
                                            None => Some(_mul(
×
1470
                                                SymbolExpr::Value(rv - lv),
×
1471
                                                l_rhs.as_ref().clone(),
×
1472
                                            )),
×
1473
                                        };
1474
                                    }
2,558✔
1475
                                }
17,552✔
1476
                                if self.expand().to_string() == rhs.expand().to_string() {
20,110✔
1477
                                    return Some(SymbolExpr::Value(Value::Int(0)));
114✔
1478
                                }
19,996✔
1479
                            }
852✔
1480
                        }
19,122✔
1481
                    } else if let SymbolExpr::Symbol(r) = rhs {
42,554✔
1482
                        if let (
1483
                            BinaryOp::Mul | BinaryOp::Div,
1484
                            SymbolExpr::Value(v),
1,316✔
1485
                            SymbolExpr::Symbol(s),
1,316✔
1486
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
22,146✔
1487
                        {
1488
                            if s == r {
1,316✔
1489
                                let t = v - &Value::Int(1);
12✔
1490
                                if t.is_zero() {
12✔
1491
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1492
                                } else {
1493
                                    return Some(_mul(
12✔
1494
                                        SymbolExpr::Value(t),
12✔
1495
                                        l_rhs.as_ref().clone(),
12✔
1496
                                    ));
12✔
1497
                                }
1498
                            }
1,304✔
1499
                        }
20,830✔
1500
                    }
20,408✔
1501
                    if recursive {
82,512✔
1502
                        if let BinaryOp::Add = op {
68,354✔
1503
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
39,796✔
1504
                                return match e.add_opt(l_rhs, true) {
18,392✔
1505
                                    Some(ee) => Some(ee),
17,970✔
1506
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
422✔
1507
                                };
1508
                            }
21,404✔
1509
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
21,404✔
1510
                                return match l_lhs.add_opt(&e, true) {
17,620✔
1511
                                    Some(ee) => Some(ee),
17,564✔
1512
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
56✔
1513
                                };
1514
                            }
3,784✔
1515
                        }
28,558✔
1516
                        if let BinaryOp::Sub = op {
32,342✔
1517
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
6,986✔
1518
                                return match e.sub_opt(l_rhs, true) {
830✔
1519
                                    Some(ee) => Some(ee),
302✔
1520
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
528✔
1521
                                };
1522
                            }
6,156✔
1523
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
6,156✔
1524
                                return match l_lhs.sub_opt(&e, true) {
42✔
1525
                                    Some(ee) => Some(ee),
×
1526
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
42✔
1527
                                };
1528
                            }
6,114✔
1529
                        }
25,356✔
1530
                    }
14,158✔
1531
                    // swap nodes by sorting rule
1532
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
45,628✔
1533
                        match rhs {
27,050✔
1534
                            SymbolExpr::Binary { op: rop, .. } => {
24,146✔
1535
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
24,146✔
1536
                                    if self > rhs {
20,188✔
1537
                                        match rhs.neg_opt() {
62✔
1538
                                            Some(e) => Some(_add(e, self.clone())),
8✔
1539
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
54✔
1540
                                        }
1541
                                    } else {
1542
                                        None
20,126✔
1543
                                    }
1544
                                } else {
1545
                                    None
3,958✔
1546
                                }
1547
                            }
1548
                            _ => {
1549
                                if self > rhs {
2,904✔
1550
                                    match rhs.neg_opt() {
2,904✔
1551
                                        Some(e) => Some(_add(e, self.clone())),
1,004✔
1552
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
1,900✔
1553
                                    }
1554
                                } else {
1555
                                    None
×
1556
                                }
1557
                            }
1558
                        }
1559
                    } else {
1560
                        None
18,578✔
1561
                    }
1562
                }
1563
            }
1564
        }
1565
    }
240,544✔
1566

1567
    /// Mul with heuristic optimization
1568
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,722,040✔
1569
        if self.is_zero() {
2,722,040✔
1570
            Some(self.clone())
20,716✔
1571
        } else if rhs.is_zero() || self.is_one() {
2,701,324✔
1572
            Some(rhs.clone())
2,387,146✔
1573
        } else if rhs.is_one() {
314,178✔
1574
            Some(self.clone())
84,680✔
1575
        } else if self.is_minus_one() {
229,498✔
1576
            match rhs.neg_opt() {
2,990✔
1577
                Some(e) => Some(e),
1,510✔
1578
                None => Some(_neg(rhs.clone())),
1,480✔
1579
            }
1580
        } else if rhs.is_minus_one() {
226,508✔
1581
            match self.neg_opt() {
26,660✔
1582
                Some(e) => Some(e),
8,874✔
1583
                None => Some(_neg(self.clone())),
17,786✔
1584
            }
1585
        } else {
1586
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
199,848✔
1587
                if let SymbolExpr::Unary { .. } = self {
158,636✔
1588
                    return match rhs.mul_opt(self, recursive) {
5,190✔
1589
                        Some(e) => Some(e),
4,910✔
1590
                        None => Some(_mul(rhs.clone(), self.clone())),
280✔
1591
                    };
1592
                }
153,446✔
1593
            }
41,212✔
1594

1595
            match self {
194,658✔
1596
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
109,592✔
1597
                SymbolExpr::Symbol(e) => match rhs {
32,674✔
1598
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
14,822✔
1599
                    SymbolExpr::Symbol(r) => {
9,882✔
1600
                        if r < e {
9,882✔
1601
                            Some(_mul(rhs.clone(), self.clone()))
4,026✔
1602
                        } else {
1603
                            None
5,856✔
1604
                        }
1605
                    }
1606
                    SymbolExpr::Unary {
1607
                        op: UnaryOp::Neg,
1608
                        expr,
2,326✔
1609
                    } => match expr.as_ref() {
2,326✔
1610
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1611
                        SymbolExpr::Symbol(s) => {
2,326✔
1612
                            if s < e {
2,326✔
1613
                                Some(_neg(_mul(*expr.clone(), self.clone())))
1,152✔
1614
                            } else {
1615
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
1,174✔
1616
                            }
1617
                        }
1618
                        SymbolExpr::Binary { .. } => match self.mul_opt(expr, recursive) {
×
1619
                            Some(e) => match e.neg_opt() {
×
1620
                                Some(ee) => Some(ee),
×
1621
                                None => Some(_neg(e)),
×
1622
                            },
1623
                            None => None,
×
1624
                        },
1625
                        _ => None,
×
1626
                    },
1627
                    _ => None,
5,644✔
1628
                },
1629
                SymbolExpr::Unary { op, expr } => match op {
2,216✔
1630
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
2,200✔
1631
                        Some(e) => match e.neg_opt() {
502✔
1632
                            Some(ee) => Some(ee),
502✔
1633
                            None => Some(_neg(e)),
×
1634
                        },
1635
                        None => None,
1,698✔
1636
                    },
1637
                    UnaryOp::Abs => match rhs {
2✔
1638
                        SymbolExpr::Unary {
1639
                            op: UnaryOp::Abs,
1640
                            expr: rexpr,
2✔
1641
                        } => match expr.mul_opt(rexpr, recursive) {
2✔
1642
                            Some(e) => Some(SymbolExpr::Unary {
×
1643
                                op: UnaryOp::Abs,
×
1644
                                expr: Box::new(e),
×
1645
                            }),
×
1646
                            None => Some(SymbolExpr::Unary {
2✔
1647
                                op: UnaryOp::Abs,
2✔
1648
                                expr: Box::new(_mul(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
1649
                            }),
2✔
1650
                        },
1651
                        _ => None,
×
1652
                    },
1653
                    _ => None,
14✔
1654
                },
1655
                SymbolExpr::Binary {
1656
                    op,
50,176✔
1657
                    lhs: l_lhs,
50,176✔
1658
                    rhs: l_rhs,
50,176✔
1659
                } => {
50,176✔
1660
                    if recursive {
50,176✔
1661
                        if let SymbolExpr::Binary {
1662
                            op: rop,
186✔
1663
                            lhs: r_lhs,
186✔
1664
                            rhs: r_rhs,
186✔
1665
                        } = rhs
3,164✔
1666
                        {
1667
                            if let BinaryOp::Mul = &rop {
186✔
1668
                                if let Some(e) = self.mul_opt(r_lhs, true) {
166✔
1669
                                    return match e.mul_opt(r_rhs, true) {
166✔
1670
                                        Some(ee) => Some(ee),
152✔
1671
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
14✔
1672
                                    };
1673
                                }
×
1674
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
1675
                                    return match e.mul_opt(r_lhs, true) {
×
1676
                                        Some(ee) => Some(ee),
×
1677
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1678
                                    };
1679
                                }
×
1680
                            }
20✔
1681
                            if let BinaryOp::Div = &rop {
20✔
1682
                                if let Some(e) = self.mul_opt(r_lhs, true) {
×
1683
                                    return match e.div_opt(r_rhs, true) {
×
1684
                                        Some(ee) => Some(ee),
×
1685
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
1686
                                    };
1687
                                }
×
1688
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
1689
                                    return match e.mul_opt(r_lhs, true) {
×
1690
                                        Some(ee) => Some(ee),
×
1691
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1692
                                    };
1693
                                }
×
1694
                            }
20✔
1695
                        }
2,978✔
1696

1697
                        if let BinaryOp::Mul = &op {
2,998✔
1698
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
2,992✔
1699
                                return match e.mul_opt(l_rhs, true) {
930✔
1700
                                    Some(ee) => Some(ee),
874✔
1701
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
56✔
1702
                                };
1703
                            }
2,062✔
1704
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
2,062✔
1705
                                return match l_lhs.mul_opt(&e, true) {
1,320✔
1706
                                    Some(ee) => Some(ee),
×
1707
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
1,320✔
1708
                                };
1709
                            }
742✔
1710
                        } else if let BinaryOp::Div = &op {
6✔
1711
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
×
1712
                                return match e.div_opt(l_rhs, true) {
×
1713
                                    Some(ee) => Some(ee),
×
1714
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
1715
                                };
1716
                            }
×
1717
                            if let Some(e) = rhs.div_opt(l_rhs, true) {
×
1718
                                return match l_lhs.mul_opt(&e, true) {
×
1719
                                    Some(ee) => Some(ee),
×
1720
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1721
                                };
1722
                            }
×
1723
                        }
6✔
1724
                        None
748✔
1725
                    } else {
1726
                        match rhs {
47,012✔
1727
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
31,154✔
1728
                                SymbolExpr::Value(lv) => match op {
10,586✔
1729
                                    BinaryOp::Mul => Some(_mul(
10,182✔
1730
                                        SymbolExpr::Value(lv * v),
10,182✔
1731
                                        l_rhs.as_ref().clone(),
10,182✔
1732
                                    )),
10,182✔
1733
                                    BinaryOp::Div => Some(_div(
×
1734
                                        SymbolExpr::Value(lv * v),
×
1735
                                        l_rhs.as_ref().clone(),
×
1736
                                    )),
×
1737
                                    _ => None,
404✔
1738
                                },
1739
                                _ => match l_rhs.as_ref() {
20,568✔
1740
                                    SymbolExpr::Value(rv) => match op {
288✔
1741
                                        BinaryOp::Mul => Some(_mul(
×
1742
                                            SymbolExpr::Value(rv * v),
×
1743
                                            l_lhs.as_ref().clone(),
×
1744
                                        )),
×
1745
                                        BinaryOp::Div => Some(_mul(
×
1746
                                            SymbolExpr::Value(v / rv),
×
1747
                                            l_lhs.as_ref().clone(),
×
1748
                                        )),
×
1749
                                        _ => None,
288✔
1750
                                    },
1751
                                    _ => None,
20,280✔
1752
                                },
1753
                            },
1754
                            SymbolExpr::Binary {
1755
                                op: rop,
9,650✔
1756
                                lhs: r_lhs,
9,650✔
1757
                                rhs: r_rhs,
9,650✔
1758
                            } => match (l_lhs.as_ref(), r_lhs.as_ref()) {
9,650✔
1759
                                (SymbolExpr::Value(lv), SymbolExpr::Value(rv)) => match (op, rop) {
1,580✔
1760
                                    (BinaryOp::Mul, BinaryOp::Mul) => Some(_mul(
826✔
1761
                                        SymbolExpr::Value(lv * rv),
826✔
1762
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
826✔
1763
                                    )),
826✔
1764
                                    (BinaryOp::Mul, BinaryOp::Div) => Some(_mul(
×
1765
                                        SymbolExpr::Value(lv * rv),
×
1766
                                        _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1767
                                    )),
×
1768
                                    (BinaryOp::Div, BinaryOp::Mul) => Some(_mul(
×
1769
                                        SymbolExpr::Value(lv * rv),
×
1770
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1771
                                    )),
×
1772
                                    (BinaryOp::Div, BinaryOp::Div) => Some(_div(
×
1773
                                        SymbolExpr::Value(lv * rv),
×
1774
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1775
                                    )),
×
1776
                                    (_, _) => None,
754✔
1777
                                },
1778
                                (_, _) => None,
8,070✔
1779
                            },
1780
                            _ => None,
6,208✔
1781
                        }
1782
                    }
1783
                }
1784
            }
1785
        }
1786
    }
2,722,040✔
1787
    /// expand with optimization for mul operation
1788
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
164,096✔
1789
        if let SymbolExpr::Binary {
1790
            op: rop,
22,150✔
1791
            lhs: r_lhs,
22,150✔
1792
            rhs: r_rhs,
22,150✔
1793
        } = rhs
164,096✔
1794
        {
1795
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
22,150✔
1796
                let el = match self.mul_expand(r_lhs) {
1,430✔
1797
                    Some(e) => e,
794✔
1798
                    None => match self.mul_opt(r_lhs, true) {
636✔
1799
                        Some(e) => e,
400✔
1800
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
236✔
1801
                    },
1802
                };
1803
                let er = match self.mul_expand(r_rhs) {
1,430✔
1804
                    Some(e) => e,
534✔
1805
                    None => match self.mul_opt(r_rhs, true) {
896✔
1806
                        Some(e) => e,
204✔
1807
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
692✔
1808
                    },
1809
                };
1810
                return match &rop {
1,430✔
1811
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
808✔
1812
                        Some(e) => Some(e),
24✔
1813
                        None => Some(_sub(el, er)),
784✔
1814
                    },
1815
                    _ => match el.add_opt(&er, true) {
622✔
1816
                        Some(e) => Some(e),
14✔
1817
                        None => Some(_add(el, er)),
608✔
1818
                    },
1819
                };
1820
            }
20,720✔
1821
            if let BinaryOp::Mul = &rop {
20,720✔
1822
                return match self.mul_expand(r_lhs) {
20,554✔
1823
                    Some(e) => match e.mul_expand(r_rhs) {
792✔
1824
                        Some(ee) => Some(ee),
696✔
1825
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
96✔
1826
                    },
1827
                    None => self
19,762✔
1828
                        .mul_expand(r_rhs)
19,762✔
1829
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
19,762✔
1830
                };
1831
            }
166✔
1832
            if let BinaryOp::Div = &rop {
166✔
1833
                return match self.mul_expand(r_lhs) {
×
1834
                    Some(e) => match e.mul_expand(r_rhs) {
×
1835
                        Some(ee) => Some(ee),
×
1836
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
1837
                    },
1838
                    None => self
×
1839
                        .div_expand(r_rhs)
×
1840
                        .map(|e| _div(e, r_lhs.as_ref().clone())),
×
1841
                };
1842
            }
166✔
1843
        }
141,946✔
1844
        if let SymbolExpr::Unary {
1845
            op: UnaryOp::Neg,
1846
            expr: rexpr,
520✔
1847
        } = rhs
1,782✔
1848
        {
1849
            return match self.mul_expand(rexpr) {
520✔
1850
                Some(e) => match e.neg_opt() {
182✔
1851
                    Some(ee) => Some(ee),
182✔
1852
                    None => Some(_neg(e)),
×
1853
                },
1854
                None => match self.mul_opt(rexpr, true) {
338✔
1855
                    Some(e) => match e.neg_opt() {
60✔
1856
                        Some(ee) => Some(ee),
24✔
1857
                        None => Some(_neg(e)),
36✔
1858
                    },
1859
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
278✔
1860
                },
1861
            };
1862
        }
141,592✔
1863

1864
        match self {
884✔
1865
            SymbolExpr::Unary {
1866
                op: UnaryOp::Neg,
1867
                expr,
846✔
1868
            } => match expr.mul_expand(rhs) {
846✔
1869
                Some(e) => match e.neg_opt() {
×
1870
                    Some(ee) => Some(ee),
×
1871
                    None => Some(_neg(e)),
×
1872
                },
1873
                None => match expr.mul_opt(rhs, true) {
846✔
1874
                    Some(e) => match e.neg_opt() {
638✔
1875
                        Some(ee) => Some(ee),
358✔
1876
                        None => Some(_neg(e)),
280✔
1877
                    },
1878
                    None => None,
208✔
1879
                },
1880
            },
1881
            SymbolExpr::Binary {
1882
                op,
18,848✔
1883
                lhs: l_lhs,
18,848✔
1884
                rhs: l_rhs,
18,848✔
1885
            } => match &op {
18,848✔
1886
                BinaryOp::Add | BinaryOp::Sub => {
1887
                    let l = match l_lhs.mul_expand(rhs) {
3,358✔
1888
                        Some(e) => e,
1,812✔
1889
                        None => match l_lhs.mul_opt(rhs, true) {
1,546✔
1890
                            Some(e) => e,
1,186✔
1891
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
360✔
1892
                        },
1893
                    };
1894
                    let r = match l_rhs.mul_expand(rhs) {
3,358✔
1895
                        Some(e) => e,
16✔
1896
                        None => match l_rhs.mul_opt(rhs, true) {
3,342✔
1897
                            Some(e) => e,
2,710✔
1898
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
632✔
1899
                        },
1900
                    };
1901
                    match &op {
3,358✔
1902
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
1,492✔
1903
                            Some(e) => Some(e),
146✔
1904
                            None => Some(_sub(l, r)),
1,346✔
1905
                        },
1906
                        _ => match l.add_opt(&r, true) {
1,866✔
1907
                            Some(e) => Some(e),
202✔
1908
                            None => Some(_add(l, r)),
1,664✔
1909
                        },
1910
                    }
1911
                }
1912
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
15,490✔
1913
                    Some(e) => match e.mul_expand(l_rhs) {
×
1914
                        Some(ee) => Some(ee),
×
1915
                        None => match e.mul_opt(l_rhs, true) {
×
1916
                            Some(ee) => Some(ee),
×
1917
                            None => Some(_mul(e, l_rhs.as_ref().clone())),
×
1918
                        },
1919
                    },
1920
                    None => match l_rhs.mul_expand(rhs) {
15,490✔
1921
                        Some(e) => match l_lhs.mul_expand(&e) {
24✔
1922
                            Some(ee) => Some(ee),
24✔
1923
                            None => match l_lhs.mul_opt(&e, true) {
×
1924
                                Some(ee) => Some(ee),
×
1925
                                None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1926
                            },
1927
                        },
1928
                        None => None,
15,466✔
1929
                    },
1930
                },
1931
                BinaryOp::Div => match l_lhs.div_expand(rhs) {
×
1932
                    Some(e) => Some(_div(e, l_rhs.as_ref().clone())),
×
1933
                    None => l_rhs
×
1934
                        .div_expand(rhs)
×
1935
                        .map(|e| _div(l_lhs.as_ref().clone(), e)),
×
1936
                },
1937
                _ => None,
×
1938
            },
1939
            _ => None,
121,898✔
1940
        }
1941
    }
164,096✔
1942

1943
    /// Div with heuristic optimization
1944
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
13,646✔
1945
        if rhs.is_zero() {
13,646✔
1946
            // return inf to detect divide by zero without panic
1947
            Some(SymbolExpr::Value(Value::Real(f64::INFINITY)))
1,108✔
1948
        } else if rhs.is_one() {
12,538✔
1949
            Some(self.clone())
520✔
1950
        } else if rhs.is_minus_one() {
12,018✔
1951
            match self.neg_opt() {
392✔
1952
                Some(e) => Some(e),
100✔
1953
                None => Some(_neg(self.clone())),
292✔
1954
            }
1955
        } else if *self == *rhs {
11,626✔
1956
            let l_is_int = self.is_int().unwrap_or_default();
1,878✔
1957
            let r_is_int = rhs.is_int().unwrap_or_default();
1,878✔
1958
            if l_is_int || r_is_int {
1,878✔
1959
                Some(SymbolExpr::Value(Value::Int(1)))
620✔
1960
            } else {
1961
                Some(SymbolExpr::Value(Value::Real(1.0)))
1,258✔
1962
            }
1963
        } else {
1964
            if let SymbolExpr::Value(v) = rhs {
9,748✔
1965
                if let Value::Real(r) = v {
4,900✔
1966
                    let t = 1.0 / r;
728✔
1967
                    if &(1.0 / t) == r {
728✔
1968
                        if recursive {
722✔
1969
                            return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
1970
                        } else {
1971
                            return Some(&SymbolExpr::Value(Value::Real(t)) * self);
722✔
1972
                        }
1973
                    }
6✔
1974
                } else if let Value::Int(i) = v {
4,172✔
1975
                    let a = i.unsigned_abs();
2,114✔
1976
                    if ((a - 1) & a) == 0 {
2,114✔
1977
                        if recursive {
954✔
1978
                            return self.mul_opt(
×
1979
                                &SymbolExpr::Value(Value::Real(1.0 / (*i as f64))),
×
1980
                                recursive,
×
1981
                            );
×
1982
                        } else {
1983
                            return Some(&SymbolExpr::Value(Value::Real(1.0 / (*i as f64))) * self);
954✔
1984
                        }
1985
                    }
1,160✔
1986
                }
2,058✔
1987
            }
4,848✔
1988

1989
            match self {
8,072✔
1990
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
4,468✔
1991
                SymbolExpr::Symbol(_) => None,
1,882✔
1992
                SymbolExpr::Unary { op, expr } => match op {
46✔
1993
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
24✔
1994
                        Some(e) => match e.neg_opt() {
12✔
1995
                            Some(ee) => Some(ee),
12✔
1996
                            None => Some(_neg(e)),
×
1997
                        },
1998
                        None => None,
12✔
1999
                    },
2000
                    UnaryOp::Abs => match rhs {
2✔
2001
                        SymbolExpr::Unary {
2002
                            op: UnaryOp::Abs,
2003
                            expr: rexpr,
2✔
2004
                        } => match expr.div_opt(rexpr, recursive) {
2✔
2005
                            Some(e) => Some(SymbolExpr::Unary {
×
2006
                                op: UnaryOp::Abs,
×
2007
                                expr: Box::new(e),
×
2008
                            }),
×
2009
                            None => Some(SymbolExpr::Unary {
2✔
2010
                                op: UnaryOp::Abs,
2✔
2011
                                expr: Box::new(_div(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
2012
                            }),
2✔
2013
                        },
2014
                        _ => None,
×
2015
                    },
2016
                    _ => None,
20✔
2017
                },
2018
                SymbolExpr::Binary {
2019
                    op,
1,676✔
2020
                    lhs: l_lhs,
1,676✔
2021
                    rhs: l_rhs,
1,676✔
2022
                } => {
1,676✔
2023
                    if recursive {
1,676✔
2024
                        if let SymbolExpr::Binary {
2025
                            op: rop,
×
2026
                            lhs: r_lhs,
×
2027
                            rhs: r_rhs,
×
2028
                        } = rhs
×
2029
                        {
2030
                            if let BinaryOp::Mul = &rop {
×
2031
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2032
                                    return match e.div_opt(r_rhs, true) {
×
2033
                                        Some(ee) => Some(ee),
×
2034
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
2035
                                    };
2036
                                }
×
2037
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
2038
                                    return match e.div_opt(r_lhs, true) {
×
2039
                                        Some(ee) => Some(ee),
×
2040
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2041
                                    };
2042
                                }
×
2043
                            }
×
2044
                            if let BinaryOp::Div = &rop {
×
2045
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
2046
                                    return match e.div_opt(r_lhs, true) {
×
2047
                                        Some(ee) => Some(ee),
×
2048
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2049
                                    };
2050
                                }
×
2051
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2052
                                    return match e.mul_opt(r_rhs, true) {
×
2053
                                        Some(ee) => Some(ee),
×
2054
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2055
                                    };
2056
                                }
×
2057
                            }
×
2058
                        }
×
2059

2060
                        if let BinaryOp::Mul = &op {
×
2061
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2062
                                return match e.mul_opt(l_rhs, true) {
×
2063
                                    Some(ee) => Some(ee),
×
2064
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2065
                                };
2066
                            }
×
2067
                            if let Some(e) = l_rhs.div_opt(rhs, true) {
×
2068
                                return match l_lhs.mul_opt(&e, true) {
×
2069
                                    Some(ee) => Some(ee),
×
2070
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2071
                                };
2072
                            }
×
2073
                        } else if let BinaryOp::Div = &op {
×
2074
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
×
2075
                                return match l_lhs.div_opt(&e, true) {
×
2076
                                    Some(ee) => Some(ee),
×
2077
                                    None => Some(_div(l_lhs.as_ref().clone(), e)),
×
2078
                                };
2079
                            }
×
2080
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2081
                                return match e.div_opt(l_rhs, true) {
×
2082
                                    Some(ee) => Some(ee),
×
2083
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
2084
                                };
2085
                            }
×
2086
                        }
×
2087
                        None
×
2088
                    } else {
2089
                        match rhs {
1,676✔
2090
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
768✔
2091
                                SymbolExpr::Value(lv) => match op {
376✔
2092
                                    BinaryOp::Mul => Some(_mul(
224✔
2093
                                        SymbolExpr::Value(lv / v),
224✔
2094
                                        l_rhs.as_ref().clone(),
224✔
2095
                                    )),
224✔
2096
                                    BinaryOp::Div => Some(_div(
×
2097
                                        SymbolExpr::Value(lv / v),
×
2098
                                        l_rhs.as_ref().clone(),
×
2099
                                    )),
×
2100
                                    _ => None,
152✔
2101
                                },
2102
                                _ => match l_rhs.as_ref() {
392✔
2103
                                    SymbolExpr::Value(rv) => match op {
240✔
2104
                                        BinaryOp::Mul => Some(_mul(
×
2105
                                            SymbolExpr::Value(rv / v),
×
2106
                                            l_lhs.as_ref().clone(),
×
2107
                                        )),
×
2108
                                        BinaryOp::Div => Some(_mul(
×
2109
                                            SymbolExpr::Value(v * rv).rcp(),
×
2110
                                            l_lhs.as_ref().clone(),
×
2111
                                        )),
×
2112
                                        _ => None,
240✔
2113
                                    },
2114
                                    _ => None,
152✔
2115
                                },
2116
                            },
2117
                            SymbolExpr::Binary {
2118
                                op: rop,
320✔
2119
                                lhs: r_lhs,
320✔
2120
                                rhs: r_rhs,
320✔
2121
                            } => match (l_lhs.as_ref(), r_lhs.as_ref()) {
320✔
2122
                                (SymbolExpr::Value(lv), SymbolExpr::Value(rv)) => match (op, rop) {
×
2123
                                    (BinaryOp::Mul, BinaryOp::Mul) => Some(_mul(
×
2124
                                        SymbolExpr::Value(lv / rv),
×
2125
                                        _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2126
                                    )),
×
2127
                                    (BinaryOp::Mul, BinaryOp::Div) => Some(_mul(
×
2128
                                        SymbolExpr::Value(lv / rv),
×
2129
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2130
                                    )),
×
2131
                                    (BinaryOp::Div, BinaryOp::Mul) => Some(_div(
×
2132
                                        SymbolExpr::Value(lv / rv),
×
2133
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2134
                                    )),
×
2135
                                    (BinaryOp::Div, BinaryOp::Div) => Some(_div(
×
2136
                                        SymbolExpr::Value(lv / rv),
×
2137
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2138
                                    )),
×
2139
                                    (_, _) => None,
×
2140
                                },
2141
                                (_, _) => None,
320✔
2142
                            },
2143
                            _ => None,
588✔
2144
                        }
2145
                    }
2146
                }
2147
            }
2148
        }
2149
    }
13,646✔
2150

2151
    /// expand with optimization for div operation
2152
    fn div_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
150✔
2153
        match self {
150✔
2154
            SymbolExpr::Unary { op, expr } => match op {
84✔
2155
                UnaryOp::Neg => match expr.div_expand(rhs) {
×
2156
                    Some(e) => match e.neg_opt() {
×
2157
                        Some(ee) => Some(ee),
×
2158
                        None => Some(_neg(e)),
×
2159
                    },
2160
                    None => match expr.div_opt(rhs, true) {
×
2161
                        Some(e) => match e.neg_opt() {
×
2162
                            Some(ee) => Some(ee),
×
2163
                            None => Some(_neg(e)),
×
2164
                        },
2165
                        None => None,
×
2166
                    },
2167
                },
2168
                _ => None,
84✔
2169
            },
2170
            SymbolExpr::Binary {
2171
                op,
28✔
2172
                lhs: l_lhs,
28✔
2173
                rhs: l_rhs,
28✔
2174
            } => match &op {
28✔
2175
                BinaryOp::Add | BinaryOp::Sub => {
2176
                    let l = match l_lhs.div_expand(rhs) {
16✔
2177
                        Some(e) => e,
12✔
2178
                        None => match l_lhs.div_opt(rhs, true) {
4✔
2179
                            Some(e) => e,
×
2180
                            None => _div(l_lhs.as_ref().clone(), rhs.clone()),
4✔
2181
                        },
2182
                    };
2183
                    let r = match l_rhs.div_expand(rhs) {
16✔
2184
                        Some(e) => e,
×
2185
                        None => match l_rhs.div_opt(rhs, true) {
16✔
2186
                            Some(e) => e,
×
2187
                            None => _div(l_rhs.as_ref().clone(), rhs.clone()),
16✔
2188
                        },
2189
                    };
2190
                    match &op {
16✔
2191
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
4✔
2192
                            Some(e) => Some(e),
4✔
2193
                            None => Some(_sub(l, r)),
×
2194
                        },
2195
                        _ => match l.add_opt(&r, true) {
12✔
2196
                            Some(e) => Some(e),
4✔
2197
                            None => Some(_add(l, r)),
8✔
2198
                        },
2199
                    }
2200
                }
2201
                _ => None,
12✔
2202
            },
2203
            _ => self.div_opt(rhs, true),
38✔
2204
        }
2205
    }
150✔
2206

2207
    /// optimization for neg
2208
    fn neg_opt(&self) -> Option<SymbolExpr> {
320,770✔
2209
        match self {
17,296✔
2210
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
69,970✔
2211
            SymbolExpr::Unary {
2212
                op: UnaryOp::Neg,
2213
                expr,
15,560✔
2214
            } => Some(expr.as_ref().clone()),
15,560✔
2215
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
108,954✔
2216
                BinaryOp::Add => match lhs.neg_opt() {
3,540✔
2217
                    Some(ln) => match rhs.neg_opt() {
2,538✔
2218
                        Some(rn) => Some(_add(ln, rn)),
1,124✔
2219
                        None => Some(_sub(ln, rhs.as_ref().clone())),
1,414✔
2220
                    },
2221
                    None => match rhs.neg_opt() {
1,002✔
2222
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
196✔
2223
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
806✔
2224
                    },
2225
                },
2226
                BinaryOp::Sub => match lhs.neg_opt() {
2,498✔
2227
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
2,136✔
2228
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
362✔
2229
                },
2230
                BinaryOp::Mul => match lhs.neg_opt() {
101,804✔
2231
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
43,730✔
2232
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
58,074✔
2233
                },
2234
                BinaryOp::Div => match lhs.neg_opt() {
48✔
2235
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
×
2236
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
48✔
2237
                },
2238
                _ => None,
1,064✔
2239
            },
2240
            _ => None,
126,286✔
2241
        }
2242
    }
320,770✔
2243

2244
    /// optimize the equation
2245
    pub fn optimize(&self) -> SymbolExpr {
326,102✔
2246
        match self {
326,102✔
2247
            SymbolExpr::Value(_) => self.clone(),
85,972✔
2248
            SymbolExpr::Symbol(_) => self.clone(),
120,020✔
2249
            SymbolExpr::Unary { op, expr } => {
168✔
2250
                let opt = expr.optimize();
168✔
2251
                match op {
168✔
2252
                    UnaryOp::Neg => match opt.neg_opt() {
168✔
2253
                        Some(e) => e,
×
2254
                        None => _neg(opt),
168✔
2255
                    },
2256
                    _ => SymbolExpr::Unary {
×
2257
                        op: op.clone(),
×
2258
                        expr: Box::new(opt),
×
2259
                    },
×
2260
                }
2261
            }
2262
            SymbolExpr::Binary { op, lhs, rhs } => {
119,942✔
2263
                let opt_lhs = lhs.optimize();
119,942✔
2264
                let opt_rhs = rhs.optimize();
119,942✔
2265
                match op {
119,942✔
2266
                    BinaryOp::Add => match opt_lhs.add_opt(&opt_rhs, true) {
34,010✔
2267
                        Some(e) => e,
×
2268
                        None => _add(opt_lhs, opt_rhs),
34,010✔
2269
                    },
2270
                    BinaryOp::Sub => match opt_lhs.sub_opt(&opt_rhs, true) {
33,942✔
2271
                        Some(e) => e,
33,788✔
2272
                        None => _sub(opt_lhs, opt_rhs),
154✔
2273
                    },
2274
                    BinaryOp::Mul => match opt_lhs.mul_opt(&opt_rhs, true) {
18,228✔
2275
                        Some(e) => e,
16,880✔
2276
                        None => _mul(opt_lhs, opt_rhs),
1,348✔
2277
                    },
2278
                    BinaryOp::Div => match opt_lhs.div_opt(&opt_rhs, true) {
2✔
2279
                        Some(e) => e,
×
2280
                        None => _div(opt_lhs, opt_rhs),
2✔
2281
                    },
2282
                    BinaryOp::Pow => _pow(opt_lhs, opt_rhs),
33,760✔
2283
                }
2284
            }
2285
        }
2286
    }
326,102✔
2287
}
2288

2289
impl Add for SymbolExpr {
2290
    type Output = SymbolExpr;
2291
    fn add(self, rhs: Self) -> SymbolExpr {
89,876✔
2292
        match self.add_opt(&rhs, false) {
89,876✔
2293
            Some(e) => e,
85,384✔
2294
            None => _add(self, rhs),
4,492✔
2295
        }
2296
    }
89,876✔
2297
}
2298

2299
impl Add for &SymbolExpr {
2300
    type Output = SymbolExpr;
2301
    fn add(self, rhs: Self) -> SymbolExpr {
2,388,158✔
2302
        match self.add_opt(rhs, false) {
2,388,158✔
2303
            Some(e) => e,
2,312,520✔
2304
            None => _add(self.clone(), rhs.clone()),
75,638✔
2305
        }
2306
    }
2,388,158✔
2307
}
2308

2309
impl Sub for SymbolExpr {
2310
    type Output = SymbolExpr;
2311
    fn sub(self, rhs: Self) -> SymbolExpr {
64,132✔
2312
        match self.sub_opt(&rhs, false) {
64,132✔
2313
            Some(e) => e,
61,620✔
2314
            None => _sub(self, rhs),
2,512✔
2315
        }
2316
    }
64,132✔
2317
}
2318

2319
impl Sub for &SymbolExpr {
2320
    type Output = SymbolExpr;
2321
    fn sub(self, rhs: Self) -> SymbolExpr {
19,550✔
2322
        match self.sub_opt(rhs, false) {
19,550✔
2323
            Some(e) => e,
13,872✔
2324
            None => _sub(self.clone(), rhs.clone()),
5,678✔
2325
        }
2326
    }
19,550✔
2327
}
2328

2329
impl Mul for SymbolExpr {
2330
    type Output = SymbolExpr;
2331
    fn mul(self, rhs: Self) -> SymbolExpr {
262,862✔
2332
        match self.mul_opt(&rhs, false) {
262,862✔
2333
            Some(e) => e,
250,926✔
2334
            None => _mul(self, rhs),
11,936✔
2335
        }
2336
    }
262,862✔
2337
}
2338

2339
impl Mul for &SymbolExpr {
2340
    type Output = SymbolExpr;
2341
    fn mul(self, rhs: Self) -> SymbolExpr {
2,411,094✔
2342
        match self.mul_opt(rhs, false) {
2,411,094✔
2343
            Some(e) => e,
2,362,102✔
2344
            None => _mul(self.clone(), rhs.clone()),
48,992✔
2345
        }
2346
    }
2,411,094✔
2347
}
2348

2349
impl Div for SymbolExpr {
2350
    type Output = SymbolExpr;
2351
    fn div(self, rhs: Self) -> SymbolExpr {
5,506✔
2352
        match self.div_opt(&rhs, false) {
5,506✔
2353
            Some(e) => e,
5,024✔
2354
            None => _div(self, rhs),
482✔
2355
        }
2356
    }
5,506✔
2357
}
2358

2359
impl Div for &SymbolExpr {
2360
    type Output = SymbolExpr;
2361
    fn div(self, rhs: Self) -> SymbolExpr {
8,054✔
2362
        match self.div_opt(rhs, false) {
8,054✔
2363
            Some(e) => e,
2,770✔
2364
            None => _div(self.clone(), rhs.clone()),
5,284✔
2365
        }
2366
    }
8,054✔
2367
}
2368

2369
impl Neg for SymbolExpr {
2370
    type Output = SymbolExpr;
2371
    fn neg(self) -> SymbolExpr {
×
2372
        match self.neg_opt() {
×
2373
            Some(e) => e,
×
2374
            None => _neg(self),
×
2375
        }
2376
    }
×
2377
}
2378

2379
impl Neg for &SymbolExpr {
2380
    type Output = SymbolExpr;
2381
    fn neg(self) -> SymbolExpr {
4✔
2382
        match self.neg_opt() {
4✔
2383
            Some(e) => e,
2✔
2384
            None => _neg(self.clone()),
2✔
2385
        }
2386
    }
4✔
2387
}
2388

2389
impl PartialEq for SymbolExpr {
2390
    fn eq(&self, rexpr: &Self) -> bool {
14,918✔
2391
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
14,918✔
2392
            return l == r;
4,478✔
2393
        }
10,440✔
2394

10,440✔
2395
        match (self, rexpr) {
10,440✔
2396
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
2,344✔
2397
            (SymbolExpr::Value(l), SymbolExpr::Value(r)) => l == r,
×
2398
            (
2399
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2400
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2401
            ) => {
2402
                let ex_lhs = self.expand();
2,104✔
2403
                let ex_rhs = rexpr.expand();
2,104✔
2404
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,104✔
2405
                    Some(e) => e.is_zero(),
1,890✔
2406
                    None => {
2407
                        let t = &ex_lhs - &ex_rhs;
214✔
2408
                        t.is_zero()
214✔
2409
                    }
2410
                }
2411
            }
2412
            (SymbolExpr::Binary { .. }, _) => {
2413
                let ex_lhs = self.expand();
1,480✔
2414
                match ex_lhs.sub_opt(rexpr, true) {
1,480✔
2415
                    Some(e) => e.is_zero(),
1,414✔
2416
                    None => {
2417
                        let t = &ex_lhs - rexpr;
66✔
2418
                        t.is_zero()
66✔
2419
                    }
2420
                }
2421
            }
2422
            (_, SymbolExpr::Binary { .. }) => {
2423
                let ex_rhs = rexpr.expand();
1,544✔
2424
                match self.sub_opt(&ex_rhs, true) {
1,544✔
2425
                    Some(e) => e.is_zero(),
316✔
2426
                    None => {
2427
                        let t = self - &ex_rhs;
1,228✔
2428
                        t.is_zero()
1,228✔
2429
                    }
2430
                }
2431
            }
2432
            (_, _) => false,
2,968✔
2433
        }
2434
    }
14,918✔
2435
}
2436

2437
impl PartialEq<f64> for SymbolExpr {
2438
    fn eq(&self, r: &f64) -> bool {
×
2439
        match self.eval(true) {
×
2440
            Some(v) => v == *r,
×
2441
            None => false,
×
2442
        }
2443
    }
×
2444
}
2445

2446
impl PartialEq<Complex64> for SymbolExpr {
2447
    fn eq(&self, r: &Complex64) -> bool {
×
2448
        match self.eval(true) {
×
2449
            Some(v) => v == *r,
×
2450
            None => false,
×
2451
        }
2452
    }
×
2453
}
2454

2455
// comparison rules for sorting equation
2456
impl PartialOrd for SymbolExpr {
2457
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
76,840✔
2458
        match self {
76,840✔
2459
            SymbolExpr::Value(l) => match rhs {
182✔
2460
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2461
                _ => Some(Ordering::Less),
170✔
2462
            },
2463
            SymbolExpr::Symbol(l) => match rhs {
5,008✔
2464
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2465
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
3,036✔
2466
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2467
                _ => Some(Ordering::Less),
1,972✔
2468
            },
2469
            SymbolExpr::Unary { op: _, expr } => match rhs {
10,928✔
2470
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2471
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,526✔
2472
                _ => (expr.as_ref()).partial_cmp(rhs),
9,400✔
2473
            },
2474
            SymbolExpr::Binary {
2475
                op,
60,722✔
2476
                lhs: ll,
60,722✔
2477
                rhs: lr,
60,722✔
2478
            } => match rhs {
60,722✔
2479
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
5,246✔
2480
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
5,238✔
2481
                    _ => Some(Ordering::Equal),
8✔
2482
                },
2483
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
106✔
2484
                SymbolExpr::Binary {
2485
                    op: _,
2486
                    lhs: rl,
55,370✔
2487
                    rhs: rr,
55,370✔
2488
                } => {
2489
                    let ls = match ll.as_ref() {
55,370✔
2490
                        SymbolExpr::Value(_) => lr.to_string(),
23,618✔
2491
                        _ => self.to_string(),
31,752✔
2492
                    };
2493
                    let rs = match rl.as_ref() {
55,370✔
2494
                        SymbolExpr::Value(_) => rr.to_string(),
15,440✔
2495
                        _ => rhs.to_string(),
39,930✔
2496
                    };
2497
                    if rs > ls && rs.len() > ls.len() {
55,370✔
2498
                        Some(Ordering::Less)
9,182✔
2499
                    } else if rs < ls && rs.len() < ls.len() {
46,188✔
2500
                        Some(Ordering::Greater)
384✔
2501
                    } else {
2502
                        Some(Ordering::Equal)
45,804✔
2503
                    }
2504
                }
2505
            },
2506
        }
2507
    }
76,840✔
2508
}
2509

2510
impl From<&str> for SymbolExpr {
2511
    fn from(v: &str) -> Self {
×
2512
        SymbolExpr::Symbol(Box::new(v.to_string()))
×
2513
    }
×
2514
}
2515

2516
impl fmt::Display for Value {
2517
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103,706✔
2518
        write!(
103,706✔
2519
            f,
103,706✔
2520
            "{}",
103,706✔
2521
            match self {
103,706✔
2522
                Value::Real(e) => e.to_string(),
47,214✔
2523
                Value::Int(e) => e.to_string(),
820✔
2524
                Value::Complex(e) => {
55,672✔
2525
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
55,672✔
2526
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
55,032✔
2527
                            0.to_string()
×
2528
                        } else {
2529
                            format!("{}i", e.im)
55,032✔
2530
                        }
2531
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
640✔
2532
                        e.re.to_string()
×
2533
                    } else {
2534
                        e.to_string()
640✔
2535
                    }
2536
                }
2537
            }
2538
        )
2539
    }
103,706✔
2540
}
2541

2542
// ===============================================================
2543
//  implementations for Value
2544
// ===============================================================
2545
impl Value {
2546
    pub fn as_real(&self) -> f64 {
34,836✔
2547
        match self {
34,836✔
2548
            Value::Real(e) => *e,
34,596✔
2549
            Value::Int(e) => *e as f64,
240✔
2550
            Value::Complex(e) => e.re,
×
2551
        }
2552
    }
34,836✔
2553

2554
    pub fn abs(&self) -> Value {
264✔
2555
        match self {
264✔
2556
            Value::Real(e) => Value::Real(e.abs()),
136✔
2557
            Value::Int(e) => Value::Int(e.abs()),
78✔
2558
            Value::Complex(e) => Value::Real((e.re * e.re + e.im * e.im).sqrt()),
50✔
2559
        }
2560
    }
264✔
2561

2562
    pub fn sin(&self) -> Value {
208✔
2563
        match self {
208✔
2564
            Value::Real(e) => Value::Real(e.sin()),
86✔
2565
            Value::Int(e) => Value::Real((*e as f64).sin()),
74✔
2566
            Value::Complex(e) => {
48✔
2567
                let t = Value::Complex(e.sin());
48✔
2568
                match t.opt_complex() {
48✔
2569
                    Some(v) => v,
×
2570
                    None => t,
48✔
2571
                }
2572
            }
2573
        }
2574
    }
208✔
2575
    pub fn asin(&self) -> Value {
54✔
2576
        match self {
54✔
2577
            Value::Real(e) => Value::Real(e.asin()),
48✔
2578
            Value::Int(e) => Value::Real((*e as f64).asin()),
6✔
2579
            Value::Complex(e) => {
×
2580
                let t = Value::Complex(e.asin());
×
2581
                match t.opt_complex() {
×
2582
                    Some(v) => v,
×
2583
                    None => t,
×
2584
                }
2585
            }
2586
        }
2587
    }
54✔
2588
    pub fn cos(&self) -> Value {
332✔
2589
        match self {
332✔
2590
            Value::Real(e) => Value::Real(e.cos()),
210✔
2591
            Value::Int(e) => Value::Real((*e as f64).cos()),
74✔
2592
            Value::Complex(e) => {
48✔
2593
                let t = Value::Complex(e.cos());
48✔
2594
                match t.opt_complex() {
48✔
2595
                    Some(v) => v,
×
2596
                    None => t,
48✔
2597
                }
2598
            }
2599
        }
2600
    }
332✔
2601
    pub fn acos(&self) -> Value {
52✔
2602
        match self {
52✔
2603
            Value::Real(e) => Value::Real(e.acos()),
48✔
2604
            Value::Int(e) => Value::Real((*e as f64).acos()),
4✔
2605
            Value::Complex(e) => {
×
2606
                let t = Value::Complex(e.acos());
×
2607
                match t.opt_complex() {
×
2608
                    Some(v) => v,
×
2609
                    None => t,
×
2610
                }
2611
            }
2612
        }
2613
    }
52✔
2614
    pub fn tan(&self) -> Value {
196✔
2615
        match self {
196✔
2616
            Value::Real(e) => Value::Real(e.tan()),
74✔
2617
            Value::Int(e) => Value::Real((*e as f64).tan()),
74✔
2618
            Value::Complex(e) => {
48✔
2619
                let t = Value::Complex(e.tan());
48✔
2620
                match t.opt_complex() {
48✔
2621
                    Some(v) => v,
×
2622
                    None => t,
48✔
2623
                }
2624
            }
2625
        }
2626
    }
196✔
2627
    pub fn atan(&self) -> Value {
54✔
2628
        match self {
54✔
2629
            Value::Real(e) => Value::Real(e.atan()),
48✔
2630
            Value::Int(e) => Value::Real((*e as f64).atan()),
6✔
2631
            Value::Complex(e) => {
×
2632
                let t = Value::Complex(e.atan());
×
2633
                match t.opt_complex() {
×
2634
                    Some(v) => v,
×
2635
                    None => t,
×
2636
                }
2637
            }
2638
        }
2639
    }
54✔
2640
    pub fn exp(&self) -> Value {
246✔
2641
        match self {
246✔
2642
            Value::Real(e) => Value::Real(e.exp()),
112✔
2643
            Value::Int(e) => Value::Real((*e as f64).exp()),
80✔
2644
            Value::Complex(e) => {
54✔
2645
                let t = Value::Complex(e.exp());
54✔
2646
                match t.opt_complex() {
54✔
2647
                    Some(v) => v,
×
2648
                    None => t,
54✔
2649
                }
2650
            }
2651
        }
2652
    }
246✔
2653
    pub fn log(&self) -> Value {
416✔
2654
        match self {
416✔
2655
            Value::Real(e) => {
228✔
2656
                if *e < 0.0 {
228✔
2657
                    Value::Complex(Complex64::from(e)).log()
48✔
2658
                } else {
2659
                    Value::Real(e.ln())
180✔
2660
                }
2661
            }
2662
            Value::Int(e) => Value::Real(*e as f64).log(),
92✔
2663
            Value::Complex(e) => {
96✔
2664
                let t = Value::Complex(e.ln());
96✔
2665
                match t.opt_complex() {
96✔
2666
                    Some(v) => v,
×
2667
                    None => t,
96✔
2668
                }
2669
            }
2670
        }
2671
    }
416✔
2672
    pub fn sqrt(&self) -> Value {
×
2673
        match self {
×
2674
            Value::Real(e) => {
×
2675
                if *e < 0.0 {
×
2676
                    Value::Complex(Complex64::from(e)).sqrt()
×
2677
                } else {
2678
                    Value::Real(e.sqrt())
×
2679
                }
2680
            }
2681
            Value::Int(e) => {
×
2682
                if *e < 0 {
×
2683
                    Value::Complex(Complex64::from(*e as f64)).pow(&Value::Real(0.5))
×
2684
                } else {
2685
                    let t = (*e as f64).sqrt();
×
2686
                    let d = t.floor() - t;
×
2687
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
×
2688
                        Value::Int(t as i64)
×
2689
                    } else {
2690
                        Value::Real(t)
×
2691
                    }
2692
                }
2693
            }
2694
            Value::Complex(e) => {
×
2695
                let t = Value::Complex(e.sqrt());
×
2696
                match t.opt_complex() {
×
2697
                    Some(v) => v,
×
2698
                    None => t,
×
2699
                }
2700
            }
2701
        }
2702
    }
×
2703
    pub fn pow(&self, p: &Value) -> Value {
15,916✔
2704
        match self {
15,916✔
2705
            Value::Real(e) => match p {
5,918✔
2706
                Value::Real(r) => {
5,604✔
2707
                    if *e < 0.0 && r.fract() != 0. {
5,604✔
2708
                        Value::Complex(Complex64::from(e)).pow(p)
2✔
2709
                    } else {
2710
                        Value::Real(e.powf(*r))
5,602✔
2711
                    }
2712
                }
2713
                Value::Int(i) => Value::Real(e.powf(*i as f64)),
92✔
2714
                Value::Complex(_) => Value::Complex(Complex64::from(e)).pow(p),
222✔
2715
            },
2716
            Value::Int(e) => match p {
4,858✔
2717
                Value::Real(r) => {
4,778✔
2718
                    if *e < 0 && r.fract() != 0. {
4,778✔
2719
                        Value::Complex(Complex64::from(*e as f64)).pow(p)
4✔
2720
                    } else {
2721
                        let t = (*e as f64).powf(*r);
4,774✔
2722
                        let d = t.floor() - t;
4,774✔
2723
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
4,774✔
2724
                            Value::Int(t as i64)
4,766✔
2725
                        } else {
2726
                            Value::Real(t)
8✔
2727
                        }
2728
                    }
2729
                }
2730
                Value::Int(r) => {
6✔
2731
                    if *r < 0 {
6✔
2732
                        Value::Real(*e as f64).pow(p)
2✔
2733
                    } else {
2734
                        Value::Int(e.pow(*r as u32))
4✔
2735
                    }
2736
                }
2737
                Value::Complex(_) => Value::Complex(Complex64::from(*e as f64)).pow(p),
74✔
2738
            },
2739
            Value::Complex(e) => {
5,140✔
2740
                let t = match p {
5,140✔
2741
                    Value::Real(r) => Value::Complex(e.powf(*r)),
4,340✔
2742
                    Value::Int(r) => Value::Complex(e.powf(*r as f64)),
72✔
2743
                    Value::Complex(r) => Value::Complex(e.powc(*r)),
728✔
2744
                };
2745
                match t.opt_complex() {
5,140✔
2746
                    Some(v) => v,
288✔
2747
                    None => t,
4,852✔
2748
                }
2749
            }
2750
        }
2751
    }
15,916✔
2752
    pub fn rcp(&self) -> Value {
×
2753
        match self {
×
2754
            Value::Real(e) => Value::Real(1.0 / e),
×
2755
            Value::Int(e) => {
×
2756
                let t = 1.0 / (*e as f64);
×
2757
                let d = t.floor() - t;
×
2758
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
×
2759
                    Value::Int(t as i64)
×
2760
                } else {
2761
                    Value::Real(t)
×
2762
                }
2763
            }
2764
            Value::Complex(e) => Value::Complex(1.0 / e),
×
2765
        }
2766
    }
×
2767
    pub fn sign(&self) -> Value {
6✔
2768
        match self {
6✔
2769
            Value::Real(e) => {
×
2770
                if *e > SYMEXPR_EPSILON {
×
2771
                    Value::Real(1.0)
×
2772
                } else if *e < -SYMEXPR_EPSILON {
×
2773
                    Value::Real(-1.0)
×
2774
                } else {
2775
                    Value::Real(0.0)
×
2776
                }
2777
            }
2778
            Value::Int(e) => {
6✔
2779
                if *e > 0 {
6✔
2780
                    Value::Int(1)
2✔
2781
                } else if *e < 0 {
4✔
2782
                    Value::Int(-1)
2✔
2783
                } else {
2784
                    Value::Int(0)
2✔
2785
                }
2786
            }
2787
            Value::Complex(_) => *self,
×
2788
        }
2789
    }
6✔
2790

2791
    pub fn is_zero(&self) -> bool {
5,675,788✔
2792
        match self {
5,675,788✔
2793
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,842,378✔
2794
            Value::Int(i) => *i == 0,
553,240✔
2795
            Value::Complex(c) => {
280,170✔
2796
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
280,170✔
2797
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
213,338✔
2798
            }
2799
        }
2800
    }
5,675,788✔
2801
    pub fn is_one(&self) -> bool {
544,080✔
2802
        match self {
544,080✔
2803
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
226,352✔
2804
            Value::Int(i) => *i == 1,
181,858✔
2805
            Value::Complex(c) => {
135,870✔
2806
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
135,870✔
2807
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,352✔
2808
            }
2809
        }
2810
    }
544,080✔
2811
    pub fn is_minus_one(&self) -> bool {
277,918✔
2812
        match self {
277,918✔
2813
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
179,994✔
2814
            Value::Int(i) => *i == -1,
14,784✔
2815
            Value::Complex(c) => {
83,140✔
2816
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
83,140✔
2817
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
3,378✔
2818
            }
2819
        }
2820
    }
277,918✔
2821

2822
    pub fn is_negative(&self) -> bool {
61,464✔
2823
        match self {
61,464✔
2824
            Value::Real(r) => *r < 0.0,
13,698✔
2825
            Value::Int(i) => *i < 0,
2,882✔
2826
            Value::Complex(c) => {
44,884✔
2827
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
44,884✔
2828
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
44,884✔
2829
            }
2830
        }
2831
    }
61,464✔
2832

2833
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
112,304✔
2834
        match rhs {
5,128✔
2835
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
76,906✔
2836
            SymbolExpr::Unary {
2837
                op: UnaryOp::Neg,
2838
                expr,
4,470✔
2839
            } => {
4,470✔
2840
                let l = SymbolExpr::Value(-self);
4,470✔
2841
                match l.mul_opt(expr, recursive) {
4,470✔
2842
                    Some(e) => Some(e),
16✔
2843
                    None => Some(_mul(l, expr.as_ref().clone())),
4,454✔
2844
                }
2845
            }
2846
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
13,716✔
2847
                if recursive {
13,716✔
2848
                    match op {
1,582✔
2849
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
1,372✔
2850
                            Some(e) => match e.mul_opt(r, recursive) {
32✔
2851
                                Some(ee) => Some(ee),
8✔
2852
                                None => Some(_mul(e, r.as_ref().clone())),
24✔
2853
                            },
2854
                            None => self
1,340✔
2855
                                .mul_opt(r, recursive)
1,340✔
2856
                                .map(|e| _mul(e, l.as_ref().clone())),
1,340✔
2857
                        },
2858
                        BinaryOp::Div => match self.mul_opt(l, recursive) {
×
2859
                            Some(e) => Some(_div(e, r.as_ref().clone())),
×
2860
                            None => self
×
2861
                                .div_opt(r, recursive)
×
2862
                                .map(|e| _mul(e, l.as_ref().clone())),
×
2863
                        },
2864
                        _ => None,
210✔
2865
                    }
2866
                } else {
2867
                    match l.as_ref() {
12,134✔
2868
                        SymbolExpr::Value(v) => match op {
4,166✔
2869
                            BinaryOp::Mul => {
2870
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
2,474✔
2871
                            }
2872
                            BinaryOp::Div => {
2873
                                Some(_div(SymbolExpr::Value(self * v), r.as_ref().clone()))
×
2874
                            }
2875
                            _ => None,
1,692✔
2876
                        },
2877
                        _ => match r.as_ref() {
7,968✔
2878
                            SymbolExpr::Value(v) => match op {
942✔
2879
                                BinaryOp::Mul => {
2880
                                    Some(_mul(SymbolExpr::Value(self * v), l.as_ref().clone()))
28✔
2881
                                }
2882
                                BinaryOp::Div => {
2883
                                    Some(_mul(SymbolExpr::Value(self / v), l.as_ref().clone()))
8✔
2884
                                }
2885
                                _ => None,
906✔
2886
                            },
2887
                            _ => None,
7,026✔
2888
                        },
2889
                    }
2890
                }
2891
            }
2892
            _ => None,
17,212✔
2893
        }
2894
    }
112,304✔
2895

2896
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
4,468✔
2897
        match rhs {
20✔
2898
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self / r)),
1,802✔
2899
            SymbolExpr::Unary {
2900
                op: UnaryOp::Neg,
2901
                expr,
×
2902
            } => {
×
2903
                if recursive {
×
2904
                    self.div_opt(expr, recursive).map(_neg)
×
2905
                } else {
2906
                    None
×
2907
                }
2908
            }
2909
            SymbolExpr::Binary { op, lhs: l, rhs: r } => match l.as_ref() {
1,270✔
2910
                SymbolExpr::Value(v) => match op {
490✔
2911
                    BinaryOp::Mul => Some(_div(SymbolExpr::Value(self / v), r.as_ref().clone())),
192✔
2912
                    BinaryOp::Div => Some(_mul(SymbolExpr::Value(self / v), r.as_ref().clone())),
×
2913
                    _ => None,
298✔
2914
                },
2915
                _ => match r.as_ref() {
780✔
2916
                    SymbolExpr::Value(v) => match op {
580✔
2917
                        BinaryOp::Mul => {
2918
                            Some(_div(SymbolExpr::Value(self / v), l.as_ref().clone()))
×
2919
                        }
2920
                        BinaryOp::Div => {
2921
                            Some(_div(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
2922
                        }
2923
                        _ => None,
580✔
2924
                    },
2925
                    _ => None,
200✔
2926
                },
2927
            },
2928
            _ => None,
1,396✔
2929
        }
2930
    }
4,468✔
2931

2932
    pub fn opt_complex(&self) -> Option<Value> {
249,516✔
2933
        match self {
249,516✔
2934
            Value::Complex(c) => {
106,420✔
2935
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
106,420✔
2936
                    Some(Value::Real(c.re))
22,042✔
2937
                } else {
2938
                    None
84,378✔
2939
                }
2940
            }
2941
            _ => None,
143,096✔
2942
        }
2943
    }
249,516✔
2944
}
2945

2946
impl From<f64> for Value {
2947
    fn from(v: f64) -> Self {
1,087,810✔
2948
        Value::Real(v)
1,087,810✔
2949
    }
1,087,810✔
2950
}
2951

2952
impl From<i64> for Value {
2953
    fn from(v: i64) -> Self {
2,439,098✔
2954
        Value::Int(v)
2,439,098✔
2955
    }
2,439,098✔
2956
}
2957

2958
impl From<Complex64> for Value {
2959
    fn from(v: Complex64) -> Self {
4,004,958✔
2960
        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&v.im) {
4,004,958✔
2961
            Value::Real(v.re)
3,071,652✔
2962
        } else {
2963
            Value::Complex(v)
933,306✔
2964
        }
2965
    }
4,004,958✔
2966
}
2967

2968
impl Add for &Value {
2969
    type Output = Value;
2970
    fn add(self, rhs: Self) -> Value {
74,696✔
2971
        *self + *rhs
74,696✔
2972
    }
74,696✔
2973
}
2974

2975
impl Add for Value {
2976
    type Output = Value;
2977
    fn add(self, rhs: Self) -> Value {
76,120✔
2978
        let t = match self {
76,120✔
2979
            Value::Real(l) => match rhs {
24,038✔
2980
                Value::Real(r) => Value::Real(l + r),
20,118✔
2981
                Value::Int(r) => Value::Real(l + r as f64),
1,910✔
2982
                Value::Complex(r) => Value::Complex(l + r),
2,010✔
2983
            },
2984
            Value::Int(l) => match rhs {
21,740✔
2985
                Value::Real(r) => Value::Real(l as f64 + r),
1,204✔
2986
                Value::Int(r) => Value::Int(l + r),
11,748✔
2987
                Value::Complex(r) => Value::Complex(l as f64 + r),
8,788✔
2988
            },
2989
            Value::Complex(l) => match rhs {
30,342✔
2990
                Value::Real(r) => Value::Complex(l + r),
586✔
2991
                Value::Int(r) => Value::Complex(l + r as f64),
12,192✔
2992
                Value::Complex(r) => Value::Complex(l + r),
17,564✔
2993
            },
2994
        };
2995
        match t.opt_complex() {
76,120✔
2996
            Some(v) => v,
4,242✔
2997
            None => t,
71,878✔
2998
        }
2999
    }
76,120✔
3000
}
3001

3002
impl Sub for &Value {
3003
    type Output = Value;
3004
    fn sub(self, rhs: Self) -> Value {
73,492✔
3005
        *self - *rhs
73,492✔
3006
    }
73,492✔
3007
}
3008

3009
impl Sub for Value {
3010
    type Output = Value;
3011
    fn sub(self, rhs: Self) -> Value {
73,972✔
3012
        let t = match self {
73,972✔
3013
            Value::Real(l) => match rhs {
10,572✔
3014
                Value::Real(r) => Value::Real(l - r),
6,678✔
3015
                Value::Int(r) => Value::Real(l - r as f64),
2,230✔
3016
                Value::Complex(r) => Value::Complex(l - r),
1,664✔
3017
            },
3018
            Value::Int(l) => match rhs {
34,430✔
3019
                Value::Real(r) => Value::Real(l as f64 - r),
226✔
3020
                Value::Int(r) => Value::Int(l - r),
26,462✔
3021
                Value::Complex(r) => Value::Complex(l as f64 - r),
7,742✔
3022
            },
3023
            Value::Complex(l) => match rhs {
28,970✔
3024
                Value::Real(r) => Value::Complex(l - r),
284✔
3025
                Value::Int(r) => Value::Complex(l - r as f64),
11,778✔
3026
                Value::Complex(r) => Value::Complex(l - r),
16,908✔
3027
            },
3028
        };
3029
        match t.opt_complex() {
73,972✔
3030
            Some(v) => v,
5,362✔
3031
            None => t,
68,610✔
3032
        }
3033
    }
73,972✔
3034
}
3035

3036
impl Mul for &Value {
3037
    type Output = Value;
3038
    fn mul(self, rhs: Self) -> Value {
90,416✔
3039
        *self * *rhs
90,416✔
3040
    }
90,416✔
3041
}
3042

3043
impl Mul for Value {
3044
    type Output = Value;
3045
    fn mul(self, rhs: Self) -> Value {
91,280✔
3046
        let t = match self {
91,280✔
3047
            Value::Real(l) => match rhs {
70,584✔
3048
                Value::Real(r) => Value::Real(l * r),
69,842✔
3049
                Value::Int(r) => Value::Real(l * r as f64),
436✔
3050
                Value::Complex(r) => Value::Complex(l * r),
306✔
3051
            },
3052
            Value::Int(l) => match rhs {
2,654✔
3053
                Value::Real(r) => Value::Real(l as f64 * r),
312✔
3054
                Value::Int(r) => Value::Int(l * r),
1,012✔
3055
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,330✔
3056
            },
3057
            Value::Complex(l) => match rhs {
18,042✔
3058
                Value::Real(r) => Value::Complex(l * r),
286✔
3059
                Value::Int(r) => Value::Complex(l * r as f64),
902✔
3060
                Value::Complex(r) => Value::Complex(l * r),
16,854✔
3061
            },
3062
        };
3063
        match t.opt_complex() {
91,280✔
3064
            Some(v) => v,
11,678✔
3065
            None => t,
79,602✔
3066
        }
3067
    }
91,280✔
3068
}
3069

3070
impl Div for &Value {
3071
    type Output = Value;
3072
    fn div(self, rhs: Self) -> Value {
2,226✔
3073
        *self / *rhs
2,226✔
3074
    }
2,226✔
3075
}
3076

3077
impl Div for Value {
3078
    type Output = Value;
3079
    fn div(self, rhs: Self) -> Value {
2,710✔
3080
        let t = match self {
2,710✔
3081
            Value::Real(l) => match rhs {
1,196✔
3082
                Value::Real(r) => Value::Real(l / r),
106✔
3083
                Value::Int(r) => Value::Real(l / r as f64),
520✔
3084
                Value::Complex(r) => Value::Complex(l / r),
570✔
3085
            },
3086
            Value::Int(l) => {
772✔
3087
                if rhs == 0.0 {
772✔
3088
                    return Value::Real(f64::INFINITY);
×
3089
                }
772✔
3090
                match rhs {
772✔
3091
                    Value::Real(r) => Value::Real(l as f64 / r),
24✔
3092
                    Value::Int(r) => {
268✔
3093
                        let t = l as f64 / r as f64;
268✔
3094
                        let d = t.floor() - t;
268✔
3095
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
268✔
3096
                            Value::Int(t as i64)
236✔
3097
                        } else {
3098
                            Value::Real(t)
32✔
3099
                        }
3100
                    }
3101
                    Value::Complex(r) => Value::Complex(l as f64 / r),
480✔
3102
                }
3103
            }
3104
            Value::Complex(l) => match rhs {
742✔
3105
                Value::Real(r) => Value::Complex(l / r),
24✔
3106
                Value::Int(r) => Value::Complex(l / r as f64),
280✔
3107
                Value::Complex(r) => Value::Complex(l / r),
438✔
3108
            },
3109
        };
3110
        match t.opt_complex() {
2,710✔
3111
            Some(v) => v,
472✔
3112
            None => t,
2,238✔
3113
        }
3114
    }
2,710✔
3115
}
3116

3117
impl Neg for &Value {
3118
    type Output = Value;
3119
    fn neg(self) -> Value {
76,606✔
3120
        -*self
76,606✔
3121
    }
76,606✔
3122
}
3123

3124
impl Neg for Value {
3125
    type Output = Value;
3126
    fn neg(self) -> Value {
104,306✔
3127
        match self {
104,306✔
3128
            Value::Real(v) => Value::Real(-v),
20,610✔
3129
            Value::Int(v) => Value::Int(-v),
30,154✔
3130
            Value::Complex(v) => Value::Complex(-v),
53,542✔
3131
        }
3132
    }
104,306✔
3133
}
3134

3135
impl PartialEq for Value {
3136
    fn eq(&self, r: &Self) -> bool {
300,038✔
3137
        match self {
300,038✔
3138
            Value::Real(e) => match r {
243,350✔
3139
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
242,340✔
3140
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
440✔
3141
                Value::Complex(rv) => {
570✔
3142
                    let t = Complex64::from(*e) - rv;
570✔
3143
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
570✔
3144
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
112✔
3145
                }
3146
            },
3147
            Value::Int(e) => match r {
20,588✔
3148
                Value::Int(rv) => e == rv,
1,056✔
3149
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
19,088✔
3150
                Value::Complex(rv) => {
444✔
3151
                    let t = Complex64::from(*e as f64) - rv;
444✔
3152
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
444✔
3153
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
26✔
3154
                }
3155
            },
3156
            Value::Complex(e) => match r {
36,100✔
3157
                Value::Real(rv) => {
34,996✔
3158
                    let t = *e - Complex64::from(rv);
34,996✔
3159
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
34,996✔
3160
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3161
                }
3162
                Value::Int(rv) => {
232✔
3163
                    let t = *e - Complex64::from(*rv as f64);
232✔
3164
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
232✔
3165
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3166
                }
3167
                Value::Complex(rv) => {
872✔
3168
                    let t = *e - rv;
872✔
3169
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
872✔
3170
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
588✔
3171
                }
3172
            },
3173
        }
3174
    }
300,038✔
3175
}
3176

3177
impl PartialEq<f64> for Value {
3178
    fn eq(&self, r: &f64) -> bool {
772✔
3179
        match self {
772✔
3180
            Value::Real(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - r)),
24✔
3181
            Value::Int(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - r)),
268✔
3182
            Value::Complex(e) => {
480✔
3183
                let t = *e - Complex64::from(r);
480✔
3184
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
480✔
3185
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
104✔
3186
            }
3187
        }
3188
    }
772✔
3189
}
3190

3191
impl PartialEq<Complex64> for Value {
3192
    fn eq(&self, r: &Complex64) -> bool {
×
3193
        match self {
×
3194
            Value::Real(e) => {
×
3195
                let t = Complex64::from(*e) - r;
×
3196
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3197
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3198
            }
3199
            Value::Int(e) => {
×
3200
                let t = Complex64::from(*e as f64) - r;
×
3201
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3202
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3203
            }
3204
            Value::Complex(e) => {
×
3205
                let t = *e - r;
×
3206
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3207
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3208
            }
3209
        }
3210
    }
×
3211
}
3212

3213
impl PartialOrd for Value {
3214
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
12✔
3215
        match self {
12✔
3216
            Value::Real(l) => match rhs {
4✔
3217
                Value::Real(r) => l.partial_cmp(r),
4✔
3218
                Value::Int(r) => l.partial_cmp(&(*r as f64)),
×
3219
                Value::Complex(_) => None,
×
3220
            },
3221
            Value::Int(l) => match rhs {
4✔
3222
                Value::Real(r) => (*l as f64).partial_cmp(r),
×
3223
                Value::Int(r) => l.partial_cmp(r),
4✔
3224
                Value::Complex(_) => None,
×
3225
            },
3226
            Value::Complex(_) => None,
4✔
3227
        }
3228
    }
12✔
3229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc