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

Qiskit / qiskit / 15690052436

16 Jun 2025 07:27PM CUT coverage: 88.003% (-0.006%) from 88.009%
15690052436

Pull #14361

github

web-flow
Merge 7fa9dd602 into 9ec464af4
Pull Request #14361: Oxidize `VariableMapper` and uses.

512 of 597 new or added lines in 4 files covered. (85.76%)

12 existing lines in 4 files now uncovered.

83520 of 94906 relevant lines covered (88.0%)

514545.5 hits per line

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

73.9
/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 {
148,954✔
82
    if rhs.is_negative() {
148,954✔
83
        match rhs.neg_opt() {
39,884✔
84
            Some(e) => SymbolExpr::Binary {
39,884✔
85
                op: BinaryOp::Sub,
39,884✔
86
                lhs: Box::new(lhs),
39,884✔
87
                rhs: Box::new(e),
39,884✔
88
            },
39,884✔
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 {
109,070✔
97
            op: BinaryOp::Add,
109,070✔
98
            lhs: Box::new(lhs),
109,070✔
99
            rhs: Box::new(rhs),
109,070✔
100
        }
109,070✔
101
    }
102
}
148,954✔
103

104
// functions to make new expr for sub
105
#[inline(always)]
106
fn _sub(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
21,664✔
107
    if rhs.is_negative() {
21,664✔
108
        match rhs.neg_opt() {
1,082✔
109
            Some(e) => SymbolExpr::Binary {
1,082✔
110
                op: BinaryOp::Add,
1,082✔
111
                lhs: Box::new(lhs),
1,082✔
112
                rhs: Box::new(e),
1,082✔
113
            },
1,082✔
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 {
20,582✔
122
            op: BinaryOp::Sub,
20,582✔
123
            lhs: Box::new(lhs),
20,582✔
124
            rhs: Box::new(rhs),
20,582✔
125
        }
20,582✔
126
    }
127
}
21,664✔
128

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

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

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

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

171
impl fmt::Display for SymbolExpr {
172
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48,852,970✔
173
        write!(
48,852,970✔
174
            f,
48,852,970✔
175
            "{}",
48,852,970✔
176
            match self {
48,852,970✔
177
                SymbolExpr::Symbol(e) => e.to_string(),
48,281,320✔
178
                SymbolExpr::Value(e) => e.to_string(),
159,732✔
179
                SymbolExpr::Unary { op, expr } => {
10,136✔
180
                    let s = expr.to_string();
10,136✔
181
                    match op {
10,136✔
182
                        UnaryOp::Abs => format!("abs({})", s),
×
183
                        UnaryOp::Neg => match expr.as_ref() {
6,390✔
184
                            SymbolExpr::Value(e) => (-e).to_string(),
×
185
                            SymbolExpr::Binary {
186
                                op: BinaryOp::Add | BinaryOp::Sub,
187
                                ..
188
                            } => format!("-({})", s),
×
189
                            _ => format!("-{}", s),
6,390✔
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!("conjugate({})", s),
2,936✔
201
                    }
202
                }
203
                SymbolExpr::Binary { op, lhs, rhs } => {
401,782✔
204
                    let s_lhs = lhs.to_string();
401,782✔
205
                    let s_rhs = rhs.to_string();
401,782✔
206
                    let op_lhs = match lhs.as_ref() {
401,782✔
207
                        SymbolExpr::Binary { op: lop, .. } => {
92,210✔
208
                            matches!(lop, BinaryOp::Add | BinaryOp::Sub)
92,210✔
209
                        }
210
                        SymbolExpr::Value(e) => match e {
100,488✔
211
                            Value::Real(v) => *v < 0.0,
13,332✔
212
                            Value::Int(v) => *v < 0,
578✔
213
                            Value::Complex(_) => true,
86,578✔
214
                        },
215
                        _ => false,
209,084✔
216
                    };
217
                    let op_rhs = match rhs.as_ref() {
401,782✔
218
                        SymbolExpr::Binary { op: rop, .. } => match rop {
34,730✔
219
                            BinaryOp::Add | BinaryOp::Sub => true,
3,130✔
220
                            _ => matches!(op, BinaryOp::Div),
31,600✔
221
                        },
222
                        SymbolExpr::Value(e) => match e {
59,100✔
223
                            Value::Real(v) => *v < 0.0,
34,592✔
224
                            Value::Int(v) => *v < 0,
7,044✔
225
                            Value::Complex(_) => true,
17,464✔
226
                        },
227
                        _ => false,
307,952✔
228
                    };
229

230
                    match op {
401,782✔
231
                        BinaryOp::Add => match rhs.as_ref() {
9,686✔
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),
9,686✔
243
                        },
244
                        BinaryOp::Sub => match rhs.as_ref() {
8,146✔
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 {
8,146✔
262
                                    format!("{} -({})", s_lhs, s_rhs)
742✔
263
                                } else {
264
                                    format!("{} - {}", s_lhs, s_rhs)
7,404✔
265
                                }
266
                            }
267
                        },
268
                        BinaryOp::Mul => {
269
                            if op_lhs {
342,034✔
270
                                if op_rhs {
93,992✔
271
                                    format!("({})*({})", s_lhs, s_rhs)
788✔
272
                                } else {
273
                                    format!("({})*{}", s_lhs, s_rhs)
93,204✔
274
                                }
275
                            } else if op_rhs {
248,042✔
276
                                format!("{}*({})", s_lhs, s_rhs)
18,122✔
277
                            } else {
278
                                format!("{}*{}", s_lhs, s_rhs)
229,920✔
279
                            }
280
                        }
281
                        BinaryOp::Div => {
282
                            if op_lhs {
7,076✔
283
                                if op_rhs {
798✔
284
                                    format!("({})/({})", s_lhs, s_rhs)
×
285
                                } else {
286
                                    format!("({})/{}", s_lhs, s_rhs)
798✔
287
                                }
288
                            } else if op_rhs {
6,278✔
289
                                format!("{}/({})", s_lhs, s_rhs)
1,208✔
290
                            } else {
291
                                format!("{}/{}", s_lhs, s_rhs)
5,070✔
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,852,970✔
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,122,700✔
354
        match self {
1,122,700✔
355
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
446,416✔
356
                Some(v) => SymbolExpr::Value(*v),
445,206✔
357
                None => self.clone(),
1,210✔
358
            },
359
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
229,930✔
360
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
53,150✔
361
                op: op.clone(),
53,150✔
362
                expr: Box::new(expr.bind(maps)),
53,150✔
363
            },
53,150✔
364
            SymbolExpr::Binary { op, lhs, rhs } => {
393,204✔
365
                let new_lhs = lhs.bind(maps);
393,204✔
366
                let new_rhs = rhs.bind(maps);
393,204✔
367
                match op {
393,204✔
368
                    BinaryOp::Add => new_lhs + new_rhs,
77,416✔
369
                    BinaryOp::Sub => new_lhs - new_rhs,
59,886✔
370
                    BinaryOp::Mul => new_lhs * new_rhs,
174,414✔
371
                    BinaryOp::Div => new_lhs / new_rhs,
73,266✔
372
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
8,222✔
373
                }
374
            }
375
        }
376
    }
1,122,700✔
377

378
    /// substitute symbol node to other expression
379
    pub fn subs(&self, maps: &HashMap<String, SymbolExpr>) -> SymbolExpr {
54,856✔
380
        match self {
54,856✔
381
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
16,258✔
382
                Some(v) => v.clone(),
13,388✔
383
                None => self.clone(),
2,870✔
384
            },
385
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
14,990✔
386
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
5,742✔
387
                op: op.clone(),
5,742✔
388
                expr: Box::new(expr.subs(maps)),
5,742✔
389
            },
5,742✔
390
            SymbolExpr::Binary { op, lhs, rhs } => {
17,866✔
391
                let new_lhs = lhs.subs(maps);
17,866✔
392
                let new_rhs = rhs.subs(maps);
17,866✔
393
                match op {
17,866✔
394
                    BinaryOp::Add => new_lhs + new_rhs,
3,256✔
395
                    BinaryOp::Sub => new_lhs - new_rhs,
2,664✔
396
                    BinaryOp::Mul => new_lhs * new_rhs,
2,440✔
397
                    BinaryOp::Div => new_lhs / new_rhs,
9,488✔
398
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
399
                }
400
            }
401
        }
402
    }
54,856✔
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> {
46,115,496✔
407
        match self {
46,115,496✔
408
            SymbolExpr::Symbol(_) => None,
16,739,124✔
409
            SymbolExpr::Value(e) => Some(*e),
12,185,700✔
410
            SymbolExpr::Unary { op, expr } => {
570,296✔
411
                let val: Value;
570,296✔
412
                if recurse {
570,296✔
413
                    match expr.eval(recurse) {
570,296✔
414
                        Some(v) => val = v,
57,308✔
415
                        None => return None,
512,988✔
416
                    }
417
                } else {
418
                    match expr.as_ref() {
×
419
                        SymbolExpr::Value(e) => val = *e,
×
420
                        _ => return None,
×
421
                    }
422
                }
423
                let ret = match op {
57,308✔
424
                    UnaryOp::Abs => val.abs(),
258✔
425
                    UnaryOp::Neg => -val,
55,302✔
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 {
57,308✔
441
                    Value::Real(_) => Some(ret),
38,318✔
442
                    Value::Int(_) => Some(ret),
18,020✔
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,620,376✔
453
                let lval: Value;
16,620,376✔
454
                let rval: Value;
16,620,376✔
455
                if recurse {
16,620,376✔
456
                    match (lhs.eval(true), rhs.eval(true)) {
16,620,376✔
457
                        (Some(left), Some(right)) => {
18,946✔
458
                            lval = left;
18,946✔
459
                            rval = right;
18,946✔
460
                        }
18,946✔
461
                        _ => return None,
16,601,430✔
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,946✔
473
                    BinaryOp::Add => lval + rval,
1,424✔
474
                    BinaryOp::Sub => lval - rval,
480✔
475
                    BinaryOp::Mul => lval * rval,
864✔
476
                    BinaryOp::Div => lval / rval,
566✔
477
                    BinaryOp::Pow => lval.pow(&rval),
15,612✔
478
                };
479
                match ret {
18,946✔
480
                    Value::Real(_) => Some(ret),
7,356✔
481
                    Value::Int(_) => Some(ret),
5,500✔
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
    }
46,115,496✔
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())
16✔
578
                        + &(lhs.as_ref() * &rhs.derivative(param)?)),
16✔
579
                    BinaryOp::Div => Ok(&(&(&(&lhs.derivative(param)? * rhs.as_ref())
6✔
580
                        - &(lhs.as_ref() * &rhs.derivative(param)?))
6✔
581
                        / rhs.as_ref())
6✔
582
                        / rhs.as_ref()),
6✔
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 {
161,454✔
630
        match self {
161,454✔
631
            SymbolExpr::Symbol(_) => self.clone(),
30,470✔
632
            SymbolExpr::Value(_) => self.clone(),
1,878✔
633
            SymbolExpr::Unary { op, expr } => {
5,336✔
634
                let ex = expr.expand();
5,336✔
635
                match op {
5,336✔
636
                    UnaryOp::Neg => match ex.neg_opt() {
2,726✔
637
                        Some(ne) => ne,
×
638
                        None => _neg(ex),
2,726✔
639
                    },
640
                    _ => SymbolExpr::Unary {
2,610✔
641
                        op: op.clone(),
2,610✔
642
                        expr: Box::new(ex),
2,610✔
643
                    },
2,610✔
644
                }
645
            }
646
            SymbolExpr::Binary { op, lhs, rhs } => {
123,770✔
647
                match op {
123,770✔
648
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
105,456✔
649
                        Some(e) => e,
3,134✔
650
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
102,322✔
651
                    },
652
                    BinaryOp::Div => match lhs.div_expand(rhs) {
4,918✔
653
                        Some(e) => e,
494✔
654
                        None => _div(lhs.as_ref().clone(), rhs.as_ref().clone()),
4,424✔
655
                    },
656
                    BinaryOp::Add => match lhs.add_opt(rhs, true) {
5,696✔
657
                        Some(e) => e,
186✔
658
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
5,510✔
659
                    },
660
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
5,982✔
661
                        Some(e) => e,
2,198✔
662
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,784✔
663
                    },
664
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
1,718✔
665
                }
666
            }
667
        }
668
    }
161,454✔
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 hashset of all symbols this equation contains
729
    pub fn symbols_in_string(&self) -> HashSet<String> {
×
730
        match self {
×
731
            SymbolExpr::Symbol(s) => HashSet::<String>::from([s.as_ref().clone()]),
×
732
            SymbolExpr::Value(_) => HashSet::<String>::new(),
×
733
            SymbolExpr::Unary { op: _, expr } => expr.symbols_in_string(),
×
734
            SymbolExpr::Binary { op: _, lhs, rhs } => {
×
735
                let mut symbols = HashSet::<String>::new();
×
736
                for s in lhs.symbols_in_string().union(&rhs.symbols_in_string()) {
×
737
                    symbols.insert(s.to_string());
×
738
                }
×
739
                symbols
×
740
            }
741
        }
742
    }
×
743

744
    /// return all numbers in the equation
745
    pub fn values(&self) -> Vec<Value> {
182✔
746
        match self {
182✔
747
            SymbolExpr::Symbol(_) => Vec::<Value>::new(),
86✔
748
            SymbolExpr::Value(v) => Vec::<Value>::from([*v]),
44✔
749
            SymbolExpr::Unary { op: _, expr } => expr.values(),
×
750
            SymbolExpr::Binary { op: _, lhs, rhs } => {
52✔
751
                let mut l = lhs.values();
52✔
752
                let r = rhs.values();
52✔
753
                l.extend(r);
52✔
754
                l
52✔
755
            }
756
        }
757
    }
182✔
758

759
    /// check if a symbol is in this equation
760
    pub fn has_symbol(&self, param: &String) -> bool {
12✔
761
        match self {
12✔
762
            SymbolExpr::Symbol(e) => e.as_ref() == param,
6✔
763
            SymbolExpr::Value(_) => false,
6✔
764
            SymbolExpr::Unary { op: _, expr } => expr.has_symbol(param),
×
765
            SymbolExpr::Binary { op: _, lhs, rhs } => lhs.has_symbol(param) | rhs.has_symbol(param),
×
766
        }
767
    }
12✔
768

769
    /// return reciprocal of the equation
770
    pub fn rcp(&self) -> SymbolExpr {
1,998✔
771
        match self {
1,998✔
772
            SymbolExpr::Symbol(e) => _div(
×
773
                SymbolExpr::Value(Value::Real(1.0)),
×
774
                SymbolExpr::Symbol(e.clone()),
×
775
            ),
×
776
            SymbolExpr::Value(e) => SymbolExpr::Value(e.rcp()),
1,998✔
777
            SymbolExpr::Unary { .. } => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
778
            SymbolExpr::Binary { op, lhs, rhs } => match op {
×
779
                BinaryOp::Div => SymbolExpr::Binary {
×
780
                    op: op.clone(),
×
781
                    lhs: Box::new(*rhs.clone()),
×
782
                    rhs: Box::new(*lhs.clone()),
×
783
                },
×
784
                _ => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
785
            },
786
        }
787
    }
1,998✔
788
    /// return square root of the equation
789
    pub fn sqrt(&self) -> SymbolExpr {
×
790
        match self {
×
791
            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
792
            _ => self.pow(&SymbolExpr::Value(Value::Real(0.5))),
×
793
        }
794
    }
×
795

796
    /// return conjugate of the equation
797
    pub fn conjugate(&self) -> SymbolExpr {
4,146✔
798
        match self {
4,146✔
799
            SymbolExpr::Symbol(_) => SymbolExpr::Unary {
1,716✔
800
                op: UnaryOp::Conj,
1,716✔
801
                expr: Box::new(self.clone()),
1,716✔
802
            },
1,716✔
803
            SymbolExpr::Value(e) => match e {
1,050✔
804
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
542✔
805
                _ => SymbolExpr::Value(*e),
508✔
806
            },
807
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
298✔
808
                op: op.clone(),
298✔
809
                expr: Box::new(expr.conjugate()),
298✔
810
            },
298✔
811
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
1,082✔
812
                op: op.clone(),
1,082✔
813
                lhs: Box::new(lhs.conjugate()),
1,082✔
814
                rhs: Box::new(rhs.conjugate()),
1,082✔
815
            },
1,082✔
816
        }
817
    }
4,146✔
818

819
    /// check if complex number or not
820
    pub fn is_complex(&self) -> Option<bool> {
×
821
        match self.eval(true) {
×
822
            Some(v) => match v {
×
823
                Value::Complex(c) => Some(!(-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
×
824
                _ => Some(false),
×
825
            },
826
            None => None,
×
827
        }
828
    }
×
829

830
    /// check if real number or not
831
    pub fn is_real(&self) -> Option<bool> {
×
832
        match self.eval(true) {
×
833
            Some(v) => match v {
×
834
                Value::Real(_) => Some(true),
×
835
                Value::Int(_) => Some(false),
×
836
                Value::Complex(c) => Some((-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
×
837
            },
838
            None => None,
×
839
        }
840
    }
×
841

842
    /// check if integer or not
843
    pub fn is_int(&self) -> Option<bool> {
4,212✔
844
        match self.eval(true) {
4,212✔
845
            Some(v) => match v {
3,824✔
846
                Value::Int(_) => Some(true),
1,470✔
847
                _ => Some(false),
2,354✔
848
            },
849
            None => None,
388✔
850
        }
851
    }
4,212✔
852

853
    /// check if evaluated result is 0
854
    pub fn is_zero(&self) -> bool {
9,845,236✔
855
        match self.eval(true) {
9,845,236✔
856
            Some(v) => v.is_zero(),
5,642,980✔
857
            None => false,
4,202,256✔
858
        }
859
    }
9,845,236✔
860

861
    /// check if evaluated result is 1
862
    pub fn is_one(&self) -> bool {
742,892✔
863
        match self.eval(true) {
742,892✔
864
            Some(v) => v.is_one(),
526,714✔
865
            None => false,
216,178✔
866
        }
867
    }
742,892✔
868

869
    /// check if evaluated result is -1
870
    pub fn is_minus_one(&self) -> bool {
445,612✔
871
        match self.eval(true) {
445,612✔
872
            Some(v) => v.is_minus_one(),
263,926✔
873
            None => false,
181,686✔
874
        }
875
    }
445,612✔
876

877
    /// check if evaluated result is negative
878
    fn is_negative(&self) -> bool {
471,744✔
879
        match self {
471,744✔
880
            SymbolExpr::Value(v) => v.is_negative(),
68,726✔
881
            SymbolExpr::Symbol(_) => false,
229,442✔
882
            SymbolExpr::Unary { op, expr } => match op {
17,866✔
883
                UnaryOp::Abs => false,
6✔
884
                UnaryOp::Neg => !expr.is_negative(),
15,974✔
885
                _ => false, // TO DO add heuristic determination
1,886✔
886
            },
887
            SymbolExpr::Binary { op, lhs, rhs } => match op {
155,710✔
888
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
134,844✔
889
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
15,464✔
890
                _ => false, // TO DO add heuristic determination for pow
5,402✔
891
            },
892
        }
893
    }
471,744✔
894

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

999
    // Add with heuristic optimization
1000
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,610,760✔
1001
        if self.is_zero() {
2,610,760✔
1002
            Some(rhs.clone())
1,307,510✔
1003
        } else if rhs.is_zero() {
1,303,250✔
1004
            Some(self.clone())
1,046,026✔
1005
        } else {
1006
            // if neg operation, call sub_opt
1007
            if let SymbolExpr::Unary { op, expr } = rhs {
257,224✔
1008
                if let UnaryOp::Neg = op {
15,380✔
1009
                    return self.sub_opt(expr, recursive);
13,626✔
1010
                }
1,754✔
1011
            } else if recursive {
241,844✔
1012
                if let SymbolExpr::Binary {
1013
                    op,
48,560✔
1014
                    lhs: r_lhs,
48,560✔
1015
                    rhs: r_rhs,
48,560✔
1016
                } = rhs
98,070✔
1017
                {
1018
                    // recursive optimization for add and sub
1019
                    if let BinaryOp::Add = &op {
48,560✔
1020
                        if let Some(e) = self.add_opt(r_lhs, true) {
4,298✔
1021
                            return match e.add_opt(r_rhs, true) {
86✔
1022
                                Some(ee) => Some(ee),
48✔
1023
                                None => Some(_add(e, r_rhs.as_ref().clone())),
38✔
1024
                            };
1025
                        }
4,212✔
1026
                        if let Some(e) = self.add_opt(r_rhs, true) {
4,212✔
1027
                            return match e.add_opt(r_lhs, true) {
12✔
1028
                                Some(ee) => Some(ee),
×
1029
                                None => Some(_add(e, r_lhs.as_ref().clone())),
12✔
1030
                            };
1031
                        }
4,200✔
1032
                    }
44,262✔
1033
                    if let BinaryOp::Sub = &op {
48,462✔
1034
                        if let Some(e) = self.add_opt(r_lhs, true) {
3,496✔
1035
                            return match e.sub_opt(r_rhs, true) {
110✔
1036
                                Some(ee) => Some(ee),
80✔
1037
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
30✔
1038
                            };
1039
                        }
3,386✔
1040
                        if let Some(e) = self.sub_opt(r_rhs, true) {
3,386✔
1041
                            return match e.add_opt(r_lhs, true) {
12✔
1042
                                Some(ee) => Some(ee),
×
1043
                                None => Some(_add(e, r_lhs.as_ref().clone())),
12✔
1044
                            };
1045
                        }
3,374✔
1046
                    }
44,966✔
1047
                }
49,510✔
1048
            }
143,774✔
1049

1050
            // optimization for each node type
1051
            match self {
243,378✔
1052
                SymbolExpr::Value(l) => match rhs {
90,878✔
1053
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
63,130✔
1054
                    SymbolExpr::Binary {
1055
                        op,
3,502✔
1056
                        lhs: r_lhs,
3,502✔
1057
                        rhs: r_rhs,
3,502✔
1058
                    } => {
1059
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
3,502✔
1060
                            let t = l + v;
1,666✔
1061
                            match op {
1,666✔
1062
                                BinaryOp::Add => {
1063
                                    if t.is_zero() {
12✔
1064
                                        Some(r_rhs.as_ref().clone())
×
1065
                                    } else {
1066
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
12✔
1067
                                    }
1068
                                }
1069
                                BinaryOp::Sub => {
1070
                                    if t.is_zero() {
×
1071
                                        match r_rhs.neg_opt() {
×
1072
                                            Some(e) => Some(e),
×
1073
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1074
                                        }
1075
                                    } else {
1076
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1077
                                    }
1078
                                }
1079
                                _ => None,
1,654✔
1080
                            }
1081
                        } else {
1082
                            None
1,836✔
1083
                        }
1084
                    }
1085
                    _ => None,
24,246✔
1086
                },
1087
                SymbolExpr::Symbol(l) => match rhs {
33,094✔
1088
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
2,804✔
1089
                    SymbolExpr::Symbol(r) => {
26,844✔
1090
                        if r == l {
26,844✔
1091
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
140✔
1092
                        } else if r < l {
26,704✔
1093
                            Some(_add(rhs.clone(), self.clone()))
1,786✔
1094
                        } else {
1095
                            None
24,918✔
1096
                        }
1097
                    }
1098
                    SymbolExpr::Binary {
1099
                        op,
3,446✔
1100
                        lhs: r_lhs,
3,446✔
1101
                        rhs: r_rhs,
3,446✔
1102
                    } => {
1103
                        if let (
1104
                            BinaryOp::Mul | BinaryOp::Div,
1105
                            SymbolExpr::Value(v),
2,434✔
1106
                            SymbolExpr::Symbol(s),
2,434✔
1107
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,446✔
1108
                        {
1109
                            if l == s {
2,434✔
1110
                                let t = v + &Value::Int(1);
10✔
1111
                                if t.is_zero() {
10✔
1112
                                    Some(SymbolExpr::Value(Value::Int(0)))
6✔
1113
                                } else {
1114
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
4✔
1115
                                }
1116
                            } else {
1117
                                None
2,424✔
1118
                            }
1119
                        } else {
1120
                            None
1,012✔
1121
                        }
1122
                    }
1123
                    _ => None,
×
1124
                },
1125
                SymbolExpr::Unary { op, expr } => {
14,306✔
1126
                    if let UnaryOp::Neg = op {
14,306✔
1127
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
12,940✔
1128
                            return match e.neg_opt() {
5,884✔
1129
                                Some(ee) => Some(ee),
5,884✔
1130
                                None => Some(_neg(e)),
×
1131
                            };
1132
                        }
7,056✔
1133
                    } else if let SymbolExpr::Unary {
1134
                        op: rop,
712✔
1135
                        expr: rexpr,
712✔
1136
                    } = rhs
1,366✔
1137
                    {
1138
                        if op == rop {
712✔
1139
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
420✔
1140
                                if t.is_zero() {
12✔
1141
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1142
                                }
12✔
1143
                            }
408✔
1144
                        }
292✔
1145
                    }
654✔
1146

1147
                    // swap nodes by sorting rule
1148
                    match rhs {
8,422✔
1149
                        SymbolExpr::Binary { op: rop, .. } => {
5,978✔
1150
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
5,978✔
1151
                                if self > rhs {
5,190✔
1152
                                    Some(_add(rhs.clone(), self.clone()))
×
1153
                                } else {
1154
                                    None
5,190✔
1155
                                }
1156
                            } else {
1157
                                None
788✔
1158
                            }
1159
                        }
1160
                        _ => {
1161
                            if self > rhs {
2,444✔
1162
                                Some(_add(rhs.clone(), self.clone()))
36✔
1163
                            } else {
1164
                                None
2,408✔
1165
                            }
1166
                        }
1167
                    }
1168
                }
1169
                SymbolExpr::Binary {
1170
                    op,
105,100✔
1171
                    lhs: l_lhs,
105,100✔
1172
                    rhs: l_rhs,
105,100✔
1173
                } => {
1174
                    if let SymbolExpr::Binary {
1175
                        op: rop,
96,918✔
1176
                        lhs: r_lhs,
96,918✔
1177
                        rhs: r_rhs,
96,918✔
1178
                    } = rhs
105,100✔
1179
                    {
1180
                        match (
1181
                            l_lhs.as_ref(),
96,918✔
1182
                            l_rhs.as_ref(),
96,918✔
1183
                            r_lhs.as_ref(),
96,918✔
1184
                            r_rhs.as_ref(),
96,918✔
1185
                        ) {
1186
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
9,008✔
1187
                                if l_rhs.expand().to_string() == r_rhs.expand().to_string() {
9,008✔
1188
                                    let t = SymbolExpr::Value(lv + rv);
784✔
1189
                                    if t.is_zero() {
784✔
1190
                                        return Some(SymbolExpr::Value(Value::Int(0)));
380✔
1191
                                    }
404✔
1192
                                    match (op, rop) {
404✔
1193
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1194
                                            return match t.mul_opt(l_rhs, recursive) {
356✔
1195
                                                Some(e) => Some(e),
8✔
1196
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
348✔
1197
                                            }
1198
                                        }
1199
                                        (BinaryOp::Div, BinaryOp::Div) => {
1200
                                            return match t.div_opt(l_rhs, recursive) {
×
1201
                                                Some(e) => Some(e),
×
1202
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1203
                                            }
1204
                                        }
1205
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1206
                                            return match t.pow_opt(l_rhs) {
48✔
1207
                                                Some(e) => Some(e),
48✔
1208
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1209
                                            }
1210
                                        }
1211
                                        (_, _) => (),
×
1212
                                    }
1213
                                }
8,224✔
1214
                            }
1215
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
3,214✔
1216
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
3,214✔
1217
                                    if l_lhs.expand().to_string() == r_lhs.expand().to_string()
1,130✔
1218
                                        || _neg(l_lhs.as_ref().clone()).expand().to_string()
1,100✔
1219
                                            == r_lhs.expand().to_string()
1,100✔
1220
                                    {
1221
                                        let tl =
30✔
1222
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
30✔
1223
                                        let tr =
30✔
1224
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
30✔
1225
                                        let b = SymbolExpr::Value(lv * rv);
30✔
1226
                                        return match tl.add_opt(&tr, recursive) {
30✔
1227
                                            Some(e) => Some(_div(e, b)),
30✔
1228
                                            None => Some(_div(_add(tl, tr), b)),
×
1229
                                        };
1230
                                    }
1,100✔
1231
                                }
2,084✔
1232
                            }
1233
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
574✔
1234
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
574✔
1235
                                    if l_rhs.expand().to_string() == r_lhs.expand().to_string()
×
1236
                                        || _neg(l_rhs.as_ref().clone()).expand().to_string()
×
1237
                                            == r_lhs.expand().to_string()
×
1238
                                    {
1239
                                        let r = _mul(
×
1240
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
×
1241
                                            r_lhs.as_ref().clone(),
×
1242
                                        );
×
1243
                                        if let Some(e) = self.add_opt(&r, recursive) {
×
1244
                                            return Some(e);
×
1245
                                        }
×
1246
                                    }
×
1247
                                }
574✔
1248
                            }
1249
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
536✔
1250
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
536✔
1251
                                    if l_lhs.expand().to_string() == r_rhs.expand().to_string()
8✔
1252
                                        || _neg(l_lhs.as_ref().clone()).expand().to_string()
4✔
1253
                                            == r_rhs.expand().to_string()
4✔
1254
                                    {
1255
                                        let l = _mul(
8✔
1256
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
8✔
1257
                                            l_lhs.as_ref().clone(),
8✔
1258
                                        );
8✔
1259
                                        if let Some(e) = l.add_opt(rhs, recursive) {
8✔
1260
                                            return Some(e);
8✔
1261
                                        }
×
1262
                                    }
×
1263
                                }
528✔
1264
                            }
1265
                            (_, _, _, _) => (),
83,586✔
1266
                        }
1267

1268
                        if op == rop {
96,096✔
1269
                            if let Some(e) = rhs.neg_opt() {
40,118✔
1270
                                if self.expand().to_string() == e.expand().to_string() {
24,664✔
1271
                                    return Some(SymbolExpr::Value(Value::Int(0)));
838✔
1272
                                }
23,826✔
1273
                            }
15,454✔
1274
                        }
55,978✔
1275
                    } else if let SymbolExpr::Symbol(r) = rhs {
8,182✔
1276
                        if let (
1277
                            BinaryOp::Mul | BinaryOp::Div,
1278
                            SymbolExpr::Value(v),
1,404✔
1279
                            SymbolExpr::Symbol(s),
1,404✔
1280
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
6,494✔
1281
                        {
1282
                            if s == r {
1,404✔
1283
                                let t = v + &Value::Int(1);
×
1284
                                if t.is_zero() {
×
1285
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1286
                                } else {
1287
                                    return Some(_mul(
×
1288
                                        SymbolExpr::Value(t),
×
1289
                                        l_rhs.as_ref().clone(),
×
1290
                                    ));
×
1291
                                }
1292
                            }
1,404✔
1293
                        }
5,090✔
1294
                    }
1,688✔
1295
                    if recursive {
103,440✔
1296
                        if let BinaryOp::Add = op {
45,330✔
1297
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
7,580✔
1298
                                return match e.add_opt(l_rhs, true) {
452✔
1299
                                    Some(ee) => Some(ee),
238✔
1300
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
214✔
1301
                                };
1302
                            }
7,128✔
1303
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,128✔
1304
                                return match l_lhs.add_opt(&e, true) {
188✔
1305
                                    Some(ee) => Some(ee),
×
1306
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
188✔
1307
                                };
1308
                            }
6,940✔
1309
                        } else if let BinaryOp::Sub = op {
37,750✔
1310
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
6,886✔
1311
                                return match e.sub_opt(l_rhs, true) {
908✔
1312
                                    Some(ee) => Some(ee),
262✔
1313
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
646✔
1314
                                };
1315
                            }
5,978✔
1316
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
5,978✔
1317
                                return match l_lhs.sub_opt(&e, true) {
262✔
1318
                                    Some(ee) => Some(ee),
60✔
1319
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
202✔
1320
                                };
1321
                            }
5,716✔
1322
                        }
30,864✔
1323
                    }
58,110✔
1324
                    // swap nodes by sorting rule
1325
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
101,630✔
1326
                        match rhs {
44,428✔
1327
                            SymbolExpr::Binary { op: rop, .. } => {
42,166✔
1328
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
42,166✔
1329
                                    if self > rhs {
37,790✔
1330
                                        Some(_add(rhs.clone(), self.clone()))
696✔
1331
                                    } else {
1332
                                        None
37,094✔
1333
                                    }
1334
                                } else {
1335
                                    None
4,376✔
1336
                                }
1337
                            }
1338
                            _ => {
1339
                                if self > rhs {
2,262✔
1340
                                    Some(_add(rhs.clone(), self.clone()))
2,262✔
1341
                                } else {
1342
                                    None
×
1343
                                }
1344
                            }
1345
                        }
1346
                    } else {
1347
                        None
57,202✔
1348
                    }
1349
                }
1350
            }
1351
        }
1352
    }
2,610,760✔
1353

1354
    /// Sub with heuristic optimization
1355
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
263,870✔
1356
        if self.is_zero() {
263,870✔
1357
            match rhs.neg_opt() {
7,058✔
1358
                Some(e) => Some(e),
6,246✔
1359
                None => Some(_neg(rhs.clone())),
812✔
1360
            }
1361
        } else if rhs.is_zero() {
256,812✔
1362
            Some(self.clone())
2,254✔
1363
        } else {
1364
            // if neg, call add_opt
1365
            if let SymbolExpr::Unary { op, expr } = rhs {
254,558✔
1366
                if let UnaryOp::Neg = op {
4,566✔
1367
                    return self.add_opt(expr, recursive);
2,356✔
1368
                }
2,210✔
1369
            } else if recursive {
249,992✔
1370
                if let SymbolExpr::Binary {
1371
                    op,
47,476✔
1372
                    lhs: r_lhs,
47,476✔
1373
                    rhs: r_rhs,
47,476✔
1374
                } = rhs
156,236✔
1375
                {
1376
                    // recursive optimization for add and sub
1377
                    if let BinaryOp::Add = &op {
47,476✔
1378
                        if let Some(e) = self.sub_opt(r_lhs, true) {
4,126✔
1379
                            return match e.sub_opt(r_rhs, true) {
498✔
1380
                                Some(ee) => Some(ee),
470✔
1381
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
28✔
1382
                            };
1383
                        }
3,628✔
1384
                        if let Some(e) = self.sub_opt(r_rhs, true) {
3,628✔
1385
                            return match e.sub_opt(r_lhs, true) {
12✔
1386
                                Some(ee) => Some(ee),
×
1387
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
12✔
1388
                            };
1389
                        }
3,616✔
1390
                    }
43,350✔
1391
                    if let BinaryOp::Sub = &op {
46,966✔
1392
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,724✔
1393
                            return match e.add_opt(r_rhs, true) {
586✔
1394
                                Some(ee) => Some(ee),
544✔
1395
                                None => Some(_add(e, r_rhs.as_ref().clone())),
42✔
1396
                            };
1397
                        }
3,138✔
1398
                        if let Some(e) = self.add_opt(r_rhs, true) {
3,138✔
1399
                            return match e.sub_opt(r_lhs, true) {
16✔
1400
                                Some(ee) => Some(ee),
×
1401
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
16✔
1402
                            };
1403
                        }
3,122✔
1404
                    }
43,242✔
1405
                }
108,760✔
1406
            }
93,756✔
1407

1408
            // optimization for each type
1409
            match self {
251,090✔
1410
                SymbolExpr::Value(l) => match &rhs {
78,524✔
1411
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
70,846✔
1412
                    SymbolExpr::Binary {
1413
                        op,
3,510✔
1414
                        lhs: r_lhs,
3,510✔
1415
                        rhs: r_rhs,
3,510✔
1416
                    } => {
1417
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
3,510✔
1418
                            let t = l - v;
1,514✔
1419
                            match op {
1,514✔
1420
                                BinaryOp::Add => {
1421
                                    if t.is_zero() {
×
1422
                                        match r_rhs.neg_opt() {
×
1423
                                            Some(e) => Some(e),
×
1424
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1425
                                        }
1426
                                    } else {
1427
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1428
                                    }
1429
                                }
1430
                                BinaryOp::Sub => {
1431
                                    if t.is_zero() {
×
1432
                                        Some(r_rhs.as_ref().clone())
×
1433
                                    } else {
1434
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1435
                                    }
1436
                                }
1437
                                _ => None,
1,514✔
1438
                            }
1439
                        } else {
1440
                            None
1,996✔
1441
                        }
1442
                    }
1443
                    _ => None,
4,168✔
1444
                },
1445
                SymbolExpr::Symbol(l) => match &rhs {
59,686✔
1446
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
3,182✔
1447
                    SymbolExpr::Symbol(r) => {
52,814✔
1448
                        if r == l {
52,814✔
1449
                            Some(SymbolExpr::Value(Value::Int(0)))
29,082✔
1450
                        } else if r < l {
23,732✔
1451
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,340✔
1452
                        } else {
1453
                            None
22,392✔
1454
                        }
1455
                    }
1456
                    SymbolExpr::Binary {
1457
                        op,
3,690✔
1458
                        lhs: r_lhs,
3,690✔
1459
                        rhs: r_rhs,
3,690✔
1460
                    } => {
1461
                        if let (
1462
                            BinaryOp::Mul | BinaryOp::Div,
1463
                            SymbolExpr::Value(v),
2,254✔
1464
                            SymbolExpr::Symbol(s),
2,254✔
1465
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,690✔
1466
                        {
1467
                            if l == s {
2,254✔
1468
                                let t = &Value::Int(1) - v;
14✔
1469
                                if t.is_zero() {
14✔
1470
                                    Some(SymbolExpr::Value(Value::Int(0)))
4✔
1471
                                } else {
1472
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
10✔
1473
                                }
1474
                            } else {
1475
                                None
2,240✔
1476
                            }
1477
                        } else {
1478
                            None
1,436✔
1479
                        }
1480
                    }
1481
                    _ => None,
×
1482
                },
1483
                SymbolExpr::Unary { op, expr } => {
14,680✔
1484
                    if let UnaryOp::Neg = op {
14,680✔
1485
                        if let Some(e) = expr.add_opt(rhs, recursive) {
12,484✔
1486
                            return match e.neg_opt() {
6,760✔
1487
                                Some(ee) => Some(ee),
6,760✔
1488
                                None => Some(_neg(e)),
×
1489
                            };
1490
                        }
5,724✔
1491
                    }
2,196✔
1492
                    if let SymbolExpr::Unary {
1493
                        op: rop,
1,652✔
1494
                        expr: rexpr,
1,652✔
1495
                    } = rhs
7,920✔
1496
                    {
1497
                        if op == rop {
1,652✔
1498
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
1,192✔
1499
                                if t.is_zero() {
836✔
1500
                                    return Some(SymbolExpr::Value(Value::Int(0)));
836✔
UNCOV
1501
                                }
×
1502
                            }
356✔
1503
                        }
460✔
1504
                    }
6,268✔
1505

1506
                    // swap nodes by sorting rule
1507
                    match rhs {
7,084✔
1508
                        SymbolExpr::Binary { op: rop, .. } => {
4,476✔
1509
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
4,476✔
1510
                                if self > rhs {
3,860✔
1511
                                    match rhs.neg_opt() {
×
1512
                                        Some(e) => Some(_add(e, self.clone())),
×
1513
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
×
1514
                                    }
1515
                                } else {
1516
                                    None
3,860✔
1517
                                }
1518
                            } else {
1519
                                None
616✔
1520
                            }
1521
                        }
1522
                        _ => {
1523
                            if self > rhs {
2,608✔
1524
                                match rhs.neg_opt() {
24✔
1525
                                    Some(e) => Some(_add(e, self.clone())),
×
1526
                                    None => Some(_add(_neg(rhs.clone()), self.clone())),
24✔
1527
                                }
1528
                            } else {
1529
                                None
2,584✔
1530
                            }
1531
                        }
1532
                    }
1533
                }
1534
                SymbolExpr::Binary {
1535
                    op,
98,200✔
1536
                    lhs: l_lhs,
98,200✔
1537
                    rhs: l_rhs,
98,200✔
1538
                } => {
1539
                    if let SymbolExpr::Binary {
1540
                        op: rop,
48,868✔
1541
                        lhs: r_lhs,
48,868✔
1542
                        rhs: r_rhs,
48,868✔
1543
                    } = rhs
98,200✔
1544
                    {
1545
                        match (
1546
                            l_lhs.as_ref(),
48,868✔
1547
                            l_rhs.as_ref(),
48,868✔
1548
                            r_lhs.as_ref(),
48,868✔
1549
                            r_rhs.as_ref(),
48,868✔
1550
                        ) {
1551
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
4,530✔
1552
                                if l_rhs.expand().to_string() == r_rhs.expand().to_string() {
4,530✔
1553
                                    let t = SymbolExpr::Value(lv - rv);
1,200✔
1554
                                    if t.is_zero() {
1,200✔
1555
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,200✔
1556
                                    }
×
1557
                                    match (op, rop) {
×
1558
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1559
                                            return match t.mul_opt(l_rhs, recursive) {
×
1560
                                                Some(e) => Some(e),
×
1561
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
×
1562
                                            }
1563
                                        }
1564
                                        (BinaryOp::Div, BinaryOp::Div) => {
1565
                                            return match t.div_opt(l_rhs, recursive) {
×
1566
                                                Some(e) => Some(e),
×
1567
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1568
                                            }
1569
                                        }
1570
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1571
                                            return match t.pow_opt(l_rhs) {
×
1572
                                                Some(e) => Some(e),
×
1573
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1574
                                            }
1575
                                        }
1576
                                        (_, _) => (),
×
1577
                                    }
1578
                                }
3,330✔
1579
                            }
1580
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
510✔
1581
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
510✔
1582
                                    if l_lhs.expand().to_string() == r_lhs.expand().to_string()
260✔
1583
                                        || _neg(l_lhs.as_ref().clone()).expand().to_string()
204✔
1584
                                            == r_lhs.expand().to_string()
204✔
1585
                                    {
1586
                                        let tl =
60✔
1587
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
60✔
1588
                                        let tr =
60✔
1589
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
60✔
1590
                                        let b = SymbolExpr::Value(lv * rv);
60✔
1591
                                        return match tl.sub_opt(&tr, recursive) {
60✔
1592
                                            Some(e) => Some(_div(e, b)),
60✔
1593
                                            None => Some(_div(_sub(tl, tr), b)),
×
1594
                                        };
1595
                                    }
200✔
1596
                                }
250✔
1597
                            }
1598
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
218✔
1599
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
218✔
1600
                                    if l_rhs.expand().to_string() == r_lhs.expand().to_string()
4✔
1601
                                        || _neg(l_rhs.as_ref().clone()).expand().to_string()
×
1602
                                            == r_lhs.expand().to_string()
×
1603
                                    {
1604
                                        let r = _mul(
4✔
1605
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
4✔
1606
                                            r_lhs.as_ref().clone(),
4✔
1607
                                        );
4✔
1608
                                        if let Some(e) = self.sub_opt(&r, recursive) {
4✔
1609
                                            return Some(e);
4✔
1610
                                        }
×
1611
                                    }
×
1612
                                }
214✔
1613
                            }
1614
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
166✔
1615
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
166✔
1616
                                    if l_lhs.expand().to_string() == r_rhs.expand().to_string()
54✔
1617
                                        || _neg(l_lhs.as_ref().clone()).expand().to_string()
24✔
1618
                                            == r_rhs.expand().to_string()
24✔
1619
                                    {
1620
                                        let l = _mul(
50✔
1621
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
50✔
1622
                                            l_lhs.as_ref().clone(),
50✔
1623
                                        );
50✔
1624
                                        if let Some(e) = l.sub_opt(rhs, recursive) {
50✔
1625
                                            return Some(e);
50✔
1626
                                        }
×
1627
                                    }
4✔
1628
                                }
112✔
1629
                            }
1630
                            (_, _, _, _) => (),
43,444✔
1631
                        }
1632

1633
                        if op == rop && self.expand().to_string() == rhs.expand().to_string() {
47,554✔
1634
                            return Some(SymbolExpr::Value(Value::Int(0)));
212✔
1635
                        }
47,342✔
1636
                    } else if let SymbolExpr::Symbol(r) = rhs {
49,332✔
1637
                        if let (
1638
                            BinaryOp::Mul | BinaryOp::Div,
1639
                            SymbolExpr::Value(v),
1,374✔
1640
                            SymbolExpr::Symbol(s),
1,374✔
1641
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
22,274✔
1642
                        {
1643
                            if s == r {
1,374✔
1644
                                let t = v - &Value::Int(1);
12✔
1645
                                if t.is_zero() {
12✔
1646
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1647
                                } else {
1648
                                    return Some(_mul(
12✔
1649
                                        SymbolExpr::Value(t),
12✔
1650
                                        l_rhs.as_ref().clone(),
12✔
1651
                                    ));
12✔
1652
                                }
1653
                            }
1,362✔
1654
                        }
20,900✔
1655
                    }
27,058✔
1656
                    if recursive {
96,662✔
1657
                        if let BinaryOp::Add = op {
82,914✔
1658
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
44,318✔
1659
                                return match e.add_opt(l_rhs, true) {
21,980✔
1660
                                    Some(ee) => Some(ee),
18,004✔
1661
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
3,976✔
1662
                                };
1663
                            }
22,338✔
1664
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
22,338✔
1665
                                return match l_lhs.add_opt(&e, true) {
17,822✔
1666
                                    Some(ee) => Some(ee),
17,660✔
1667
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
162✔
1668
                                };
1669
                            }
4,516✔
1670
                        }
38,596✔
1671
                        if let BinaryOp::Sub = op {
43,112✔
1672
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
8,830✔
1673
                                return match e.sub_opt(l_rhs, true) {
1,448✔
1674
                                    Some(ee) => Some(ee),
326✔
1675
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
1,122✔
1676
                                };
1677
                            }
7,382✔
1678
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,382✔
1679
                                return match l_lhs.sub_opt(&e, true) {
148✔
1680
                                    Some(ee) => Some(ee),
8✔
1681
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
140✔
1682
                                };
1683
                            }
7,234✔
1684
                        }
34,282✔
1685
                    }
13,748✔
1686
                    // swap nodes by sorting rule
1687
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
55,264✔
1688
                        match rhs {
35,282✔
1689
                            SymbolExpr::Binary { op: rop, .. } => {
30,198✔
1690
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
30,198✔
1691
                                    if self > rhs {
26,142✔
1692
                                        match rhs.neg_opt() {
130✔
1693
                                            Some(e) => Some(_add(e, self.clone())),
38✔
1694
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
92✔
1695
                                        }
1696
                                    } else {
1697
                                        None
26,012✔
1698
                                    }
1699
                                } else {
1700
                                    None
4,056✔
1701
                                }
1702
                            }
1703
                            _ => {
1704
                                if self > rhs {
5,084✔
1705
                                    match rhs.neg_opt() {
5,084✔
1706
                                        Some(e) => Some(_add(e, self.clone())),
3,114✔
1707
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
1,970✔
1708
                                    }
1709
                                } else {
1710
                                    None
×
1711
                                }
1712
                            }
1713
                        }
1714
                    } else {
1715
                        None
19,982✔
1716
                    }
1717
                }
1718
            }
1719
        }
1720
    }
263,870✔
1721

1722
    /// Mul with heuristic optimization
1723
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,640,774✔
1724
        if self.is_zero() {
2,640,774✔
1725
            Some(self.clone())
20,796✔
1726
        } else if rhs.is_zero() || self.is_one() {
2,619,978✔
1727
            Some(rhs.clone())
2,377,816✔
1728
        } else if rhs.is_one() {
242,162✔
1729
            Some(self.clone())
84,936✔
1730
        } else if self.is_minus_one() {
157,226✔
1731
            match rhs.neg_opt() {
3,378✔
1732
                Some(e) => Some(e),
1,110✔
1733
                None => Some(_neg(rhs.clone())),
2,268✔
1734
            }
1735
        } else if rhs.is_minus_one() {
153,848✔
1736
            match self.neg_opt() {
26,366✔
1737
                Some(e) => Some(e),
8,452✔
1738
                None => Some(_neg(self.clone())),
17,914✔
1739
            }
1740
        } else {
1741
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
127,482✔
1742
                if let SymbolExpr::Unary { .. } = self {
93,680✔
1743
                    return match rhs.mul_opt(self, recursive) {
5,462✔
1744
                        Some(e) => Some(e),
5,166✔
1745
                        None => Some(_mul(rhs.clone(), self.clone())),
296✔
1746
                    };
1747
                }
88,218✔
1748
            }
33,802✔
1749

1750
            match self {
122,020✔
1751
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
36,894✔
1752
                SymbolExpr::Symbol(e) => match rhs {
32,116✔
1753
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
14,544✔
1754
                    SymbolExpr::Symbol(r) => {
11,958✔
1755
                        if r < e {
11,958✔
1756
                            Some(_mul(rhs.clone(), self.clone()))
4,026✔
1757
                        } else {
1758
                            None
7,932✔
1759
                        }
1760
                    }
1761
                    SymbolExpr::Unary {
1762
                        op: UnaryOp::Neg,
1763
                        expr,
1,428✔
1764
                    } => match expr.as_ref() {
1,428✔
1765
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1766
                        SymbolExpr::Symbol(s) => {
1,428✔
1767
                            if s < e {
1,428✔
1768
                                Some(_neg(_mul(*expr.clone(), self.clone())))
1,044✔
1769
                            } else {
1770
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
384✔
1771
                            }
1772
                        }
1773
                        SymbolExpr::Binary { .. } => match self.mul_opt(expr, recursive) {
×
1774
                            Some(e) => match e.neg_opt() {
×
1775
                                Some(ee) => Some(ee),
×
1776
                                None => Some(_neg(e)),
×
1777
                            },
1778
                            None => None,
×
1779
                        },
1780
                        _ => None,
×
1781
                    },
1782
                    _ => None,
4,186✔
1783
                },
1784
                SymbolExpr::Unary { op, expr } => match op {
562✔
1785
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
546✔
1786
                        Some(e) => match e.neg_opt() {
82✔
1787
                            Some(ee) => Some(ee),
82✔
1788
                            None => Some(_neg(e)),
×
1789
                        },
1790
                        None => None,
464✔
1791
                    },
1792
                    UnaryOp::Abs => match rhs {
2✔
1793
                        SymbolExpr::Unary {
1794
                            op: UnaryOp::Abs,
1795
                            expr: rexpr,
2✔
1796
                        } => match expr.mul_opt(rexpr, recursive) {
2✔
1797
                            Some(e) => Some(SymbolExpr::Unary {
×
1798
                                op: UnaryOp::Abs,
×
1799
                                expr: Box::new(e),
×
1800
                            }),
×
1801
                            None => Some(SymbolExpr::Unary {
2✔
1802
                                op: UnaryOp::Abs,
2✔
1803
                                expr: Box::new(_mul(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
1804
                            }),
2✔
1805
                        },
1806
                        _ => None,
×
1807
                    },
1808
                    _ => None,
14✔
1809
                },
1810
                SymbolExpr::Binary {
1811
                    op,
52,448✔
1812
                    lhs: l_lhs,
52,448✔
1813
                    rhs: l_rhs,
52,448✔
1814
                } => {
52,448✔
1815
                    if recursive {
52,448✔
1816
                        if let SymbolExpr::Binary {
1817
                            op: rop,
426✔
1818
                            lhs: r_lhs,
426✔
1819
                            rhs: r_rhs,
426✔
1820
                        } = rhs
5,940✔
1821
                        {
1822
                            if let BinaryOp::Mul = &rop {
426✔
1823
                                if let Some(e) = self.mul_opt(r_lhs, true) {
406✔
1824
                                    return match e.mul_opt(r_rhs, true) {
406✔
1825
                                        Some(ee) => Some(ee),
312✔
1826
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
94✔
1827
                                    };
1828
                                }
×
1829
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
1830
                                    return match e.mul_opt(r_lhs, true) {
×
1831
                                        Some(ee) => Some(ee),
×
1832
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1833
                                    };
1834
                                }
×
1835
                            }
20✔
1836
                            if let BinaryOp::Div = &rop {
20✔
1837
                                if let Some(e) = self.mul_opt(r_lhs, true) {
×
1838
                                    return match e.div_opt(r_rhs, true) {
×
1839
                                        Some(ee) => Some(ee),
×
1840
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
1841
                                    };
1842
                                }
×
1843
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
1844
                                    return match e.mul_opt(r_lhs, true) {
×
1845
                                        Some(ee) => Some(ee),
×
1846
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1847
                                    };
1848
                                }
×
1849
                            }
20✔
1850
                        }
5,514✔
1851

1852
                        if let BinaryOp::Mul = &op {
5,534✔
1853
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
5,514✔
1854
                                return match e.mul_opt(l_rhs, true) {
1,994✔
1855
                                    Some(ee) => Some(ee),
1,850✔
1856
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1857
                                };
1858
                            }
3,520✔
1859
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
3,520✔
1860
                                return match l_lhs.mul_opt(&e, true) {
1,386✔
1861
                                    Some(ee) => Some(ee),
×
1862
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
1,386✔
1863
                                };
1864
                            }
2,134✔
1865
                        } else if let BinaryOp::Div = &op {
20✔
1866
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
14✔
1867
                                return match e.div_opt(l_rhs, true) {
×
1868
                                    Some(ee) => Some(ee),
×
1869
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
1870
                                };
1871
                            }
14✔
1872
                            if let Some(e) = rhs.div_opt(l_rhs, true) {
14✔
1873
                                return match l_lhs.mul_opt(&e, true) {
×
1874
                                    Some(ee) => Some(ee),
×
1875
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1876
                                };
1877
                            }
14✔
1878
                        }
6✔
1879
                        None
2,154✔
1880
                    } else {
1881
                        match rhs {
46,508✔
1882
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
29,784✔
1883
                                SymbolExpr::Value(lv) => match op {
9,994✔
1884
                                    BinaryOp::Mul => Some(_mul(
9,590✔
1885
                                        SymbolExpr::Value(lv * v),
9,590✔
1886
                                        l_rhs.as_ref().clone(),
9,590✔
1887
                                    )),
9,590✔
1888
                                    BinaryOp::Div => Some(_div(
×
1889
                                        SymbolExpr::Value(lv * v),
×
1890
                                        l_rhs.as_ref().clone(),
×
1891
                                    )),
×
1892
                                    _ => None,
404✔
1893
                                },
1894
                                _ => match l_rhs.as_ref() {
19,790✔
1895
                                    SymbolExpr::Value(rv) => match op {
288✔
1896
                                        BinaryOp::Mul => Some(_mul(
×
1897
                                            SymbolExpr::Value(rv * v),
×
1898
                                            l_lhs.as_ref().clone(),
×
1899
                                        )),
×
1900
                                        BinaryOp::Div => Some(_mul(
×
1901
                                            SymbolExpr::Value(v / rv),
×
1902
                                            l_lhs.as_ref().clone(),
×
1903
                                        )),
×
1904
                                        _ => None,
288✔
1905
                                    },
1906
                                    _ => None,
19,502✔
1907
                                },
1908
                            },
1909
                            SymbolExpr::Binary {
1910
                                op: rop,
12,252✔
1911
                                lhs: r_lhs,
12,252✔
1912
                                rhs: r_rhs,
12,252✔
1913
                            } => match (op, rop) {
12,252✔
1914
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1915
                                    l_lhs.as_ref(),
1,520✔
1916
                                    l_rhs.as_ref(),
1,520✔
1917
                                    r_lhs.as_ref(),
1,520✔
1918
                                    r_rhs.as_ref(),
1,520✔
1919
                                ) {
1920
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
1,520✔
1921
                                        Some(_mul(
1,520✔
1922
                                            SymbolExpr::Value(lv * rv),
1,520✔
1923
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
1,520✔
1924
                                        ))
1,520✔
1925
                                    }
1926
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1927
                                        Some(_mul(
×
1928
                                            SymbolExpr::Value(lv * rv),
×
1929
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1930
                                        ))
×
1931
                                    }
1932
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1933
                                        Some(_mul(
×
1934
                                            SymbolExpr::Value(lv * rv),
×
1935
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1936
                                        ))
×
1937
                                    }
1938
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1939
                                        Some(_mul(
×
1940
                                            SymbolExpr::Value(lv * rv),
×
1941
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1942
                                        ))
×
1943
                                    }
1944
                                    (_, _, _, _) => None,
×
1945
                                },
1946
                                (BinaryOp::Mul, BinaryOp::Div) => match (
1947
                                    l_lhs.as_ref(),
×
1948
                                    l_rhs.as_ref(),
×
1949
                                    r_lhs.as_ref(),
×
1950
                                    r_rhs.as_ref(),
×
1951
                                ) {
1952
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1953
                                        Some(_mul(
×
1954
                                            SymbolExpr::Value(lv * rv),
×
1955
                                            _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1956
                                        ))
×
1957
                                    }
1958
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1959
                                        Some(_mul(
×
1960
                                            SymbolExpr::Value(lv / rv),
×
1961
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1962
                                        ))
×
1963
                                    }
1964
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1965
                                        Some(_mul(
×
1966
                                            SymbolExpr::Value(lv * rv),
×
1967
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1968
                                        ))
×
1969
                                    }
1970
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1971
                                        Some(_mul(
×
1972
                                            SymbolExpr::Value(lv / rv),
×
1973
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1974
                                        ))
×
1975
                                    }
1976
                                    (_, _, _, _) => None,
×
1977
                                },
1978
                                (BinaryOp::Div, BinaryOp::Mul) => match (
1979
                                    l_lhs.as_ref(),
×
1980
                                    l_rhs.as_ref(),
×
1981
                                    r_lhs.as_ref(),
×
1982
                                    r_rhs.as_ref(),
×
1983
                                ) {
1984
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1985
                                        Some(_mul(
×
1986
                                            SymbolExpr::Value(lv * rv),
×
1987
                                            _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1988
                                        ))
×
1989
                                    }
1990
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1991
                                        Some(_mul(
×
1992
                                            SymbolExpr::Value(lv * rv),
×
1993
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1994
                                        ))
×
1995
                                    }
1996
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1997
                                        Some(_mul(
×
1998
                                            SymbolExpr::Value(rv / lv),
×
1999
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2000
                                        ))
×
2001
                                    }
2002
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
2003
                                        Some(_mul(
×
2004
                                            SymbolExpr::Value(rv / lv),
×
2005
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
2006
                                        ))
×
2007
                                    }
2008
                                    (_, _, _, _) => None,
×
2009
                                },
2010
                                (BinaryOp::Div, BinaryOp::Div) => match (
2011
                                    l_lhs.as_ref(),
2✔
2012
                                    l_rhs.as_ref(),
2✔
2013
                                    r_lhs.as_ref(),
2✔
2014
                                    r_rhs.as_ref(),
2✔
2015
                                ) {
2016
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
2017
                                        Some(_div(
×
2018
                                            SymbolExpr::Value(lv * rv),
×
2019
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2020
                                        ))
×
2021
                                    }
2022
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
2023
                                        Some(_mul(
×
2024
                                            SymbolExpr::Value(lv / rv),
×
2025
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2026
                                        ))
×
2027
                                    }
2028
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
2029
                                        Some(_mul(
×
2030
                                            SymbolExpr::Value(rv / lv),
×
2031
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2032
                                        ))
×
2033
                                    }
2034
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2✔
2035
                                        Some(_div(
2✔
2036
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
2✔
2037
                                            SymbolExpr::Value(lv * rv),
2✔
2038
                                        ))
2✔
2039
                                    }
2040
                                    (_, _, _, _) => None,
×
2041
                                },
2042
                                (_, _) => None,
10,730✔
2043
                            },
2044
                            _ => None,
4,472✔
2045
                        }
2046
                    }
2047
                }
2048
            }
2049
        }
2050
    }
2,640,774✔
2051
    /// expand with optimization for mul operation
2052
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
231,734✔
2053
        if let SymbolExpr::Binary {
2054
            op: rop,
18,712✔
2055
            lhs: r_lhs,
18,712✔
2056
            rhs: r_rhs,
18,712✔
2057
        } = rhs
231,734✔
2058
        {
2059
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
18,712✔
2060
                let el = match self.mul_expand(r_lhs) {
2,048✔
2061
                    Some(e) => e,
1,568✔
2062
                    None => match self.mul_opt(r_lhs, true) {
480✔
2063
                        Some(e) => e,
218✔
2064
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
262✔
2065
                    },
2066
                };
2067
                let er = match self.mul_expand(r_rhs) {
2,048✔
2068
                    Some(e) => e,
1,146✔
2069
                    None => match self.mul_opt(r_rhs, true) {
902✔
2070
                        Some(e) => e,
432✔
2071
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
470✔
2072
                    },
2073
                };
2074
                return match &rop {
2,048✔
2075
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
994✔
2076
                        Some(e) => Some(e),
52✔
2077
                        None => Some(_sub(el, er)),
942✔
2078
                    },
2079
                    _ => match el.add_opt(&er, true) {
1,054✔
2080
                        Some(e) => Some(e),
52✔
2081
                        None => Some(_add(el, er)),
1,002✔
2082
                    },
2083
                };
2084
            }
16,664✔
2085
            if let BinaryOp::Mul = &rop {
16,664✔
2086
                return match self.mul_expand(r_lhs) {
16,574✔
2087
                    Some(e) => match e.mul_expand(r_rhs) {
1,304✔
2088
                        Some(ee) => Some(ee),
1,274✔
2089
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
30✔
2090
                    },
2091
                    None => self
15,270✔
2092
                        .mul_expand(r_rhs)
15,270✔
2093
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
15,270✔
2094
                };
2095
            }
90✔
2096
            if let BinaryOp::Div = &rop {
90✔
2097
                return match self.mul_expand(r_lhs) {
×
2098
                    Some(e) => match e.mul_expand(r_rhs) {
×
2099
                        Some(ee) => Some(ee),
×
2100
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2101
                    },
2102
                    None => self
×
2103
                        .div_expand(r_rhs)
×
2104
                        .map(|e| _div(e, r_lhs.as_ref().clone())),
×
2105
                };
2106
            }
90✔
2107
        }
213,022✔
2108
        if let SymbolExpr::Unary {
2109
            op: UnaryOp::Neg,
2110
            expr: rexpr,
1,530✔
2111
        } = rhs
2,410✔
2112
        {
2113
            return match self.mul_expand(rexpr) {
1,530✔
2114
                Some(e) => match e.neg_opt() {
380✔
2115
                    Some(ee) => Some(ee),
380✔
2116
                    None => Some(_neg(e)),
×
2117
                },
2118
                None => match self.mul_opt(rexpr, true) {
1,150✔
2119
                    Some(e) => match e.neg_opt() {
82✔
2120
                        Some(ee) => Some(ee),
42✔
2121
                        None => Some(_neg(e)),
40✔
2122
                    },
2123
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
1,068✔
2124
                },
2125
            };
2126
        }
211,582✔
2127

2128
        match self {
1,172✔
2129
            SymbolExpr::Unary {
2130
                op: UnaryOp::Neg,
2131
                expr,
1,172✔
2132
            } => match expr.mul_expand(rhs) {
1,172✔
2133
                Some(e) => match e.neg_opt() {
×
2134
                    Some(ee) => Some(ee),
×
2135
                    None => Some(_neg(e)),
×
2136
                },
2137
                None => match expr.mul_opt(rhs, true) {
1,172✔
2138
                    Some(e) => match e.neg_opt() {
710✔
2139
                        Some(ee) => Some(ee),
398✔
2140
                        None => Some(_neg(e)),
312✔
2141
                    },
2142
                    None => None,
462✔
2143
                },
2144
            },
2145
            SymbolExpr::Binary {
2146
                op,
43,192✔
2147
                lhs: l_lhs,
43,192✔
2148
                rhs: l_rhs,
43,192✔
2149
            } => match &op {
43,192✔
2150
                BinaryOp::Add | BinaryOp::Sub => {
2151
                    let l = match l_lhs.mul_expand(rhs) {
5,114✔
2152
                        Some(e) => e,
1,712✔
2153
                        None => match l_lhs.mul_opt(rhs, true) {
3,402✔
2154
                            Some(e) => e,
2,230✔
2155
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
1,172✔
2156
                        },
2157
                    };
2158
                    let r = match l_rhs.mul_expand(rhs) {
5,114✔
2159
                        Some(e) => e,
120✔
2160
                        None => match l_rhs.mul_opt(rhs, true) {
4,994✔
2161
                            Some(e) => e,
3,166✔
2162
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
1,828✔
2163
                        },
2164
                    };
2165
                    match &op {
5,114✔
2166
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
2,248✔
2167
                            Some(e) => Some(e),
308✔
2168
                            None => Some(_sub(l, r)),
1,940✔
2169
                        },
2170
                        _ => match l.add_opt(&r, true) {
2,866✔
2171
                            Some(e) => Some(e),
556✔
2172
                            None => Some(_add(l, r)),
2,310✔
2173
                        },
2174
                    }
2175
                }
2176
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
38,040✔
2177
                    Some(e) => match e.mul_expand(l_rhs) {
44✔
2178
                        Some(ee) => Some(ee),
44✔
2179
                        None => match e.mul_opt(l_rhs, true) {
×
2180
                            Some(ee) => Some(ee),
×
2181
                            None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2182
                        },
2183
                    },
2184
                    None => match l_rhs.mul_expand(rhs) {
37,996✔
2185
                        Some(e) => match l_lhs.mul_expand(&e) {
24✔
2186
                            Some(ee) => Some(ee),
24✔
2187
                            None => match l_lhs.mul_opt(&e, true) {
×
2188
                                Some(ee) => Some(ee),
×
2189
                                None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2190
                            },
2191
                        },
2192
                        None => None,
37,972✔
2193
                    },
2194
                },
2195
                BinaryOp::Div => match l_lhs.div_expand(rhs) {
38✔
2196
                    Some(e) => Some(_div(e, l_rhs.as_ref().clone())),
×
2197
                    None => l_rhs
38✔
2198
                        .div_expand(rhs)
38✔
2199
                        .map(|e| _div(l_lhs.as_ref().clone(), e)),
38✔
2200
                },
2201
                _ => None,
×
2202
            },
2203
            _ => None,
167,218✔
2204
        }
2205
    }
231,734✔
2206

2207
    /// Div with heuristic optimization
2208
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
136,194✔
2209
        if rhs.is_zero() {
136,194✔
2210
            // return inf to detect divide by zero without panic
2211
            Some(SymbolExpr::Value(Value::Real(f64::INFINITY)))
1,108✔
2212
        } else if rhs.is_one() {
135,086✔
2213
            Some(self.clone())
548✔
2214
        } else if rhs.is_minus_one() {
134,538✔
2215
            match self.neg_opt() {
392✔
2216
                Some(e) => Some(e),
100✔
2217
                None => Some(_neg(self.clone())),
292✔
2218
            }
2219
        } else if *self == *rhs {
134,146✔
2220
            let l_is_int = self.is_int().unwrap_or_default();
2,106✔
2221
            let r_is_int = rhs.is_int().unwrap_or_default();
2,106✔
2222
            if l_is_int || r_is_int {
2,106✔
2223
                Some(SymbolExpr::Value(Value::Int(1)))
850✔
2224
            } else {
2225
                Some(SymbolExpr::Value(Value::Real(1.0)))
1,256✔
2226
            }
2227
        } else {
2228
            if let SymbolExpr::Value(Value::Real(r)) = rhs {
127,154✔
2229
                let t = 1.0 / r;
728✔
2230
                if &(1.0 / t) == r {
728✔
2231
                    if recursive {
722✔
2232
                        return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
2233
                    } else {
2234
                        return Some(&SymbolExpr::Value(Value::Real(t)) * self);
722✔
2235
                    }
2236
                }
6✔
2237
            }
131,312✔
2238

2239
            match self {
131,318✔
2240
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
71,308✔
2241
                SymbolExpr::Symbol(_) => None,
15,640✔
2242
                SymbolExpr::Unary { op, expr } => match op {
37,262✔
2243
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
37,218✔
2244
                        Some(e) => match e.neg_opt() {
33,192✔
2245
                            Some(ee) => Some(ee),
33,192✔
2246
                            None => Some(_neg(e)),
×
2247
                        },
2248
                        None => None,
4,026✔
2249
                    },
2250
                    UnaryOp::Abs => match rhs {
2✔
2251
                        SymbolExpr::Unary {
2252
                            op: UnaryOp::Abs,
2253
                            expr: rexpr,
2✔
2254
                        } => match expr.div_opt(rexpr, recursive) {
2✔
2255
                            Some(e) => Some(SymbolExpr::Unary {
×
2256
                                op: UnaryOp::Abs,
×
2257
                                expr: Box::new(e),
×
2258
                            }),
×
2259
                            None => Some(SymbolExpr::Unary {
2✔
2260
                                op: UnaryOp::Abs,
2✔
2261
                                expr: Box::new(_div(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
2262
                            }),
2✔
2263
                        },
2264
                        _ => None,
×
2265
                    },
2266
                    _ => None,
42✔
2267
                },
2268
                SymbolExpr::Binary {
2269
                    op,
7,108✔
2270
                    lhs: l_lhs,
7,108✔
2271
                    rhs: l_rhs,
7,108✔
2272
                } => {
7,108✔
2273
                    if recursive {
7,108✔
2274
                        if let SymbolExpr::Binary {
2275
                            op: rop,
×
2276
                            lhs: r_lhs,
×
2277
                            rhs: r_rhs,
×
2278
                        } = rhs
398✔
2279
                        {
2280
                            if let BinaryOp::Mul = &rop {
×
2281
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2282
                                    return match e.div_opt(r_rhs, true) {
×
2283
                                        Some(ee) => Some(ee),
×
2284
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
2285
                                    };
2286
                                }
×
2287
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
2288
                                    return match e.div_opt(r_lhs, true) {
×
2289
                                        Some(ee) => Some(ee),
×
2290
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2291
                                    };
2292
                                }
×
2293
                            }
×
2294
                            if let BinaryOp::Div = &rop {
×
2295
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
2296
                                    return match e.div_opt(r_lhs, true) {
×
2297
                                        Some(ee) => Some(ee),
×
2298
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2299
                                    };
2300
                                }
×
2301
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2302
                                    return match e.mul_opt(r_rhs, true) {
×
2303
                                        Some(ee) => Some(ee),
×
2304
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2305
                                    };
2306
                                }
×
2307
                            }
×
2308
                        }
398✔
2309

2310
                        if let BinaryOp::Mul = &op {
398✔
2311
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2312
                                return match e.mul_opt(l_rhs, true) {
×
2313
                                    Some(ee) => Some(ee),
×
2314
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2315
                                };
2316
                            }
×
2317
                            if let Some(e) = l_rhs.div_opt(rhs, true) {
×
2318
                                return match l_lhs.mul_opt(&e, true) {
×
2319
                                    Some(ee) => Some(ee),
×
2320
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2321
                                };
2322
                            }
×
2323
                        } else if let BinaryOp::Div = &op {
398✔
2324
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
94✔
2325
                                return match l_lhs.div_opt(&e, true) {
94✔
2326
                                    Some(ee) => Some(ee),
×
2327
                                    None => Some(_div(l_lhs.as_ref().clone(), e)),
94✔
2328
                                };
2329
                            }
×
2330
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2331
                                return match e.div_opt(l_rhs, true) {
×
2332
                                    Some(ee) => Some(ee),
×
2333
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
2334
                                };
2335
                            }
×
2336
                        }
304✔
2337
                        None
304✔
2338
                    } else {
2339
                        match rhs {
6,710✔
2340
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
5,802✔
2341
                                SymbolExpr::Value(lv) => match op {
1,244✔
2342
                                    BinaryOp::Mul => Some(_mul(
224✔
2343
                                        SymbolExpr::Value(lv / v),
224✔
2344
                                        l_rhs.as_ref().clone(),
224✔
2345
                                    )),
224✔
2346
                                    BinaryOp::Div => Some(_div(
×
2347
                                        SymbolExpr::Value(lv / v),
×
2348
                                        l_rhs.as_ref().clone(),
×
2349
                                    )),
×
2350
                                    _ => None,
1,020✔
2351
                                },
2352
                                _ => match l_rhs.as_ref() {
4,558✔
2353
                                    SymbolExpr::Value(rv) => match op {
2,800✔
2354
                                        BinaryOp::Mul => Some(_mul(
8✔
2355
                                            SymbolExpr::Value(rv / v),
8✔
2356
                                            l_lhs.as_ref().clone(),
8✔
2357
                                        )),
8✔
2358
                                        BinaryOp::Div => Some(_mul(
1,998✔
2359
                                            SymbolExpr::Value(v * rv).rcp(),
1,998✔
2360
                                            l_lhs.as_ref().clone(),
1,998✔
2361
                                        )),
1,998✔
2362
                                        _ => None,
794✔
2363
                                    },
2364
                                    _ => None,
1,758✔
2365
                                },
2366
                            },
2367
                            SymbolExpr::Binary {
2368
                                op: rop,
320✔
2369
                                lhs: r_lhs,
320✔
2370
                                rhs: r_rhs,
320✔
2371
                            } => match (l_lhs.as_ref(), r_lhs.as_ref()) {
320✔
2372
                                (SymbolExpr::Value(lv), SymbolExpr::Value(rv)) => match (op, rop) {
×
2373
                                    (BinaryOp::Mul, BinaryOp::Mul) => Some(_mul(
×
2374
                                        SymbolExpr::Value(lv / rv),
×
2375
                                        _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2376
                                    )),
×
2377
                                    (BinaryOp::Mul, BinaryOp::Div) => Some(_mul(
×
2378
                                        SymbolExpr::Value(lv / rv),
×
2379
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2380
                                    )),
×
2381
                                    (BinaryOp::Div, BinaryOp::Mul) => Some(_div(
×
2382
                                        SymbolExpr::Value(lv / rv),
×
2383
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2384
                                    )),
×
2385
                                    (BinaryOp::Div, BinaryOp::Div) => Some(_div(
×
2386
                                        SymbolExpr::Value(lv / rv),
×
2387
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2388
                                    )),
×
2389
                                    (_, _) => None,
×
2390
                                },
2391
                                (_, _) => None,
320✔
2392
                            },
2393
                            _ => None,
588✔
2394
                        }
2395
                    }
2396
                }
2397
            }
2398
        }
2399
    }
136,194✔
2400

2401
    /// expand with optimization for div operation
2402
    fn div_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
7,118✔
2403
        match self {
7,118✔
2404
            SymbolExpr::Unary { op, expr } => match op {
1,240✔
2405
                UnaryOp::Neg => match expr.div_expand(rhs) {
1,112✔
2406
                    Some(e) => match e.neg_opt() {
4✔
2407
                        Some(ee) => Some(ee),
4✔
2408
                        None => Some(_neg(e)),
×
2409
                    },
2410
                    None => match expr.div_opt(rhs, true) {
1,108✔
2411
                        Some(e) => match e.neg_opt() {
×
2412
                            Some(ee) => Some(ee),
×
2413
                            None => Some(_neg(e)),
×
2414
                        },
2415
                        None => None,
1,108✔
2416
                    },
2417
                },
2418
                _ => None,
128✔
2419
            },
2420
            SymbolExpr::Binary {
2421
                op,
616✔
2422
                lhs: l_lhs,
616✔
2423
                rhs: l_rhs,
616✔
2424
            } => match &op {
616✔
2425
                BinaryOp::Add | BinaryOp::Sub => {
2426
                    let l = match l_lhs.div_expand(rhs) {
506✔
2427
                        Some(e) => e,
200✔
2428
                        None => match l_lhs.div_opt(rhs, true) {
306✔
2429
                            Some(e) => e,
×
2430
                            None => _div(l_lhs.as_ref().clone(), rhs.clone()),
306✔
2431
                        },
2432
                    };
2433
                    let r = match l_rhs.div_expand(rhs) {
506✔
2434
                        Some(e) => e,
×
2435
                        None => match l_rhs.div_opt(rhs, true) {
506✔
2436
                            Some(e) => e,
94✔
2437
                            None => _div(l_rhs.as_ref().clone(), rhs.clone()),
412✔
2438
                        },
2439
                    };
2440
                    match &op {
506✔
2441
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
200✔
2442
                            Some(e) => Some(e),
4✔
2443
                            None => Some(_sub(l, r)),
196✔
2444
                        },
2445
                        _ => match l.add_opt(&r, true) {
306✔
2446
                            Some(e) => Some(e),
4✔
2447
                            None => Some(_add(l, r)),
302✔
2448
                        },
2449
                    }
2450
                }
2451
                _ => None,
110✔
2452
            },
2453
            _ => self.div_opt(rhs, true),
5,262✔
2454
        }
2455
    }
7,118✔
2456

2457
    /// pow with heuristic optimization
2458
    fn pow_opt(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
48✔
2459
        if self.is_zero() || rhs.is_one() {
48✔
2460
            return Some(self.clone());
48✔
2461
        } else if rhs.is_zero() {
×
2462
            return Some(SymbolExpr::Value(Value::Int(1)));
×
2463
        }
×
2464
        None
×
2465
    }
48✔
2466

2467
    /// optimization for neg
2468
    fn neg_opt(&self) -> Option<SymbolExpr> {
409,922✔
2469
        match self {
18,788✔
2470
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
115,494✔
2471
            SymbolExpr::Unary {
2472
                op: UnaryOp::Neg,
2473
                expr,
16,936✔
2474
            } => Some(expr.as_ref().clone()),
16,936✔
2475
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
135,014✔
2476
                BinaryOp::Add => match lhs.neg_opt() {
6,210✔
2477
                    Some(ln) => match rhs.neg_opt() {
4,536✔
2478
                        Some(rn) => Some(_add(ln, rn)),
1,930✔
2479
                        None => Some(_sub(ln, rhs.as_ref().clone())),
2,606✔
2480
                    },
2481
                    None => match rhs.neg_opt() {
1,674✔
2482
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
312✔
2483
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
1,362✔
2484
                    },
2485
                },
2486
                BinaryOp::Sub => match lhs.neg_opt() {
4,046✔
2487
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
3,212✔
2488
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
834✔
2489
                },
2490
                BinaryOp::Mul => match lhs.neg_opt() {
120,900✔
2491
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
60,944✔
2492
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
59,956✔
2493
                },
2494
                BinaryOp::Div => match lhs.neg_opt() {
2,794✔
2495
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
1,688✔
2496
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
1,106✔
2497
                },
2498
                _ => None,
1,064✔
2499
            },
2500
            _ => None,
142,478✔
2501
        }
2502
    }
409,922✔
2503

2504
    /// optimize the equation
2505
    pub fn optimize(&self) -> SymbolExpr {
326,550✔
2506
        match self {
326,550✔
2507
            SymbolExpr::Value(_) => self.clone(),
85,972✔
2508
            SymbolExpr::Symbol(_) => self.clone(),
120,020✔
2509
            SymbolExpr::Unary { op, expr } => {
616✔
2510
                let opt = expr.optimize();
616✔
2511
                match op {
616✔
2512
                    UnaryOp::Neg => match opt.neg_opt() {
616✔
2513
                        Some(e) => e,
×
2514
                        None => _neg(opt),
616✔
2515
                    },
2516
                    _ => SymbolExpr::Unary {
×
2517
                        op: op.clone(),
×
2518
                        expr: Box::new(opt),
×
2519
                    },
×
2520
                }
2521
            }
2522
            SymbolExpr::Binary { op, lhs, rhs } => {
119,942✔
2523
                let opt_lhs = lhs.optimize();
119,942✔
2524
                let opt_rhs = rhs.optimize();
119,942✔
2525
                match op {
119,942✔
2526
                    BinaryOp::Add => match opt_lhs.add_opt(&opt_rhs, true) {
34,010✔
2527
                        Some(e) => e,
×
2528
                        None => _add(opt_lhs, opt_rhs),
34,010✔
2529
                    },
2530
                    BinaryOp::Sub => match opt_lhs.sub_opt(&opt_rhs, true) {
33,942✔
2531
                        Some(e) => e,
33,788✔
2532
                        None => _sub(opt_lhs, opt_rhs),
154✔
2533
                    },
2534
                    BinaryOp::Mul => match opt_lhs.mul_opt(&opt_rhs, true) {
17,052✔
2535
                        Some(e) => e,
16,880✔
2536
                        None => _mul(opt_lhs, opt_rhs),
172✔
2537
                    },
2538
                    BinaryOp::Div => match opt_lhs.div_opt(&opt_rhs, true) {
1,178✔
2539
                        Some(e) => e,
×
2540
                        None => _div(opt_lhs, opt_rhs),
1,178✔
2541
                    },
2542
                    BinaryOp::Pow => _pow(opt_lhs, opt_rhs),
33,760✔
2543
                }
2544
            }
2545
        }
2546
    }
326,550✔
2547

2548
    // convert sympy compatible format
2549
    pub fn sympify(&self) -> SymbolExpr {
×
2550
        match self {
×
2551
            SymbolExpr::Symbol { .. } => self.clone(),
×
2552
            SymbolExpr::Value(e) => e.sympify(),
×
2553
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
×
2554
                op: op.clone(),
×
2555
                expr: Box::new(expr.sympify()),
×
2556
            },
×
2557
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
×
2558
                op: op.clone(),
×
2559
                lhs: Box::new(lhs.sympify()),
×
2560
                rhs: Box::new(rhs.sympify()),
×
2561
            },
×
2562
        }
2563
    }
×
2564
}
2565

2566
impl Add for SymbolExpr {
2567
    type Output = SymbolExpr;
2568
    fn add(self, rhs: Self) -> SymbolExpr {
80,682✔
2569
        match self.add_opt(&rhs, false) {
80,682✔
2570
            Some(e) => e,
76,608✔
2571
            None => _add(self, rhs),
4,074✔
2572
        }
2573
    }
80,682✔
2574
}
2575

2576
impl Add for &SymbolExpr {
2577
    type Output = SymbolExpr;
2578
    fn add(self, rhs: Self) -> SymbolExpr {
2,385,590✔
2579
        match self.add_opt(rhs, false) {
2,385,590✔
2580
            Some(e) => e,
2,312,132✔
2581
            None => _add(self.clone(), rhs.clone()),
73,458✔
2582
        }
2583
    }
2,385,590✔
2584
}
2585

2586
impl Sub for SymbolExpr {
2587
    type Output = SymbolExpr;
2588
    fn sub(self, rhs: Self) -> SymbolExpr {
62,550✔
2589
        match self.sub_opt(&rhs, false) {
62,550✔
2590
            Some(e) => e,
59,714✔
2591
            None => _sub(self, rhs),
2,836✔
2592
        }
2593
    }
62,550✔
2594
}
2595

2596
impl Sub for &SymbolExpr {
2597
    type Output = SymbolExpr;
2598
    fn sub(self, rhs: Self) -> SymbolExpr {
19,634✔
2599
        match self.sub_opt(rhs, false) {
19,634✔
2600
            Some(e) => e,
13,986✔
2601
            None => _sub(self.clone(), rhs.clone()),
5,648✔
2602
        }
2603
    }
19,634✔
2604
}
2605

2606
impl Mul for SymbolExpr {
2607
    type Output = SymbolExpr;
2608
    fn mul(self, rhs: Self) -> SymbolExpr {
176,862✔
2609
        match self.mul_opt(&rhs, false) {
176,862✔
2610
            Some(e) => e,
173,472✔
2611
            None => _mul(self, rhs),
3,390✔
2612
        }
2613
    }
176,862✔
2614
}
2615

2616
impl Mul for &SymbolExpr {
2617
    type Output = SymbolExpr;
2618
    fn mul(self, rhs: Self) -> SymbolExpr {
2,410,624✔
2619
        match self.mul_opt(rhs, false) {
2,410,624✔
2620
            Some(e) => e,
2,364,160✔
2621
            None => _mul(self.clone(), rhs.clone()),
46,464✔
2622
        }
2623
    }
2,410,624✔
2624
}
2625

2626
impl Div for SymbolExpr {
2627
    type Output = SymbolExpr;
2628
    fn div(self, rhs: Self) -> SymbolExpr {
82,754✔
2629
        match self.div_opt(&rhs, false) {
82,754✔
2630
            Some(e) => e,
73,916✔
2631
            None => _div(self, rhs),
8,838✔
2632
        }
2633
    }
82,754✔
2634
}
2635

2636
impl Div for &SymbolExpr {
2637
    type Output = SymbolExpr;
2638
    fn div(self, rhs: Self) -> SymbolExpr {
7,752✔
2639
        match self.div_opt(rhs, false) {
7,752✔
2640
            Some(e) => e,
1,800✔
2641
            None => _div(self.clone(), rhs.clone()),
5,952✔
2642
        }
2643
    }
7,752✔
2644
}
2645

2646
impl Neg for SymbolExpr {
2647
    type Output = SymbolExpr;
2648
    fn neg(self) -> SymbolExpr {
×
2649
        match self.neg_opt() {
×
2650
            Some(e) => e,
×
2651
            None => _neg(self),
×
2652
        }
2653
    }
×
2654
}
2655

2656
impl Neg for &SymbolExpr {
2657
    type Output = SymbolExpr;
2658
    fn neg(self) -> SymbolExpr {
4✔
2659
        match self.neg_opt() {
4✔
2660
            Some(e) => e,
2✔
2661
            None => _neg(self.clone()),
2✔
2662
        }
2663
    }
4✔
2664
}
2665

2666
impl PartialEq for SymbolExpr {
2667
    fn eq(&self, rexpr: &Self) -> bool {
138,312✔
2668
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
138,312✔
2669
            return l == r;
103,288✔
2670
        }
35,024✔
2671

35,024✔
2672
        match (self, rexpr) {
35,024✔
2673
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
2,934✔
2674
            (SymbolExpr::Value(l), SymbolExpr::Value(r)) => l == r,
×
2675
            (
2676
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2677
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2678
            ) => {
2679
                let ex_lhs = self.expand();
2,388✔
2680
                let ex_rhs = rexpr.expand();
2,388✔
2681
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,388✔
2682
                    Some(e) => e.is_zero(),
2,174✔
2683
                    None => {
2684
                        let t = &ex_lhs - &ex_rhs;
214✔
2685
                        t.is_zero()
214✔
2686
                    }
2687
                }
2688
            }
2689
            (SymbolExpr::Binary { .. }, _) => {
2690
                let ex_lhs = self.expand();
6,748✔
2691
                match ex_lhs.sub_opt(rexpr, true) {
6,748✔
2692
                    Some(e) => e.is_zero(),
6,682✔
2693
                    None => {
2694
                        let t = &ex_lhs - rexpr;
66✔
2695
                        t.is_zero()
66✔
2696
                    }
2697
                }
2698
            }
2699
            (_, SymbolExpr::Binary { .. }) => {
2700
                let ex_rhs = rexpr.expand();
1,582✔
2701
                match self.sub_opt(&ex_rhs, true) {
1,582✔
2702
                    Some(e) => e.is_zero(),
316✔
2703
                    None => {
2704
                        let t = self - &ex_rhs;
1,266✔
2705
                        t.is_zero()
1,266✔
2706
                    }
2707
                }
2708
            }
2709
            (_, _) => false,
21,372✔
2710
        }
2711
    }
138,312✔
2712
}
2713

2714
impl PartialEq<f64> for SymbolExpr {
2715
    fn eq(&self, r: &f64) -> bool {
×
2716
        match self.eval(true) {
×
2717
            Some(v) => v == *r,
×
2718
            None => false,
×
2719
        }
2720
    }
×
2721
}
2722

2723
impl PartialEq<Complex64> for SymbolExpr {
2724
    fn eq(&self, r: &Complex64) -> bool {
×
2725
        match self.eval(true) {
×
2726
            Some(v) => v == *r,
×
2727
            None => false,
×
2728
        }
2729
    }
×
2730
}
2731

2732
// comparison rules for sorting equation
2733
impl PartialOrd for SymbolExpr {
2734
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
100,208✔
2735
        match self {
100,208✔
2736
            SymbolExpr::Value(l) => match rhs {
182✔
2737
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2738
                _ => Some(Ordering::Less),
170✔
2739
            },
2740
            SymbolExpr::Symbol(l) => match rhs {
7,436✔
2741
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2742
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
4,794✔
2743
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2744
                _ => Some(Ordering::Less),
2,642✔
2745
            },
2746
            SymbolExpr::Unary { op: _, expr } => match rhs {
14,696✔
2747
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2748
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,654✔
2749
                _ => (expr.as_ref()).partial_cmp(rhs),
13,040✔
2750
            },
2751
            SymbolExpr::Binary {
2752
                op,
77,894✔
2753
                lhs: ll,
77,894✔
2754
                rhs: lr,
77,894✔
2755
            } => match rhs {
77,894✔
2756
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
7,404✔
2757
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
7,396✔
2758
                    _ => Some(Ordering::Equal),
8✔
2759
                },
2760
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
134✔
2761
                SymbolExpr::Binary {
2762
                    op: _,
2763
                    lhs: rl,
70,356✔
2764
                    rhs: rr,
70,356✔
2765
                } => {
2766
                    let ls = match ll.as_ref() {
70,356✔
2767
                        SymbolExpr::Value(_) => lr.to_string(),
13,908✔
2768
                        _ => self.to_string(),
56,448✔
2769
                    };
2770
                    let rs = match rl.as_ref() {
70,356✔
2771
                        SymbolExpr::Value(_) => rr.to_string(),
16,770✔
2772
                        _ => rhs.to_string(),
53,586✔
2773
                    };
2774
                    if rs > ls && rs.len() > ls.len() {
70,356✔
2775
                        Some(Ordering::Less)
8,876✔
2776
                    } else if rs < ls && rs.len() < ls.len() {
61,480✔
2777
                        Some(Ordering::Greater)
830✔
2778
                    } else {
2779
                        Some(Ordering::Equal)
60,650✔
2780
                    }
2781
                }
2782
            },
2783
        }
2784
    }
100,208✔
2785
}
2786

2787
impl From<&str> for SymbolExpr {
2788
    fn from(v: &str) -> Self {
×
2789
        SymbolExpr::Symbol(Box::new(v.to_string()))
×
2790
    }
×
2791
}
2792

2793
impl fmt::Display for Value {
2794
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159,912✔
2795
        write!(
159,912✔
2796
            f,
159,912✔
2797
            "{}",
159,912✔
2798
            match self {
159,912✔
2799
                Value::Real(e) => e.to_string(),
48,170✔
2800
                Value::Int(e) => e.to_string(),
7,688✔
2801
                Value::Complex(e) => {
104,054✔
2802
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
104,054✔
2803
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
103,382✔
2804
                            0.to_string()
×
2805
                        } else {
2806
                            format!("{}i", e.im)
103,382✔
2807
                        }
2808
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
672✔
2809
                        e.re.to_string()
×
2810
                    } else {
2811
                        e.to_string()
672✔
2812
                    }
2813
                }
2814
            }
2815
        )
2816
    }
159,912✔
2817
}
2818

2819
// ===============================================================
2820
//  implementations for Value
2821
// ===============================================================
2822
impl Value {
2823
    pub fn as_real(&self) -> f64 {
34,836✔
2824
        match self {
34,836✔
2825
            Value::Real(e) => *e,
34,596✔
2826
            Value::Int(e) => *e as f64,
240✔
2827
            Value::Complex(e) => e.re,
×
2828
        }
2829
    }
34,836✔
2830

2831
    pub fn abs(&self) -> Value {
264✔
2832
        match self {
264✔
2833
            Value::Real(e) => Value::Real(e.abs()),
136✔
2834
            Value::Int(e) => Value::Int(e.abs()),
78✔
2835
            Value::Complex(e) => Value::Real((e.re * e.re + e.im * e.im).sqrt()),
50✔
2836
        }
2837
    }
264✔
2838

2839
    pub fn sin(&self) -> Value {
208✔
2840
        match self {
208✔
2841
            Value::Real(e) => Value::Real(e.sin()),
86✔
2842
            Value::Int(e) => Value::Real((*e as f64).sin()),
74✔
2843
            Value::Complex(e) => {
48✔
2844
                let t = Value::Complex(e.sin());
48✔
2845
                match t.opt_complex() {
48✔
2846
                    Some(v) => v,
×
2847
                    None => t,
48✔
2848
                }
2849
            }
2850
        }
2851
    }
208✔
2852
    pub fn asin(&self) -> Value {
54✔
2853
        match self {
54✔
2854
            Value::Real(e) => Value::Real(e.asin()),
48✔
2855
            Value::Int(e) => Value::Real((*e as f64).asin()),
6✔
2856
            Value::Complex(e) => {
×
2857
                let t = Value::Complex(e.asin());
×
2858
                match t.opt_complex() {
×
2859
                    Some(v) => v,
×
2860
                    None => t,
×
2861
                }
2862
            }
2863
        }
2864
    }
54✔
2865
    pub fn cos(&self) -> Value {
332✔
2866
        match self {
332✔
2867
            Value::Real(e) => Value::Real(e.cos()),
210✔
2868
            Value::Int(e) => Value::Real((*e as f64).cos()),
74✔
2869
            Value::Complex(e) => {
48✔
2870
                let t = Value::Complex(e.cos());
48✔
2871
                match t.opt_complex() {
48✔
2872
                    Some(v) => v,
×
2873
                    None => t,
48✔
2874
                }
2875
            }
2876
        }
2877
    }
332✔
2878
    pub fn acos(&self) -> Value {
52✔
2879
        match self {
52✔
2880
            Value::Real(e) => Value::Real(e.acos()),
48✔
2881
            Value::Int(e) => Value::Real((*e as f64).acos()),
4✔
2882
            Value::Complex(e) => {
×
2883
                let t = Value::Complex(e.acos());
×
2884
                match t.opt_complex() {
×
2885
                    Some(v) => v,
×
2886
                    None => t,
×
2887
                }
2888
            }
2889
        }
2890
    }
52✔
2891
    pub fn tan(&self) -> Value {
196✔
2892
        match self {
196✔
2893
            Value::Real(e) => Value::Real(e.tan()),
74✔
2894
            Value::Int(e) => Value::Real((*e as f64).tan()),
74✔
2895
            Value::Complex(e) => {
48✔
2896
                let t = Value::Complex(e.tan());
48✔
2897
                match t.opt_complex() {
48✔
2898
                    Some(v) => v,
×
2899
                    None => t,
48✔
2900
                }
2901
            }
2902
        }
2903
    }
196✔
2904
    pub fn atan(&self) -> Value {
54✔
2905
        match self {
54✔
2906
            Value::Real(e) => Value::Real(e.atan()),
48✔
2907
            Value::Int(e) => Value::Real((*e as f64).atan()),
6✔
2908
            Value::Complex(e) => {
×
2909
                let t = Value::Complex(e.atan());
×
2910
                match t.opt_complex() {
×
2911
                    Some(v) => v,
×
2912
                    None => t,
×
2913
                }
2914
            }
2915
        }
2916
    }
54✔
2917
    pub fn exp(&self) -> Value {
246✔
2918
        match self {
246✔
2919
            Value::Real(e) => Value::Real(e.exp()),
112✔
2920
            Value::Int(e) => Value::Real((*e as f64).exp()),
80✔
2921
            Value::Complex(e) => {
54✔
2922
                let t = Value::Complex(e.exp());
54✔
2923
                match t.opt_complex() {
54✔
2924
                    Some(v) => v,
×
2925
                    None => t,
54✔
2926
                }
2927
            }
2928
        }
2929
    }
246✔
2930
    pub fn log(&self) -> Value {
416✔
2931
        match self {
416✔
2932
            Value::Real(e) => {
228✔
2933
                if *e < 0.0 {
228✔
2934
                    Value::Complex(Complex64::from(e)).log()
48✔
2935
                } else {
2936
                    Value::Real(e.ln())
180✔
2937
                }
2938
            }
2939
            Value::Int(e) => Value::Real(*e as f64).log(),
92✔
2940
            Value::Complex(e) => {
96✔
2941
                let t = Value::Complex(e.ln());
96✔
2942
                match t.opt_complex() {
96✔
2943
                    Some(v) => v,
×
2944
                    None => t,
96✔
2945
                }
2946
            }
2947
        }
2948
    }
416✔
2949
    pub fn sqrt(&self) -> Value {
×
2950
        match self {
×
2951
            Value::Real(e) => {
×
2952
                if *e < 0.0 {
×
2953
                    Value::Complex(Complex64::from(e)).sqrt()
×
2954
                } else {
2955
                    Value::Real(e.sqrt())
×
2956
                }
2957
            }
2958
            Value::Int(e) => {
×
2959
                if *e < 0 {
×
2960
                    Value::Complex(Complex64::from(*e as f64)).pow(&Value::Real(0.5))
×
2961
                } else {
2962
                    let t = (*e as f64).sqrt();
×
2963
                    let d = t.floor() - t;
×
2964
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
×
2965
                        Value::Int(t as i64)
×
2966
                    } else {
2967
                        Value::Real(t)
×
2968
                    }
2969
                }
2970
            }
2971
            Value::Complex(e) => {
×
2972
                let t = Value::Complex(e.sqrt());
×
2973
                match t.opt_complex() {
×
2974
                    Some(v) => v,
×
2975
                    None => t,
×
2976
                }
2977
            }
2978
        }
2979
    }
×
2980
    pub fn pow(&self, p: &Value) -> Value {
15,916✔
2981
        match self {
15,916✔
2982
            Value::Real(e) => match p {
5,918✔
2983
                Value::Real(r) => {
5,604✔
2984
                    if *e < 0.0 && r.fract() != 0. {
5,604✔
2985
                        Value::Complex(Complex64::from(e)).pow(p)
2✔
2986
                    } else {
2987
                        Value::Real(e.powf(*r))
5,602✔
2988
                    }
2989
                }
2990
                Value::Int(i) => Value::Real(e.powf(*i as f64)),
92✔
2991
                Value::Complex(_) => Value::Complex(Complex64::from(e)).pow(p),
222✔
2992
            },
2993
            Value::Int(e) => match p {
4,858✔
2994
                Value::Real(r) => {
4,778✔
2995
                    if *e < 0 && r.fract() != 0. {
4,778✔
2996
                        Value::Complex(Complex64::from(*e as f64)).pow(p)
4✔
2997
                    } else {
2998
                        let t = (*e as f64).powf(*r);
4,774✔
2999
                        let d = t.floor() - t;
4,774✔
3000
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
4,774✔
3001
                            Value::Int(t as i64)
4,766✔
3002
                        } else {
3003
                            Value::Real(t)
8✔
3004
                        }
3005
                    }
3006
                }
3007
                Value::Int(r) => {
6✔
3008
                    if *r < 0 {
6✔
3009
                        Value::Real(*e as f64).pow(p)
2✔
3010
                    } else {
3011
                        Value::Int(e.pow(*r as u32))
4✔
3012
                    }
3013
                }
3014
                Value::Complex(_) => Value::Complex(Complex64::from(*e as f64)).pow(p),
74✔
3015
            },
3016
            Value::Complex(e) => {
5,140✔
3017
                let t = match p {
5,140✔
3018
                    Value::Real(r) => Value::Complex(e.powf(*r)),
4,340✔
3019
                    Value::Int(r) => Value::Complex(e.powf(*r as f64)),
72✔
3020
                    Value::Complex(r) => Value::Complex(e.powc(*r)),
728✔
3021
                };
3022
                match t.opt_complex() {
5,140✔
3023
                    Some(v) => v,
288✔
3024
                    None => t,
4,852✔
3025
                }
3026
            }
3027
        }
3028
    }
15,916✔
3029
    pub fn rcp(&self) -> Value {
1,998✔
3030
        match self {
1,998✔
3031
            Value::Real(e) => Value::Real(1.0 / e),
×
3032
            Value::Int(e) => {
1,998✔
3033
                let t = 1.0 / (*e as f64);
1,998✔
3034
                let d = t.floor() - t;
1,998✔
3035
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
1,998✔
3036
                    Value::Int(t as i64)
×
3037
                } else {
3038
                    Value::Real(t)
1,998✔
3039
                }
3040
            }
3041
            Value::Complex(e) => Value::Complex(1.0 / e),
×
3042
        }
3043
    }
1,998✔
3044
    pub fn sign(&self) -> Value {
6✔
3045
        match self {
6✔
3046
            Value::Real(e) => {
×
3047
                if *e > SYMEXPR_EPSILON {
×
3048
                    Value::Real(1.0)
×
3049
                } else if *e < -SYMEXPR_EPSILON {
×
3050
                    Value::Real(-1.0)
×
3051
                } else {
3052
                    Value::Real(0.0)
×
3053
                }
3054
            }
3055
            Value::Int(e) => {
6✔
3056
                if *e > 0 {
6✔
3057
                    Value::Int(1)
2✔
3058
                } else if *e < 0 {
4✔
3059
                    Value::Int(-1)
2✔
3060
                } else {
3061
                    Value::Int(0)
2✔
3062
                }
3063
            }
3064
            Value::Complex(_) => *self,
×
3065
        }
3066
    }
6✔
3067

3068
    pub fn is_zero(&self) -> bool {
5,643,028✔
3069
        match self {
5,643,028✔
3070
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,675,630✔
3071
            Value::Int(i) => *i == 0,
687,302✔
3072
            Value::Complex(c) => {
280,096✔
3073
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
280,096✔
3074
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
214,664✔
3075
            }
3076
        }
3077
    }
5,643,028✔
3078
    pub fn is_one(&self) -> bool {
526,714✔
3079
        match self {
526,714✔
3080
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
86,926✔
3081
            Value::Int(i) => *i == 1,
299,708✔
3082
            Value::Complex(c) => {
140,080✔
3083
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
140,080✔
3084
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,864✔
3085
            }
3086
        }
3087
    }
526,714✔
3088
    pub fn is_minus_one(&self) -> bool {
263,926✔
3089
        match self {
263,926✔
3090
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
39,788✔
3091
            Value::Int(i) => *i == -1,
135,946✔
3092
            Value::Complex(c) => {
88,192✔
3093
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
88,192✔
3094
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
3,486✔
3095
            }
3096
        }
3097
    }
263,926✔
3098

3099
    pub fn is_negative(&self) -> bool {
68,726✔
3100
        match self {
68,726✔
3101
            Value::Real(r) => *r < 0.0,
11,336✔
3102
            Value::Int(i) => *i < 0,
7,618✔
3103
            Value::Complex(c) => {
49,772✔
3104
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
49,772✔
3105
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
49,772✔
3106
            }
3107
        }
3108
    }
68,726✔
3109

3110
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
39,738✔
3111
        match rhs {
4,968✔
3112
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
14,146✔
3113
            SymbolExpr::Unary {
3114
                op: UnaryOp::Neg,
3115
                expr,
4,404✔
3116
            } => {
4,404✔
3117
                let l = SymbolExpr::Value(-self);
4,404✔
3118
                match l.mul_opt(expr, recursive) {
4,404✔
3119
                    Some(e) => Some(e),
2✔
3120
                    None => Some(_mul(l, expr.as_ref().clone())),
4,402✔
3121
                }
3122
            }
3123
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
8,314✔
3124
                if recursive {
8,314✔
3125
                    match op {
1,438✔
3126
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
1,438✔
3127
                            Some(e) => match e.mul_opt(r, recursive) {
32✔
3128
                                Some(ee) => Some(ee),
8✔
3129
                                None => Some(_mul(e, r.as_ref().clone())),
24✔
3130
                            },
3131
                            None => self
1,406✔
3132
                                .mul_opt(r, recursive)
1,406✔
3133
                                .map(|e| _mul(e, l.as_ref().clone())),
1,406✔
3134
                        },
3135
                        BinaryOp::Div => match self.mul_opt(l, recursive) {
×
3136
                            Some(e) => Some(_div(e, r.as_ref().clone())),
×
3137
                            None => self
×
3138
                                .div_opt(r, recursive)
×
3139
                                .map(|e| _mul(e, l.as_ref().clone())),
×
3140
                        },
3141
                        _ => None,
×
3142
                    }
3143
                } else {
3144
                    match l.as_ref() {
6,876✔
3145
                        SymbolExpr::Value(v) => match op {
830✔
3146
                            BinaryOp::Mul => {
3147
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
346✔
3148
                            }
3149
                            BinaryOp::Div => {
3150
                                Some(_div(SymbolExpr::Value(self * v), r.as_ref().clone()))
×
3151
                            }
3152
                            _ => None,
484✔
3153
                        },
3154
                        _ => match r.as_ref() {
6,046✔
3155
                            SymbolExpr::Value(v) => match op {
364✔
3156
                                BinaryOp::Mul => {
3157
                                    Some(_mul(SymbolExpr::Value(self * v), l.as_ref().clone()))
20✔
3158
                                }
3159
                                BinaryOp::Div => {
3160
                                    Some(_mul(SymbolExpr::Value(self / v), l.as_ref().clone()))
8✔
3161
                                }
3162
                                _ => None,
336✔
3163
                            },
3164
                            _ => None,
5,682✔
3165
                        },
3166
                    }
3167
                }
3168
            }
3169
            _ => None,
12,874✔
3170
        }
3171
    }
39,738✔
3172

3173
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
71,308✔
3174
        match rhs {
20✔
3175
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self / r)),
68,604✔
3176
            SymbolExpr::Unary {
3177
                op: UnaryOp::Neg,
3178
                expr,
×
3179
            } => {
×
3180
                if recursive {
×
3181
                    self.div_opt(expr, recursive).map(_neg)
×
3182
                } else {
3183
                    None
×
3184
                }
3185
            }
3186
            SymbolExpr::Binary { op, lhs: l, rhs: r } => match l.as_ref() {
1,308✔
3187
                SymbolExpr::Value(v) => match op {
490✔
3188
                    BinaryOp::Mul => Some(_div(SymbolExpr::Value(self / v), r.as_ref().clone())),
192✔
3189
                    BinaryOp::Div => Some(_mul(SymbolExpr::Value(self / v), r.as_ref().clone())),
×
3190
                    _ => None,
298✔
3191
                },
3192
                _ => match r.as_ref() {
818✔
3193
                    SymbolExpr::Value(v) => match op {
618✔
3194
                        BinaryOp::Mul => {
3195
                            Some(_div(SymbolExpr::Value(self / v), l.as_ref().clone()))
×
3196
                        }
3197
                        BinaryOp::Div => {
3198
                            Some(_div(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
3199
                        }
3200
                        _ => None,
618✔
3201
                    },
3202
                    _ => None,
200✔
3203
                },
3204
            },
3205
            _ => None,
1,396✔
3206
        }
3207
    }
71,308✔
3208

3209
    pub fn opt_complex(&self) -> Option<Value> {
244,754✔
3210
        match self {
244,754✔
3211
            Value::Complex(c) => {
106,200✔
3212
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
106,200✔
3213
                    Some(Value::Real(c.re))
23,024✔
3214
                } else {
3215
                    None
83,176✔
3216
                }
3217
            }
3218
            _ => None,
138,554✔
3219
        }
3220
    }
244,754✔
3221

3222
    // convert sympy compatible format
3223
    pub fn sympify(&self) -> SymbolExpr {
×
3224
        match self {
×
3225
            // imaginary number is comverted to value * symbol 'I'
3226
            Value::Complex(c) => _add(
×
3227
                SymbolExpr::Value(Value::Real(c.re)),
×
3228
                _mul(
×
3229
                    SymbolExpr::Value(Value::Real(c.im)),
×
3230
                    SymbolExpr::Symbol(Box::new("I".to_string())),
×
3231
                ),
×
3232
            ),
×
3233
            _ => SymbolExpr::Value(*self),
×
3234
        }
3235
    }
×
3236
}
3237

3238
impl From<f64> for Value {
3239
    fn from(v: f64) -> Self {
1,074,256✔
3240
        Value::Real(v)
1,074,256✔
3241
    }
1,074,256✔
3242
}
3243

3244
impl From<i64> for Value {
3245
    fn from(v: i64) -> Self {
2,438,550✔
3246
        Value::Int(v)
2,438,550✔
3247
    }
2,438,550✔
3248
}
3249

3250
impl From<Complex64> for Value {
3251
    fn from(v: Complex64) -> Self {
3,975,432✔
3252
        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&v.im) {
3,975,432✔
3253
            Value::Real(v.re)
3,043,798✔
3254
        } else {
3255
            Value::Complex(v)
931,634✔
3256
        }
3257
    }
3,975,432✔
3258
}
3259

3260
impl Add for &Value {
3261
    type Output = Value;
3262
    fn add(self, rhs: Self) -> Value {
65,590✔
3263
        *self + *rhs
65,590✔
3264
    }
65,590✔
3265
}
3266

3267
impl Add for Value {
3268
    type Output = Value;
3269
    fn add(self, rhs: Self) -> Value {
67,014✔
3270
        let t = match self {
67,014✔
3271
            Value::Real(l) => match rhs {
16,020✔
3272
                Value::Real(r) => Value::Real(l + r),
12,114✔
3273
                Value::Int(r) => Value::Real(l + r as f64),
2,020✔
3274
                Value::Complex(r) => Value::Complex(l + r),
1,886✔
3275
            },
3276
            Value::Int(l) => match rhs {
22,004✔
3277
                Value::Real(r) => Value::Real(l as f64 + r),
1,196✔
3278
                Value::Int(r) => Value::Int(l + r),
11,678✔
3279
                Value::Complex(r) => Value::Complex(l as f64 + r),
9,130✔
3280
            },
3281
            Value::Complex(l) => match rhs {
28,990✔
3282
                Value::Real(r) => Value::Complex(l + r),
622✔
3283
                Value::Int(r) => Value::Complex(l + r as f64),
11,474✔
3284
                Value::Complex(r) => Value::Complex(l + r),
16,894✔
3285
            },
3286
        };
3287
        match t.opt_complex() {
67,014✔
3288
            Some(v) => v,
4,156✔
3289
            None => t,
62,858✔
3290
        }
3291
    }
67,014✔
3292
}
3293

3294
impl Sub for &Value {
3295
    type Output = Value;
3296
    fn sub(self, rhs: Self) -> Value {
73,586✔
3297
        *self - *rhs
73,586✔
3298
    }
73,586✔
3299
}
3300

3301
impl Sub for Value {
3302
    type Output = Value;
3303
    fn sub(self, rhs: Self) -> Value {
74,066✔
3304
        let t = match self {
74,066✔
3305
            Value::Real(l) => match rhs {
10,948✔
3306
                Value::Real(r) => Value::Real(l - r),
5,796✔
3307
                Value::Int(r) => Value::Real(l - r as f64),
3,730✔
3308
                Value::Complex(r) => Value::Complex(l - r),
1,422✔
3309
            },
3310
            Value::Int(l) => match rhs {
35,456✔
3311
                Value::Real(r) => Value::Real(l as f64 - r),
234✔
3312
                Value::Int(r) => Value::Int(l - r),
27,144✔
3313
                Value::Complex(r) => Value::Complex(l as f64 - r),
8,078✔
3314
            },
3315
            Value::Complex(l) => match rhs {
27,662✔
3316
                Value::Real(r) => Value::Complex(l - r),
334✔
3317
                Value::Int(r) => Value::Complex(l - r as f64),
10,824✔
3318
                Value::Complex(r) => Value::Complex(l - r),
16,504✔
3319
            },
3320
        };
3321
        match t.opt_complex() {
74,066✔
3322
            Some(v) => v,
5,346✔
3323
            None => t,
68,720✔
3324
        }
3325
    }
74,066✔
3326
}
3327

3328
impl Mul for &Value {
3329
    type Output = Value;
3330
    fn mul(self, rhs: Self) -> Value {
27,712✔
3331
        *self * *rhs
27,712✔
3332
    }
27,712✔
3333
}
3334

3335
impl Mul for Value {
3336
    type Output = Value;
3337
    fn mul(self, rhs: Self) -> Value {
28,576✔
3338
        let t = match self {
28,576✔
3339
            Value::Real(l) => match rhs {
3,540✔
3340
                Value::Real(r) => Value::Real(l * r),
2,866✔
3341
                Value::Int(r) => Value::Real(l * r as f64),
368✔
3342
                Value::Complex(r) => Value::Complex(l * r),
306✔
3343
            },
3344
            Value::Int(l) => match rhs {
5,032✔
3345
                Value::Real(r) => Value::Real(l as f64 * r),
308✔
3346
                Value::Int(r) => Value::Int(l * r),
3,230✔
3347
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,494✔
3348
            },
3349
            Value::Complex(l) => match rhs {
20,004✔
3350
                Value::Real(r) => Value::Complex(l * r),
278✔
3351
                Value::Int(r) => Value::Complex(l * r as f64),
1,128✔
3352
                Value::Complex(r) => Value::Complex(l * r),
18,598✔
3353
            },
3354
        };
3355
        match t.opt_complex() {
28,576✔
3356
            Some(v) => v,
12,818✔
3357
            None => t,
15,758✔
3358
        }
3359
    }
28,576✔
3360
}
3361

3362
impl Div for &Value {
3363
    type Output = Value;
3364
    fn div(self, rhs: Self) -> Value {
69,036✔
3365
        *self / *rhs
69,036✔
3366
    }
69,036✔
3367
}
3368

3369
impl Div for Value {
3370
    type Output = Value;
3371
    fn div(self, rhs: Self) -> Value {
69,664✔
3372
        let t = match self {
69,664✔
3373
            Value::Real(l) => match rhs {
67,986✔
3374
                Value::Real(r) => Value::Real(l / r),
106✔
3375
                Value::Int(r) => Value::Real(l / r as f64),
67,310✔
3376
                Value::Complex(r) => Value::Complex(l / r),
570✔
3377
            },
3378
            Value::Int(l) => {
994✔
3379
                if rhs == 0.0 {
994✔
3380
                    return Value::Real(f64::INFINITY);
×
3381
                }
994✔
3382
                match rhs {
994✔
3383
                    Value::Real(r) => Value::Real(l as f64 / r),
24✔
3384
                    Value::Int(r) => {
430✔
3385
                        let t = l as f64 / r as f64;
430✔
3386
                        let d = t.floor() - t;
430✔
3387
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
430✔
3388
                            Value::Int(t as i64)
398✔
3389
                        } else {
3390
                            Value::Real(t)
32✔
3391
                        }
3392
                    }
3393
                    Value::Complex(r) => Value::Complex(l as f64 / r),
540✔
3394
                }
3395
            }
3396
            Value::Complex(l) => match rhs {
684✔
3397
                Value::Real(r) => Value::Complex(l / r),
24✔
3398
                Value::Int(r) => Value::Complex(l / r as f64),
280✔
3399
                Value::Complex(r) => Value::Complex(l / r),
380✔
3400
            },
3401
        };
3402
        match t.opt_complex() {
69,664✔
3403
            Some(v) => v,
416✔
3404
            None => t,
69,248✔
3405
        }
3406
    }
69,664✔
3407
}
3408

3409
impl Neg for &Value {
3410
    type Output = Value;
3411
    fn neg(self) -> Value {
123,080✔
3412
        -*self
123,080✔
3413
    }
123,080✔
3414
}
3415

3416
impl Neg for Value {
3417
    type Output = Value;
3418
    fn neg(self) -> Value {
178,382✔
3419
        match self {
178,382✔
3420
            Value::Real(v) => Value::Real(-v),
85,654✔
3421
            Value::Int(v) => Value::Int(-v),
31,842✔
3422
            Value::Complex(v) => Value::Complex(-v),
60,886✔
3423
        }
3424
    }
178,382✔
3425
}
3426

3427
impl PartialEq for Value {
3428
    fn eq(&self, r: &Self) -> bool {
386,086✔
3429
        match self {
386,086✔
3430
            Value::Real(e) => match r {
329,810✔
3431
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
230,090✔
3432
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
99,150✔
3433
                Value::Complex(rv) => {
570✔
3434
                    let t = Complex64::from(*e) - rv;
570✔
3435
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
570✔
3436
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
104✔
3437
                }
3438
            },
3439
            Value::Int(e) => match r {
20,734✔
3440
                Value::Int(rv) => e == rv,
1,056✔
3441
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
19,146✔
3442
                Value::Complex(rv) => {
532✔
3443
                    let t = Complex64::from(*e as f64) - rv;
532✔
3444
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
532✔
3445
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
24✔
3446
                }
3447
            },
3448
            Value::Complex(e) => match r {
35,542✔
3449
                Value::Real(rv) => {
34,426✔
3450
                    let t = *e - Complex64::from(rv);
34,426✔
3451
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
34,426✔
3452
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3453
                }
3454
                Value::Int(rv) => {
232✔
3455
                    let t = *e - Complex64::from(*rv as f64);
232✔
3456
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
232✔
3457
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3458
                }
3459
                Value::Complex(rv) => {
884✔
3460
                    let t = *e - rv;
884✔
3461
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
884✔
3462
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
584✔
3463
                }
3464
            },
3465
        }
3466
    }
386,086✔
3467
}
3468

3469
impl PartialEq<f64> for Value {
3470
    fn eq(&self, r: &f64) -> bool {
994✔
3471
        match self {
994✔
3472
            Value::Real(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - r)),
24✔
3473
            Value::Int(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - r)),
430✔
3474
            Value::Complex(e) => {
540✔
3475
                let t = *e - Complex64::from(r);
540✔
3476
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
540✔
3477
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
164✔
3478
            }
3479
        }
3480
    }
994✔
3481
}
3482

3483
impl PartialEq<Complex64> for Value {
3484
    fn eq(&self, r: &Complex64) -> bool {
×
3485
        match self {
×
3486
            Value::Real(e) => {
×
3487
                let t = Complex64::from(*e) - r;
×
3488
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3489
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3490
            }
3491
            Value::Int(e) => {
×
3492
                let t = Complex64::from(*e as f64) - r;
×
3493
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3494
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3495
            }
3496
            Value::Complex(e) => {
×
3497
                let t = *e - r;
×
3498
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3499
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3500
            }
3501
        }
3502
    }
×
3503
}
3504

3505
impl PartialOrd for Value {
3506
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
12✔
3507
        match self {
12✔
3508
            Value::Real(l) => match rhs {
4✔
3509
                Value::Real(r) => l.partial_cmp(r),
4✔
3510
                Value::Int(r) => l.partial_cmp(&(*r as f64)),
×
3511
                Value::Complex(_) => None,
×
3512
            },
3513
            Value::Int(l) => match rhs {
4✔
3514
                Value::Real(r) => (*l as f64).partial_cmp(r),
×
3515
                Value::Int(r) => l.partial_cmp(r),
4✔
3516
                Value::Complex(_) => None,
×
3517
            },
3518
            Value::Complex(_) => None,
4✔
3519
        }
3520
    }
12✔
3521
}
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