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

Qiskit / qiskit / 18104357474

29 Sep 2025 04:22PM UTC coverage: 88.301% (-0.006%) from 88.307%
18104357474

push

github

web-flow
Bump Rust edition to edition 2024 (#14876)

* Bump Rust edition to edition 2024

Now that our MSRV is set to be 1.85 this enables us to use the new rust
edition 2024. While there are some behavior changes especially around
temporaries, drop order, etc there are also some nice QoL improvements
to using the new edition. This commit opts in to using the new edition,
runs cargo fix on the repository to auto update a lot of the code,
fixes the compilation errors after this, and then cleans up the code.
The details on what changes in rust edition 2024 can be found here:

https://doc.rust-lang.org/nightly/edition-guide/rust-2024/index.html

For right now the cargo fmt rules are left on edition 2021 to minimize
the diff size here. We will do that change in a follow up PR as it will
be a larger diff that we likely want to add to the git blame exclude
list.

* Fix clippy issue

* Undo conversions of `if let`

`cargo fix --edition` converts all `if let` into corresponding `match`
statements, because the drop order changed slightly.  We do not rely on
the old drop order in any cases, so in general we can remove all those
changes.  This commit leaves a couple in place where the `match`
statement resulted in neater code.

* Avoid wildcard `match` statements

* Fix clippy complaints

* Run formatter

---------

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

70 of 89 new or added lines in 18 files covered. (78.65%)

18 existing lines in 4 files now uncovered.

92857 of 105160 relevant lines covered (88.3%)

1168674.65 hits per line

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

72.82
/crates/circuit/src/parameter/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
use hashbrown::HashMap;
14
use pyo3::exceptions::PyTypeError;
15
use pyo3::exceptions::PyValueError;
16
use pyo3::IntoPyObjectExt;
17
use std::cmp::Ordering;
18
use std::cmp::PartialOrd;
19
use std::convert::From;
20
use std::fmt;
21
use std::hash::Hash;
22
use std::ops::{Add, Div, Mul, Neg, Sub};
23
use std::sync::Arc;
24
use uuid::Uuid;
25

26
use num_complex::Complex64;
27
use pyo3::prelude::*;
28

29
use crate::parameter::parameter_expression::PyParameter;
30
use crate::parameter::parameter_expression::PyParameterVectorElement;
31

32
// epsilon for SymbolExpr is heuristically defined
33
pub const SYMEXPR_EPSILON: f64 = f64::EPSILON * 8.0;
34

35
#[derive(Debug, Clone)]
36
pub struct Symbol {
37
    name: String,                  // the name of the symbol
38
    pub uuid: Uuid,                // the unique identifier
39
    pub index: Option<u32>,        // an optional index, if part of a vector
40
    pub vector: Option<Py<PyAny>>, // Python only: a reference to the vector, if it is an element
41
}
42

43
/// Custom implementations of Eq, PartialEq, PartialOrd and Hash to ignore the ``vector`` field
44
impl PartialEq for Symbol {
45
    fn eq(&self, other: &Self) -> bool {
15,111,022✔
46
        self.name == other.name && self.uuid == other.uuid && self.index == other.index
15,111,022✔
47
    }
15,111,022✔
48
}
49

50
impl Eq for Symbol {}
51

52
impl PartialOrd for Symbol {
53
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36,592✔
54
        (&self.name, self.uuid, self.index).partial_cmp(&(&other.name, other.uuid, other.index))
36,592✔
55
    }
36,592✔
56
}
57

58
impl Hash for Symbol {
59
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46,189,784✔
60
        (&self.name, self.uuid, self.index).hash(state);
46,189,784✔
61
    }
46,189,784✔
62
}
63

64
impl<'py> FromPyObject<'py> for Symbol {
65
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
18,270✔
66
        if let Ok(py_vector_element) = ob.extract::<PyParameterVectorElement>() {
18,270✔
67
            Ok(py_vector_element.symbol().clone())
16,460✔
68
        } else if let Ok(py_param) = ob.extract::<PyParameter>() {
1,810✔
69
            Ok(py_param.symbol().clone())
1,810✔
70
        } else {
71
            Err(PyTypeError::new_err("Cannot extract Symbol from {ob:?}"))
×
72
        }
73
    }
18,270✔
74
}
75

76
impl<'py> IntoPyObject<'py> for Symbol {
77
    type Target = PyAny; // to cover PyParameter and PyParameterVectorElement
78
    type Output = Bound<'py, Self::Target>;
79
    type Error = PyErr;
80

81
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
58,040✔
82
        match (&self.index, &self.vector) {
58,040✔
83
            (Some(_), Some(_)) => Py::new(py, PyParameterVectorElement::from_symbol(self.clone()))?
52,672✔
84
                .into_bound_py_any(py),
52,672✔
85
            _ => Py::new(py, PyParameter::from_symbol(self.clone()))?.into_bound_py_any(py),
5,368✔
86
        }
87
    }
58,040✔
88
}
89

90
impl Symbol {
91
    pub fn new(name: &str, uuid: Option<Uuid>, index: Option<u32>) -> Self {
94,192✔
92
        Self {
94,192✔
93
            name: name.to_string(),
94,192✔
94
            uuid: uuid.unwrap_or(Uuid::new_v4()),
94,192✔
95
            index,
94,192✔
96
            vector: None, // Python only
94,192✔
97
        }
94,192✔
98
    }
94,192✔
99

100
    /// In addition to ``new``, this also takes a vector.
101
    pub fn py_new(
27,860✔
102
        name: &str,
27,860✔
103
        uuid: Option<u128>,
27,860✔
104
        index: Option<u32>,
27,860✔
105
        vector: Option<Py<PyAny>>,
27,860✔
106
    ) -> PyResult<Self> {
27,860✔
107
        if index.is_some() != vector.is_some() {
27,860✔
108
            return Err(PyValueError::new_err(
×
109
                "Either both of vector and index must be provided, or neither of them",
×
110
            ));
×
111
        }
27,860✔
112

113
        Ok(Self {
27,860✔
114
            name: name.to_string(),
27,860✔
115
            uuid: uuid.map_or_else(Uuid::new_v4, Uuid::from_u128),
27,860✔
116
            index,
27,860✔
117
            vector,
27,860✔
118
        })
27,860✔
119
    }
27,860✔
120

121
    pub fn name(&self) -> &str {
88,296✔
122
        &self.name
88,296✔
123
    }
88,296✔
124

125
    pub fn repr(&self, with_uuid: bool) -> String {
15,252,904✔
126
        match (self.index, with_uuid) {
15,252,904✔
127
            (Some(i), true) => format!("{}[{}]_{}", self.name, i, self.uuid.as_u128()),
9,679,876✔
128
            (Some(i), false) => format!("{}[{}]", self.name, i),
4,822,452✔
129
            (None, true) => format!("{}_{}", self.name, self.uuid.as_u128()),
140,820✔
130
            (None, false) => self.name.clone(),
609,756✔
131
        }
132
    }
15,252,904✔
133
}
134

135
/// node types of expression tree
136
#[derive(Debug, Clone)]
137
pub enum SymbolExpr {
138
    Symbol(Arc<Symbol>),
139
    Value(Value),
140
    Unary {
141
        op: UnaryOp,
142
        expr: Arc<SymbolExpr>,
143
    },
144
    Binary {
145
        op: BinaryOp,
146
        lhs: Arc<SymbolExpr>,
147
        rhs: Arc<SymbolExpr>,
148
    },
149
}
150

151
/// Value type, can be integer, real or complex number
152
#[derive(Debug, Clone, Copy, IntoPyObject, IntoPyObjectRef)]
153
pub enum Value {
154
    Real(f64),
155
    Int(i64),
156
    Complex(Complex64),
157
}
158

159
impl<'py> FromPyObject<'py> for Value {
160
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
4,555,044✔
161
        if let Ok(i) = ob.extract::<i64>() {
4,555,044✔
162
            Ok(Value::Int(i))
2,376,122✔
163
        } else if let Ok(r) = ob.extract::<f64>() {
2,178,922✔
164
            Ok(Value::Real(r))
897,992✔
165
        } else if let Ok(c) = ob.extract::<Complex64>() {
1,280,930✔
166
            Ok(Value::Complex(c))
1,280,930✔
167
        } else {
168
            Err(PyValueError::new_err(
×
169
                "Could not cast Bound<PyAny> to Value.",
×
170
            ))
×
171
        }
172
    }
4,555,044✔
173
}
174

175
/// definition of unary operations
176
#[derive(Debug, Clone, PartialEq)]
177
pub enum UnaryOp {
178
    Abs,
179
    Neg,
180
    Sin,
181
    Asin,
182
    Cos,
183
    Acos,
184
    Tan,
185
    Atan,
186
    Exp,
187
    Log,
188
    Sign,
189
    Conj,
190
}
191

192
/// definition of binary operations
193
#[derive(Debug, Clone, PartialEq)]
194
pub enum BinaryOp {
195
    Add,
196
    Sub,
197
    Mul,
198
    Div,
199
    Pow,
200
}
201

202
// functions to make new expr for add
203
#[inline(always)]
204
fn _add(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
127,556✔
205
    if rhs.is_negative() {
127,556✔
206
        match rhs.neg_opt() {
40,396✔
207
            Some(e) => SymbolExpr::Binary {
40,396✔
208
                op: BinaryOp::Sub,
40,396✔
209
                lhs: Arc::new(lhs),
40,396✔
210
                rhs: Arc::new(e),
40,396✔
211
            },
40,396✔
212
            None => SymbolExpr::Binary {
×
213
                op: BinaryOp::Sub,
×
214
                lhs: Arc::new(lhs),
×
215
                rhs: Arc::new(_neg(rhs)),
×
216
            },
×
217
        }
218
    } else {
219
        SymbolExpr::Binary {
87,160✔
220
            op: BinaryOp::Add,
87,160✔
221
            lhs: Arc::new(lhs),
87,160✔
222
            rhs: Arc::new(rhs),
87,160✔
223
        }
87,160✔
224
    }
225
}
127,556✔
226

227
// functions to make new expr for sub
228
#[inline(always)]
229
fn _sub(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
24,866✔
230
    if rhs.is_negative() {
24,866✔
231
        match rhs.neg_opt() {
1,060✔
232
            Some(e) => SymbolExpr::Binary {
1,060✔
233
                op: BinaryOp::Add,
1,060✔
234
                lhs: Arc::new(lhs),
1,060✔
235
                rhs: Arc::new(e),
1,060✔
236
            },
1,060✔
237
            None => SymbolExpr::Binary {
×
238
                op: BinaryOp::Add,
×
239
                lhs: Arc::new(lhs),
×
240
                rhs: Arc::new(_neg(rhs)),
×
241
            },
×
242
        }
243
    } else {
244
        SymbolExpr::Binary {
23,806✔
245
            op: BinaryOp::Sub,
23,806✔
246
            lhs: Arc::new(lhs),
23,806✔
247
            rhs: Arc::new(rhs),
23,806✔
248
        }
23,806✔
249
    }
250
}
24,866✔
251

252
// functions to make new expr for mul
253
#[inline(always)]
254
fn _mul(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
389,372✔
255
    SymbolExpr::Binary {
389,372✔
256
        op: BinaryOp::Mul,
389,372✔
257
        lhs: Arc::new(lhs),
389,372✔
258
        rhs: Arc::new(rhs),
389,372✔
259
    }
389,372✔
260
}
389,372✔
261

262
// functions to make new expr for div
263
#[inline(always)]
264
fn _div(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
10,292✔
265
    SymbolExpr::Binary {
10,292✔
266
        op: BinaryOp::Div,
10,292✔
267
        lhs: Arc::new(lhs),
10,292✔
268
        rhs: Arc::new(rhs),
10,292✔
269
    }
10,292✔
270
}
10,292✔
271

272
// functions to make new expr for pow
273
#[inline(always)]
274
fn _pow(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
18,170✔
275
    SymbolExpr::Binary {
18,170✔
276
        op: BinaryOp::Pow,
18,170✔
277
        lhs: Arc::new(lhs),
18,170✔
278
        rhs: Arc::new(rhs),
18,170✔
279
    }
18,170✔
280
}
18,170✔
281

282
// functions to make new expr for neg
283
#[inline(always)]
284
fn _neg(expr: SymbolExpr) -> SymbolExpr {
31,392✔
285
    match expr.neg_opt() {
31,392✔
286
        Some(e) => e,
82✔
287
        None => SymbolExpr::Unary {
31,310✔
288
            op: UnaryOp::Neg,
31,310✔
289
            expr: Arc::new(expr),
31,310✔
290
        },
31,310✔
291
    }
292
}
31,392✔
293

294
impl fmt::Display for SymbolExpr {
295
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143,874✔
296
        write!(f, "{}", self.repr(false))
143,874✔
297
    }
143,874✔
298
}
299

300
impl SymbolExpr {
301
    /// bind value to symbol node
302
    pub fn bind(&self, maps: &HashMap<&Symbol, Value>) -> SymbolExpr {
1,279,228✔
303
        match self {
1,279,228✔
304
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
571,300✔
305
                Some(v) => SymbolExpr::Value(*v),
568,646✔
306
                None => self.clone(),
2,654✔
307
            },
308
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
259,018✔
309
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
21,538✔
310
                op: op.clone(),
21,538✔
311
                expr: Arc::new(expr.bind(maps)),
21,538✔
312
            },
21,538✔
313
            SymbolExpr::Binary { op, lhs, rhs } => {
427,372✔
314
                let new_lhs = lhs.bind(maps);
427,372✔
315
                let new_rhs = rhs.bind(maps);
427,372✔
316
                match op {
427,372✔
317
                    BinaryOp::Add => new_lhs + new_rhs,
88,112✔
318
                    BinaryOp::Sub => new_lhs - new_rhs,
65,142✔
319
                    BinaryOp::Mul => new_lhs * new_rhs,
249,964✔
320
                    BinaryOp::Div => new_lhs / new_rhs,
9,142✔
321
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
15,012✔
322
                }
323
            }
324
        }
325
    }
1,279,228✔
326

327
    /// substitute symbol node to other expression
328
    /// allows unknown expressions
329
    /// does not allow duplicate names with different UUID
330
    pub fn subs(&self, maps: &HashMap<Symbol, SymbolExpr>) -> SymbolExpr {
415,074✔
331
        match self {
415,074✔
332
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
242,898✔
333
                Some(v) => v.clone(),
37,466✔
334
                None => self.clone(),
205,432✔
335
            },
336
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
80,680✔
337
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
1,572✔
338
                op: op.clone(),
1,572✔
339
                expr: Arc::new(expr.subs(maps)),
1,572✔
340
            },
1,572✔
341
            SymbolExpr::Binary { op, lhs, rhs } => {
89,924✔
342
                let new_lhs = lhs.subs(maps);
89,924✔
343
                let new_rhs = rhs.subs(maps);
89,924✔
344
                match op {
89,924✔
345
                    BinaryOp::Add => new_lhs + new_rhs,
15,174✔
346
                    BinaryOp::Sub => new_lhs - new_rhs,
4,798✔
347
                    BinaryOp::Mul => new_lhs * new_rhs,
69,918✔
348
                    BinaryOp::Div => new_lhs / new_rhs,
16✔
349
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
350
                }
351
            }
352
        }
353
    }
415,074✔
354

355
    /// evaluate the equation
356
    /// if recursive is false, only this node will be evaluated
357
    pub fn eval(&self, recurse: bool) -> Option<Value> {
56,087,612✔
358
        match self {
56,087,612✔
359
            SymbolExpr::Symbol(_) => None,
26,270,494✔
360
            SymbolExpr::Value(e) => Some(*e),
12,335,300✔
361
            SymbolExpr::Unary { op, expr } => {
530,446✔
362
                let val: Value;
363
                if recurse {
530,446✔
364
                    match expr.eval(recurse) {
530,446✔
365
                        Some(v) => val = v,
28,006✔
366
                        None => return None,
502,440✔
367
                    }
368
                } else {
369
                    match expr.as_ref() {
×
370
                        SymbolExpr::Value(e) => val = *e,
×
371
                        _ => return None,
×
372
                    }
373
                }
374
                let ret = match op {
28,006✔
375
                    UnaryOp::Abs => val.abs(),
462✔
376
                    UnaryOp::Neg => -val,
24,662✔
377
                    UnaryOp::Sin => val.sin(),
364✔
378
                    UnaryOp::Asin => val.asin(),
90✔
379
                    UnaryOp::Cos => val.cos(),
610✔
380
                    UnaryOp::Acos => val.acos(),
88✔
381
                    UnaryOp::Tan => val.tan(),
340✔
382
                    UnaryOp::Atan => val.atan(),
90✔
383
                    UnaryOp::Exp => val.exp(),
402✔
384
                    UnaryOp::Log => val.log(),
384✔
385
                    UnaryOp::Sign => val.sign(),
6✔
386
                    UnaryOp::Conj => match val {
508✔
387
                        Value::Complex(v) => Value::Complex(v.conj()),
186✔
388
                        _ => val,
322✔
389
                    },
390
                };
391
                match ret {
28,006✔
392
                    Value::Real(_) => Some(ret),
4,634✔
393
                    Value::Int(_) => Some(ret),
21,320✔
394
                    Value::Complex(c) => {
2,052✔
395
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
2,052✔
396
                            Some(Value::Real(c.re))
418✔
397
                        } else {
398
                            Some(ret)
1,634✔
399
                        }
400
                    }
401
                }
402
            }
403
            SymbolExpr::Binary { op, lhs, rhs } => {
16,951,372✔
404
                let lval: Value;
405
                let rval: Value;
406
                if recurse {
16,951,372✔
407
                    match (lhs.eval(true), rhs.eval(true)) {
16,951,372✔
408
                        (Some(left), Some(right)) => {
34,700✔
409
                            lval = left;
34,700✔
410
                            rval = right;
34,700✔
411
                        }
34,700✔
412
                        _ => return None,
16,916,672✔
413
                    }
414
                } else {
415
                    match (lhs.as_ref(), rhs.as_ref()) {
×
416
                        (SymbolExpr::Value(l), SymbolExpr::Value(r)) => {
×
417
                            lval = *l;
×
418
                            rval = *r;
×
419
                        }
×
420
                        _ => return None,
×
421
                    }
422
                }
423
                let ret = match op {
34,700✔
424
                    BinaryOp::Add => lval + rval,
2,600✔
425
                    BinaryOp::Sub => lval - rval,
876✔
426
                    BinaryOp::Mul => lval * rval,
1,560✔
427
                    BinaryOp::Div => lval / rval,
974✔
428
                    BinaryOp::Pow => lval.pow(&rval),
28,690✔
429
                };
430
                match ret {
34,700✔
431
                    Value::Real(_) => Some(ret),
13,464✔
432
                    Value::Int(_) => Some(ret),
10,010✔
433
                    Value::Complex(c) => {
11,226✔
434
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
11,226✔
435
                            Some(Value::Real(c.re))
×
436
                        } else {
437
                            Some(ret)
11,226✔
438
                        }
439
                    }
440
                }
441
            }
442
        }
443
    }
56,087,612✔
444

445
    /// calculate derivative of the equantion for a symbol passed by param
446
    pub fn derivative(&self, param: &Symbol) -> Result<SymbolExpr, String> {
212✔
447
        if let SymbolExpr::Symbol(s) = self {
212✔
448
            if s.as_ref() == param {
94✔
449
                return Ok(SymbolExpr::Value(Value::Real(1.0)));
78✔
450
            }
16✔
451
        }
118✔
452

453
        match self {
134✔
454
            SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => Ok(SymbolExpr::Value(Value::Real(0.0))),
34✔
455
            SymbolExpr::Unary { op, expr } => {
50✔
456
                let expr_d = expr.derivative(param)?;
50✔
457
                match op {
50✔
458
                    UnaryOp::Abs => Ok(&(expr.as_ref() * &expr_d)
4✔
459
                        / &SymbolExpr::Unary {
4✔
460
                            op: op.clone(),
4✔
461
                            expr: Arc::new(expr.as_ref().clone()),
4✔
462
                        }),
4✔
463
                    UnaryOp::Neg => Ok(SymbolExpr::Unary {
×
464
                        op: UnaryOp::Neg,
×
465
                        expr: Arc::new(expr_d),
×
466
                    }),
×
467
                    UnaryOp::Sin => {
468
                        let lhs = SymbolExpr::Unary {
10✔
469
                            op: UnaryOp::Cos,
10✔
470
                            expr: Arc::new(expr.as_ref().clone()),
10✔
471
                        };
10✔
472
                        Ok(lhs * expr_d)
10✔
473
                    }
474
                    UnaryOp::Asin => {
475
                        let d =
4✔
476
                            &SymbolExpr::Value(Value::Real(1.0)) - &(expr.as_ref() * expr.as_ref());
4✔
477
                        let rhs = match d {
4✔
478
                            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
479
                            _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
4✔
480
                        };
481
                        Ok(&expr_d / &rhs)
4✔
482
                    }
483
                    UnaryOp::Cos => {
484
                        let lhs = SymbolExpr::Unary {
4✔
485
                            op: UnaryOp::Sin,
4✔
486
                            expr: Arc::new(expr.as_ref().clone()),
4✔
487
                        };
4✔
488
                        Ok(&-&lhs * &expr_d)
4✔
489
                    }
490
                    UnaryOp::Acos => {
491
                        let d =
4✔
492
                            &SymbolExpr::Value(Value::Real(1.0)) - &(expr.as_ref() * expr.as_ref());
4✔
493
                        let rhs = match d {
4✔
494
                            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
495
                            _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
4✔
496
                        };
497
                        Ok(&-&expr_d / &rhs)
4✔
498
                    }
499
                    UnaryOp::Tan => {
500
                        let d = SymbolExpr::Unary {
4✔
501
                            op: UnaryOp::Cos,
4✔
502
                            expr: Arc::new(expr.as_ref().clone()),
4✔
503
                        };
4✔
504
                        Ok(&(&expr_d / &d) / &d)
4✔
505
                    }
506
                    UnaryOp::Atan => {
507
                        let d =
4✔
508
                            &SymbolExpr::Value(Value::Real(1.0)) + &(expr.as_ref() * expr.as_ref());
4✔
509
                        Ok(&expr_d / &d)
4✔
510
                    }
511
                    UnaryOp::Exp => Ok(&SymbolExpr::Unary {
4✔
512
                        op: UnaryOp::Exp,
4✔
513
                        expr: Arc::new(expr.as_ref().clone()),
4✔
514
                    } * &expr_d),
4✔
515
                    UnaryOp::Log => Ok(&expr_d / expr.as_ref()),
4✔
516
                    UnaryOp::Sign => {
517
                        Err("SymbolExpr::derivative does not support sign function.".to_string())
4✔
518
                    }
519
                    UnaryOp::Conj => {
520
                        // we assume real parameters, hence Conj acts as identity
521
                        Ok(SymbolExpr::Value(Value::Real(1.0)))
4✔
522
                    }
523
                }
524
            }
525
            SymbolExpr::Binary { op, lhs, rhs } => match op {
50✔
526
                BinaryOp::Add => Ok(lhs.derivative(param)? + rhs.derivative(param)?),
14✔
527
                BinaryOp::Sub => Ok(lhs.derivative(param)? - rhs.derivative(param)?),
4✔
528
                BinaryOp::Mul => Ok(&(&lhs.derivative(param)? * rhs.as_ref())
22✔
529
                    + &(lhs.as_ref() * &rhs.derivative(param)?)),
22✔
530
                BinaryOp::Div => Ok(&(&(&(&lhs.derivative(param)? * rhs.as_ref())
4✔
531
                    - &(lhs.as_ref() * &rhs.derivative(param)?))
4✔
532
                    / rhs.as_ref())
4✔
533
                    / rhs.as_ref()),
4✔
534
                BinaryOp::Pow => {
535
                    if !lhs.has_symbol(param) {
6✔
536
                        if !rhs.has_symbol(param) {
6✔
537
                            Ok(SymbolExpr::Value(Value::Real(0.0)))
6✔
538
                        } else {
539
                            Ok(_mul(
×
540
                                SymbolExpr::Binary {
×
541
                                    op: BinaryOp::Pow,
×
542
                                    lhs: Arc::new(lhs.as_ref().clone()),
×
543
                                    rhs: Arc::new(rhs.as_ref().clone()),
×
544
                                },
×
545
                                SymbolExpr::Unary {
×
546
                                    op: UnaryOp::Log,
×
547
                                    expr: Arc::new(lhs.as_ref().clone()),
×
548
                                },
×
549
                            ))
×
550
                        }
551
                    } else if !rhs.has_symbol(param) {
×
552
                        Ok(rhs.as_ref()
×
553
                            * &SymbolExpr::Binary {
×
554
                                op: BinaryOp::Pow,
×
555
                                lhs: Arc::new(lhs.as_ref().clone()),
×
556
                                rhs: Arc::new(rhs.as_ref() - &SymbolExpr::Value(Value::Real(1.0))),
×
557
                            })
×
558
                    } else {
559
                        let new_expr = SymbolExpr::Unary {
×
560
                            op: UnaryOp::Exp,
×
561
                            expr: Arc::new(_mul(
×
562
                                SymbolExpr::Unary {
×
563
                                    op: UnaryOp::Log,
×
564
                                    expr: Arc::new(lhs.as_ref().clone()),
×
565
                                },
×
566
                                rhs.as_ref().clone(),
×
567
                            )),
×
568
                        };
×
569
                        new_expr.derivative(param)
×
570
                    }
571
                }
572
            },
573
        }
574
    }
212✔
575

576
    /// expand the equation
577
    pub fn expand(&self) -> SymbolExpr {
192,598✔
578
        match self {
192,598✔
579
            SymbolExpr::Symbol(_) => self.clone(),
26,628✔
580
            SymbolExpr::Value(_) => self.clone(),
3,436✔
581
            SymbolExpr::Unary { op, expr } => {
2,340✔
582
                let ex = expr.expand();
2,340✔
583
                match op {
2,340✔
584
                    UnaryOp::Neg => match ex.neg_opt() {
390✔
585
                        Some(ne) => ne,
×
586
                        None => _neg(ex),
390✔
587
                    },
588
                    _ => SymbolExpr::Unary {
1,950✔
589
                        op: op.clone(),
1,950✔
590
                        expr: Arc::new(ex),
1,950✔
591
                    },
1,950✔
592
                }
593
            }
594
            SymbolExpr::Binary { op, lhs, rhs } => {
160,194✔
595
                match op {
160,194✔
596
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
145,786✔
597
                        Some(e) => e,
2,478✔
598
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
143,308✔
599
                    },
600
                    BinaryOp::Div => match lhs.div_expand(rhs) {
142✔
601
                        Some(e) => e,
8✔
602
                        None => _div(lhs.as_ref().clone(), rhs.as_ref().clone()),
134✔
603
                    },
604
                    BinaryOp::Add => match lhs.add_opt(rhs, true) {
4,786✔
605
                        Some(e) => e,
268✔
606
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
4,518✔
607
                    },
608
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
6,348✔
609
                        Some(e) => e,
2,396✔
610
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,952✔
611
                    },
612
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
3,132✔
613
                }
614
            }
615
        }
616
    }
192,598✔
617

618
    /// sign operator
619
    pub fn sign(&self) -> SymbolExpr {
10✔
620
        SymbolExpr::Unary {
10✔
621
            op: UnaryOp::Sign,
10✔
622
            expr: Arc::new(self.clone()),
10✔
623
        }
10✔
624
    }
10✔
625

626
    /// return real number if equation can be evaluated
627
    pub fn real(&self) -> Option<f64> {
×
628
        match self.eval(true) {
×
629
            Some(v) => match v {
×
630
                Value::Real(r) => Some(r),
×
631
                Value::Int(r) => Some(r as f64),
×
632
                Value::Complex(c) => Some(c.re),
×
633
            },
634
            None => None,
×
635
        }
636
    }
×
637
    /// return imaginary part of the value if equation can be evaluated as complex number
638
    pub fn imag(&self) -> Option<f64> {
×
639
        match self.eval(true) {
×
640
            Some(v) => match v {
×
641
                Value::Real(_) => Some(0.0),
×
642
                Value::Int(_) => Some(0.0),
×
643
                Value::Complex(c) => Some(c.im),
×
644
            },
645
            None => None,
×
646
        }
647
    }
×
648
    /// return complex number if equation can be evaluated as complex
649
    pub fn complex(&self) -> Option<Complex64> {
×
650
        match self.eval(true) {
×
651
            Some(v) => match v {
×
652
                Value::Real(r) => Some(r.into()),
×
653
                Value::Int(i) => Some((i as f64).into()),
×
654
                Value::Complex(c) => Some(c),
×
655
            },
656
            None => None,
×
657
        }
658
    }
×
659

660
    /// Iterate over all symbols this equation contains.
661
    pub fn iter_symbols(&self) -> Box<dyn Iterator<Item = &Symbol> + '_> {
14,112,376✔
662
        // This could maybe be more elegantly resolved with a SymbolIter type>
663
        match self {
14,112,376✔
664
            SymbolExpr::Symbol(e) => Box::new(::std::iter::once(e.as_ref())),
14,021,776✔
665
            SymbolExpr::Value(_) => Box::new(::std::iter::empty()),
43,708✔
666
            SymbolExpr::Unary { op: _, expr } => expr.iter_symbols(),
2,460✔
667
            SymbolExpr::Binary { op: _, lhs, rhs } => {
44,432✔
668
                Box::new(lhs.iter_symbols().chain(rhs.iter_symbols()))
44,432✔
669
            }
670
        }
671
    }
14,112,376✔
672

673
    /// Map of parameter name to the parameter.
674
    pub fn name_map(&self) -> HashMap<String, Symbol> {
4,765,038✔
675
        self.iter_symbols()
4,765,038✔
676
            .map(|param| (param.repr(false), param.clone()))
4,765,038✔
677
            .collect()
4,765,038✔
678
    }
4,765,038✔
679

680
    /// return all numbers in the equation
681
    pub fn values(&self) -> Vec<Value> {
182✔
682
        match self {
182✔
683
            SymbolExpr::Symbol(_) => Vec::<Value>::new(),
86✔
684
            SymbolExpr::Value(v) => Vec::<Value>::from([*v]),
44✔
685
            SymbolExpr::Unary { op: _, expr } => expr.values(),
×
686
            SymbolExpr::Binary { op: _, lhs, rhs } => {
52✔
687
                let mut l = lhs.values();
52✔
688
                let r = rhs.values();
52✔
689
                l.extend(r);
52✔
690
                l
52✔
691
            }
692
        }
693
    }
182✔
694

695
    /// check if a symbol is in this equation
696
    pub fn has_symbol(&self, param: &Symbol) -> bool {
12✔
697
        match self {
12✔
698
            SymbolExpr::Symbol(e) => e.as_ref().eq(param),
6✔
699
            SymbolExpr::Value(_) => false,
6✔
700
            SymbolExpr::Unary { op: _, expr } => expr.has_symbol(param),
×
701
            SymbolExpr::Binary { op: _, lhs, rhs } => lhs.has_symbol(param) | rhs.has_symbol(param),
×
702
        }
703
    }
12✔
704

705
    /// return reciprocal of the equation
706
    pub fn rcp(&self) -> SymbolExpr {
×
707
        match self {
×
708
            SymbolExpr::Symbol(e) => _div(
×
709
                SymbolExpr::Value(Value::Real(1.0)),
×
710
                SymbolExpr::Symbol(e.clone()),
×
711
            ),
712
            SymbolExpr::Value(e) => SymbolExpr::Value(e.rcp()),
×
713
            SymbolExpr::Unary { .. } => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
714
            SymbolExpr::Binary { op, lhs, rhs } => match op {
×
715
                BinaryOp::Div => SymbolExpr::Binary {
×
716
                    op: op.clone(),
×
717
                    lhs: rhs.clone(),
×
718
                    rhs: lhs.clone(),
×
719
                },
×
720
                _ => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
721
            },
722
        }
723
    }
×
724
    /// return square root of the equation
725
    pub fn sqrt(&self) -> SymbolExpr {
×
726
        match self {
×
727
            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
728
            _ => self.pow(&SymbolExpr::Value(Value::Real(0.5))),
×
729
        }
730
    }
×
731

732
    /// return conjugate of the equation
733
    pub fn conjugate(&self) -> SymbolExpr {
4,754✔
734
        match self {
4,754✔
735
            SymbolExpr::Symbol(_) => SymbolExpr::Unary {
1,864✔
736
                op: UnaryOp::Conj,
1,864✔
737
                expr: Arc::new(self.clone()),
1,864✔
738
            },
1,864✔
739
            SymbolExpr::Value(e) => match e {
1,314✔
740
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
594✔
741
                _ => SymbolExpr::Value(*e),
720✔
742
            },
743
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
230✔
744
                op: op.clone(),
230✔
745
                expr: Arc::new(expr.conjugate()),
230✔
746
            },
230✔
747
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
1,346✔
748
                op: op.clone(),
1,346✔
749
                lhs: Arc::new(lhs.conjugate()),
1,346✔
750
                rhs: Arc::new(rhs.conjugate()),
1,346✔
751
            },
1,346✔
752
        }
753
    }
4,754✔
754

755
    /// check if complex number or not
756
    pub fn is_complex(&self) -> Option<bool> {
23,078✔
757
        match self.eval(true) {
23,078✔
758
            Some(v) => match v {
6✔
759
                Value::Complex(c) => Some(!(-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
6✔
760
                _ => Some(false),
×
761
            },
762
            None => None,
23,072✔
763
        }
764
    }
23,078✔
765

766
    /// check if real number or not
767
    pub fn is_real(&self) -> Option<bool> {
270✔
768
        self.eval(true).map(|value| value.is_real())
270✔
769
    }
270✔
770

771
    /// check if integer or not
772
    pub fn is_int(&self) -> Option<bool> {
91,530✔
773
        match self.eval(true) {
91,530✔
774
            Some(v) => match v {
67,782✔
775
                Value::Int(_) => Some(true),
64,488✔
776
                _ => Some(false),
3,294✔
777
            },
778
            None => None,
23,748✔
779
        }
780
    }
91,530✔
781

782
    /// check if evaluated result is 0
783
    pub fn is_zero(&self) -> bool {
9,786,388✔
784
        match self.eval(true) {
9,786,388✔
785
            Some(v) => v.is_zero(),
5,661,158✔
786
            None => false,
4,125,230✔
787
        }
788
    }
9,786,388✔
789

790
    /// check if evaluated result is 1
791
    pub fn is_one(&self) -> bool {
882,238✔
792
        match self.eval(true) {
882,238✔
793
            Some(v) => v.is_one(),
591,616✔
794
            None => false,
290,622✔
795
        }
796
    }
882,238✔
797

798
    /// check if evaluated result is -1
799
    pub fn is_minus_one(&self) -> bool {
605,140✔
800
        match self.eval(true) {
605,140✔
801
            Some(v) => v.is_minus_one(),
348,646✔
802
            None => false,
256,494✔
803
        }
804
    }
605,140✔
805

806
    /// check if evaluated result is negative
807
    fn is_negative(&self) -> bool {
464,510✔
808
        match self {
464,510✔
809
            SymbolExpr::Value(v) => v.is_negative(),
74,418✔
810
            SymbolExpr::Symbol(_) => false,
204,664✔
811
            SymbolExpr::Unary { op, expr } => match op {
18,484✔
812
                UnaryOp::Abs => false,
8✔
813
                UnaryOp::Neg => !expr.is_negative(),
16,158✔
814
                _ => false, // TO DO add heuristic determination
2,318✔
815
            },
816
            SymbolExpr::Binary { op, lhs, rhs } => match op {
166,944✔
817
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
138,826✔
818
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
18,278✔
819
                _ => false, // TO DO add heuristic determination for pow
9,840✔
820
            },
821
        }
822
    }
464,510✔
823

824
    /// unary operations
825
    pub fn abs(&self) -> SymbolExpr {
378✔
826
        match self {
4✔
827
            SymbolExpr::Value(l) => SymbolExpr::Value(l.abs()),
6✔
828
            SymbolExpr::Unary {
829
                op: UnaryOp::Abs | UnaryOp::Neg,
830
                expr,
4✔
831
            } => expr.abs(),
4✔
832
            _ => SymbolExpr::Unary {
368✔
833
                op: UnaryOp::Abs,
368✔
834
                expr: Arc::new(self.clone()),
368✔
835
            },
368✔
836
        }
837
    }
378✔
838
    pub fn sin(&self) -> SymbolExpr {
362✔
839
        match self {
362✔
840
            SymbolExpr::Value(l) => SymbolExpr::Value(l.sin()),
×
841
            _ => SymbolExpr::Unary {
362✔
842
                op: UnaryOp::Sin,
362✔
843
                expr: Arc::new(self.clone()),
362✔
844
            },
362✔
845
        }
846
    }
362✔
847
    pub fn asin(&self) -> SymbolExpr {
100✔
848
        match self {
100✔
849
            SymbolExpr::Value(l) => SymbolExpr::Value(l.asin()),
×
850
            _ => SymbolExpr::Unary {
100✔
851
                op: UnaryOp::Asin,
100✔
852
                expr: Arc::new(self.clone()),
100✔
853
            },
100✔
854
        }
855
    }
100✔
856
    pub fn cos(&self) -> SymbolExpr {
352✔
857
        match self {
352✔
858
            SymbolExpr::Value(l) => SymbolExpr::Value(l.cos()),
×
859
            _ => SymbolExpr::Unary {
352✔
860
                op: UnaryOp::Cos,
352✔
861
                expr: Arc::new(self.clone()),
352✔
862
            },
352✔
863
        }
864
    }
352✔
865
    pub fn acos(&self) -> SymbolExpr {
100✔
866
        match self {
100✔
867
            SymbolExpr::Value(l) => SymbolExpr::Value(l.acos()),
×
868
            _ => SymbolExpr::Unary {
100✔
869
                op: UnaryOp::Acos,
100✔
870
                expr: Arc::new(self.clone()),
100✔
871
            },
100✔
872
        }
873
    }
100✔
874
    pub fn tan(&self) -> SymbolExpr {
352✔
875
        match self {
352✔
876
            SymbolExpr::Value(l) => SymbolExpr::Value(l.tan()),
×
877
            _ => SymbolExpr::Unary {
352✔
878
                op: UnaryOp::Tan,
352✔
879
                expr: Arc::new(self.clone()),
352✔
880
            },
352✔
881
        }
882
    }
352✔
883
    pub fn atan(&self) -> SymbolExpr {
100✔
884
        match self {
100✔
885
            SymbolExpr::Value(l) => SymbolExpr::Value(l.atan()),
×
886
            _ => SymbolExpr::Unary {
100✔
887
                op: UnaryOp::Atan,
100✔
888
                expr: Arc::new(self.clone()),
100✔
889
            },
100✔
890
        }
891
    }
100✔
892
    pub fn exp(&self) -> SymbolExpr {
350✔
893
        match self {
350✔
894
            SymbolExpr::Value(l) => SymbolExpr::Value(l.exp()),
×
895
            _ => SymbolExpr::Unary {
350✔
896
                op: UnaryOp::Exp,
350✔
897
                expr: Arc::new(self.clone()),
350✔
898
            },
350✔
899
        }
900
    }
350✔
901
    pub fn log(&self) -> SymbolExpr {
266✔
902
        match self {
266✔
903
            SymbolExpr::Value(l) => SymbolExpr::Value(l.log()),
×
904
            _ => SymbolExpr::Unary {
266✔
905
                op: UnaryOp::Log,
266✔
906
                expr: Arc::new(self.clone()),
266✔
907
            },
266✔
908
        }
909
    }
266✔
910
    pub fn pow(&self, rhs: &SymbolExpr) -> SymbolExpr {
3,016✔
911
        match self {
3,016✔
912
            SymbolExpr::Value(l) => match rhs {
1,030✔
913
                SymbolExpr::Value(r) => SymbolExpr::Value(l.pow(r)),
×
914
                _ => SymbolExpr::Binary {
1,030✔
915
                    op: BinaryOp::Pow,
1,030✔
916
                    lhs: Arc::new(SymbolExpr::Value(*l)),
1,030✔
917
                    rhs: Arc::new(rhs.clone()),
1,030✔
918
                },
1,030✔
919
            },
920
            _ => SymbolExpr::Binary {
1,986✔
921
                op: BinaryOp::Pow,
1,986✔
922
                lhs: Arc::new(self.clone()),
1,986✔
923
                rhs: Arc::new(rhs.clone()),
1,986✔
924
            },
1,986✔
925
        }
926
    }
3,016✔
927

928
    pub fn string_id(&self) -> String {
9,505,666✔
929
        self.repr(true)
9,505,666✔
930
    }
9,505,666✔
931

932
    // Add with heuristic optimization
933
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,571,184✔
934
        if self.is_zero() {
2,571,184✔
935
            Some(rhs.clone())
1,301,224✔
936
        } else if rhs.is_zero() {
1,269,960✔
937
            Some(self.clone())
1,020,980✔
938
        } else {
939
            // if neg operation, call sub_opt
940
            if let SymbolExpr::Unary { op, expr } = rhs {
248,980✔
941
                if let UnaryOp::Neg = op {
16,272✔
942
                    return self.sub_opt(expr, recursive);
14,308✔
943
                }
1,964✔
944
            } else if recursive {
232,708✔
945
                if let SymbolExpr::Binary {
946
                    op,
60,484✔
947
                    lhs: r_lhs,
60,484✔
948
                    rhs: r_rhs,
60,484✔
949
                } = rhs
65,222✔
950
                {
951
                    // recursive optimization for add and sub
952
                    if let BinaryOp::Add = &op {
60,484✔
953
                        if let Some(e) = self.add_opt(r_lhs, true) {
5,080✔
954
                            return match e.add_opt(r_rhs, true) {
48✔
955
                                Some(ee) => Some(ee),
42✔
956
                                None => Some(_add(e, r_rhs.as_ref().clone())),
6✔
957
                            };
958
                        }
5,032✔
959
                        if let Some(e) = self.add_opt(r_rhs, true) {
5,032✔
UNCOV
960
                            return match e.add_opt(r_lhs, true) {
×
961
                                Some(ee) => Some(ee),
×
UNCOV
962
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
963
                            };
964
                        }
5,032✔
965
                    }
55,404✔
966
                    if let BinaryOp::Sub = &op {
60,436✔
967
                        if let Some(e) = self.add_opt(r_lhs, true) {
4,692✔
968
                            return match e.sub_opt(r_rhs, true) {
94✔
969
                                Some(ee) => Some(ee),
94✔
UNCOV
970
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
×
971
                            };
972
                        }
4,598✔
973
                        if let Some(e) = self.sub_opt(r_rhs, true) {
4,598✔
UNCOV
974
                            return match e.add_opt(r_lhs, true) {
×
975
                                Some(ee) => Some(ee),
×
UNCOV
976
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
977
                            };
978
                        }
4,598✔
979
                    }
55,744✔
980
                }
4,738✔
981
            }
167,486✔
982

983
            // optimization for each node type
984
            match self {
234,530✔
985
                SymbolExpr::Value(l) => match rhs {
84,764✔
986
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
70,054✔
987
                    SymbolExpr::Binary {
988
                        op,
6,046✔
989
                        lhs: r_lhs,
6,046✔
990
                        rhs: r_rhs,
6,046✔
991
                    } => {
992
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
6,046✔
993
                            let t = l + v;
4,548✔
994
                            match op {
4,548✔
995
                                BinaryOp::Add => {
996
                                    if t.is_zero() {
12✔
997
                                        Some(r_rhs.as_ref().clone())
×
998
                                    } else {
999
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
12✔
1000
                                    }
1001
                                }
1002
                                BinaryOp::Sub => {
1003
                                    if t.is_zero() {
×
1004
                                        match r_rhs.neg_opt() {
×
1005
                                            Some(e) => Some(e),
×
1006
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1007
                                        }
1008
                                    } else {
1009
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1010
                                    }
1011
                                }
1012
                                _ => None,
4,536✔
1013
                            }
1014
                        } else {
1015
                            None
1,498✔
1016
                        }
1017
                    }
1018
                    _ => None,
8,664✔
1019
                },
1020
                SymbolExpr::Symbol(l) => match rhs {
17,174✔
1021
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
2,520✔
1022
                    SymbolExpr::Symbol(r) => {
11,358✔
1023
                        if r == l {
11,358✔
1024
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
232✔
1025
                        } else if r < l {
11,126✔
1026
                            Some(_add(rhs.clone(), self.clone()))
1,532✔
1027
                        } else {
1028
                            None
9,594✔
1029
                        }
1030
                    }
1031
                    SymbolExpr::Binary {
1032
                        op,
3,296✔
1033
                        lhs: r_lhs,
3,296✔
1034
                        rhs: r_rhs,
3,296✔
1035
                    } => {
1036
                        if let (
1037
                            BinaryOp::Mul | BinaryOp::Div,
1038
                            SymbolExpr::Value(v),
2,200✔
1039
                            SymbolExpr::Symbol(s),
2,200✔
1040
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,296✔
1041
                        {
1042
                            if l == s {
2,200✔
1043
                                let t = v + &Value::Int(1);
6✔
1044
                                if t.is_zero() {
6✔
1045
                                    Some(SymbolExpr::Value(Value::Int(0)))
2✔
1046
                                } else {
1047
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
4✔
1048
                                }
1049
                            } else {
1050
                                None
2,194✔
1051
                            }
1052
                        } else {
1053
                            None
1,096✔
1054
                        }
1055
                    }
1056
                    _ => None,
×
1057
                },
1058
                SymbolExpr::Unary { op, expr } => {
14,066✔
1059
                    if let UnaryOp::Neg = op {
14,066✔
1060
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
12,598✔
1061
                            return match e.neg_opt() {
4,856✔
1062
                                Some(ee) => Some(ee),
4,856✔
1063
                                None => Some(_neg(e)),
×
1064
                            };
1065
                        }
7,742✔
1066
                    } else if let SymbolExpr::Unary {
1067
                        op: rop,
728✔
1068
                        expr: rexpr,
728✔
1069
                    } = rhs
1,468✔
1070
                    {
1071
                        if op == rop {
728✔
1072
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
388✔
1073
                                if t.is_zero() {
12✔
1074
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1075
                                }
12✔
1076
                            }
376✔
1077
                        }
340✔
1078
                    }
740✔
1079

1080
                    // swap nodes by sorting rule
1081
                    match rhs {
9,210✔
1082
                        SymbolExpr::Binary { op: rop, .. } => {
6,676✔
1083
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
6,676✔
1084
                                if self > rhs {
5,926✔
1085
                                    Some(_add(rhs.clone(), self.clone()))
×
1086
                                } else {
1087
                                    None
5,926✔
1088
                                }
1089
                            } else {
1090
                                None
750✔
1091
                            }
1092
                        }
1093
                        _ => {
1094
                            if self > rhs {
2,534✔
1095
                                Some(_add(rhs.clone(), self.clone()))
40✔
1096
                            } else {
1097
                                None
2,494✔
1098
                            }
1099
                        }
1100
                    }
1101
                }
1102
                SymbolExpr::Binary {
1103
                    op,
118,526✔
1104
                    lhs: l_lhs,
118,526✔
1105
                    rhs: l_rhs,
118,526✔
1106
                } => {
1107
                    if let SymbolExpr::Binary {
1108
                        op: rop,
109,722✔
1109
                        lhs: r_lhs,
109,722✔
1110
                        rhs: r_rhs,
109,722✔
1111
                    } = rhs
118,526✔
1112
                    {
1113
                        match (
1114
                            l_lhs.as_ref(),
109,722✔
1115
                            l_rhs.as_ref(),
109,722✔
1116
                            r_lhs.as_ref(),
109,722✔
1117
                            r_rhs.as_ref(),
109,722✔
1118
                        ) {
1119
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
13,534✔
1120
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
13,534✔
1121
                                    let t = SymbolExpr::Value(lv + rv);
1,604✔
1122
                                    if t.is_zero() {
1,604✔
1123
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,284✔
1124
                                    }
320✔
1125
                                    match (op, rop) {
320✔
1126
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1127
                                            return match t.mul_opt(l_rhs, recursive) {
224✔
1128
                                                Some(e) => Some(e),
8✔
1129
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
216✔
1130
                                            }
1131
                                        }
1132
                                        (BinaryOp::Div, BinaryOp::Div) => {
1133
                                            return match t.div_opt(l_rhs, recursive) {
×
1134
                                                Some(e) => Some(e),
×
1135
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1136
                                            }
1137
                                        }
1138
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1139
                                            return match t.pow_opt(l_rhs) {
96✔
1140
                                                Some(e) => Some(e),
96✔
1141
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1142
                                            }
1143
                                        }
1144
                                        (_, _) => (),
×
1145
                                    }
1146
                                }
11,930✔
1147
                            }
1148
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2,336✔
1149
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
2,336✔
1150
                                    if l_lhs.expand().string_id() == r_lhs.expand().string_id()
×
1151
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
×
1152
                                            == r_lhs.expand().string_id()
×
1153
                                    {
1154
                                        let tl =
×
1155
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
×
1156
                                        let tr =
×
1157
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
×
1158
                                        let b = SymbolExpr::Value(lv * rv);
×
1159
                                        return match tl.add_opt(&tr, recursive) {
×
1160
                                            Some(e) => Some(_div(e, b)),
×
1161
                                            None => Some(_div(_add(tl, tr), b)),
×
1162
                                        };
1163
                                    }
×
1164
                                }
2,336✔
1165
                            }
1166
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
384✔
1167
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
384✔
1168
                                    if l_rhs.expand().string_id() == r_lhs.expand().string_id()
×
1169
                                        || _neg(l_rhs.as_ref().clone()).expand().string_id()
×
1170
                                            == r_lhs.expand().string_id()
×
1171
                                    {
1172
                                        let r = _mul(
×
1173
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
×
1174
                                            r_lhs.as_ref().clone(),
×
1175
                                        );
1176
                                        if let Some(e) = self.add_opt(&r, recursive) {
×
1177
                                            return Some(e);
×
1178
                                        }
×
1179
                                    }
×
1180
                                }
384✔
1181
                            }
1182
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
340✔
1183
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
340✔
1184
                                    if l_lhs.expand().string_id() == r_rhs.expand().string_id()
4✔
1185
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
×
1186
                                            == r_rhs.expand().string_id()
×
1187
                                    {
1188
                                        let l = _mul(
4✔
1189
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
4✔
1190
                                            l_lhs.as_ref().clone(),
4✔
1191
                                        );
1192
                                        if let Some(e) = l.add_opt(rhs, recursive) {
4✔
1193
                                            return Some(e);
4✔
1194
                                        }
×
1195
                                    }
×
1196
                                }
336✔
1197
                            }
1198
                            (_, _, _, _) => (),
93,128✔
1199
                        }
1200

1201
                        if op == rop {
108,114✔
1202
                            if let Some(e) = rhs.neg_opt() {
47,282✔
1203
                                if self.expand().string_id() == e.expand().string_id() {
31,022✔
1204
                                    return Some(SymbolExpr::Value(Value::Int(0)));
4✔
1205
                                }
31,018✔
1206
                            }
16,260✔
1207
                        }
60,832✔
1208
                    } else if let SymbolExpr::Symbol(r) = rhs {
8,804✔
1209
                        if let (
1210
                            BinaryOp::Mul | BinaryOp::Div,
1211
                            SymbolExpr::Value(v),
1,678✔
1212
                            SymbolExpr::Symbol(s),
1,678✔
1213
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,030✔
1214
                        {
1215
                            if s == r {
1,678✔
1216
                                let t = v + &Value::Int(1);
×
1217
                                if t.is_zero() {
×
1218
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1219
                                } else {
1220
                                    return Some(_mul(
×
1221
                                        SymbolExpr::Value(t),
×
1222
                                        l_rhs.as_ref().clone(),
×
1223
                                    ));
×
1224
                                }
1225
                            }
1,678✔
1226
                        }
3,352✔
1227
                    }
3,774✔
1228
                    if recursive {
116,914✔
1229
                        if let BinaryOp::Add = op {
55,252✔
1230
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
7,910✔
1231
                                return match e.add_opt(l_rhs, true) {
418✔
1232
                                    Some(ee) => Some(ee),
278✔
1233
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
140✔
1234
                                };
1235
                            }
7,492✔
1236
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,492✔
1237
                                return match l_lhs.add_opt(&e, true) {
180✔
1238
                                    Some(ee) => Some(ee),
×
1239
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
180✔
1240
                                };
1241
                            }
7,312✔
1242
                        } else if let BinaryOp::Sub = op {
47,342✔
1243
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
7,174✔
1244
                                return match e.sub_opt(l_rhs, true) {
966✔
1245
                                    Some(ee) => Some(ee),
386✔
1246
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
580✔
1247
                                };
1248
                            }
6,208✔
1249
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
6,208✔
1250
                                return match l_lhs.sub_opt(&e, true) {
186✔
1251
                                    Some(ee) => Some(ee),
44✔
1252
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
142✔
1253
                                };
1254
                            }
6,022✔
1255
                        }
40,168✔
1256
                    }
61,662✔
1257
                    // swap nodes by sorting rule
1258
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
115,164✔
1259
                        match rhs {
55,006✔
1260
                            SymbolExpr::Binary { op: rop, .. } => {
51,628✔
1261
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
51,628✔
1262
                                    if self > rhs {
45,574✔
1263
                                        Some(_add(rhs.clone(), self.clone()))
376✔
1264
                                    } else {
1265
                                        None
45,198✔
1266
                                    }
1267
                                } else {
1268
                                    None
6,054✔
1269
                                }
1270
                            }
1271
                            _ => {
1272
                                if self > rhs {
3,378✔
1273
                                    Some(_add(rhs.clone(), self.clone()))
3,378✔
1274
                                } else {
1275
                                    None
×
1276
                                }
1277
                            }
1278
                        }
1279
                    } else {
1280
                        None
60,158✔
1281
                    }
1282
                }
1283
            }
1284
        }
1285
    }
2,571,184✔
1286

1287
    /// Sub with heuristic optimization
1288
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
195,704✔
1289
        if self.is_zero() {
195,704✔
1290
            match rhs.neg_opt() {
6,992✔
1291
                Some(e) => Some(e),
5,594✔
1292
                None => Some(_neg(rhs.clone())),
1,398✔
1293
            }
1294
        } else if rhs.is_zero() {
188,712✔
1295
            Some(self.clone())
3,126✔
1296
        } else {
1297
            // if neg, call add_opt
1298
            if let SymbolExpr::Unary { op, expr } = rhs {
185,586✔
1299
                if let UnaryOp::Neg = op {
4,876✔
1300
                    return self.add_opt(expr, recursive);
2,492✔
1301
                }
2,384✔
1302
            } else if recursive {
180,710✔
1303
                if let SymbolExpr::Binary {
1304
                    op,
59,906✔
1305
                    lhs: r_lhs,
59,906✔
1306
                    rhs: r_rhs,
59,906✔
1307
                } = rhs
73,308✔
1308
                {
1309
                    // recursive optimization for add and sub
1310
                    if let BinaryOp::Add = &op {
59,906✔
1311
                        if let Some(e) = self.sub_opt(r_lhs, true) {
5,270✔
1312
                            return match e.sub_opt(r_rhs, true) {
712✔
1313
                                Some(ee) => Some(ee),
708✔
1314
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
4✔
1315
                            };
1316
                        }
4,558✔
1317
                        if let Some(e) = self.sub_opt(r_rhs, true) {
4,558✔
UNCOV
1318
                            return match e.sub_opt(r_lhs, true) {
×
1319
                                Some(ee) => Some(ee),
×
UNCOV
1320
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
×
1321
                            };
1322
                        }
4,558✔
1323
                    }
54,636✔
1324
                    if let BinaryOp::Sub = &op {
59,194✔
1325
                        if let Some(e) = self.sub_opt(r_lhs, true) {
5,612✔
1326
                            return match e.add_opt(r_rhs, true) {
624✔
1327
                                Some(ee) => Some(ee),
616✔
1328
                                None => Some(_add(e, r_rhs.as_ref().clone())),
8✔
1329
                            };
1330
                        }
4,988✔
1331
                        if let Some(e) = self.add_opt(r_rhs, true) {
4,988✔
UNCOV
1332
                            return match e.sub_opt(r_lhs, true) {
×
1333
                                Some(ee) => Some(ee),
×
UNCOV
1334
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
×
1335
                            };
1336
                        }
4,988✔
1337
                    }
53,582✔
1338
                }
13,402✔
1339
            }
107,402✔
1340

1341
            // optimization for each type
1342
            match self {
181,758✔
1343
                SymbolExpr::Value(l) => match &rhs {
68,340✔
1344
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
57,988✔
1345
                    SymbolExpr::Binary {
1346
                        op,
5,908✔
1347
                        lhs: r_lhs,
5,908✔
1348
                        rhs: r_rhs,
5,908✔
1349
                    } => {
1350
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,908✔
1351
                            let t = l - v;
3,302✔
1352
                            match op {
3,302✔
1353
                                BinaryOp::Add => {
1354
                                    if t.is_zero() {
×
1355
                                        match r_rhs.neg_opt() {
×
1356
                                            Some(e) => Some(e),
×
1357
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1358
                                        }
1359
                                    } else {
1360
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1361
                                    }
1362
                                }
1363
                                BinaryOp::Sub => {
1364
                                    if t.is_zero() {
×
1365
                                        Some(r_rhs.as_ref().clone())
×
1366
                                    } else {
1367
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1368
                                    }
1369
                                }
1370
                                _ => None,
3,302✔
1371
                            }
1372
                        } else {
1373
                            None
2,606✔
1374
                        }
1375
                    }
1376
                    _ => None,
4,444✔
1377
                },
1378
                SymbolExpr::Symbol(l) => match &rhs {
27,430✔
1379
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
3,190✔
1380
                    SymbolExpr::Symbol(r) => {
20,006✔
1381
                        if r == l {
20,006✔
1382
                            Some(SymbolExpr::Value(Value::Int(0)))
12,534✔
1383
                        } else if r < l {
7,472✔
1384
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,216✔
1385
                        } else {
1386
                            None
6,256✔
1387
                        }
1388
                    }
1389
                    SymbolExpr::Binary {
1390
                        op,
4,234✔
1391
                        lhs: r_lhs,
4,234✔
1392
                        rhs: r_rhs,
4,234✔
1393
                    } => {
1394
                        if let (
1395
                            BinaryOp::Mul | BinaryOp::Div,
1396
                            SymbolExpr::Value(v),
2,316✔
1397
                            SymbolExpr::Symbol(s),
2,316✔
1398
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
4,234✔
1399
                        {
1400
                            if l == s {
2,316✔
1401
                                let t = &Value::Int(1) - v;
10✔
1402
                                if t.is_zero() {
10✔
1403
                                    Some(SymbolExpr::Value(Value::Int(0)))
×
1404
                                } else {
1405
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
10✔
1406
                                }
1407
                            } else {
1408
                                None
2,306✔
1409
                            }
1410
                        } else {
1411
                            None
1,918✔
1412
                        }
1413
                    }
1414
                    _ => None,
×
1415
                },
1416
                SymbolExpr::Unary { op, expr } => {
12,448✔
1417
                    if let UnaryOp::Neg = op {
12,448✔
1418
                        if let Some(e) = expr.add_opt(rhs, recursive) {
10,284✔
1419
                            return match e.neg_opt() {
4,646✔
1420
                                Some(ee) => Some(ee),
4,646✔
1421
                                None => Some(_neg(e)),
×
1422
                            };
1423
                        }
5,638✔
1424
                    }
2,164✔
1425
                    if let SymbolExpr::Unary {
1426
                        op: rop,
1,566✔
1427
                        expr: rexpr,
1,566✔
1428
                    } = rhs
7,802✔
1429
                    {
1430
                        if op == rop {
1,566✔
1431
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
1,060✔
1432
                                if t.is_zero() {
784✔
1433
                                    return Some(SymbolExpr::Value(Value::Int(0)));
784✔
1434
                                }
×
1435
                            }
276✔
1436
                        }
506✔
1437
                    }
6,236✔
1438

1439
                    // swap nodes by sorting rule
1440
                    match rhs {
7,018✔
1441
                        SymbolExpr::Binary { op: rop, .. } => {
5,292✔
1442
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
5,292✔
1443
                                if self > rhs {
4,498✔
1444
                                    match rhs.neg_opt() {
×
1445
                                        Some(e) => Some(_add(e, self.clone())),
×
1446
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
×
1447
                                    }
1448
                                } else {
1449
                                    None
4,498✔
1450
                                }
1451
                            } else {
1452
                                None
794✔
1453
                            }
1454
                        }
1455
                        _ => {
1456
                            if self > rhs {
1,726✔
1457
                                match rhs.neg_opt() {
28✔
1458
                                    Some(e) => Some(_add(e, self.clone())),
×
1459
                                    None => Some(_add(_neg(rhs.clone()), self.clone())),
28✔
1460
                                }
1461
                            } else {
1462
                                None
1,698✔
1463
                            }
1464
                        }
1465
                    }
1466
                }
1467
                SymbolExpr::Binary {
1468
                    op,
73,540✔
1469
                    lhs: l_lhs,
73,540✔
1470
                    rhs: l_rhs,
73,540✔
1471
                } => {
1472
                    if let SymbolExpr::Binary {
1473
                        op: rop,
60,780✔
1474
                        lhs: r_lhs,
60,780✔
1475
                        rhs: r_rhs,
60,780✔
1476
                    } = rhs
73,540✔
1477
                    {
1478
                        match (
1479
                            l_lhs.as_ref(),
60,780✔
1480
                            l_rhs.as_ref(),
60,780✔
1481
                            r_lhs.as_ref(),
60,780✔
1482
                            r_rhs.as_ref(),
60,780✔
1483
                        ) {
1484
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
7,504✔
1485
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
7,504✔
1486
                                    let t = SymbolExpr::Value(lv - rv);
1,146✔
1487
                                    if t.is_zero() {
1,146✔
1488
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,146✔
1489
                                    }
×
1490
                                    match (op, rop) {
×
1491
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1492
                                            return match t.mul_opt(l_rhs, recursive) {
×
1493
                                                Some(e) => Some(e),
×
1494
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
×
1495
                                            }
1496
                                        }
1497
                                        (BinaryOp::Div, BinaryOp::Div) => {
1498
                                            return match t.div_opt(l_rhs, recursive) {
×
1499
                                                Some(e) => Some(e),
×
1500
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1501
                                            }
1502
                                        }
1503
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1504
                                            return match t.pow_opt(l_rhs) {
×
1505
                                                Some(e) => Some(e),
×
1506
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1507
                                            }
1508
                                        }
1509
                                        (_, _) => (),
×
1510
                                    }
1511
                                }
6,358✔
1512
                            }
1513
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
460✔
1514
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
460✔
1515
                                    if l_lhs.expand().string_id() == r_lhs.expand().string_id()
10✔
1516
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
4✔
1517
                                            == r_lhs.expand().string_id()
4✔
1518
                                    {
1519
                                        let tl =
6✔
1520
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
6✔
1521
                                        let tr =
6✔
1522
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
6✔
1523
                                        let b = SymbolExpr::Value(lv * rv);
6✔
1524
                                        return match tl.sub_opt(&tr, recursive) {
6✔
1525
                                            Some(e) => Some(_div(e, b)),
6✔
1526
                                            None => Some(_div(_sub(tl, tr), b)),
×
1527
                                        };
1528
                                    }
4✔
1529
                                }
450✔
1530
                            }
1531
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
226✔
1532
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
226✔
1533
                                    if l_rhs.expand().string_id() == r_lhs.expand().string_id()
2✔
1534
                                        || _neg(l_rhs.as_ref().clone()).expand().string_id()
×
1535
                                            == r_lhs.expand().string_id()
×
1536
                                    {
1537
                                        let r = _mul(
2✔
1538
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
2✔
1539
                                            r_lhs.as_ref().clone(),
2✔
1540
                                        );
1541
                                        if let Some(e) = self.sub_opt(&r, recursive) {
2✔
1542
                                            return Some(e);
2✔
1543
                                        }
×
1544
                                    }
×
1545
                                }
224✔
1546
                            }
1547
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
256✔
1548
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
256✔
1549
                                    if l_lhs.expand().string_id() == r_rhs.expand().string_id()
8✔
1550
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
8✔
1551
                                            == r_rhs.expand().string_id()
8✔
1552
                                    {
1553
                                        let l = _mul(
8✔
1554
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
8✔
1555
                                            l_lhs.as_ref().clone(),
8✔
1556
                                        );
1557
                                        if let Some(e) = l.sub_opt(rhs, recursive) {
8✔
1558
                                            return Some(e);
8✔
1559
                                        }
×
1560
                                    }
×
1561
                                }
248✔
1562
                            }
1563
                            (_, _, _, _) => (),
52,334✔
1564
                        }
1565

1566
                        if op == rop && self.expand().string_id() == rhs.expand().string_id() {
59,618✔
1567
                            return Some(SymbolExpr::Value(Value::Int(0)));
288✔
1568
                        }
59,330✔
1569
                    } else if let SymbolExpr::Symbol(r) = rhs {
12,760✔
1570
                        if let (
1571
                            BinaryOp::Mul | BinaryOp::Div,
1572
                            SymbolExpr::Value(v),
1,636✔
1573
                            SymbolExpr::Symbol(s),
1,636✔
1574
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,706✔
1575
                        {
1576
                            if s == r {
1,636✔
1577
                                let t = v - &Value::Int(1);
20✔
1578
                                if t.is_zero() {
20✔
1579
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1580
                                } else {
1581
                                    return Some(_mul(
20✔
1582
                                        SymbolExpr::Value(t),
20✔
1583
                                        l_rhs.as_ref().clone(),
20✔
1584
                                    ));
20✔
1585
                                }
1586
                            }
1,616✔
1587
                        }
4,070✔
1588
                    }
7,054✔
1589
                    if recursive {
72,070✔
1590
                        if let BinaryOp::Add = op {
55,080✔
1591
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
9,390✔
1592
                                return match e.add_opt(l_rhs, true) {
2,434✔
1593
                                    Some(ee) => Some(ee),
1,972✔
1594
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
462✔
1595
                                };
1596
                            }
6,956✔
1597
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
6,956✔
1598
                                return match l_lhs.add_opt(&e, true) {
928✔
1599
                                    Some(ee) => Some(ee),
776✔
1600
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
152✔
1601
                                };
1602
                            }
6,028✔
1603
                        }
45,690✔
1604
                        if let BinaryOp::Sub = op {
51,718✔
1605
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
9,670✔
1606
                                return match e.sub_opt(l_rhs, true) {
710✔
1607
                                    Some(ee) => Some(ee),
326✔
1608
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
384✔
1609
                                };
1610
                            }
8,960✔
1611
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
8,960✔
1612
                                return match l_lhs.sub_opt(&e, true) {
130✔
1613
                                    Some(ee) => Some(ee),
×
1614
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
130✔
1615
                                };
1616
                            }
8,830✔
1617
                        }
42,048✔
1618
                    }
16,990✔
1619
                    // swap nodes by sorting rule
1620
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
67,868✔
1621
                        match rhs {
42,158✔
1622
                            SymbolExpr::Binary { op: rop, .. } => {
37,780✔
1623
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
37,780✔
1624
                                    if self > rhs {
31,990✔
1625
                                        match rhs.neg_opt() {
70✔
1626
                                            Some(e) => Some(_add(e, self.clone())),
2✔
1627
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
68✔
1628
                                        }
1629
                                    } else {
1630
                                        None
31,920✔
1631
                                    }
1632
                                } else {
1633
                                    None
5,790✔
1634
                                }
1635
                            }
1636
                            _ => {
1637
                                if self > rhs {
4,378✔
1638
                                    match rhs.neg_opt() {
4,378✔
1639
                                        Some(e) => Some(_add(e, self.clone())),
1,722✔
1640
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
2,656✔
1641
                                    }
1642
                                } else {
1643
                                    None
×
1644
                                }
1645
                            }
1646
                        }
1647
                    } else {
1648
                        None
25,710✔
1649
                    }
1650
                }
1651
            }
1652
        }
1653
    }
195,704✔
1654

1655
    /// Mul with heuristic optimization
1656
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,768,902✔
1657
        if self.is_zero() {
2,768,902✔
1658
            Some(self.clone())
22,524✔
1659
        } else if rhs.is_zero() || self.is_one() {
2,746,378✔
1660
            Some(rhs.clone())
2,369,108✔
1661
        } else if rhs.is_one() {
377,270✔
1662
            Some(self.clone())
82,468✔
1663
        } else if self.is_minus_one() {
294,802✔
1664
            match rhs.neg_opt() {
3,260✔
1665
                Some(e) => Some(e),
1,236✔
1666
                None => Some(_neg(rhs.clone())),
2,024✔
1667
            }
1668
        } else if rhs.is_minus_one() {
291,542✔
1669
            match self.neg_opt() {
27,058✔
1670
                Some(e) => Some(e),
8,924✔
1671
                None => Some(_neg(self.clone())),
18,134✔
1672
            }
1673
        } else {
1674
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
264,484✔
1675
                if let SymbolExpr::Unary { .. } = self {
217,900✔
1676
                    return match rhs.mul_opt(self, recursive) {
5,596✔
1677
                        Some(e) => Some(e),
5,296✔
1678
                        None => Some(_mul(rhs.clone(), self.clone())),
300✔
1679
                    };
1680
                }
212,304✔
1681
            }
46,584✔
1682

1683
            match self {
258,888✔
1684
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
171,490✔
1685
                SymbolExpr::Symbol(e) => match rhs {
34,424✔
1686
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
15,896✔
1687
                    SymbolExpr::Symbol(r) => {
11,934✔
1688
                        if r < e {
11,934✔
1689
                            Some(_mul(rhs.clone(), self.clone()))
5,042✔
1690
                        } else {
1691
                            None
6,892✔
1692
                        }
1693
                    }
1694
                    SymbolExpr::Unary {
1695
                        op: UnaryOp::Neg,
1696
                        expr,
2,088✔
1697
                    } => match expr.as_ref() {
2,088✔
1698
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1699
                        SymbolExpr::Symbol(s) => {
2,088✔
1700
                            if s < e {
2,088✔
1701
                                Some(_neg(_mul(expr.as_ref().clone(), self.clone())))
1,456✔
1702
                            } else {
1703
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
632✔
1704
                            }
1705
                        }
1706
                        SymbolExpr::Binary { .. } => match self.mul_opt(expr, recursive) {
×
1707
                            Some(e) => match e.neg_opt() {
×
1708
                                Some(ee) => Some(ee),
×
1709
                                None => Some(_neg(e)),
×
1710
                            },
1711
                            None => None,
×
1712
                        },
1713
                        _ => None,
×
1714
                    },
1715
                    _ => None,
4,506✔
1716
                },
1717
                SymbolExpr::Unary { op, expr } => match op {
1,414✔
1718
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
1,404✔
1719
                        Some(e) => match e.neg_opt() {
300✔
1720
                            Some(ee) => Some(ee),
300✔
1721
                            None => Some(_neg(e)),
×
1722
                        },
1723
                        None => None,
1,104✔
1724
                    },
1725
                    UnaryOp::Abs => match rhs {
2✔
1726
                        SymbolExpr::Unary {
1727
                            op: UnaryOp::Abs,
1728
                            expr: rexpr,
2✔
1729
                        } => match expr.mul_opt(rexpr, recursive) {
2✔
1730
                            Some(e) => Some(SymbolExpr::Unary {
×
1731
                                op: UnaryOp::Abs,
×
1732
                                expr: Arc::new(e),
×
1733
                            }),
×
1734
                            None => Some(SymbolExpr::Unary {
2✔
1735
                                op: UnaryOp::Abs,
2✔
1736
                                expr: Arc::new(_mul(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
1737
                            }),
2✔
1738
                        },
1739
                        _ => None,
×
1740
                    },
1741
                    _ => None,
8✔
1742
                },
1743
                SymbolExpr::Binary {
1744
                    op,
51,560✔
1745
                    lhs: l_lhs,
51,560✔
1746
                    rhs: l_rhs,
51,560✔
1747
                } => {
1748
                    if recursive {
51,560✔
1749
                        if let SymbolExpr::Binary {
1750
                            op: rop,
330✔
1751
                            lhs: r_lhs,
330✔
1752
                            rhs: r_rhs,
330✔
1753
                        } = rhs
4,722✔
1754
                        {
1755
                            if let BinaryOp::Mul = &rop {
330✔
1756
                                if let Some(e) = self.mul_opt(r_lhs, true) {
322✔
1757
                                    return match e.mul_opt(r_rhs, true) {
322✔
1758
                                        Some(ee) => Some(ee),
252✔
1759
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
70✔
1760
                                    };
1761
                                }
×
1762
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
1763
                                    return match e.mul_opt(r_lhs, true) {
×
1764
                                        Some(ee) => Some(ee),
×
1765
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1766
                                    };
1767
                                }
×
1768
                            }
8✔
1769
                            if let BinaryOp::Div = &rop {
8✔
1770
                                if let Some(e) = self.mul_opt(r_lhs, true) {
×
1771
                                    return match e.div_opt(r_rhs, true) {
×
1772
                                        Some(ee) => Some(ee),
×
1773
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
1774
                                    };
1775
                                }
×
1776
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
1777
                                    return match e.mul_opt(r_lhs, true) {
×
1778
                                        Some(ee) => Some(ee),
×
1779
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1780
                                    };
1781
                                }
×
1782
                            }
8✔
1783
                        }
4,392✔
1784

1785
                        if let BinaryOp::Mul = &op {
4,400✔
1786
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
4,392✔
1787
                                return match e.mul_opt(l_rhs, true) {
1,264✔
1788
                                    Some(ee) => Some(ee),
1,120✔
1789
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1790
                                };
1791
                            }
3,128✔
1792
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
3,128✔
1793
                                return match l_lhs.mul_opt(&e, true) {
1,886✔
1794
                                    Some(ee) => Some(ee),
×
1795
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
1,886✔
1796
                                };
1797
                            }
1,242✔
1798
                        } else if let BinaryOp::Div = &op {
8✔
1799
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
8✔
1800
                                return match e.div_opt(l_rhs, true) {
×
1801
                                    Some(ee) => Some(ee),
×
1802
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
1803
                                };
1804
                            }
8✔
1805
                            if let Some(e) = rhs.div_opt(l_rhs, true) {
8✔
1806
                                return match l_lhs.mul_opt(&e, true) {
×
1807
                                    Some(ee) => Some(ee),
×
1808
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1809
                                };
1810
                            }
8✔
1811
                        }
×
1812
                        None
1,250✔
1813
                    } else {
1814
                        match rhs {
46,838✔
1815
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
30,718✔
1816
                                SymbolExpr::Value(lv) => match op {
10,358✔
1817
                                    BinaryOp::Mul => Some(_mul(
9,662✔
1818
                                        SymbolExpr::Value(lv * v),
9,662✔
1819
                                        l_rhs.as_ref().clone(),
9,662✔
1820
                                    )),
9,662✔
1821
                                    BinaryOp::Div => Some(_div(
×
1822
                                        SymbolExpr::Value(lv * v),
×
1823
                                        l_rhs.as_ref().clone(),
×
1824
                                    )),
×
1825
                                    _ => None,
696✔
1826
                                },
1827
                                _ => match l_rhs.as_ref() {
20,360✔
1828
                                    SymbolExpr::Value(rv) => match op {
576✔
1829
                                        BinaryOp::Mul => Some(_mul(
×
1830
                                            SymbolExpr::Value(rv * v),
×
1831
                                            l_lhs.as_ref().clone(),
×
1832
                                        )),
×
1833
                                        BinaryOp::Div => Some(_mul(
×
1834
                                            SymbolExpr::Value(v / rv),
×
1835
                                            l_lhs.as_ref().clone(),
×
1836
                                        )),
×
1837
                                        _ => None,
576✔
1838
                                    },
1839
                                    _ => None,
19,784✔
1840
                                },
1841
                            },
1842
                            SymbolExpr::Binary {
1843
                                op: rop,
9,560✔
1844
                                lhs: r_lhs,
9,560✔
1845
                                rhs: r_rhs,
9,560✔
1846
                            } => match (op, rop) {
9,560✔
1847
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1848
                                    l_lhs.as_ref(),
944✔
1849
                                    l_rhs.as_ref(),
944✔
1850
                                    r_lhs.as_ref(),
944✔
1851
                                    r_rhs.as_ref(),
944✔
1852
                                ) {
1853
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
944✔
1854
                                        Some(_mul(
944✔
1855
                                            SymbolExpr::Value(lv * rv),
944✔
1856
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
944✔
1857
                                        ))
944✔
1858
                                    }
1859
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1860
                                        Some(_mul(
×
1861
                                            SymbolExpr::Value(lv * rv),
×
1862
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1863
                                        ))
×
1864
                                    }
1865
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1866
                                        Some(_mul(
×
1867
                                            SymbolExpr::Value(lv * rv),
×
1868
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1869
                                        ))
×
1870
                                    }
1871
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1872
                                        Some(_mul(
×
1873
                                            SymbolExpr::Value(lv * rv),
×
1874
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1875
                                        ))
×
1876
                                    }
1877
                                    (_, _, _, _) => None,
×
1878
                                },
1879
                                (BinaryOp::Mul, BinaryOp::Div) => match (
1880
                                    l_lhs.as_ref(),
×
1881
                                    l_rhs.as_ref(),
×
1882
                                    r_lhs.as_ref(),
×
1883
                                    r_rhs.as_ref(),
×
1884
                                ) {
1885
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1886
                                        Some(_mul(
×
1887
                                            SymbolExpr::Value(lv * rv),
×
1888
                                            _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1889
                                        ))
×
1890
                                    }
1891
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1892
                                        Some(_mul(
×
1893
                                            SymbolExpr::Value(lv / rv),
×
1894
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1895
                                        ))
×
1896
                                    }
1897
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1898
                                        Some(_mul(
×
1899
                                            SymbolExpr::Value(lv * rv),
×
1900
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1901
                                        ))
×
1902
                                    }
1903
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1904
                                        Some(_mul(
×
1905
                                            SymbolExpr::Value(lv / rv),
×
1906
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1907
                                        ))
×
1908
                                    }
1909
                                    (_, _, _, _) => None,
×
1910
                                },
1911
                                (BinaryOp::Div, BinaryOp::Mul) => match (
1912
                                    l_lhs.as_ref(),
×
1913
                                    l_rhs.as_ref(),
×
1914
                                    r_lhs.as_ref(),
×
1915
                                    r_rhs.as_ref(),
×
1916
                                ) {
1917
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1918
                                        Some(_mul(
×
1919
                                            SymbolExpr::Value(lv * rv),
×
1920
                                            _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1921
                                        ))
×
1922
                                    }
1923
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1924
                                        Some(_mul(
×
1925
                                            SymbolExpr::Value(lv * rv),
×
1926
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1927
                                        ))
×
1928
                                    }
1929
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1930
                                        Some(_mul(
×
1931
                                            SymbolExpr::Value(rv / lv),
×
1932
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1933
                                        ))
×
1934
                                    }
1935
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1936
                                        Some(_mul(
×
1937
                                            SymbolExpr::Value(rv / lv),
×
1938
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1939
                                        ))
×
1940
                                    }
1941
                                    (_, _, _, _) => None,
×
1942
                                },
1943
                                (BinaryOp::Div, BinaryOp::Div) => match (
1944
                                    l_lhs.as_ref(),
2✔
1945
                                    l_rhs.as_ref(),
2✔
1946
                                    r_lhs.as_ref(),
2✔
1947
                                    r_rhs.as_ref(),
2✔
1948
                                ) {
1949
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1950
                                        Some(_div(
×
1951
                                            SymbolExpr::Value(lv * rv),
×
1952
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1953
                                        ))
×
1954
                                    }
1955
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1956
                                        Some(_mul(
×
1957
                                            SymbolExpr::Value(lv / rv),
×
1958
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1959
                                        ))
×
1960
                                    }
1961
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1962
                                        Some(_mul(
×
1963
                                            SymbolExpr::Value(rv / lv),
×
1964
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1965
                                        ))
×
1966
                                    }
1967
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2✔
1968
                                        Some(_div(
2✔
1969
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
2✔
1970
                                            SymbolExpr::Value(lv * rv),
2✔
1971
                                        ))
2✔
1972
                                    }
1973
                                    (_, _, _, _) => None,
×
1974
                                },
1975
                                (_, _) => None,
8,614✔
1976
                            },
1977
                            _ => None,
6,560✔
1978
                        }
1979
                    }
1980
                }
1981
            }
1982
        }
1983
    }
2,768,902✔
1984
    /// expand with optimization for mul operation
1985
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
310,144✔
1986
        if let SymbolExpr::Binary {
1987
            op: rop,
41,252✔
1988
            lhs: r_lhs,
41,252✔
1989
            rhs: r_rhs,
41,252✔
1990
        } = rhs
310,144✔
1991
        {
1992
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
41,252✔
1993
                let el = match self.mul_expand(r_lhs) {
2,200✔
1994
                    Some(e) => e,
1,250✔
1995
                    None => match self.mul_opt(r_lhs, true) {
950✔
1996
                        Some(e) => e,
652✔
1997
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
298✔
1998
                    },
1999
                };
2000
                let er = match self.mul_expand(r_rhs) {
2,200✔
2001
                    Some(e) => e,
1,100✔
2002
                    None => match self.mul_opt(r_rhs, true) {
1,100✔
2003
                        Some(e) => e,
438✔
2004
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
662✔
2005
                    },
2006
                };
2007
                return match &rop {
2,200✔
2008
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
1,010✔
2009
                        Some(e) => Some(e),
6✔
2010
                        None => Some(_sub(el, er)),
1,004✔
2011
                    },
2012
                    _ => match el.add_opt(&er, true) {
1,190✔
2013
                        Some(e) => Some(e),
6✔
2014
                        None => Some(_add(el, er)),
1,184✔
2015
                    },
2016
                };
2017
            }
39,052✔
2018
            if let BinaryOp::Mul = &rop {
39,052✔
2019
                return match self.mul_expand(r_lhs) {
39,004✔
2020
                    Some(e) => match e.mul_expand(r_rhs) {
952✔
2021
                        Some(ee) => Some(ee),
856✔
2022
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
96✔
2023
                    },
2024
                    None => self
38,052✔
2025
                        .mul_expand(r_rhs)
38,052✔
2026
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
38,052✔
2027
                };
2028
            }
48✔
2029
            if let BinaryOp::Div = &rop {
48✔
2030
                return match self.mul_expand(r_lhs) {
×
2031
                    Some(e) => match e.mul_expand(r_rhs) {
×
2032
                        Some(ee) => Some(ee),
×
2033
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2034
                    },
2035
                    None => self
×
2036
                        .div_expand(r_rhs)
×
2037
                        .map(|e| _div(e, r_lhs.as_ref().clone())),
×
2038
                };
2039
            }
48✔
2040
        }
268,892✔
2041
        if let SymbolExpr::Unary {
2042
            op: UnaryOp::Neg,
2043
            expr: rexpr,
722✔
2044
        } = rhs
1,410✔
2045
        {
2046
            return match self.mul_expand(rexpr) {
722✔
2047
                Some(e) => match e.neg_opt() {
410✔
2048
                    Some(ee) => Some(ee),
410✔
2049
                    None => Some(_neg(e)),
×
2050
                },
2051
                None => match self.mul_opt(rexpr, true) {
312✔
2052
                    Some(e) => match e.neg_opt() {
220✔
2053
                        Some(ee) => Some(ee),
208✔
2054
                        None => Some(_neg(e)),
12✔
2055
                    },
2056
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
92✔
2057
                },
2058
            };
2059
        }
268,218✔
2060

2061
        match self {
1,104✔
2062
            SymbolExpr::Unary {
2063
                op: UnaryOp::Neg,
2064
                expr,
1,104✔
2065
            } => match expr.mul_expand(rhs) {
1,104✔
2066
                Some(e) => match e.neg_opt() {
×
2067
                    Some(ee) => Some(ee),
×
2068
                    None => Some(_neg(e)),
×
2069
                },
2070
                None => match expr.mul_opt(rhs, true) {
1,104✔
2071
                    Some(e) => match e.neg_opt() {
790✔
2072
                        Some(ee) => Some(ee),
402✔
2073
                        None => Some(_neg(e)),
388✔
2074
                    },
2075
                    None => None,
314✔
2076
                },
2077
            },
2078
            SymbolExpr::Binary {
2079
                op,
40,070✔
2080
                lhs: l_lhs,
40,070✔
2081
                rhs: l_rhs,
40,070✔
2082
            } => match &op {
40,070✔
2083
                BinaryOp::Add | BinaryOp::Sub => {
2084
                    let l = match l_lhs.mul_expand(rhs) {
4,308✔
2085
                        Some(e) => e,
1,738✔
2086
                        None => match l_lhs.mul_opt(rhs, true) {
2,570✔
2087
                            Some(e) => e,
1,872✔
2088
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
698✔
2089
                        },
2090
                    };
2091
                    let r = match l_rhs.mul_expand(rhs) {
4,308✔
2092
                        Some(e) => e,
76✔
2093
                        None => match l_rhs.mul_opt(rhs, true) {
4,232✔
2094
                            Some(e) => e,
3,064✔
2095
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
1,168✔
2096
                        },
2097
                    };
2098
                    match &op {
4,308✔
2099
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
1,982✔
2100
                            Some(e) => Some(e),
196✔
2101
                            None => Some(_sub(l, r)),
1,786✔
2102
                        },
2103
                        _ => match l.add_opt(&r, true) {
2,326✔
2104
                            Some(e) => Some(e),
222✔
2105
                            None => Some(_add(l, r)),
2,104✔
2106
                        },
2107
                    }
2108
                }
2109
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
35,742✔
2110
                    Some(e) => match e.mul_expand(l_rhs) {
88✔
2111
                        Some(ee) => Some(ee),
88✔
2112
                        None => match e.mul_opt(l_rhs, true) {
×
2113
                            Some(ee) => Some(ee),
×
2114
                            None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2115
                        },
2116
                    },
2117
                    None => match l_rhs.mul_expand(rhs) {
35,654✔
2118
                        Some(e) => match l_lhs.mul_expand(&e) {
24✔
2119
                            Some(ee) => Some(ee),
24✔
2120
                            None => match l_lhs.mul_opt(&e, true) {
×
2121
                                Some(ee) => Some(ee),
×
2122
                                None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2123
                            },
2124
                        },
2125
                        None => None,
35,630✔
2126
                    },
2127
                },
2128
                BinaryOp::Div => match l_lhs.div_expand(rhs) {
20✔
2129
                    Some(e) => Some(_div(e, l_rhs.as_ref().clone())),
×
2130
                    None => l_rhs
20✔
2131
                        .div_expand(rhs)
20✔
2132
                        .map(|e| _div(l_lhs.as_ref().clone(), e)),
20✔
2133
                },
2134
                _ => None,
×
2135
            },
2136
            _ => None,
227,044✔
2137
        }
2138
    }
310,144✔
2139

2140
    /// Div with heuristic optimization
2141
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
21,336✔
2142
        if rhs.is_zero() {
21,336✔
2143
            // return inf to detect divide by zero without panic
2144
            Some(SymbolExpr::Value(Value::Real(f64::INFINITY)))
1,828✔
2145
        } else if rhs.is_one() {
19,508✔
2146
            Some(self.clone())
712✔
2147
        } else if rhs.is_minus_one() {
18,796✔
2148
            match self.neg_opt() {
684✔
2149
                Some(e) => Some(e),
168✔
2150
                None => Some(_neg(self.clone())),
516✔
2151
            }
2152
        } else if *self == *rhs {
18,112✔
2153
            let l_is_int = self.is_int().unwrap_or_default();
2,960✔
2154
            let r_is_int = rhs.is_int().unwrap_or_default();
2,960✔
2155
            if l_is_int || r_is_int {
2,960✔
2156
                Some(SymbolExpr::Value(Value::Int(1)))
978✔
2157
            } else {
2158
                Some(SymbolExpr::Value(Value::Real(1.0)))
1,982✔
2159
            }
2160
        } else {
2161
            if let SymbolExpr::Value(Value::Real(r)) = rhs {
7,066✔
2162
                let t = 1.0 / r;
1,602✔
2163
                if &(1.0 / t) == r {
1,602✔
2164
                    if recursive {
1,590✔
2165
                        return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
2166
                    } else {
2167
                        return Some(&SymbolExpr::Value(Value::Real(t)) * self);
1,590✔
2168
                    }
2169
                }
12✔
2170
            }
13,550✔
2171

2172
            match self {
13,562✔
2173
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
7,728✔
2174
                SymbolExpr::Symbol(_) => None,
3,062✔
2175
                SymbolExpr::Unary { op, expr } => match op {
100✔
2176
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
68✔
2177
                        Some(e) => match e.neg_opt() {
30✔
2178
                            Some(ee) => Some(ee),
30✔
2179
                            None => Some(_neg(e)),
×
2180
                        },
2181
                        None => None,
38✔
2182
                    },
2183
                    UnaryOp::Abs => match rhs {
2✔
2184
                        SymbolExpr::Unary {
2185
                            op: UnaryOp::Abs,
2186
                            expr: rexpr,
2✔
2187
                        } => match expr.div_opt(rexpr, recursive) {
2✔
2188
                            Some(e) => Some(SymbolExpr::Unary {
×
2189
                                op: UnaryOp::Abs,
×
2190
                                expr: Arc::new(e),
×
2191
                            }),
×
2192
                            None => Some(SymbolExpr::Unary {
2✔
2193
                                op: UnaryOp::Abs,
2✔
2194
                                expr: Arc::new(_div(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
2195
                            }),
2✔
2196
                        },
2197
                        _ => None,
×
2198
                    },
2199
                    _ => None,
30✔
2200
                },
2201
                SymbolExpr::Binary {
2202
                    op,
2,672✔
2203
                    lhs: l_lhs,
2,672✔
2204
                    rhs: l_rhs,
2,672✔
2205
                } => {
2206
                    if recursive {
2,672✔
2207
                        if let SymbolExpr::Binary {
2208
                            op: rop,
×
2209
                            lhs: r_lhs,
×
2210
                            rhs: r_rhs,
×
2211
                        } = rhs
8✔
2212
                        {
2213
                            if let BinaryOp::Mul = &rop {
×
2214
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2215
                                    return match e.div_opt(r_rhs, true) {
×
2216
                                        Some(ee) => Some(ee),
×
2217
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
2218
                                    };
2219
                                }
×
2220
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
2221
                                    return match e.div_opt(r_lhs, true) {
×
2222
                                        Some(ee) => Some(ee),
×
2223
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2224
                                    };
2225
                                }
×
2226
                            }
×
2227
                            if let BinaryOp::Div = &rop {
×
2228
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
2229
                                    return match e.div_opt(r_lhs, true) {
×
2230
                                        Some(ee) => Some(ee),
×
2231
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2232
                                    };
2233
                                }
×
2234
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2235
                                    return match e.mul_opt(r_rhs, true) {
×
2236
                                        Some(ee) => Some(ee),
×
2237
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2238
                                    };
2239
                                }
×
2240
                            }
×
2241
                        }
8✔
2242

2243
                        if let BinaryOp::Mul = &op {
8✔
2244
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2245
                                return match e.mul_opt(l_rhs, true) {
×
2246
                                    Some(ee) => Some(ee),
×
2247
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2248
                                };
2249
                            }
×
2250
                            if let Some(e) = l_rhs.div_opt(rhs, true) {
×
2251
                                return match l_lhs.mul_opt(&e, true) {
×
2252
                                    Some(ee) => Some(ee),
×
2253
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2254
                                };
2255
                            }
×
2256
                        } else if let BinaryOp::Div = &op {
8✔
2257
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
×
2258
                                return match l_lhs.div_opt(&e, true) {
×
2259
                                    Some(ee) => Some(ee),
×
2260
                                    None => Some(_div(l_lhs.as_ref().clone(), e)),
×
2261
                                };
2262
                            }
×
2263
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2264
                                return match e.div_opt(l_rhs, true) {
×
2265
                                    Some(ee) => Some(ee),
×
2266
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
2267
                                };
2268
                            }
×
2269
                        }
8✔
2270
                        None
8✔
2271
                    } else {
2272
                        match rhs {
2,664✔
2273
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
1,230✔
2274
                                SymbolExpr::Value(lv) => match op {
572✔
2275
                                    BinaryOp::Mul => Some(_mul(
268✔
2276
                                        SymbolExpr::Value(lv / v),
268✔
2277
                                        l_rhs.as_ref().clone(),
268✔
2278
                                    )),
268✔
2279
                                    BinaryOp::Div => Some(_div(
×
2280
                                        SymbolExpr::Value(lv / v),
×
2281
                                        l_rhs.as_ref().clone(),
×
2282
                                    )),
×
2283
                                    _ => None,
304✔
2284
                                },
2285
                                _ => match l_rhs.as_ref() {
658✔
2286
                                    SymbolExpr::Value(rv) => match op {
488✔
2287
                                        BinaryOp::Mul => Some(_mul(
8✔
2288
                                            SymbolExpr::Value(rv / v),
8✔
2289
                                            l_lhs.as_ref().clone(),
8✔
2290
                                        )),
8✔
2291
                                        BinaryOp::Div => Some(_mul(
×
2292
                                            SymbolExpr::Value(v * rv).rcp(),
×
2293
                                            l_lhs.as_ref().clone(),
×
2294
                                        )),
×
2295
                                        _ => None,
480✔
2296
                                    },
2297
                                    _ => None,
170✔
2298
                                },
2299
                            },
2300
                            SymbolExpr::Binary {
2301
                                op: rop,
512✔
2302
                                lhs: r_lhs,
512✔
2303
                                rhs: r_rhs,
512✔
2304
                            } => match (l_lhs.as_ref(), r_lhs.as_ref()) {
512✔
2305
                                (SymbolExpr::Value(lv), SymbolExpr::Value(rv)) => match (op, rop) {
×
2306
                                    (BinaryOp::Mul, BinaryOp::Mul) => Some(_mul(
×
2307
                                        SymbolExpr::Value(lv / rv),
×
2308
                                        _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2309
                                    )),
×
2310
                                    (BinaryOp::Mul, BinaryOp::Div) => Some(_mul(
×
2311
                                        SymbolExpr::Value(lv / rv),
×
2312
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2313
                                    )),
×
2314
                                    (BinaryOp::Div, BinaryOp::Mul) => Some(_div(
×
2315
                                        SymbolExpr::Value(lv / rv),
×
2316
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2317
                                    )),
×
2318
                                    (BinaryOp::Div, BinaryOp::Div) => Some(_div(
×
2319
                                        SymbolExpr::Value(lv / rv),
×
2320
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2321
                                    )),
×
2322
                                    (_, _) => None,
×
2323
                                },
2324
                                (_, _) => None,
512✔
2325
                            },
2326
                            _ => None,
922✔
2327
                        }
2328
                    }
2329
                }
2330
            }
2331
        }
2332
    }
21,336✔
2333

2334
    /// expand with optimization for div operation
2335
    fn div_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
234✔
2336
        match self {
234✔
2337
            SymbolExpr::Unary { op, expr } => match op {
116✔
2338
                UnaryOp::Neg => match expr.div_expand(rhs) {
12✔
2339
                    Some(e) => match e.neg_opt() {
×
2340
                        Some(ee) => Some(ee),
×
2341
                        None => Some(_neg(e)),
×
2342
                    },
2343
                    None => match expr.div_opt(rhs, true) {
12✔
2344
                        Some(e) => match e.neg_opt() {
×
2345
                            Some(ee) => Some(ee),
×
2346
                            None => Some(_neg(e)),
×
2347
                        },
2348
                        None => None,
12✔
2349
                    },
2350
                },
2351
                _ => None,
104✔
2352
            },
2353
            SymbolExpr::Binary {
2354
                op,
36✔
2355
                lhs: l_lhs,
36✔
2356
                rhs: l_rhs,
36✔
2357
            } => match &op {
36✔
2358
                BinaryOp::Add | BinaryOp::Sub => {
2359
                    let l = match l_lhs.div_expand(rhs) {
20✔
2360
                        Some(e) => e,
12✔
2361
                        None => match l_lhs.div_opt(rhs, true) {
8✔
2362
                            Some(e) => e,
×
2363
                            None => _div(l_lhs.as_ref().clone(), rhs.clone()),
8✔
2364
                        },
2365
                    };
2366
                    let r = match l_rhs.div_expand(rhs) {
20✔
2367
                        Some(e) => e,
×
2368
                        None => match l_rhs.div_opt(rhs, true) {
20✔
2369
                            Some(e) => e,
×
2370
                            None => _div(l_rhs.as_ref().clone(), rhs.clone()),
20✔
2371
                        },
2372
                    };
2373
                    match &op {
20✔
2374
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
8✔
2375
                            Some(e) => Some(e),
4✔
2376
                            None => Some(_sub(l, r)),
4✔
2377
                        },
2378
                        _ => match l.add_opt(&r, true) {
12✔
2379
                            Some(e) => Some(e),
4✔
2380
                            None => Some(_add(l, r)),
8✔
2381
                        },
2382
                    }
2383
                }
2384
                _ => None,
16✔
2385
            },
2386
            _ => self.div_opt(rhs, true),
82✔
2387
        }
2388
    }
234✔
2389

2390
    /// pow with heuristic optimization
2391
    fn pow_opt(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
96✔
2392
        if self.is_zero() || rhs.is_one() {
96✔
2393
            return Some(self.clone());
96✔
2394
        } else if rhs.is_zero() {
×
2395
            return Some(SymbolExpr::Value(Value::Int(1)));
×
2396
        }
×
2397
        None
×
2398
    }
96✔
2399

2400
    /// optimization for neg
2401
    fn neg_opt(&self) -> Option<SymbolExpr> {
381,138✔
2402
        match self {
18,306✔
2403
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
84,940✔
2404
            SymbolExpr::Unary {
2405
                op: UnaryOp::Neg,
2406
                expr,
16,714✔
2407
            } => Some(expr.as_ref().clone()),
16,714✔
2408
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
141,834✔
2409
                BinaryOp::Add => match lhs.neg_opt() {
4,616✔
2410
                    Some(ln) => match rhs.neg_opt() {
3,378✔
2411
                        Some(rn) => Some(_add(ln, rn)),
2,034✔
2412
                        None => Some(_sub(ln, rhs.as_ref().clone())),
1,344✔
2413
                    },
2414
                    None => match rhs.neg_opt() {
1,238✔
2415
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
440✔
2416
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
798✔
2417
                    },
2418
                },
2419
                BinaryOp::Sub => match lhs.neg_opt() {
4,416✔
2420
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
3,686✔
2421
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
730✔
2422
                },
2423
                BinaryOp::Mul => match lhs.neg_opt() {
130,646✔
2424
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
68,672✔
2425
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
61,974✔
2426
                },
2427
                BinaryOp::Div => match lhs.neg_opt() {
76✔
2428
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
16✔
2429
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
60✔
2430
                },
2431
                _ => None,
2,080✔
2432
            },
2433
            _ => None,
137,650✔
2434
        }
2435
    }
381,138✔
2436

2437
    /// optimize the equation
2438
    pub fn optimize(&self) -> SymbolExpr {
×
2439
        match self {
×
2440
            SymbolExpr::Value(_) => self.clone(),
×
2441
            SymbolExpr::Symbol(_) => self.clone(),
×
2442
            SymbolExpr::Unary { op, expr } => {
×
2443
                let opt = expr.optimize();
×
2444
                match op {
×
2445
                    UnaryOp::Neg => match opt.neg_opt() {
×
2446
                        Some(e) => e,
×
2447
                        None => _neg(opt),
×
2448
                    },
2449
                    _ => SymbolExpr::Unary {
×
2450
                        op: op.clone(),
×
2451
                        expr: Arc::new(opt),
×
2452
                    },
×
2453
                }
2454
            }
2455
            SymbolExpr::Binary { op, lhs, rhs } => {
×
2456
                let opt_lhs = lhs.optimize();
×
2457
                let opt_rhs = rhs.optimize();
×
2458
                match op {
×
2459
                    BinaryOp::Add => match opt_lhs.add_opt(&opt_rhs, true) {
×
2460
                        Some(e) => e,
×
2461
                        None => _add(opt_lhs, opt_rhs),
×
2462
                    },
2463
                    BinaryOp::Sub => match opt_lhs.sub_opt(&opt_rhs, true) {
×
2464
                        Some(e) => e,
×
2465
                        None => _sub(opt_lhs, opt_rhs),
×
2466
                    },
2467
                    BinaryOp::Mul => match opt_lhs.mul_opt(&opt_rhs, true) {
×
2468
                        Some(e) => e,
×
2469
                        None => _mul(opt_lhs, opt_rhs),
×
2470
                    },
2471
                    BinaryOp::Div => match opt_lhs.div_opt(&opt_rhs, true) {
×
2472
                        Some(e) => e,
×
2473
                        None => _div(opt_lhs, opt_rhs),
×
2474
                    },
2475
                    BinaryOp::Pow => _pow(opt_lhs, opt_rhs),
×
2476
                }
2477
            }
2478
        }
2479
    }
×
2480

2481
    // convert sympy compatible format
2482
    pub fn sympify(&self) -> SymbolExpr {
×
2483
        match self {
×
2484
            SymbolExpr::Symbol { .. } => self.clone(),
×
2485
            SymbolExpr::Value(e) => e.sympify(),
×
2486
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
×
2487
                op: op.clone(),
×
2488
                expr: Arc::new(expr.sympify()),
×
2489
            },
×
2490
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
×
2491
                op: op.clone(),
×
2492
                lhs: Arc::new(lhs.sympify()),
×
2493
                rhs: Arc::new(rhs.sympify()),
×
2494
            },
×
2495
        }
2496
    }
×
2497

2498
    fn repr(&self, with_uuid: bool) -> String {
10,950,430✔
2499
        match self {
10,950,430✔
2500
            SymbolExpr::Symbol(e) => e.repr(with_uuid),
9,998,350✔
2501
            SymbolExpr::Value(e) => e.to_string(),
298,446✔
2502
            SymbolExpr::Unary { op, expr } => {
6,378✔
2503
                let s = expr.repr(with_uuid);
6,378✔
2504
                match op {
6,378✔
2505
                    UnaryOp::Abs => format!("abs({s})"),
×
2506
                    UnaryOp::Neg => match expr.as_ref() {
3,530✔
2507
                        SymbolExpr::Value(e) => (-e).to_string(),
×
2508
                        SymbolExpr::Binary {
2509
                            op: BinaryOp::Add | BinaryOp::Sub,
2510
                            ..
2511
                        } => format!("-({s})"),
×
2512
                        _ => format!("-{s}"),
3,530✔
2513
                    },
2514
                    UnaryOp::Sin => format!("sin({s})"),
120✔
2515
                    UnaryOp::Asin => format!("asin({s})"),
108✔
2516
                    UnaryOp::Cos => format!("cos({s})"),
80✔
2517
                    UnaryOp::Acos => format!("acos({s})"),
92✔
2518
                    UnaryOp::Tan => format!("tan({s})"),
64✔
2519
                    UnaryOp::Atan => format!("atan({s})"),
76✔
2520
                    UnaryOp::Exp => format!("exp({s})"),
260✔
2521
                    UnaryOp::Log => format!("log({s})"),
×
2522
                    UnaryOp::Sign => format!("sign({s})"),
×
2523
                    UnaryOp::Conj => format!("conj({s})"),
2,048✔
2524
                }
2525
            }
2526
            SymbolExpr::Binary { op, lhs, rhs } => {
647,256✔
2527
                let s_lhs = lhs.repr(with_uuid);
647,256✔
2528
                let s_rhs = rhs.repr(with_uuid);
647,256✔
2529
                let op_lhs = match lhs.as_ref() {
647,256✔
2530
                    SymbolExpr::Binary { op: lop, .. } => {
134,330✔
2531
                        matches!(lop, BinaryOp::Add | BinaryOp::Sub)
134,330✔
2532
                    }
2533
                    SymbolExpr::Value(e) => match e {
185,034✔
2534
                        Value::Real(v) => *v < 0.0,
17,588✔
2535
                        Value::Int(v) => *v < 0,
64,522✔
2536
                        Value::Complex(_) => true,
102,924✔
2537
                    },
2538
                    _ => false,
327,892✔
2539
                };
2540
                let op_rhs = match rhs.as_ref() {
647,256✔
2541
                    SymbolExpr::Binary { op: rop, .. } => match rop {
62,786✔
2542
                        BinaryOp::Add | BinaryOp::Sub => true,
2,778✔
2543
                        _ => matches!(op, BinaryOp::Div),
60,008✔
2544
                    },
2545
                    SymbolExpr::Value(e) => match e {
113,124✔
2546
                        Value::Real(v) => *v < 0.0,
65,302✔
2547
                        Value::Int(v) => *v < 0,
32,046✔
2548
                        Value::Complex(_) => true,
15,776✔
2549
                    },
2550
                    _ => false,
471,346✔
2551
                };
2552

2553
                match op {
647,256✔
2554
                    BinaryOp::Add => match rhs.as_ref() {
58,762✔
2555
                        SymbolExpr::Unary {
2556
                            op: UnaryOp::Neg,
2557
                            expr: _,
2558
                        } => {
2559
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2560
                                format!("{s_lhs} {s_rhs}")
×
2561
                            } else {
2562
                                format!("{s_lhs} + {s_rhs}")
×
2563
                            }
2564
                        }
2565
                        _ => format!("{s_lhs} + {s_rhs}"),
58,762✔
2566
                    },
2567
                    BinaryOp::Sub => match rhs.as_ref() {
57,336✔
2568
                        SymbolExpr::Unary {
2569
                            op: UnaryOp::Neg,
2570
                            expr: _,
2571
                        } => {
2572
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2573
                                let st = s_rhs.char_indices().nth(0).unwrap().0;
×
2574
                                let ed = s_rhs.char_indices().nth(1).unwrap().0;
×
2575
                                let s_rhs_new: &str = &s_rhs.as_str()[st..ed];
×
2576
                                format!("{s_lhs} + {s_rhs_new}")
×
2577
                            } else if op_rhs {
×
2578
                                format!("{s_lhs} -({s_rhs})")
×
2579
                            } else {
2580
                                format!("{s_lhs} - {s_rhs}")
×
2581
                            }
2582
                        }
2583
                        _ => {
2584
                            if op_rhs {
57,336✔
2585
                                format!("{s_lhs} -({s_rhs})")
612✔
2586
                            } else {
2587
                                format!("{s_lhs} - {s_rhs}")
56,724✔
2588
                            }
2589
                        }
2590
                    },
2591
                    BinaryOp::Mul => {
2592
                        if op_lhs {
465,446✔
2593
                            if op_rhs {
110,246✔
2594
                                format!("({s_lhs})*({s_rhs})")
556✔
2595
                            } else {
2596
                                format!("({s_lhs})*{s_rhs}")
109,690✔
2597
                            }
2598
                        } else if op_rhs {
355,200✔
2599
                            format!("{s_lhs}*({s_rhs})")
16,626✔
2600
                        } else {
2601
                            format!("{s_lhs}*{s_rhs}")
338,574✔
2602
                        }
2603
                    }
2604
                    BinaryOp::Div => {
2605
                        if op_lhs {
404✔
2606
                            if op_rhs {
40✔
2607
                                format!("({s_lhs})/({s_rhs})")
×
2608
                            } else {
2609
                                format!("({s_lhs})/{s_rhs}")
40✔
2610
                            }
2611
                        } else if op_rhs {
364✔
2612
                            format!("{s_lhs}/({s_rhs})")
8✔
2613
                        } else {
2614
                            format!("{s_lhs}/{s_rhs}")
356✔
2615
                        }
2616
                    }
2617
                    BinaryOp::Pow => match lhs.as_ref() {
65,308✔
2618
                        SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2619
                            match rhs.as_ref() {
4✔
2620
                                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2621
                                    format!("({s_lhs})**({s_rhs})")
×
2622
                                }
2623
                                SymbolExpr::Value(r) => {
×
2624
                                    if r.as_real() < 0.0 {
×
2625
                                        format!("({s_lhs})**({s_rhs})")
×
2626
                                    } else {
2627
                                        format!("({s_lhs})**{s_rhs}")
×
2628
                                    }
2629
                                }
2630
                                _ => format!("({s_lhs})**{s_rhs}"),
4✔
2631
                            }
2632
                        }
2633
                        SymbolExpr::Value(l) => {
4✔
2634
                            if l.as_real() < 0.0 {
4✔
2635
                                match rhs.as_ref() {
×
2636
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2637
                                        format!("({s_lhs})**({s_rhs})")
×
2638
                                    }
2639
                                    _ => format!("({s_lhs})**{s_rhs}"),
×
2640
                                }
2641
                            } else {
2642
                                match rhs.as_ref() {
4✔
2643
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2644
                                        format!("{s_lhs}**({s_rhs})")
×
2645
                                    }
2646
                                    _ => format!("{s_lhs}**{s_rhs}"),
4✔
2647
                                }
2648
                            }
2649
                        }
2650
                        _ => match rhs.as_ref() {
65,300✔
2651
                            SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2652
                                format!("{s_lhs}**({s_rhs})")
×
2653
                            }
2654
                            SymbolExpr::Value(r) => {
65,300✔
2655
                                if r.as_real() < 0.0 {
65,300✔
2656
                                    format!("{s_lhs}**({s_rhs})")
×
2657
                                } else {
2658
                                    format!("{s_lhs}**{s_rhs}")
65,300✔
2659
                                }
2660
                            }
2661
                            _ => format!("{s_lhs}**{s_rhs}"),
×
2662
                        },
2663
                    },
2664
                }
2665
            }
2666
        }
2667
    }
10,950,430✔
2668
}
2669

2670
impl Add for SymbolExpr {
2671
    type Output = SymbolExpr;
2672
    fn add(self, rhs: Self) -> SymbolExpr {
103,300✔
2673
        match self.add_opt(&rhs, false) {
103,300✔
2674
            Some(e) => e,
86,048✔
2675
            None => _add(self, rhs),
17,252✔
2676
        }
2677
    }
103,300✔
2678
}
2679

2680
impl Add for &SymbolExpr {
2681
    type Output = SymbolExpr;
2682
    fn add(self, rhs: Self) -> SymbolExpr {
2,390,442✔
2683
        match self.add_opt(rhs, false) {
2,390,442✔
2684
            Some(e) => e,
2,312,530✔
2685
            None => _add(self.clone(), rhs.clone()),
77,912✔
2686
        }
2687
    }
2,390,442✔
2688
}
2689

2690
impl Sub for SymbolExpr {
2691
    type Output = SymbolExpr;
2692
    fn sub(self, rhs: Self) -> SymbolExpr {
69,944✔
2693
        match self.sub_opt(&rhs, false) {
69,944✔
2694
            Some(e) => e,
64,256✔
2695
            None => _sub(self, rhs),
5,688✔
2696
        }
2697
    }
69,944✔
2698
}
2699

2700
impl Sub for &SymbolExpr {
2701
    type Output = SymbolExpr;
2702
    fn sub(self, rhs: Self) -> SymbolExpr {
25,756✔
2703
        match self.sub_opt(rhs, false) {
25,756✔
2704
            Some(e) => e,
16,706✔
2705
            None => _sub(self.clone(), rhs.clone()),
9,050✔
2706
        }
2707
    }
25,756✔
2708
}
2709

2710
impl Mul for SymbolExpr {
2711
    type Output = SymbolExpr;
2712
    fn mul(self, rhs: Self) -> SymbolExpr {
319,892✔
2713
        match self.mul_opt(&rhs, false) {
319,892✔
2714
            Some(e) => e,
249,080✔
2715
            None => _mul(self, rhs),
70,812✔
2716
        }
2717
    }
319,892✔
2718
}
2719

2720
impl Mul for &SymbolExpr {
2721
    type Output = SymbolExpr;
2722
    fn mul(self, rhs: Self) -> SymbolExpr {
2,415,900✔
2723
        match self.mul_opt(rhs, false) {
2,415,900✔
2724
            Some(e) => e,
2,367,152✔
2725
            None => _mul(self.clone(), rhs.clone()),
48,748✔
2726
        }
2727
    }
2,415,900✔
2728
}
2729

2730
impl Div for SymbolExpr {
2731
    type Output = SymbolExpr;
2732
    fn div(self, rhs: Self) -> SymbolExpr {
9,158✔
2733
        match self.div_opt(&rhs, false) {
9,158✔
2734
            Some(e) => e,
8,192✔
2735
            None => _div(self, rhs),
966✔
2736
        }
2737
    }
9,158✔
2738
}
2739

2740
impl Div for &SymbolExpr {
2741
    type Output = SymbolExpr;
2742
    fn div(self, rhs: Self) -> SymbolExpr {
11,978✔
2743
        match self.div_opt(rhs, false) {
11,978✔
2744
            Some(e) => e,
3,236✔
2745
            None => _div(self.clone(), rhs.clone()),
8,742✔
2746
        }
2747
    }
11,978✔
2748
}
2749

2750
impl Neg for SymbolExpr {
2751
    type Output = SymbolExpr;
2752
    fn neg(self) -> SymbolExpr {
×
2753
        match self.neg_opt() {
×
2754
            Some(e) => e,
×
2755
            None => _neg(self),
×
2756
        }
2757
    }
×
2758
}
2759

2760
impl Neg for &SymbolExpr {
2761
    type Output = SymbolExpr;
2762
    fn neg(self) -> SymbolExpr {
492✔
2763
        match self.neg_opt() {
492✔
2764
            Some(e) => e,
90✔
2765
            None => _neg(self.clone()),
402✔
2766
        }
2767
    }
492✔
2768
}
2769

2770
impl PartialEq for SymbolExpr {
2771
    fn eq(&self, rexpr: &Self) -> bool {
66,632✔
2772
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
66,632✔
2773
            return l == r;
7,452✔
2774
        }
59,180✔
2775

2776
        match (self, rexpr) {
59,180✔
2777
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
31,102✔
2778
            (SymbolExpr::Value(l), SymbolExpr::Value(r)) => l == r,
×
2779
            (
2780
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2781
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2782
            ) => {
2783
                let ex_lhs = self.expand();
2,740✔
2784
                let ex_rhs = rexpr.expand();
2,740✔
2785
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,740✔
2786
                    Some(e) => e.is_zero(),
2,396✔
2787
                    None => {
2788
                        let t = &ex_lhs - &ex_rhs;
344✔
2789
                        t.is_zero()
344✔
2790
                    }
2791
                }
2792
            }
2793
            (SymbolExpr::Binary { .. }, _) => {
2794
                let ex_lhs = self.expand();
2,210✔
2795
                match ex_lhs.sub_opt(rexpr, true) {
2,210✔
2796
                    Some(e) => e.is_zero(),
2,098✔
2797
                    None => {
2798
                        let t = &ex_lhs - rexpr;
112✔
2799
                        t.is_zero()
112✔
2800
                    }
2801
                }
2802
            }
2803
            (_, SymbolExpr::Binary { .. }) => {
2804
                let ex_rhs = rexpr.expand();
2,664✔
2805
                match self.sub_opt(&ex_rhs, true) {
2,664✔
2806
                    Some(e) => e.is_zero(),
558✔
2807
                    None => {
2808
                        let t = self - &ex_rhs;
2,106✔
2809
                        t.is_zero()
2,106✔
2810
                    }
2811
                }
2812
            }
2813
            (_, _) => false,
20,464✔
2814
        }
2815
    }
66,632✔
2816
}
2817

2818
impl PartialEq<f64> for SymbolExpr {
2819
    fn eq(&self, r: &f64) -> bool {
×
2820
        match self.eval(true) {
×
2821
            Some(v) => v == *r,
×
2822
            None => false,
×
2823
        }
2824
    }
×
2825
}
2826

2827
impl PartialEq<Complex64> for SymbolExpr {
2828
    fn eq(&self, r: &Complex64) -> bool {
×
2829
        match self.eval(true) {
×
2830
            Some(v) => v == *r,
×
2831
            None => false,
×
2832
        }
2833
    }
×
2834
}
2835

2836
// comparison rules for sorting equation
2837
impl PartialOrd for SymbolExpr {
2838
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
115,648✔
2839
        match self {
115,648✔
2840
            SymbolExpr::Value(l) => match rhs {
302✔
2841
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2842
                _ => Some(Ordering::Less),
290✔
2843
            },
2844
            SymbolExpr::Symbol(l) => match rhs {
6,790✔
2845
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2846
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
3,972✔
2847
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2848
                _ => Some(Ordering::Less),
2,818✔
2849
            },
2850
            SymbolExpr::Unary { op: _, expr } => match rhs {
15,242✔
2851
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2852
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,620✔
2853
                _ => (expr.as_ref()).partial_cmp(rhs),
13,620✔
2854
            },
2855
            SymbolExpr::Binary {
2856
                op,
93,314✔
2857
                lhs: ll,
93,314✔
2858
                rhs: lr,
93,314✔
2859
            } => match rhs {
93,314✔
2860
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
7,822✔
2861
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
7,814✔
2862
                    _ => Some(Ordering::Equal),
8✔
2863
                },
2864
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
404✔
2865
                SymbolExpr::Binary {
2866
                    op: _,
2867
                    lhs: rl,
85,088✔
2868
                    rhs: rr,
85,088✔
2869
                } => {
2870
                    let ls = match ll.as_ref() {
85,088✔
2871
                        SymbolExpr::Value(_) => lr.string_id(),
30,176✔
2872
                        _ => self.string_id(),
54,912✔
2873
                    };
2874
                    let rs = match rl.as_ref() {
85,088✔
2875
                        SymbolExpr::Value(_) => rr.string_id(),
30,534✔
2876
                        _ => rhs.string_id(),
54,554✔
2877
                    };
2878
                    if rs > ls && rs.len() > ls.len() {
85,088✔
2879
                        Some(Ordering::Less)
9,542✔
2880
                    } else if rs < ls && rs.len() < ls.len() {
75,546✔
2881
                        Some(Ordering::Greater)
450✔
2882
                    } else {
2883
                        Some(Ordering::Equal)
75,096✔
2884
                    }
2885
                }
2886
            },
2887
        }
2888
    }
115,648✔
2889
}
2890

2891
impl From<&str> for SymbolExpr {
2892
    fn from(v: &str) -> Self {
×
2893
        SymbolExpr::Symbol(Arc::new(Symbol::new(v, None, None)))
×
2894
    }
×
2895
}
2896

2897
impl fmt::Display for Value {
2898
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298,630✔
2899
        write!(
298,630✔
2900
            f,
298,630✔
2901
            "{}",
298,630✔
2902
            match self {
298,630✔
2903
                Value::Real(e) => e.to_string(),
83,280✔
2904
                Value::Int(e) => e.to_string(),
96,638✔
2905
                Value::Complex(e) => {
118,712✔
2906
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
118,712✔
2907
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
118,040✔
2908
                            0.to_string()
×
2909
                        } else {
2910
                            format!("{}i", e.im)
118,040✔
2911
                        }
2912
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
672✔
2913
                        e.re.to_string()
×
2914
                    } else {
2915
                        e.to_string()
672✔
2916
                    }
2917
                }
2918
            }
2919
        )
2920
    }
298,630✔
2921
}
2922

2923
// ===============================================================
2924
//  implementations for Value
2925
// ===============================================================
2926
impl Value {
2927
    pub fn as_real(&self) -> f64 {
65,304✔
2928
        match self {
65,304✔
2929
            Value::Real(e) => *e,
65,108✔
2930
            Value::Int(e) => *e as f64,
196✔
2931
            Value::Complex(e) => e.re,
×
2932
        }
2933
    }
65,304✔
2934

2935
    pub fn is_real(&self) -> bool {
184✔
2936
        match self {
184✔
2937
            Value::Real(_) | Value::Int(_) => true,
130✔
2938
            Value::Complex(c) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im),
54✔
2939
        }
2940
    }
184✔
2941

2942
    pub fn abs(&self) -> Value {
468✔
2943
        match self {
468✔
2944
            Value::Real(e) => Value::Real(e.abs()),
218✔
2945
            Value::Int(e) => Value::Int(e.abs()),
134✔
2946
            Value::Complex(e) => Value::Real((e.re * e.re + e.im * e.im).sqrt()),
116✔
2947
        }
2948
    }
468✔
2949

2950
    pub fn sin(&self) -> Value {
364✔
2951
        match self {
364✔
2952
            Value::Real(e) => Value::Real(e.sin()),
120✔
2953
            Value::Int(e) => Value::Real((*e as f64).sin()),
130✔
2954
            Value::Complex(e) => {
114✔
2955
                let t = Value::Complex(e.sin());
114✔
2956
                match t.opt_complex() {
114✔
2957
                    Some(v) => v,
30✔
2958
                    None => t,
84✔
2959
                }
2960
            }
2961
        }
2962
    }
364✔
2963
    pub fn asin(&self) -> Value {
90✔
2964
        match self {
90✔
2965
            Value::Real(e) => Value::Real(e.asin()),
84✔
2966
            Value::Int(e) => Value::Real((*e as f64).asin()),
6✔
2967
            Value::Complex(e) => {
×
2968
                let t = Value::Complex(e.asin());
×
2969
                match t.opt_complex() {
×
2970
                    Some(v) => v,
×
2971
                    None => t,
×
2972
                }
2973
            }
2974
        }
2975
    }
90✔
2976
    pub fn cos(&self) -> Value {
610✔
2977
        match self {
610✔
2978
            Value::Real(e) => Value::Real(e.cos()),
366✔
2979
            Value::Int(e) => Value::Real((*e as f64).cos()),
130✔
2980
            Value::Complex(e) => {
114✔
2981
                let t = Value::Complex(e.cos());
114✔
2982
                match t.opt_complex() {
114✔
2983
                    Some(v) => v,
30✔
2984
                    None => t,
84✔
2985
                }
2986
            }
2987
        }
2988
    }
610✔
2989
    pub fn acos(&self) -> Value {
88✔
2990
        match self {
88✔
2991
            Value::Real(e) => Value::Real(e.acos()),
84✔
2992
            Value::Int(e) => Value::Real((*e as f64).acos()),
4✔
2993
            Value::Complex(e) => {
×
2994
                let t = Value::Complex(e.acos());
×
2995
                match t.opt_complex() {
×
2996
                    Some(v) => v,
×
2997
                    None => t,
×
2998
                }
2999
            }
3000
        }
3001
    }
88✔
3002
    pub fn tan(&self) -> Value {
340✔
3003
        match self {
340✔
3004
            Value::Real(e) => Value::Real(e.tan()),
96✔
3005
            Value::Int(e) => Value::Real((*e as f64).tan()),
130✔
3006
            Value::Complex(e) => {
114✔
3007
                let t = Value::Complex(e.tan());
114✔
3008
                match t.opt_complex() {
114✔
3009
                    Some(v) => v,
30✔
3010
                    None => t,
84✔
3011
                }
3012
            }
3013
        }
3014
    }
340✔
3015
    pub fn atan(&self) -> Value {
90✔
3016
        match self {
90✔
3017
            Value::Real(e) => Value::Real(e.atan()),
84✔
3018
            Value::Int(e) => Value::Real((*e as f64).atan()),
6✔
3019
            Value::Complex(e) => {
×
3020
                let t = Value::Complex(e.atan());
×
3021
                match t.opt_complex() {
×
3022
                    Some(v) => v,
×
3023
                    None => t,
×
3024
                }
3025
            }
3026
        }
3027
    }
90✔
3028
    pub fn exp(&self) -> Value {
402✔
3029
        match self {
402✔
3030
            Value::Real(e) => Value::Real(e.exp()),
146✔
3031
            Value::Int(e) => Value::Real((*e as f64).exp()),
136✔
3032
            Value::Complex(e) => {
120✔
3033
                let t = Value::Complex(e.exp());
120✔
3034
                match t.opt_complex() {
120✔
3035
                    Some(v) => v,
30✔
3036
                    None => t,
90✔
3037
                }
3038
            }
3039
        }
3040
    }
402✔
3041
    pub fn log(&self) -> Value {
596✔
3042
        match self {
596✔
3043
            Value::Real(e) => {
300✔
3044
                if *e < 0.0 {
300✔
3045
                    Value::Complex(Complex64::from(e)).log()
84✔
3046
                } else {
3047
                    Value::Real(e.ln())
216✔
3048
                }
3049
            }
3050
            Value::Int(e) => Value::Real(*e as f64).log(),
128✔
3051
            Value::Complex(e) => {
168✔
3052
                let t = Value::Complex(e.ln());
168✔
3053
                match t.opt_complex() {
168✔
3054
                    Some(v) => v,
×
3055
                    None => t,
168✔
3056
                }
3057
            }
3058
        }
3059
    }
596✔
3060
    pub fn sqrt(&self) -> Value {
×
3061
        match self {
×
3062
            Value::Real(e) => {
×
3063
                if *e < 0.0 {
×
3064
                    Value::Complex(Complex64::from(e)).sqrt()
×
3065
                } else {
3066
                    Value::Real(e.sqrt())
×
3067
                }
3068
            }
3069
            Value::Int(e) => {
×
3070
                if *e < 0 {
×
3071
                    Value::Complex(Complex64::from(*e as f64)).pow(&Value::Real(0.5))
×
3072
                } else {
3073
                    let t = (*e as f64).sqrt();
×
3074
                    let d = t.floor() - t;
×
3075
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
×
3076
                        Value::Int(t as i64)
×
3077
                    } else {
3078
                        Value::Real(t)
×
3079
                    }
3080
                }
3081
            }
3082
            Value::Complex(e) => {
×
3083
                let t = Value::Complex(e.sqrt());
×
3084
                match t.opt_complex() {
×
3085
                    Some(v) => v,
×
3086
                    None => t,
×
3087
                }
3088
            }
3089
        }
3090
    }
×
3091
    pub fn pow(&self, p: &Value) -> Value {
29,212✔
3092
        match self {
29,212✔
3093
            Value::Real(e) => match p {
9,368✔
3094
                Value::Real(r) => {
8,838✔
3095
                    if *e < 0.0 && r.fract() != 0. {
8,838✔
3096
                        Value::Complex(Complex64::from(e)).pow(p)
2✔
3097
                    } else {
3098
                        Value::Real(e.powf(*r))
8,836✔
3099
                    }
3100
                }
3101
                Value::Int(i) => Value::Real(e.powf(*i as f64)),
146✔
3102
                Value::Complex(_) => Value::Complex(Complex64::from(e)).pow(p),
384✔
3103
            },
3104
            Value::Int(e) => match p {
9,008✔
3105
                Value::Real(r) => {
8,874✔
3106
                    if *e < 0 && r.fract() != 0. {
8,874✔
3107
                        Value::Complex(Complex64::from(*e as f64)).pow(p)
6✔
3108
                    } else {
3109
                        let t = (*e as f64).powf(*r);
8,868✔
3110
                        let d = t.floor() - t;
8,868✔
3111
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
8,868✔
3112
                            Value::Int(t as i64)
8,860✔
3113
                        } else {
3114
                            Value::Real(t)
8✔
3115
                        }
3116
                    }
3117
                }
3118
                Value::Int(r) => {
6✔
3119
                    if *r < 0 {
6✔
3120
                        Value::Real(*e as f64).pow(p)
2✔
3121
                    } else {
3122
                        Value::Int(e.pow(*r as u32))
4✔
3123
                    }
3124
                }
3125
                Value::Complex(_) => Value::Complex(Complex64::from(*e as f64)).pow(p),
128✔
3126
            },
3127
            Value::Complex(e) => {
10,836✔
3128
                let t = match p {
10,836✔
3129
                    Value::Real(r) => Value::Complex(e.powf(*r)),
9,496✔
3130
                    Value::Int(r) => Value::Complex(e.powf(*r as f64)),
126✔
3131
                    Value::Complex(r) => Value::Complex(e.powc(*r)),
1,214✔
3132
                };
3133
                match t.opt_complex() {
10,836✔
3134
                    Some(v) => v,
1,972✔
3135
                    None => t,
8,864✔
3136
                }
3137
            }
3138
        }
3139
    }
29,212✔
3140
    pub fn rcp(&self) -> Value {
×
3141
        match self {
×
3142
            Value::Real(e) => Value::Real(1.0 / e),
×
3143
            Value::Int(e) => {
×
3144
                let t = 1.0 / (*e as f64);
×
3145
                let d = t.floor() - t;
×
3146
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
×
3147
                    Value::Int(t as i64)
×
3148
                } else {
3149
                    Value::Real(t)
×
3150
                }
3151
            }
3152
            Value::Complex(e) => Value::Complex(1.0 / e),
×
3153
        }
3154
    }
×
3155
    pub fn sign(&self) -> Value {
6✔
3156
        match self {
6✔
3157
            Value::Real(e) => {
×
3158
                if *e > SYMEXPR_EPSILON {
×
3159
                    Value::Real(1.0)
×
3160
                } else if *e < -SYMEXPR_EPSILON {
×
3161
                    Value::Real(-1.0)
×
3162
                } else {
3163
                    Value::Real(0.0)
×
3164
                }
3165
            }
3166
            Value::Int(e) => {
6✔
3167
                if *e > 0 {
6✔
3168
                    Value::Int(1)
2✔
3169
                } else if *e < 0 {
4✔
3170
                    Value::Int(-1)
2✔
3171
                } else {
3172
                    Value::Int(0)
2✔
3173
                }
3174
            }
3175
            Value::Complex(_) => *self,
×
3176
        }
3177
    }
6✔
3178

3179
    pub fn is_zero(&self) -> bool {
5,661,206✔
3180
        match self {
5,661,206✔
3181
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,909,262✔
3182
            Value::Int(i) => *i == 0,
455,382✔
3183
            Value::Complex(c) => {
296,562✔
3184
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
296,562✔
3185
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
214,572✔
3186
            }
3187
        }
3188
    }
5,661,206✔
3189
    pub fn is_one(&self) -> bool {
591,616✔
3190
        match self {
591,616✔
3191
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
290,560✔
3192
            Value::Int(i) => *i == 1,
163,428✔
3193
            Value::Complex(c) => {
137,628✔
3194
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
137,628✔
3195
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
5,374✔
3196
            }
3197
        }
3198
    }
591,616✔
3199
    pub fn is_minus_one(&self) -> bool {
348,646✔
3200
        match self {
348,646✔
3201
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
243,864✔
3202
            Value::Int(i) => *i == -1,
16,436✔
3203
            Value::Complex(c) => {
88,346✔
3204
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
88,346✔
3205
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,030✔
3206
            }
3207
        }
3208
    }
348,646✔
3209

3210
    pub fn is_negative(&self) -> bool {
74,418✔
3211
        match self {
74,418✔
3212
            Value::Real(r) => *r < 0.0,
17,920✔
3213
            Value::Int(i) => *i < 0,
5,258✔
3214
            Value::Complex(c) => {
51,240✔
3215
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
51,240✔
3216
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
51,240✔
3217
            }
3218
        }
3219
    }
74,418✔
3220

3221
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
175,318✔
3222
        match rhs {
4,890✔
3223
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
79,580✔
3224
            SymbolExpr::Unary {
3225
                op: UnaryOp::Neg,
3226
                expr,
4,262✔
3227
            } => {
3228
                let l = SymbolExpr::Value(-self);
4,262✔
3229
                match l.mul_opt(expr, recursive) {
4,262✔
3230
                    Some(e) => Some(e),
4✔
3231
                    None => Some(_mul(l, expr.as_ref().clone())),
4,258✔
3232
                }
3233
            }
3234
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
21,638✔
3235
                if recursive {
21,638✔
3236
                    match op {
1,930✔
3237
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
1,930✔
3238
                            Some(e) => match e.mul_opt(r, recursive) {
32✔
3239
                                Some(ee) => Some(ee),
8✔
3240
                                None => Some(_mul(e, r.as_ref().clone())),
24✔
3241
                            },
3242
                            None => self
1,898✔
3243
                                .mul_opt(r, recursive)
1,898✔
3244
                                .map(|e| _mul(e, l.as_ref().clone())),
1,898✔
3245
                        },
3246
                        BinaryOp::Div => match self.mul_opt(l, recursive) {
×
3247
                            Some(e) => Some(_div(e, r.as_ref().clone())),
×
3248
                            None => self
×
3249
                                .div_opt(r, recursive)
×
3250
                                .map(|e| _mul(e, l.as_ref().clone())),
×
3251
                        },
3252
                        _ => None,
×
3253
                    }
3254
                } else {
3255
                    match l.as_ref() {
19,708✔
3256
                        SymbolExpr::Value(v) => match op {
4,394✔
3257
                            BinaryOp::Mul => {
3258
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
2,456✔
3259
                            }
3260
                            BinaryOp::Div => {
3261
                                Some(_div(SymbolExpr::Value(self * v), r.as_ref().clone()))
×
3262
                            }
3263
                            _ => None,
1,938✔
3264
                        },
3265
                        _ => match r.as_ref() {
15,314✔
3266
                            SymbolExpr::Value(v) => match op {
2,404✔
3267
                                BinaryOp::Mul => {
3268
                                    Some(_mul(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
3269
                                }
3270
                                BinaryOp::Div => {
3271
                                    Some(_mul(SymbolExpr::Value(self / v), l.as_ref().clone()))
8✔
3272
                                }
3273
                                _ => None,
2,396✔
3274
                            },
3275
                            _ => None,
12,910✔
3276
                        },
3277
                    }
3278
                }
3279
            }
3280
            _ => None,
69,838✔
3281
        }
3282
    }
175,318✔
3283

3284
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
7,728✔
3285
        match rhs {
40✔
3286
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self / r)),
2,992✔
3287
            SymbolExpr::Unary {
3288
                op: UnaryOp::Neg,
3289
                expr,
×
3290
            } => {
3291
                if recursive {
×
3292
                    self.div_opt(expr, recursive).map(_neg)
×
3293
                } else {
3294
                    None
×
3295
                }
3296
            }
3297
            SymbolExpr::Binary { op, lhs: l, rhs: r } => match l.as_ref() {
2,360✔
3298
                SymbolExpr::Value(v) => match op {
980✔
3299
                    BinaryOp::Mul => Some(_div(SymbolExpr::Value(self / v), r.as_ref().clone())),
384✔
3300
                    BinaryOp::Div => Some(_mul(SymbolExpr::Value(self / v), r.as_ref().clone())),
×
3301
                    _ => None,
596✔
3302
                },
3303
                _ => match r.as_ref() {
1,380✔
3304
                    SymbolExpr::Value(v) => match op {
1,180✔
3305
                        BinaryOp::Mul => {
3306
                            Some(_div(SymbolExpr::Value(self / v), l.as_ref().clone()))
×
3307
                        }
3308
                        BinaryOp::Div => {
3309
                            Some(_div(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
3310
                        }
3311
                        _ => None,
1,180✔
3312
                    },
3313
                    _ => None,
200✔
3314
                },
3315
            },
3316
            _ => None,
2,376✔
3317
        }
3318
    }
7,728✔
3319

3320
    pub fn opt_complex(&self) -> Option<Value> {
252,478✔
3321
        match self {
252,478✔
3322
            Value::Complex(c) => {
121,660✔
3323
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
121,660✔
3324
                    Some(Value::Real(c.re))
23,468✔
3325
                } else {
3326
                    None
98,192✔
3327
                }
3328
            }
3329
            _ => None,
130,818✔
3330
        }
3331
    }
252,478✔
3332

3333
    // convert sympy compatible format
3334
    pub fn sympify(&self) -> SymbolExpr {
×
3335
        match self {
×
3336
            // imaginary number is comverted to value * symbol 'I'
3337
            Value::Complex(c) => _add(
×
3338
                SymbolExpr::Value(Value::Real(c.re)),
×
3339
                _mul(
×
3340
                    SymbolExpr::Value(Value::Real(c.im)),
×
3341
                    SymbolExpr::Symbol(Arc::new(Symbol::new("I", None, None))),
×
3342
                ),
3343
            ),
3344
            _ => SymbolExpr::Value(*self),
×
3345
        }
3346
    }
×
3347
}
3348

3349
impl From<f64> for Value {
3350
    fn from(v: f64) -> Self {
13,514✔
3351
        Value::Real(v)
13,514✔
3352
    }
13,514✔
3353
}
3354

3355
impl From<i64> for Value {
3356
    fn from(v: i64) -> Self {
134,152✔
3357
        Value::Int(v)
134,152✔
3358
    }
134,152✔
3359
}
3360

3361
impl From<Complex64> for Value {
3362
    fn from(v: Complex64) -> Self {
2,361,336✔
3363
        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&v.im) {
2,361,336✔
3364
            Value::Real(v.re)
2,304,032✔
3365
        } else {
3366
            Value::Complex(v)
57,304✔
3367
        }
3368
    }
2,361,336✔
3369
}
3370

3371
impl Add for &Value {
3372
    type Output = Value;
3373
    fn add(self, rhs: Self) -> Value {
76,212✔
3374
        *self + *rhs
76,212✔
3375
    }
76,212✔
3376
}
3377

3378
impl Add for Value {
3379
    type Output = Value;
3380
    fn add(self, rhs: Self) -> Value {
78,812✔
3381
        let t = match self {
78,812✔
3382
            Value::Real(l) => match rhs {
20,980✔
3383
                Value::Real(r) => Value::Real(l + r),
16,142✔
3384
                Value::Int(r) => Value::Real(l + r as f64),
2,374✔
3385
                Value::Complex(r) => Value::Complex(l + r),
2,464✔
3386
            },
3387
            Value::Int(l) => match rhs {
24,908✔
3388
                Value::Real(r) => Value::Real(l as f64 + r),
2,178✔
3389
                Value::Int(r) => Value::Int(l + r),
12,742✔
3390
                Value::Complex(r) => Value::Complex(l as f64 + r),
9,988✔
3391
            },
3392
            Value::Complex(l) => match rhs {
32,924✔
3393
                Value::Real(r) => Value::Complex(l + r),
962✔
3394
                Value::Int(r) => Value::Complex(l + r as f64),
14,112✔
3395
                Value::Complex(r) => Value::Complex(l + r),
17,850✔
3396
            },
3397
        };
3398
        match t.opt_complex() {
78,812✔
3399
            Some(v) => v,
3,892✔
3400
            None => t,
74,920✔
3401
        }
3402
    }
78,812✔
3403
}
3404

3405
impl Sub for &Value {
3406
    type Output = Value;
3407
    fn sub(self, rhs: Self) -> Value {
62,466✔
3408
        *self - *rhs
62,466✔
3409
    }
62,466✔
3410
}
3411

3412
impl Sub for Value {
3413
    type Output = Value;
3414
    fn sub(self, rhs: Self) -> Value {
63,342✔
3415
        let t = match self {
63,342✔
3416
            Value::Real(l) => match rhs {
12,462✔
3417
                Value::Real(r) => Value::Real(l - r),
7,322✔
3418
                Value::Int(r) => Value::Real(l - r as f64),
3,434✔
3419
                Value::Complex(r) => Value::Complex(l - r),
1,706✔
3420
            },
3421
            Value::Int(l) => match rhs {
19,688✔
3422
                Value::Real(r) => Value::Real(l as f64 - r),
360✔
3423
                Value::Int(r) => Value::Int(l - r),
11,252✔
3424
                Value::Complex(r) => Value::Complex(l as f64 - r),
8,076✔
3425
            },
3426
            Value::Complex(l) => match rhs {
31,192✔
3427
                Value::Real(r) => Value::Complex(l - r),
458✔
3428
                Value::Int(r) => Value::Complex(l - r as f64),
13,818✔
3429
                Value::Complex(r) => Value::Complex(l - r),
16,916✔
3430
            },
3431
        };
3432
        match t.opt_complex() {
63,342✔
3433
            Some(v) => v,
5,372✔
3434
            None => t,
57,970✔
3435
        }
3436
    }
63,342✔
3437
}
3438

3439
impl Mul for &Value {
3440
    type Output = Value;
3441
    fn mul(self, rhs: Self) -> Value {
92,650✔
3442
        *self * *rhs
92,650✔
3443
    }
92,650✔
3444
}
3445

3446
impl Mul for Value {
3447
    type Output = Value;
3448
    fn mul(self, rhs: Self) -> Value {
94,210✔
3449
        let t = match self {
94,210✔
3450
            Value::Real(l) => match rhs {
71,742✔
3451
                Value::Real(r) => Value::Real(l * r),
70,566✔
3452
                Value::Int(r) => Value::Real(l * r as f64),
646✔
3453
                Value::Complex(r) => Value::Complex(l * r),
530✔
3454
            },
3455
            Value::Int(l) => match rhs {
3,558✔
3456
                Value::Real(r) => Value::Real(l as f64 * r),
488✔
3457
                Value::Int(r) => Value::Int(l * r),
1,620✔
3458
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,450✔
3459
            },
3460
            Value::Complex(l) => match rhs {
18,910✔
3461
                Value::Real(r) => Value::Complex(l * r),
482✔
3462
                Value::Int(r) => Value::Complex(l * r as f64),
1,612✔
3463
                Value::Complex(r) => Value::Complex(l * r),
16,816✔
3464
            },
3465
        };
3466
        match t.opt_complex() {
94,210✔
3467
            Some(v) => v,
11,384✔
3468
            None => t,
82,826✔
3469
        }
3470
    }
94,210✔
3471
}
3472

3473
impl Div for &Value {
3474
    type Output = Value;
3475
    fn div(self, rhs: Self) -> Value {
3,660✔
3476
        *self / *rhs
3,660✔
3477
    }
3,660✔
3478
}
3479

3480
impl Div for Value {
3481
    type Output = Value;
3482
    fn div(self, rhs: Self) -> Value {
4,648✔
3483
        let t = match self {
4,648✔
3484
            Value::Real(l) => match rhs {
1,992✔
3485
                Value::Real(r) => Value::Real(l / r),
212✔
3486
                Value::Int(r) => Value::Real(l / r as f64),
914✔
3487
                Value::Complex(r) => Value::Complex(l / r),
866✔
3488
            },
3489
            Value::Int(l) => {
1,362✔
3490
                if rhs == 0.0 {
1,362✔
3491
                    return Value::Real(f64::INFINITY);
×
3492
                }
1,362✔
3493
                match rhs {
1,362✔
3494
                    Value::Real(r) => Value::Real(l as f64 / r),
48✔
3495
                    Value::Int(r) => {
520✔
3496
                        let t = l as f64 / r as f64;
520✔
3497
                        let d = t.floor() - t;
520✔
3498
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
520✔
3499
                            Value::Int(t as i64)
454✔
3500
                        } else {
3501
                            Value::Real(t)
66✔
3502
                        }
3503
                    }
3504
                    Value::Complex(r) => Value::Complex(l as f64 / r),
794✔
3505
                }
3506
            }
3507
            Value::Complex(l) => match rhs {
1,294✔
3508
                Value::Real(r) => Value::Complex(l / r),
48✔
3509
                Value::Int(r) => Value::Complex(l / r as f64),
552✔
3510
                Value::Complex(r) => Value::Complex(l / r),
694✔
3511
            },
3512
        };
3513
        match t.opt_complex() {
4,648✔
3514
            Some(v) => v,
728✔
3515
            None => t,
3,920✔
3516
        }
3517
    }
4,648✔
3518
}
3519

3520
impl Neg for &Value {
3521
    type Output = Value;
3522
    fn neg(self) -> Value {
92,392✔
3523
        -*self
92,392✔
3524
    }
92,392✔
3525
}
3526

3527
impl Neg for Value {
3528
    type Output = Value;
3529
    fn neg(self) -> Value {
117,054✔
3530
        match self {
117,054✔
3531
            Value::Real(v) => Value::Real(-v),
17,494✔
3532
            Value::Int(v) => Value::Int(-v),
29,788✔
3533
            Value::Complex(v) => Value::Complex(-v),
69,772✔
3534
        }
3535
    }
117,054✔
3536
}
3537

3538
impl PartialEq for Value {
3539
    fn eq(&self, r: &Self) -> bool {
10,046✔
3540
        match self {
10,046✔
3541
            Value::Real(e) => match r {
5,166✔
3542
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
3,550✔
3543
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
750✔
3544
                Value::Complex(rv) => {
866✔
3545
                    let t = Complex64::from(*e) - rv;
866✔
3546
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
866✔
3547
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
132✔
3548
                }
3549
            },
3550
            Value::Int(e) => match r {
2,668✔
3551
                Value::Int(rv) => e == rv,
1,682✔
3552
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
266✔
3553
                Value::Complex(rv) => {
720✔
3554
                    let t = Complex64::from(*e as f64) - rv;
720✔
3555
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
720✔
3556
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
54✔
3557
                }
3558
            },
3559
            Value::Complex(e) => match r {
2,212✔
3560
                Value::Real(rv) => {
254✔
3561
                    let t = *e - Complex64::from(rv);
254✔
3562
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
254✔
3563
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3564
                }
3565
                Value::Int(rv) => {
456✔
3566
                    let t = *e - Complex64::from(*rv as f64);
456✔
3567
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
456✔
3568
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3569
                }
3570
                Value::Complex(rv) => {
1,502✔
3571
                    let t = *e - rv;
1,502✔
3572
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
1,502✔
3573
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
942✔
3574
                }
3575
            },
3576
        }
3577
    }
10,046✔
3578
}
3579

3580
impl PartialEq<f64> for Value {
3581
    fn eq(&self, r: &f64) -> bool {
1,362✔
3582
        match self {
1,362✔
3583
            Value::Real(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - r)),
48✔
3584
            Value::Int(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - r)),
520✔
3585
            Value::Complex(e) => {
794✔
3586
                let t = *e - Complex64::from(r);
794✔
3587
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
794✔
3588
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
194✔
3589
            }
3590
        }
3591
    }
1,362✔
3592
}
3593

3594
impl PartialEq<Complex64> for Value {
3595
    fn eq(&self, r: &Complex64) -> bool {
×
3596
        match self {
×
3597
            Value::Real(e) => {
×
3598
                let t = Complex64::from(*e) - r;
×
3599
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3600
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3601
            }
3602
            Value::Int(e) => {
×
3603
                let t = Complex64::from(*e as f64) - r;
×
3604
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3605
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3606
            }
3607
            Value::Complex(e) => {
×
3608
                let t = *e - r;
×
3609
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3610
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3611
            }
3612
        }
3613
    }
×
3614
}
3615

3616
impl PartialOrd for Value {
3617
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
12✔
3618
        match self {
12✔
3619
            Value::Real(l) => match rhs {
4✔
3620
                Value::Real(r) => l.partial_cmp(r),
4✔
3621
                Value::Int(r) => l.partial_cmp(&(*r as f64)),
×
3622
                Value::Complex(_) => None,
×
3623
            },
3624
            Value::Int(l) => match rhs {
4✔
3625
                Value::Real(r) => (*l as f64).partial_cmp(r),
×
3626
                Value::Int(r) => l.partial_cmp(r),
4✔
3627
                Value::Complex(_) => None,
×
3628
            },
3629
            Value::Complex(_) => None,
4✔
3630
        }
3631
    }
12✔
3632
}
3633

3634
/// Replace [Symbol]s in a [SymbolExpr] according to the name map. This
3635
/// is used to reconstruct a parameter expression from a string.
3636
pub fn replace_symbol(symbol_expr: &SymbolExpr, name_map: &HashMap<String, Symbol>) -> SymbolExpr {
116✔
3637
    match symbol_expr {
116✔
3638
        SymbolExpr::Symbol(existing_symbol) => {
36✔
3639
            let name = existing_symbol.repr(false);
36✔
3640
            if let Some(new_symbol) = name_map.get(&name) {
36✔
3641
                SymbolExpr::Symbol(Arc::new(new_symbol.clone()))
36✔
3642
            } else {
3643
                symbol_expr.clone()
×
3644
            }
3645
        }
3646
        SymbolExpr::Value(_) => symbol_expr.clone(), // nothing to do
56✔
3647
        SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
22✔
3648
            op: op.clone(),
22✔
3649
            lhs: Arc::new(replace_symbol(lhs, name_map)),
22✔
3650
            rhs: Arc::new(replace_symbol(rhs, name_map)),
22✔
3651
        },
22✔
3652
        SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
2✔
3653
            op: op.clone(),
2✔
3654
            expr: Arc::new(replace_symbol(expr, name_map)),
2✔
3655
        },
2✔
3656
    }
3657
}
116✔
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

© 2026 Coveralls, Inc