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

Qiskit / qiskit / 17209712632

25 Aug 2025 01:05PM UTC coverage: 88.37% (-0.08%) from 88.447%
17209712632

Pull #14659

github

web-flow
Merge e952c84f5 into c7d95a914
Pull Request #14659: Make `BasisTranslator` rust-native.

346 of 471 new or added lines in 5 files covered. (73.46%)

33 existing lines in 6 files now uncovered.

89871 of 101698 relevant lines covered (88.37%)

489685.54 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<PyObject>, // 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,072,866✔
46
        self.name == other.name && self.uuid == other.uuid && self.index == other.index
15,072,866✔
47
    }
15,072,866✔
48
}
49

50
impl Eq for Symbol {}
51

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

58
impl Hash for Symbol {
59
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46,110,846✔
60
        (&self.name, self.uuid, self.index).hash(state);
46,110,846✔
61
    }
46,110,846✔
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,022✔
82
        match (&self.index, &self.vector) {
58,022✔
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,350✔
86
        }
87
    }
58,022✔
88
}
89

90
impl Symbol {
91
    pub fn new(name: &str, uuid: Option<Uuid>, index: Option<u32>) -> Self {
92,182✔
92
        Self {
92,182✔
93
            name: name.to_string(),
92,182✔
94
            uuid: uuid.unwrap_or(Uuid::new_v4()),
92,182✔
95
            index,
92,182✔
96
            vector: None, // Python only
92,182✔
97
        }
92,182✔
98
    }
92,182✔
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<PyObject>,
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,064✔
122
        &self.name
88,064✔
123
    }
88,064✔
124

125
    pub fn repr(&self, with_uuid: bool) -> String {
15,126,624✔
126
        match (self.index, with_uuid) {
15,126,624✔
127
            (Some(i), true) => format!("{}[{}]_{}", self.name, i, self.uuid.as_u128()),
9,577,728✔
128
            (Some(i), false) => format!("{}[{}]", self.name, i),
4,822,140✔
129
            (None, true) => format!("{}_{}", self.name, self.uuid.as_u128()),
141,192✔
130
            (None, false) => self.name.clone(),
585,564✔
131
        }
132
    }
15,126,624✔
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)]
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,062✔
161
        if let Ok(i) = ob.extract::<i64>() {
4,555,062✔
162
            Ok(Value::Int(i))
2,376,122✔
163
        } else if let Ok(r) = ob.extract::<f64>() {
2,178,940✔
164
            Ok(Value::Real(r))
898,010✔
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,062✔
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,254✔
205
    if rhs.is_negative() {
127,254✔
206
        match rhs.neg_opt() {
41,002✔
207
            Some(e) => SymbolExpr::Binary {
41,002✔
208
                op: BinaryOp::Sub,
41,002✔
209
                lhs: Arc::new(lhs),
41,002✔
210
                rhs: Arc::new(e),
41,002✔
211
            },
41,002✔
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 {
86,252✔
220
            op: BinaryOp::Add,
86,252✔
221
            lhs: Arc::new(lhs),
86,252✔
222
            rhs: Arc::new(rhs),
86,252✔
223
        }
86,252✔
224
    }
225
}
127,254✔
226

227
// functions to make new expr for sub
228
#[inline(always)]
229
fn _sub(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
24,712✔
230
    if rhs.is_negative() {
24,712✔
231
        match rhs.neg_opt() {
1,154✔
232
            Some(e) => SymbolExpr::Binary {
1,154✔
233
                op: BinaryOp::Add,
1,154✔
234
                lhs: Arc::new(lhs),
1,154✔
235
                rhs: Arc::new(e),
1,154✔
236
            },
1,154✔
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,558✔
245
            op: BinaryOp::Sub,
23,558✔
246
            lhs: Arc::new(lhs),
23,558✔
247
            rhs: Arc::new(rhs),
23,558✔
248
        }
23,558✔
249
    }
250
}
24,712✔
251

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

262
// functions to make new expr for div
263
#[inline(always)]
264
fn _div(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
10,286✔
265
    SymbolExpr::Binary {
10,286✔
266
        op: BinaryOp::Div,
10,286✔
267
        lhs: Arc::new(lhs),
10,286✔
268
        rhs: Arc::new(rhs),
10,286✔
269
    }
10,286✔
270
}
10,286✔
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 {
32,182✔
285
    match expr.neg_opt() {
32,182✔
286
        Some(e) => e,
74✔
287
        None => SymbolExpr::Unary {
32,108✔
288
            op: UnaryOp::Neg,
32,108✔
289
            expr: Arc::new(expr),
32,108✔
290
        },
32,108✔
291
    }
292
}
32,182✔
293

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

300
impl SymbolExpr {
301
    /// bind value to symbol node
302
    pub fn bind(&self, maps: &HashMap<&Symbol, Value>) -> SymbolExpr {
1,258,178✔
303
        match self {
1,258,178✔
304
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
560,740✔
305
                Some(v) => SymbolExpr::Value(*v),
558,086✔
306
                None => self.clone(),
2,654✔
307
            },
308
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
252,758✔
309
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
23,914✔
310
                op: op.clone(),
23,914✔
311
                expr: Arc::new(expr.bind(maps)),
23,914✔
312
            },
23,914✔
313
            SymbolExpr::Binary { op, lhs, rhs } => {
420,766✔
314
                let new_lhs = lhs.bind(maps);
420,766✔
315
                let new_rhs = rhs.bind(maps);
420,766✔
316
                match op {
420,766✔
317
                    BinaryOp::Add => new_lhs + new_rhs,
88,742✔
318
                    BinaryOp::Sub => new_lhs - new_rhs,
64,638✔
319
                    BinaryOp::Mul => new_lhs * new_rhs,
243,236✔
320
                    BinaryOp::Div => new_lhs / new_rhs,
9,138✔
321
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
15,012✔
322
                }
323
            }
324
        }
325
    }
1,258,178✔
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 {
397,734✔
331
        match self {
397,734✔
332
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
234,226✔
333
                Some(v) => v.clone(),
37,400✔
334
                None => self.clone(),
196,826✔
335
            },
336
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
76,268✔
337
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
1,728✔
338
                op: op.clone(),
1,728✔
339
                expr: Arc::new(expr.subs(maps)),
1,728✔
340
            },
1,728✔
341
            SymbolExpr::Binary { op, lhs, rhs } => {
85,512✔
342
                let new_lhs = lhs.subs(maps);
85,512✔
343
                let new_rhs = rhs.subs(maps);
85,512✔
344
                match op {
85,512✔
345
                    BinaryOp::Add => new_lhs + new_rhs,
15,316✔
346
                    BinaryOp::Sub => new_lhs - new_rhs,
4,656✔
347
                    BinaryOp::Mul => new_lhs * new_rhs,
65,506✔
348
                    BinaryOp::Div => new_lhs / new_rhs,
16✔
349
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
350
                }
351
            }
352
        }
353
    }
397,734✔
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> {
55,460,342✔
358
        match self {
55,460,342✔
359
            SymbolExpr::Symbol(_) => None,
26,135,944✔
360
            SymbolExpr::Value(e) => Some(*e),
12,079,030✔
361
            SymbolExpr::Unary { op, expr } => {
573,222✔
362
                let val: Value;
363
                if recurse {
573,222✔
364
                    match expr.eval(recurse) {
573,222✔
365
                        Some(v) => val = v,
29,712✔
366
                        None => return None,
543,510✔
367
                    }
368
                } else {
369
                    match expr.as_ref() {
×
370
                        SymbolExpr::Value(e) => val = *e,
×
371
                        _ => return None,
×
372
                    }
373
                }
374
                let ret = match op {
29,712✔
375
                    UnaryOp::Abs => val.abs(),
462✔
376
                    UnaryOp::Neg => -val,
26,368✔
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 {
29,712✔
392
                    Value::Real(_) => Some(ret),
4,778✔
393
                    Value::Int(_) => Some(ret),
22,888✔
394
                    Value::Complex(c) => {
2,046✔
395
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
2,046✔
396
                            Some(Value::Real(c.re))
416✔
397
                        } else {
398
                            Some(ret)
1,630✔
399
                        }
400
                    }
401
                }
402
            }
403
            SymbolExpr::Binary { op, lhs, rhs } => {
16,672,146✔
404
                let lval: Value;
405
                let rval: Value;
406
                if recurse {
16,672,146✔
407
                    match (lhs.eval(true), rhs.eval(true)) {
16,672,146✔
408
                        (Some(left), Some(right)) => {
34,700✔
409
                            lval = left;
34,700✔
410
                            rval = right;
34,700✔
411
                        }
34,700✔
412
                        _ => return None,
16,637,446✔
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
    }
55,460,342✔
444

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

453
        match self {
110✔
454
            SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => Ok(SymbolExpr::Value(Value::Real(0.0))),
22✔
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 {
38✔
526
                BinaryOp::Add => Ok(lhs.derivative(param)? + rhs.derivative(param)?),
10✔
527
                BinaryOp::Sub => Ok(lhs.derivative(param)? - rhs.derivative(param)?),
×
528
                BinaryOp::Mul => Ok(&(&lhs.derivative(param)? * rhs.as_ref())
20✔
529
                    + &(lhs.as_ref() * &rhs.derivative(param)?)),
20✔
530
                BinaryOp::Div => Ok(&(&(&(&lhs.derivative(param)? * rhs.as_ref())
2✔
531
                    - &(lhs.as_ref() * &rhs.derivative(param)?))
2✔
532
                    / rhs.as_ref())
2✔
533
                    / rhs.as_ref()),
2✔
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
    }
174✔
575

576
    /// expand the equation
577
    pub fn expand(&self) -> SymbolExpr {
168,938✔
578
        match self {
168,938✔
579
            SymbolExpr::Symbol(_) => self.clone(),
28,684✔
580
            SymbolExpr::Value(_) => self.clone(),
3,436✔
581
            SymbolExpr::Unary { op, expr } => {
3,392✔
582
                let ex = expr.expand();
3,392✔
583
                match op {
3,392✔
584
                    UnaryOp::Neg => match ex.neg_opt() {
386✔
585
                        Some(ne) => ne,
×
586
                        None => _neg(ex),
386✔
587
                    },
588
                    _ => SymbolExpr::Unary {
3,006✔
589
                        op: op.clone(),
3,006✔
590
                        expr: Arc::new(ex),
3,006✔
591
                    },
3,006✔
592
                }
593
            }
594
            SymbolExpr::Binary { op, lhs, rhs } => {
133,426✔
595
                match op {
133,426✔
596
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
120,430✔
597
                        Some(e) => e,
2,704✔
598
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
117,726✔
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) {
3,904✔
605
                        Some(e) => e,
272✔
606
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,632✔
607
                    },
608
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
5,818✔
609
                        Some(e) => e,
2,332✔
610
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,486✔
611
                    },
612
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
3,132✔
613
                }
614
            }
615
        }
616
    }
168,938✔
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,091,786✔
662
        // This could maybe be more elegantly resolved with a SymbolIter type>
663
        match self {
14,091,786✔
664
            SymbolExpr::Symbol(e) => Box::new(::std::iter::once(e.as_ref())),
14,006,886✔
665
            SymbolExpr::Value(_) => Box::new(::std::iter::empty()),
40,394✔
666
            SymbolExpr::Unary { op: _, expr } => expr.iter_symbols(),
2,282✔
667
            SymbolExpr::Binary { op: _, lhs, rhs } => {
42,224✔
668
                Box::new(lhs.iter_symbols().chain(rhs.iter_symbols()))
42,224✔
669
            }
670
        }
671
    }
14,091,786✔
672

673
    /// Map of parameter name to the parameter.
674
    pub fn name_map(&self) -> HashMap<String, Symbol> {
4,758,242✔
675
        self.iter_symbols()
4,758,242✔
676
            .map(|param| (param.repr(false), param.clone()))
4,758,242✔
677
            .collect()
4,758,242✔
678
    }
4,758,242✔
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,962✔
734
        match self {
4,962✔
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,418✔
740
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
718✔
741
                _ => SymbolExpr::Value(*e),
700✔
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,450✔
748
                op: op.clone(),
1,450✔
749
                lhs: Arc::new(lhs.conjugate()),
1,450✔
750
                rhs: Arc::new(rhs.conjugate()),
1,450✔
751
            },
1,450✔
752
        }
753
    }
4,962✔
754

755
    /// check if complex number or not
756
    pub fn is_complex(&self) -> Option<bool> {
23,008✔
757
        match self.eval(true) {
23,008✔
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,002✔
763
        }
764
    }
23,008✔
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,458✔
773
        match self.eval(true) {
91,458✔
774
            Some(v) => match v {
67,780✔
775
                Value::Int(_) => Some(true),
64,486✔
776
                _ => Some(false),
3,294✔
777
            },
778
            None => None,
23,678✔
779
        }
780
    }
91,458✔
781

782
    /// check if evaluated result is 0
783
    pub fn is_zero(&self) -> bool {
9,734,966✔
784
        match self.eval(true) {
9,734,966✔
785
            Some(v) => v.is_zero(),
5,645,460✔
786
            None => false,
4,089,506✔
787
        }
788
    }
9,734,966✔
789

790
    /// check if evaluated result is 1
791
    pub fn is_one(&self) -> bool {
864,496✔
792
        match self.eval(true) {
864,496✔
793
            Some(v) => v.is_one(),
574,012✔
794
            None => false,
290,484✔
795
        }
796
    }
864,496✔
797

798
    /// check if evaluated result is -1
799
    pub fn is_minus_one(&self) -> bool {
588,210✔
800
        match self.eval(true) {
588,210✔
801
            Some(v) => v.is_minus_one(),
332,614✔
802
            None => false,
255,596✔
803
        }
804
    }
588,210✔
805

806
    /// check if evaluated result is negative
807
    fn is_negative(&self) -> bool {
464,574✔
808
        match self {
464,574✔
809
            SymbolExpr::Value(v) => v.is_negative(),
76,138✔
810
            SymbolExpr::Symbol(_) => false,
202,906✔
811
            SymbolExpr::Unary { op, expr } => match op {
18,040✔
812
                UnaryOp::Abs => false,
8✔
813
                UnaryOp::Neg => !expr.is_negative(),
15,574✔
814
                _ => false, // TO DO add heuristic determination
2,458✔
815
            },
816
            SymbolExpr::Binary { op, lhs, rhs } => match op {
167,490✔
817
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
139,384✔
818
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
18,266✔
819
                _ => false, // TO DO add heuristic determination for pow
9,840✔
820
            },
821
        }
822
    }
464,574✔
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,459,494✔
929
        self.repr(true)
9,459,494✔
930
    }
9,459,494✔
931

932
    // Add with heuristic optimization
933
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,560,598✔
934
        if self.is_zero() {
2,560,598✔
935
            Some(rhs.clone())
1,292,848✔
936
        } else if rhs.is_zero() {
1,267,750✔
937
            Some(self.clone())
1,029,840✔
938
        } else {
939
            // if neg operation, call sub_opt
940
            if let SymbolExpr::Unary { op, expr } = rhs {
237,910✔
941
                if let UnaryOp::Neg = op {
16,174✔
942
                    return self.sub_opt(expr, recursive);
14,324✔
943
                }
1,850✔
944
            } else if recursive {
221,736✔
945
                if let SymbolExpr::Binary {
946
                    op,
49,090✔
947
                    lhs: r_lhs,
49,090✔
948
                    rhs: r_rhs,
49,090✔
949
                } = rhs
53,154✔
950
                {
951
                    // recursive optimization for add and sub
952
                    if let BinaryOp::Add = &op {
49,090✔
953
                        if let Some(e) = self.add_opt(r_lhs, true) {
3,976✔
954
                            return match e.add_opt(r_rhs, true) {
52✔
955
                                Some(ee) => Some(ee),
38✔
956
                                None => Some(_add(e, r_rhs.as_ref().clone())),
14✔
957
                            };
958
                        }
3,924✔
959
                        if let Some(e) = self.add_opt(r_rhs, true) {
3,924✔
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
                        }
3,924✔
965
                    }
45,114✔
966
                    if let BinaryOp::Sub = &op {
49,038✔
967
                        if let Some(e) = self.add_opt(r_lhs, true) {
3,688✔
968
                            return match e.sub_opt(r_rhs, true) {
128✔
969
                                Some(ee) => Some(ee),
102✔
970
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
26✔
971
                            };
972
                        }
3,560✔
973
                        if let Some(e) = self.sub_opt(r_rhs, true) {
3,560✔
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
                        }
3,560✔
979
                    }
45,350✔
980
                }
4,064✔
981
            }
168,582✔
982

983
            // optimization for each node type
984
            match self {
223,406✔
985
                SymbolExpr::Value(l) => match rhs {
82,834✔
986
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
68,478✔
987
                    SymbolExpr::Binary {
988
                        op,
6,044✔
989
                        lhs: r_lhs,
6,044✔
990
                        rhs: r_rhs,
6,044✔
991
                    } => {
992
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
6,044✔
993
                            let t = l + v;
4,546✔
994
                            match op {
4,546✔
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,534✔
1013
                            }
1014
                        } else {
1015
                            None
1,498✔
1016
                        }
1017
                    }
1018
                    _ => None,
8,312✔
1019
                },
1020
                SymbolExpr::Symbol(l) => match rhs {
16,424✔
1021
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
2,458✔
1022
                    SymbolExpr::Symbol(r) => {
10,690✔
1023
                        if r == l {
10,690✔
1024
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
232✔
1025
                        } else if r < l {
10,458✔
1026
                            Some(_add(rhs.clone(), self.clone()))
1,530✔
1027
                        } else {
1028
                            None
8,928✔
1029
                        }
1030
                    }
1031
                    SymbolExpr::Binary {
1032
                        op,
3,276✔
1033
                        lhs: r_lhs,
3,276✔
1034
                        rhs: r_rhs,
3,276✔
1035
                    } => {
1036
                        if let (
1037
                            BinaryOp::Mul | BinaryOp::Div,
1038
                            SymbolExpr::Value(v),
2,246✔
1039
                            SymbolExpr::Symbol(s),
2,246✔
1040
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,276✔
1041
                        {
1042
                            if l == s {
2,246✔
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,240✔
1051
                            }
1052
                        } else {
1053
                            None
1,030✔
1054
                        }
1055
                    }
1056
                    _ => None,
×
1057
                },
1058
                SymbolExpr::Unary { op, expr } => {
17,064✔
1059
                    if let UnaryOp::Neg = op {
17,064✔
1060
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
15,650✔
1061
                            return match e.neg_opt() {
6,604✔
1062
                                Some(ee) => Some(ee),
6,604✔
1063
                                None => Some(_neg(e)),
×
1064
                            };
1065
                        }
9,046✔
1066
                    } else if let SymbolExpr::Unary {
1067
                        op: rop,
694✔
1068
                        expr: rexpr,
694✔
1069
                    } = rhs
1,414✔
1070
                    {
1071
                        if op == rop {
694✔
1072
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
354✔
1073
                                if t.is_zero() {
28✔
1074
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1075
                                }
28✔
1076
                            }
326✔
1077
                        }
340✔
1078
                    }
720✔
1079

1080
                    // swap nodes by sorting rule
1081
                    match rhs {
10,460✔
1082
                        SymbolExpr::Binary { op: rop, .. } => {
7,840✔
1083
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
7,840✔
1084
                                if self > rhs {
6,942✔
1085
                                    Some(_add(rhs.clone(), self.clone()))
×
1086
                                } else {
1087
                                    None
6,942✔
1088
                                }
1089
                            } else {
1090
                                None
898✔
1091
                            }
1092
                        }
1093
                        _ => {
1094
                            if self > rhs {
2,620✔
1095
                                Some(_add(rhs.clone(), self.clone()))
56✔
1096
                            } else {
1097
                                None
2,564✔
1098
                            }
1099
                        }
1100
                    }
1101
                }
1102
                SymbolExpr::Binary {
1103
                    op,
107,084✔
1104
                    lhs: l_lhs,
107,084✔
1105
                    rhs: l_rhs,
107,084✔
1106
                } => {
1107
                    if let SymbolExpr::Binary {
1108
                        op: rop,
98,064✔
1109
                        lhs: r_lhs,
98,064✔
1110
                        rhs: r_rhs,
98,064✔
1111
                    } = rhs
107,084✔
1112
                    {
1113
                        match (
1114
                            l_lhs.as_ref(),
98,064✔
1115
                            l_rhs.as_ref(),
98,064✔
1116
                            r_lhs.as_ref(),
98,064✔
1117
                            r_rhs.as_ref(),
98,064✔
1118
                        ) {
1119
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
11,200✔
1120
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
11,200✔
1121
                                    let t = SymbolExpr::Value(lv + rv);
1,710✔
1122
                                    if t.is_zero() {
1,710✔
1123
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,294✔
1124
                                    }
416✔
1125
                                    match (op, rop) {
416✔
1126
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1127
                                            return match t.mul_opt(l_rhs, recursive) {
320✔
1128
                                                Some(e) => Some(e),
8✔
1129
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
312✔
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
                                }
9,490✔
1147
                            }
1148
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2,768✔
1149
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
2,768✔
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,768✔
1165
                            }
1166
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
416✔
1167
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
416✔
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
                                }
416✔
1181
                            }
1182
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
276✔
1183
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
276✔
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
                                }
272✔
1197
                            }
1198
                            (_, _, _, _) => (),
83,404✔
1199
                        }
1200

1201
                        if op == rop {
96,350✔
1202
                            if let Some(e) = rhs.neg_opt() {
40,108✔
1203
                                if self.expand().string_id() == e.expand().string_id() {
29,958✔
1204
                                    return Some(SymbolExpr::Value(Value::Int(0)));
4✔
1205
                                }
29,954✔
1206
                            }
10,150✔
1207
                        }
56,242✔
1208
                    } else if let SymbolExpr::Symbol(r) = rhs {
9,020✔
1209
                        if let (
1210
                            BinaryOp::Mul | BinaryOp::Div,
1211
                            SymbolExpr::Value(v),
1,846✔
1212
                            SymbolExpr::Symbol(s),
1,846✔
1213
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,290✔
1214
                        {
1215
                            if s == r {
1,846✔
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,846✔
1226
                        }
3,444✔
1227
                    }
3,730✔
1228
                    if recursive {
105,366✔
1229
                        if let BinaryOp::Add = op {
43,212✔
1230
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
6,046✔
1231
                                return match e.add_opt(l_rhs, true) {
456✔
1232
                                    Some(ee) => Some(ee),
290✔
1233
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
166✔
1234
                                };
1235
                            }
5,590✔
1236
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
5,590✔
1237
                                return match l_lhs.add_opt(&e, true) {
130✔
1238
                                    Some(ee) => Some(ee),
×
1239
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
130✔
1240
                                };
1241
                            }
5,460✔
1242
                        } else if let BinaryOp::Sub = op {
37,166✔
1243
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
5,648✔
1244
                                return match e.sub_opt(l_rhs, true) {
1,066✔
1245
                                    Some(ee) => Some(ee),
418✔
1246
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
648✔
1247
                                };
1248
                            }
4,582✔
1249
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
4,582✔
1250
                                return match l_lhs.sub_opt(&e, true) {
156✔
1251
                                    Some(ee) => Some(ee),
44✔
1252
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
112✔
1253
                                };
1254
                            }
4,426✔
1255
                        }
31,518✔
1256
                    }
62,154✔
1257
                    // swap nodes by sorting rule
1258
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
103,558✔
1259
                        match rhs {
46,722✔
1260
                            SymbolExpr::Binary { op: rop, .. } => {
43,244✔
1261
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
43,244✔
1262
                                    if self > rhs {
38,716✔
1263
                                        Some(_add(rhs.clone(), self.clone()))
432✔
1264
                                    } else {
1265
                                        None
38,284✔
1266
                                    }
1267
                                } else {
1268
                                    None
4,528✔
1269
                                }
1270
                            }
1271
                            _ => {
1272
                                if self > rhs {
3,478✔
1273
                                    Some(_add(rhs.clone(), self.clone()))
3,478✔
1274
                                } else {
1275
                                    None
×
1276
                                }
1277
                            }
1278
                        }
1279
                    } else {
1280
                        None
56,836✔
1281
                    }
1282
                }
1283
            }
1284
        }
1285
    }
2,560,598✔
1286

1287
    /// Sub with heuristic optimization
1288
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
185,222✔
1289
        if self.is_zero() {
185,222✔
1290
            match rhs.neg_opt() {
7,422✔
1291
                Some(e) => Some(e),
5,954✔
1292
                None => Some(_neg(rhs.clone())),
1,468✔
1293
            }
1294
        } else if rhs.is_zero() {
177,800✔
1295
            Some(self.clone())
2,982✔
1296
        } else {
1297
            // if neg, call add_opt
1298
            if let SymbolExpr::Unary { op, expr } = rhs {
174,818✔
1299
                if let UnaryOp::Neg = op {
4,528✔
1300
                    return self.add_opt(expr, recursive);
2,346✔
1301
                }
2,182✔
1302
            } else if recursive {
170,290✔
1303
                if let SymbolExpr::Binary {
1304
                    op,
49,186✔
1305
                    lhs: r_lhs,
49,186✔
1306
                    rhs: r_rhs,
49,186✔
1307
                } = rhs
62,128✔
1308
                {
1309
                    // recursive optimization for add and sub
1310
                    if let BinaryOp::Add = &op {
49,186✔
1311
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,734✔
1312
                            return match e.sub_opt(r_rhs, true) {
766✔
1313
                                Some(ee) => Some(ee),
752✔
1314
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
14✔
1315
                            };
1316
                        }
2,968✔
1317
                        if let Some(e) = self.sub_opt(r_rhs, true) {
2,968✔
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
                        }
2,968✔
1323
                    }
45,452✔
1324
                    if let BinaryOp::Sub = &op {
48,420✔
1325
                        if let Some(e) = self.sub_opt(r_lhs, true) {
4,378✔
1326
                            return match e.add_opt(r_rhs, true) {
682✔
1327
                                Some(ee) => Some(ee),
664✔
1328
                                None => Some(_add(e, r_rhs.as_ref().clone())),
18✔
1329
                            };
1330
                        }
3,696✔
1331
                        if let Some(e) = self.add_opt(r_rhs, true) {
3,696✔
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
                        }
3,696✔
1337
                    }
44,042✔
1338
                }
12,942✔
1339
            }
108,162✔
1340

1341
            // optimization for each type
1342
            match self {
171,024✔
1343
                SymbolExpr::Value(l) => match &rhs {
68,476✔
1344
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
58,234✔
1345
                    SymbolExpr::Binary {
1346
                        op,
5,906✔
1347
                        lhs: r_lhs,
5,906✔
1348
                        rhs: r_rhs,
5,906✔
1349
                    } => {
1350
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,906✔
1351
                            let t = l - v;
3,300✔
1352
                            match op {
3,300✔
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,300✔
1371
                            }
1372
                        } else {
1373
                            None
2,606✔
1374
                        }
1375
                    }
1376
                    _ => None,
4,336✔
1377
                },
1378
                SymbolExpr::Symbol(l) => match &rhs {
26,730✔
1379
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
2,882✔
1380
                    SymbolExpr::Symbol(r) => {
19,630✔
1381
                        if r == l {
19,630✔
1382
                            Some(SymbolExpr::Value(Value::Int(0)))
12,488✔
1383
                        } else if r < l {
7,142✔
1384
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,250✔
1385
                        } else {
1386
                            None
5,892✔
1387
                        }
1388
                    }
1389
                    SymbolExpr::Binary {
1390
                        op,
4,218✔
1391
                        lhs: r_lhs,
4,218✔
1392
                        rhs: r_rhs,
4,218✔
1393
                    } => {
1394
                        if let (
1395
                            BinaryOp::Mul | BinaryOp::Div,
1396
                            SymbolExpr::Value(v),
2,290✔
1397
                            SymbolExpr::Symbol(s),
2,290✔
1398
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
4,218✔
1399
                        {
1400
                            if l == s {
2,290✔
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,280✔
1409
                            }
1410
                        } else {
1411
                            None
1,928✔
1412
                        }
1413
                    }
1414
                    _ => None,
×
1415
                },
1416
                SymbolExpr::Unary { op, expr } => {
13,490✔
1417
                    if let UnaryOp::Neg = op {
13,490✔
1418
                        if let Some(e) = expr.add_opt(rhs, recursive) {
11,480✔
1419
                            return match e.neg_opt() {
5,296✔
1420
                                Some(ee) => Some(ee),
5,296✔
1421
                                None => Some(_neg(e)),
×
1422
                            };
1423
                        }
6,184✔
1424
                    }
2,010✔
1425
                    if let SymbolExpr::Unary {
1426
                        op: rop,
1,372✔
1427
                        expr: rexpr,
1,372✔
1428
                    } = rhs
8,194✔
1429
                    {
1430
                        if op == rop {
1,372✔
1431
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
910✔
1432
                                if t.is_zero() {
676✔
1433
                                    return Some(SymbolExpr::Value(Value::Int(0)));
660✔
1434
                                }
16✔
1435
                            }
234✔
1436
                        }
462✔
1437
                    }
6,822✔
1438

1439
                    // swap nodes by sorting rule
1440
                    match rhs {
7,534✔
1441
                        SymbolExpr::Binary { op: rop, .. } => {
5,896✔
1442
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
5,896✔
1443
                                if self > rhs {
5,052✔
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
5,052✔
1450
                                }
1451
                            } else {
1452
                                None
844✔
1453
                            }
1454
                        }
1455
                        _ => {
1456
                            if self > rhs {
1,638✔
1457
                                match rhs.neg_opt() {
44✔
1458
                                    Some(e) => Some(_add(e, self.clone())),
×
1459
                                    None => Some(_add(_neg(rhs.clone()), self.clone())),
44✔
1460
                                }
1461
                            } else {
1462
                                None
1,594✔
1463
                            }
1464
                        }
1465
                    }
1466
                }
1467
                SymbolExpr::Binary {
1468
                    op,
62,328✔
1469
                    lhs: l_lhs,
62,328✔
1470
                    rhs: l_rhs,
62,328✔
1471
                } => {
1472
                    if let SymbolExpr::Binary {
1473
                        op: rop,
49,854✔
1474
                        lhs: r_lhs,
49,854✔
1475
                        rhs: r_rhs,
49,854✔
1476
                    } = rhs
62,328✔
1477
                    {
1478
                        match (
1479
                            l_lhs.as_ref(),
49,854✔
1480
                            l_rhs.as_ref(),
49,854✔
1481
                            r_lhs.as_ref(),
49,854✔
1482
                            r_rhs.as_ref(),
49,854✔
1483
                        ) {
1484
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
5,032✔
1485
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
5,032✔
1486
                                    let t = SymbolExpr::Value(lv - rv);
1,212✔
1487
                                    if t.is_zero() {
1,212✔
1488
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,212✔
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
                                }
3,820✔
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
                            (_, _, _, _) => (),
43,880✔
1564
                        }
1565

1566
                        if op == rop && self.expand().string_id() == rhs.expand().string_id() {
48,626✔
1567
                            return Some(SymbolExpr::Value(Value::Int(0)));
288✔
1568
                        }
48,338✔
1569
                    } else if let SymbolExpr::Symbol(r) = rhs {
12,474✔
1570
                        if let (
1571
                            BinaryOp::Mul | BinaryOp::Div,
1572
                            SymbolExpr::Value(v),
1,706✔
1573
                            SymbolExpr::Symbol(s),
1,706✔
1574
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,800✔
1575
                        {
1576
                            if s == r {
1,706✔
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,686✔
1587
                        }
4,094✔
1588
                    }
6,674✔
1589
                    if recursive {
60,792✔
1590
                        if let BinaryOp::Add = op {
43,696✔
1591
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
7,456✔
1592
                                return match e.add_opt(l_rhs, true) {
2,364✔
1593
                                    Some(ee) => Some(ee),
2,044✔
1594
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
320✔
1595
                                };
1596
                            }
5,092✔
1597
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
5,092✔
1598
                                return match l_lhs.add_opt(&e, true) {
916✔
1599
                                    Some(ee) => Some(ee),
776✔
1600
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
140✔
1601
                                };
1602
                            }
4,176✔
1603
                        }
36,240✔
1604
                        if let BinaryOp::Sub = op {
40,416✔
1605
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
7,922✔
1606
                                return match e.sub_opt(l_rhs, true) {
830✔
1607
                                    Some(ee) => Some(ee),
386✔
1608
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
444✔
1609
                                };
1610
                            }
7,092✔
1611
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,092✔
1612
                                return match l_lhs.sub_opt(&e, true) {
110✔
1613
                                    Some(ee) => Some(ee),
×
1614
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
110✔
1615
                                };
1616
                            }
6,982✔
1617
                        }
32,494✔
1618
                    }
17,096✔
1619
                    // swap nodes by sorting rule
1620
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
56,572✔
1621
                        match rhs {
34,436✔
1622
                            SymbolExpr::Binary { op: rop, .. } => {
30,064✔
1623
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
30,064✔
1624
                                    if self > rhs {
26,190✔
1625
                                        match rhs.neg_opt() {
96✔
1626
                                            Some(e) => Some(_add(e, self.clone())),
14✔
1627
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
82✔
1628
                                        }
1629
                                    } else {
1630
                                        None
26,094✔
1631
                                    }
1632
                                } else {
1633
                                    None
3,874✔
1634
                                }
1635
                            }
1636
                            _ => {
1637
                                if self > rhs {
4,372✔
1638
                                    match rhs.neg_opt() {
4,372✔
1639
                                        Some(e) => Some(_add(e, self.clone())),
1,682✔
1640
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
2,690✔
1641
                                    }
1642
                                } else {
1643
                                    None
×
1644
                                }
1645
                            }
1646
                        }
1647
                    } else {
1648
                        None
22,136✔
1649
                    }
1650
                }
1651
            }
1652
        }
1653
    }
185,222✔
1654

1655
    /// Mul with heuristic optimization
1656
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,760,986✔
1657
        if self.is_zero() {
2,760,986✔
1658
            Some(self.clone())
23,040✔
1659
        } else if rhs.is_zero() || self.is_one() {
2,737,946✔
1660
            Some(rhs.clone())
2,369,012✔
1661
        } else if rhs.is_one() {
368,934✔
1662
            Some(self.clone())
81,828✔
1663
        } else if self.is_minus_one() {
287,106✔
1664
            match rhs.neg_opt() {
4,456✔
1665
                Some(e) => Some(e),
2,242✔
1666
                None => Some(_neg(rhs.clone())),
2,214✔
1667
            }
1668
        } else if rhs.is_minus_one() {
282,650✔
1669
            match self.neg_opt() {
26,590✔
1670
                Some(e) => Some(e),
8,168✔
1671
                None => Some(_neg(self.clone())),
18,422✔
1672
            }
1673
        } else {
1674
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
256,060✔
1675
                if let SymbolExpr::Unary { .. } = self {
208,776✔
1676
                    return match rhs.mul_opt(self, recursive) {
5,816✔
1677
                        Some(e) => Some(e),
5,480✔
1678
                        None => Some(_mul(rhs.clone(), self.clone())),
336✔
1679
                    };
1680
                }
202,960✔
1681
            }
47,284✔
1682

1683
            match self {
250,244✔
1684
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
161,360✔
1685
                SymbolExpr::Symbol(e) => match rhs {
37,468✔
1686
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
16,870✔
1687
                    SymbolExpr::Symbol(r) => {
12,574✔
1688
                        if r < e {
12,574✔
1689
                            Some(_mul(rhs.clone(), self.clone()))
4,384✔
1690
                        } else {
1691
                            None
8,190✔
1692
                        }
1693
                    }
1694
                    SymbolExpr::Unary {
1695
                        op: UnaryOp::Neg,
1696
                        expr,
2,278✔
1697
                    } => match expr.as_ref() {
2,278✔
1698
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1699
                        SymbolExpr::Symbol(s) => {
2,278✔
1700
                            if s < e {
2,278✔
1701
                                Some(_neg(_mul(expr.as_ref().clone(), self.clone())))
1,434✔
1702
                            } else {
1703
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
844✔
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,
5,746✔
1716
                },
1717
                SymbolExpr::Unary { op, expr } => match op {
1,878✔
1718
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
1,868✔
1719
                        Some(e) => match e.neg_opt() {
264✔
1720
                            Some(ee) => Some(ee),
264✔
1721
                            None => Some(_neg(e)),
×
1722
                        },
1723
                        None => None,
1,604✔
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,
49,538✔
1745
                    lhs: l_lhs,
49,538✔
1746
                    rhs: l_rhs,
49,538✔
1747
                } => {
1748
                    if recursive {
49,538✔
1749
                        if let SymbolExpr::Binary {
1750
                            op: rop,
338✔
1751
                            lhs: r_lhs,
338✔
1752
                            rhs: r_rhs,
338✔
1753
                        } = rhs
5,332✔
1754
                        {
1755
                            if let BinaryOp::Mul = &rop {
338✔
1756
                                if let Some(e) = self.mul_opt(r_lhs, true) {
330✔
1757
                                    return match e.mul_opt(r_rhs, true) {
330✔
1758
                                        Some(ee) => Some(ee),
216✔
1759
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
114✔
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,994✔
1784

1785
                        if let BinaryOp::Mul = &op {
5,002✔
1786
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
4,994✔
1787
                                return match e.mul_opt(l_rhs, true) {
1,608✔
1788
                                    Some(ee) => Some(ee),
1,464✔
1789
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1790
                                };
1791
                            }
3,386✔
1792
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
3,386✔
1793
                                return match l_lhs.mul_opt(&e, true) {
1,524✔
1794
                                    Some(ee) => Some(ee),
×
1795
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
1,524✔
1796
                                };
1797
                            }
1,862✔
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,870✔
1813
                    } else {
1814
                        match rhs {
44,206✔
1815
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
29,150✔
1816
                                SymbolExpr::Value(lv) => match op {
9,886✔
1817
                                    BinaryOp::Mul => Some(_mul(
9,190✔
1818
                                        SymbolExpr::Value(lv * v),
9,190✔
1819
                                        l_rhs.as_ref().clone(),
9,190✔
1820
                                    )),
9,190✔
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() {
19,264✔
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,
18,688✔
1840
                                },
1841
                            },
1842
                            SymbolExpr::Binary {
1843
                                op: rop,
9,868✔
1844
                                lhs: r_lhs,
9,868✔
1845
                                rhs: r_rhs,
9,868✔
1846
                            } => match (op, rop) {
9,868✔
1847
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1848
                                    l_lhs.as_ref(),
936✔
1849
                                    l_rhs.as_ref(),
936✔
1850
                                    r_lhs.as_ref(),
936✔
1851
                                    r_rhs.as_ref(),
936✔
1852
                                ) {
1853
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
936✔
1854
                                        Some(_mul(
936✔
1855
                                            SymbolExpr::Value(lv * rv),
936✔
1856
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
936✔
1857
                                        ))
936✔
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,930✔
1976
                            },
1977
                            _ => None,
5,188✔
1978
                        }
1979
                    }
1980
                }
1981
            }
1982
        }
1983
    }
2,760,986✔
1984
    /// expand with optimization for mul operation
1985
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
266,432✔
1986
        if let SymbolExpr::Binary {
1987
            op: rop,
19,146✔
1988
            lhs: r_lhs,
19,146✔
1989
            rhs: r_rhs,
19,146✔
1990
        } = rhs
266,432✔
1991
        {
1992
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
19,146✔
1993
                let el = match self.mul_expand(r_lhs) {
2,474✔
1994
                    Some(e) => e,
1,420✔
1995
                    None => match self.mul_opt(r_lhs, true) {
1,054✔
1996
                        Some(e) => e,
692✔
1997
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
362✔
1998
                    },
1999
                };
2000
                let er = match self.mul_expand(r_rhs) {
2,474✔
2001
                    Some(e) => e,
1,308✔
2002
                    None => match self.mul_opt(r_rhs, true) {
1,166✔
2003
                        Some(e) => e,
382✔
2004
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
784✔
2005
                    },
2006
                };
2007
                return match &rop {
2,474✔
2008
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
1,196✔
2009
                        Some(e) => Some(e),
24✔
2010
                        None => Some(_sub(el, er)),
1,172✔
2011
                    },
2012
                    _ => match el.add_opt(&er, true) {
1,278✔
2013
                        Some(e) => Some(e),
26✔
2014
                        None => Some(_add(el, er)),
1,252✔
2015
                    },
2016
                };
2017
            }
16,672✔
2018
            if let BinaryOp::Mul = &rop {
16,672✔
2019
                return match self.mul_expand(r_lhs) {
16,624✔
2020
                    Some(e) => match e.mul_expand(r_rhs) {
1,442✔
2021
                        Some(ee) => Some(ee),
1,334✔
2022
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
108✔
2023
                    },
2024
                    None => self
15,182✔
2025
                        .mul_expand(r_rhs)
15,182✔
2026
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
15,182✔
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
        }
247,286✔
2041
        if let SymbolExpr::Unary {
2042
            op: UnaryOp::Neg,
2043
            expr: rexpr,
492✔
2044
        } = rhs
2,004✔
2045
        {
2046
            return match self.mul_expand(rexpr) {
492✔
2047
                Some(e) => match e.neg_opt() {
304✔
2048
                    Some(ee) => Some(ee),
304✔
2049
                    None => Some(_neg(e)),
×
2050
                },
2051
                None => match self.mul_opt(rexpr, true) {
188✔
2052
                    Some(e) => match e.neg_opt() {
88✔
2053
                        Some(ee) => Some(ee),
62✔
2054
                        None => Some(_neg(e)),
26✔
2055
                    },
2056
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
100✔
2057
                },
2058
            };
2059
        }
246,842✔
2060

2061
        match self {
1,650✔
2062
            SymbolExpr::Unary {
2063
                op: UnaryOp::Neg,
2064
                expr,
1,650✔
2065
            } => match expr.mul_expand(rhs) {
1,650✔
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,650✔
2071
                    Some(e) => match e.neg_opt() {
938✔
2072
                        Some(ee) => Some(ee),
650✔
2073
                        None => Some(_neg(e)),
288✔
2074
                    },
2075
                    None => None,
712✔
2076
                },
2077
            },
2078
            SymbolExpr::Binary {
2079
                op,
52,840✔
2080
                lhs: l_lhs,
52,840✔
2081
                rhs: l_rhs,
52,840✔
2082
            } => match &op {
52,840✔
2083
                BinaryOp::Add | BinaryOp::Sub => {
2084
                    let l = match l_lhs.mul_expand(rhs) {
5,358✔
2085
                        Some(e) => e,
2,064✔
2086
                        None => match l_lhs.mul_opt(rhs, true) {
3,294✔
2087
                            Some(e) => e,
2,444✔
2088
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
850✔
2089
                        },
2090
                    };
2091
                    let r = match l_rhs.mul_expand(rhs) {
5,358✔
2092
                        Some(e) => e,
16✔
2093
                        None => match l_rhs.mul_opt(rhs, true) {
5,342✔
2094
                            Some(e) => e,
3,532✔
2095
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
1,810✔
2096
                        },
2097
                    };
2098
                    match &op {
5,358✔
2099
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
2,516✔
2100
                            Some(e) => Some(e),
346✔
2101
                            None => Some(_sub(l, r)),
2,170✔
2102
                        },
2103
                        _ => match l.add_opt(&r, true) {
2,842✔
2104
                            Some(e) => Some(e),
464✔
2105
                            None => Some(_add(l, r)),
2,378✔
2106
                        },
2107
                    }
2108
                }
2109
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
47,462✔
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) {
47,374✔
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,
47,350✔
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,
192,352✔
2137
        }
2138
    }
266,432✔
2139

2140
    /// Div with heuristic optimization
2141
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
20,994✔
2142
        if rhs.is_zero() {
20,994✔
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,166✔
2146
            Some(self.clone())
712✔
2147
        } else if rhs.is_minus_one() {
18,454✔
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 {
17,770✔
2153
            let l_is_int = self.is_int().unwrap_or_default();
2,958✔
2154
            let r_is_int = rhs.is_int().unwrap_or_default();
2,958✔
2155
            if l_is_int || r_is_int {
2,958✔
2156
                Some(SymbolExpr::Value(Value::Int(1)))
976✔
2157
            } else {
2158
                Some(SymbolExpr::Value(Value::Real(1.0)))
1,982✔
2159
            }
2160
        } else {
2161
            if let SymbolExpr::Value(Value::Real(r)) = rhs {
6,726✔
2162
                let t = 1.0 / r;
1,282✔
2163
                if &(1.0 / t) == r {
1,282✔
2164
                    if recursive {
1,270✔
2165
                        return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
2166
                    } else {
2167
                        return Some(&SymbolExpr::Value(Value::Real(t)) * self);
1,270✔
2168
                    }
2169
                }
12✔
2170
            }
13,530✔
2171

2172
            match self {
13,542✔
2173
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
7,774✔
2174
                SymbolExpr::Symbol(_) => None,
3,036✔
2175
                SymbolExpr::Unary { op, expr } => match op {
88✔
2176
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
56✔
2177
                        Some(e) => match e.neg_opt() {
24✔
2178
                            Some(ee) => Some(ee),
24✔
2179
                            None => Some(_neg(e)),
×
2180
                        },
2181
                        None => None,
32✔
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,644✔
2203
                    lhs: l_lhs,
2,644✔
2204
                    rhs: l_rhs,
2,644✔
2205
                } => {
2206
                    if recursive {
2,644✔
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,636✔
2273
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
1,202✔
2274
                                SymbolExpr::Value(lv) => match op {
524✔
2275
                                    BinaryOp::Mul => Some(_mul(
220✔
2276
                                        SymbolExpr::Value(lv / v),
220✔
2277
                                        l_rhs.as_ref().clone(),
220✔
2278
                                    )),
220✔
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() {
678✔
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,
190✔
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
    }
20,994✔
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> {
373,758✔
2402
        match self {
18,460✔
2403
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
87,428✔
2404
            SymbolExpr::Unary {
2405
                op: UnaryOp::Neg,
2406
                expr,
16,844✔
2407
            } => Some(expr.as_ref().clone()),
16,844✔
2408
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
141,494✔
2409
                BinaryOp::Add => match lhs.neg_opt() {
4,660✔
2410
                    Some(ln) => match rhs.neg_opt() {
3,466✔
2411
                        Some(rn) => Some(_add(ln, rn)),
2,004✔
2412
                        None => Some(_sub(ln, rhs.as_ref().clone())),
1,462✔
2413
                    },
2414
                    None => match rhs.neg_opt() {
1,194✔
2415
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
562✔
2416
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
632✔
2417
                    },
2418
                },
2419
                BinaryOp::Sub => match lhs.neg_opt() {
4,214✔
2420
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
3,404✔
2421
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
810✔
2422
                },
2423
                BinaryOp::Mul => match lhs.neg_opt() {
130,464✔
2424
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
73,346✔
2425
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
57,118✔
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,
127,992✔
2434
        }
2435
    }
373,758✔
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,800,184✔
2499
        match self {
10,800,184✔
2500
            SymbolExpr::Symbol(e) => e.repr(with_uuid),
9,896,562✔
2501
            SymbolExpr::Value(e) => e.to_string(),
300,748✔
2502
            SymbolExpr::Unary { op, expr } => {
8,926✔
2503
                let s = expr.repr(with_uuid);
8,926✔
2504
                match op {
8,926✔
2505
                    UnaryOp::Abs => format!("abs({s})"),
×
2506
                    UnaryOp::Neg => match expr.as_ref() {
3,430✔
2507
                        SymbolExpr::Value(e) => (-e).to_string(),
×
2508
                        SymbolExpr::Binary {
2509
                            op: BinaryOp::Add | BinaryOp::Sub,
2510
                            ..
2511
                        } => format!("-({s})"),
×
2512
                        _ => format!("-{s}"),
3,430✔
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})"),
4,696✔
2524
                }
2525
            }
2526
            SymbolExpr::Binary { op, lhs, rhs } => {
593,948✔
2527
                let s_lhs = lhs.repr(with_uuid);
593,948✔
2528
                let s_rhs = rhs.repr(with_uuid);
593,948✔
2529
                let op_lhs = match lhs.as_ref() {
593,948✔
2530
                    SymbolExpr::Binary { op: lop, .. } => {
158,856✔
2531
                        matches!(lop, BinaryOp::Add | BinaryOp::Sub)
158,856✔
2532
                    }
2533
                    SymbolExpr::Value(e) => match e {
186,282✔
2534
                        Value::Real(v) => *v < 0.0,
17,350✔
2535
                        Value::Int(v) => *v < 0,
64,462✔
2536
                        Value::Complex(_) => true,
104,470✔
2537
                    },
2538
                    _ => false,
248,810✔
2539
                };
2540
                let op_rhs = match rhs.as_ref() {
593,948✔
2541
                    SymbolExpr::Binary { op: rop, .. } => match rop {
35,694✔
2542
                        BinaryOp::Add | BinaryOp::Sub => true,
2,908✔
2543
                        _ => matches!(op, BinaryOp::Div),
32,786✔
2544
                    },
2545
                    SymbolExpr::Value(e) => match e {
114,178✔
2546
                        Value::Real(v) => *v < 0.0,
65,302✔
2547
                        Value::Int(v) => *v < 0,
32,044✔
2548
                        Value::Complex(_) => true,
16,832✔
2549
                    },
2550
                    _ => false,
444,076✔
2551
                };
2552

2553
                match op {
593,948✔
2554
                    BinaryOp::Add => match rhs.as_ref() {
57,742✔
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}"),
57,742✔
2566
                    },
2567
                    BinaryOp::Sub => match rhs.as_ref() {
57,236✔
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,236✔
2585
                                format!("{s_lhs} -({s_rhs})")
604✔
2586
                            } else {
2587
                                format!("{s_lhs} - {s_rhs}")
56,632✔
2588
                            }
2589
                        }
2590
                    },
2591
                    BinaryOp::Mul => {
2592
                        if op_lhs {
413,260✔
2593
                            if op_rhs {
111,838✔
2594
                                format!("({s_lhs})*({s_rhs})")
714✔
2595
                            } else {
2596
                                format!("({s_lhs})*{s_rhs}")
111,124✔
2597
                            }
2598
                        } else if op_rhs {
301,422✔
2599
                            format!("{s_lhs}*({s_rhs})")
17,786✔
2600
                        } else {
2601
                            format!("{s_lhs}*{s_rhs}")
283,636✔
2602
                        }
2603
                    }
2604
                    BinaryOp::Div => {
2605
                        if op_lhs {
402✔
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 {
362✔
2612
                            format!("{s_lhs}/({s_rhs})")
8✔
2613
                        } else {
2614
                            format!("{s_lhs}/{s_rhs}")
354✔
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,800,184✔
2668
}
2669

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

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

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

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

2710
impl Mul for SymbolExpr {
2711
    type Output = SymbolExpr;
2712
    fn mul(self, rhs: Self) -> SymbolExpr {
308,752✔
2713
        match self.mul_opt(&rhs, false) {
308,752✔
2714
            Some(e) => e,
242,352✔
2715
            None => _mul(self, rhs),
66,400✔
2716
        }
2717
    }
308,752✔
2718
}
2719

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

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

2740
impl Div for &SymbolExpr {
2741
    type Output = SymbolExpr;
2742
    fn div(self, rhs: Self) -> SymbolExpr {
11,652✔
2743
        match self.div_opt(rhs, false) {
11,652✔
2744
            Some(e) => e,
2,916✔
2745
            None => _div(self.clone(), rhs.clone()),
8,736✔
2746
        }
2747
    }
11,652✔
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,058✔
2772
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
66,058✔
2773
            return l == r;
7,490✔
2774
        }
58,568✔
2775

2776
        match (self, rexpr) {
58,568✔
2777
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
31,052✔
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,660✔
2784
                let ex_rhs = rexpr.expand();
2,660✔
2785
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,660✔
2786
                    Some(e) => e.is_zero(),
2,316✔
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();
1,990✔
2795
                match ex_lhs.sub_opt(rexpr, true) {
1,990✔
2796
                    Some(e) => e.is_zero(),
1,878✔
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,202✔
2814
        }
2815
    }
66,058✔
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> {
106,056✔
2839
        match self {
106,056✔
2840
            SymbolExpr::Value(l) => match rhs {
300✔
2841
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2842
                _ => Some(Ordering::Less),
288✔
2843
            },
2844
            SymbolExpr::Symbol(l) => match rhs {
6,796✔
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,824✔
2849
            },
2850
            SymbolExpr::Unary { op: _, expr } => match rhs {
16,750✔
2851
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2852
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,496✔
2853
                _ => (expr.as_ref()).partial_cmp(rhs),
15,252✔
2854
            },
2855
            SymbolExpr::Binary {
2856
                op,
82,210✔
2857
                lhs: ll,
82,210✔
2858
                rhs: lr,
82,210✔
2859
            } => match rhs {
82,210✔
2860
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
7,916✔
2861
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
7,908✔
2862
                    _ => Some(Ordering::Equal),
8✔
2863
                },
2864
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
300✔
2865
                SymbolExpr::Binary {
2866
                    op: _,
2867
                    lhs: rl,
73,994✔
2868
                    rhs: rr,
73,994✔
2869
                } => {
2870
                    let ls = match ll.as_ref() {
73,994✔
2871
                        SymbolExpr::Value(_) => lr.string_id(),
17,442✔
2872
                        _ => self.string_id(),
56,552✔
2873
                    };
2874
                    let rs = match rl.as_ref() {
73,994✔
2875
                        SymbolExpr::Value(_) => rr.string_id(),
16,848✔
2876
                        _ => rhs.string_id(),
57,146✔
2877
                    };
2878
                    if rs > ls && rs.len() > ls.len() {
73,994✔
2879
                        Some(Ordering::Less)
5,676✔
2880
                    } else if rs < ls && rs.len() < ls.len() {
68,318✔
2881
                        Some(Ordering::Greater)
532✔
2882
                    } else {
2883
                        Some(Ordering::Equal)
67,786✔
2884
                    }
2885
                }
2886
            },
2887
        }
2888
    }
106,056✔
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 {
300,928✔
2899
        write!(
300,928✔
2900
            f,
300,928✔
2901
            "{}",
300,928✔
2902
            match self {
300,928✔
2903
                Value::Real(e) => e.to_string(),
83,042✔
2904
                Value::Int(e) => e.to_string(),
96,572✔
2905
                Value::Complex(e) => {
121,314✔
2906
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
121,314✔
2907
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
120,554✔
2908
                            0.to_string()
×
2909
                        } else {
2910
                            format!("{}i", e.im)
120,554✔
2911
                        }
2912
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
760✔
2913
                        e.re.to_string()
×
2914
                    } else {
2915
                        e.to_string()
760✔
2916
                    }
2917
                }
2918
            }
2919
        )
2920
    }
300,928✔
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,645,508✔
3180
        match self {
5,645,508✔
3181
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,893,848✔
3182
            Value::Int(i) => *i == 0,
461,624✔
3183
            Value::Complex(c) => {
290,036✔
3184
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
290,036✔
3185
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
211,956✔
3186
            }
3187
        }
3188
    }
5,645,508✔
3189
    pub fn is_one(&self) -> bool {
574,012✔
3190
        match self {
574,012✔
3191
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
277,464✔
3192
            Value::Int(i) => *i == 1,
161,204✔
3193
            Value::Complex(c) => {
135,344✔
3194
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
135,344✔
3195
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,658✔
3196
            }
3197
        }
3198
    }
574,012✔
3199
    pub fn is_minus_one(&self) -> bool {
332,614✔
3200
        match self {
332,614✔
3201
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
230,522✔
3202
            Value::Int(i) => *i == -1,
15,824✔
3203
            Value::Complex(c) => {
86,268✔
3204
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
86,268✔
3205
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
3,688✔
3206
            }
3207
        }
3208
    }
332,614✔
3209

3210
    pub fn is_negative(&self) -> bool {
76,138✔
3211
        match self {
76,138✔
3212
            Value::Real(r) => *r < 0.0,
17,826✔
3213
            Value::Int(i) => *i < 0,
5,360✔
3214
            Value::Complex(c) => {
52,952✔
3215
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
52,952✔
3216
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
52,952✔
3217
            }
3218
        }
3219
    }
76,138✔
3220

3221
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
164,464✔
3222
        match rhs {
4,894✔
3223
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
74,502✔
3224
            SymbolExpr::Unary {
3225
                op: UnaryOp::Neg,
3226
                expr,
4,142✔
3227
            } => {
3228
                let l = SymbolExpr::Value(-self);
4,142✔
3229
                match l.mul_opt(expr, recursive) {
4,142✔
UNCOV
3230
                    Some(e) => Some(e),
×
3231
                    None => Some(_mul(l, expr.as_ref().clone())),
4,142✔
3232
                }
3233
            }
3234
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
20,876✔
3235
                if recursive {
20,876✔
3236
                    match op {
1,568✔
3237
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
1,568✔
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,536✔
3243
                                .mul_opt(r, recursive)
1,536✔
3244
                                .map(|e| _mul(e, l.as_ref().clone())),
1,536✔
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,308✔
3256
                        SymbolExpr::Value(v) => match op {
4,310✔
3257
                            BinaryOp::Mul => {
3258
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
2,372✔
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() {
14,998✔
3266
                            SymbolExpr::Value(v) => match op {
2,340✔
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,332✔
3274
                            },
3275
                            _ => None,
12,658✔
3276
                        },
3277
                    }
3278
                }
3279
            }
3280
            _ => None,
64,944✔
3281
        }
3282
    }
164,464✔
3283

3284
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
7,774✔
3285
        match rhs {
40✔
3286
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self / r)),
3,038✔
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,774✔
3319

3320
    pub fn opt_complex(&self) -> Option<Value> {
245,672✔
3321
        match self {
245,672✔
3322
            Value::Complex(c) => {
115,802✔
3323
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
115,802✔
3324
                    Some(Value::Real(c.re))
23,936✔
3325
                } else {
3326
                    None
91,866✔
3327
                }
3328
            }
3329
            _ => None,
129,870✔
3330
        }
3331
    }
245,672✔
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,146✔
3357
        Value::Int(v)
134,146✔
3358
    }
134,146✔
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,305,392✔
3365
        } else {
3366
            Value::Complex(v)
55,944✔
3367
        }
3368
    }
2,361,336✔
3369
}
3370

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

3378
impl Add for Value {
3379
    type Output = Value;
3380
    fn add(self, rhs: Self) -> Value {
77,340✔
3381
        let t = match self {
77,340✔
3382
            Value::Real(l) => match rhs {
20,878✔
3383
                Value::Real(r) => Value::Real(l + r),
15,818✔
3384
                Value::Int(r) => Value::Real(l + r as f64),
2,586✔
3385
                Value::Complex(r) => Value::Complex(l + r),
2,474✔
3386
            },
3387
            Value::Int(l) => match rhs {
25,336✔
3388
                Value::Real(r) => Value::Real(l as f64 + r),
2,192✔
3389
                Value::Int(r) => Value::Int(l + r),
13,944✔
3390
                Value::Complex(r) => Value::Complex(l as f64 + r),
9,200✔
3391
            },
3392
            Value::Complex(l) => match rhs {
31,126✔
3393
                Value::Real(r) => Value::Complex(l + r),
1,010✔
3394
                Value::Int(r) => Value::Complex(l + r as f64),
12,018✔
3395
                Value::Complex(r) => Value::Complex(l + r),
18,098✔
3396
            },
3397
        };
3398
        match t.opt_complex() {
77,340✔
3399
            Some(v) => v,
4,362✔
3400
            None => t,
72,978✔
3401
        }
3402
    }
77,340✔
3403
}
3404

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

3412
impl Sub for Value {
3413
    type Output = Value;
3414
    fn sub(self, rhs: Self) -> Value {
63,652✔
3415
        let t = match self {
63,652✔
3416
            Value::Real(l) => match rhs {
12,426✔
3417
                Value::Real(r) => Value::Real(l - r),
7,194✔
3418
                Value::Int(r) => Value::Real(l - r as f64),
3,340✔
3419
                Value::Complex(r) => Value::Complex(l - r),
1,892✔
3420
            },
3421
            Value::Int(l) => match rhs {
21,672✔
3422
                Value::Real(r) => Value::Real(l as f64 - r),
368✔
3423
                Value::Int(r) => Value::Int(l - r),
13,938✔
3424
                Value::Complex(r) => Value::Complex(l as f64 - r),
7,366✔
3425
            },
3426
            Value::Complex(l) => match rhs {
29,554✔
3427
                Value::Real(r) => Value::Complex(l - r),
476✔
3428
                Value::Int(r) => Value::Complex(l - r as f64),
11,826✔
3429
                Value::Complex(r) => Value::Complex(l - r),
17,252✔
3430
            },
3431
        };
3432
        match t.opt_complex() {
63,652✔
3433
            Some(v) => v,
5,746✔
3434
            None => t,
57,906✔
3435
        }
3436
    }
63,652✔
3437
}
3438

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

3446
impl Mul for Value {
3447
    type Output = Value;
3448
    fn mul(self, rhs: Self) -> Value {
88,568✔
3449
        let t = match self {
88,568✔
3450
            Value::Real(l) => match rhs {
67,168✔
3451
                Value::Real(r) => Value::Real(l * r),
66,024✔
3452
                Value::Int(r) => Value::Real(l * r as f64),
614✔
3453
                Value::Complex(r) => Value::Complex(l * r),
530✔
3454
            },
3455
            Value::Int(l) => match rhs {
3,802✔
3456
                Value::Real(r) => Value::Real(l as f64 * r),
488✔
3457
                Value::Int(r) => Value::Int(l * r),
1,672✔
3458
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,642✔
3459
            },
3460
            Value::Complex(l) => match rhs {
17,598✔
3461
                Value::Real(r) => Value::Complex(l * r),
482✔
3462
                Value::Int(r) => Value::Complex(l * r as f64),
1,148✔
3463
                Value::Complex(r) => Value::Complex(l * r),
15,968✔
3464
            },
3465
        };
3466
        match t.opt_complex() {
88,568✔
3467
            Some(v) => v,
10,992✔
3468
            None => t,
77,576✔
3469
        }
3470
    }
88,568✔
3471
}
3472

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

3480
impl Div for Value {
3481
    type Output = Value;
3482
    fn div(self, rhs: Self) -> Value {
4,646✔
3483
        let t = match self {
4,646✔
3484
            Value::Real(l) => match rhs {
2,056✔
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),
930✔
3488
            },
3489
            Value::Int(l) => {
1,360✔
3490
                if rhs == 0.0 {
1,360✔
3491
                    return Value::Real(f64::INFINITY);
×
3492
                }
1,360✔
3493
                match rhs {
1,360✔
3494
                    Value::Real(r) => Value::Real(l as f64 / r),
48✔
3495
                    Value::Int(r) => {
518✔
3496
                        let t = l as f64 / r as f64;
518✔
3497
                        let d = t.floor() - t;
518✔
3498
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
518✔
3499
                            Value::Int(t as i64)
454✔
3500
                        } else {
3501
                            Value::Real(t)
64✔
3502
                        }
3503
                    }
3504
                    Value::Complex(r) => Value::Complex(l as f64 / r),
794✔
3505
                }
3506
            }
3507
            Value::Complex(l) => match rhs {
1,230✔
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),
630✔
3511
            },
3512
        };
3513
        match t.opt_complex() {
4,646✔
3514
            Some(v) => v,
744✔
3515
            None => t,
3,902✔
3516
        }
3517
    }
4,646✔
3518
}
3519

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

3527
impl Neg for Value {
3528
    type Output = Value;
3529
    fn neg(self) -> Value {
120,820✔
3530
        match self {
120,820✔
3531
            Value::Real(v) => Value::Real(-v),
16,950✔
3532
            Value::Int(v) => Value::Int(-v),
33,956✔
3533
            Value::Complex(v) => Value::Complex(-v),
69,914✔
3534
        }
3535
    }
120,820✔
3536
}
3537

3538
impl PartialEq for Value {
3539
    fn eq(&self, r: &Self) -> bool {
10,198✔
3540
        match self {
10,198✔
3541
            Value::Real(e) => match r {
5,342✔
3542
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
3,662✔
3543
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
750✔
3544
                Value::Complex(rv) => {
930✔
3545
                    let t = Complex64::from(*e) - rv;
930✔
3546
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
930✔
3547
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
160✔
3548
                }
3549
            },
3550
            Value::Int(e) => match r {
2,660✔
3551
                Value::Int(rv) => e == rv,
1,680✔
3552
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
266✔
3553
                Value::Complex(rv) => {
714✔
3554
                    let t = Complex64::from(*e as f64) - rv;
714✔
3555
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
714✔
3556
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
54✔
3557
                }
3558
            },
3559
            Value::Complex(e) => match r {
2,196✔
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,486✔
3571
                    let t = *e - rv;
1,486✔
3572
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
1,486✔
3573
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
930✔
3574
                }
3575
            },
3576
        }
3577
    }
10,198✔
3578
}
3579

3580
impl PartialEq<f64> for Value {
3581
    fn eq(&self, r: &f64) -> bool {
1,360✔
3582
        match self {
1,360✔
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)),
518✔
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)
214✔
3589
            }
3590
        }
3591
    }
1,360✔
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