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

Qiskit / qiskit / 18928476624

30 Oct 2025 03:02AM UTC coverage: 88.182% (-0.02%) from 88.199%
18928476624

Pull #15277

github

web-flow
Merge cbc852fa1 into 5d77750e2
Pull Request #15277: Combine Python types in PackedInstructions

109 of 154 new or added lines in 17 files covered. (70.78%)

25 existing lines in 5 files now uncovered.

93595 of 106138 relevant lines covered (88.18%)

1157666.34 hits per line

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

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

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

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

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

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

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

49
impl Eq for Symbol {}
50

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

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

63
impl<'a, 'py> FromPyObject<'a, 'py> for Symbol {
64
    type Error = PyErr;
65

66
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
18,270✔
67
        if let Ok(py_vector_element) = ob.extract::<PyParameterVectorElement>() {
18,270✔
68
            Ok(py_vector_element.symbol().clone())
16,460✔
69
        } else {
70
            ob.extract::<PyParameter>()
1,810✔
71
                .map(|ob| ob.symbol().clone())
1,810✔
72
                .map_err(PyErr::from)
1,810✔
73
        }
74
    }
18,270✔
75
}
76

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

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

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

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

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

122
    pub fn name(&self) -> &str {
87,924✔
123
        &self.name
87,924✔
124
    }
87,924✔
125

126
    pub fn repr(&self, with_uuid: bool) -> String {
15,332,256✔
127
        match (self.index, with_uuid) {
15,332,256✔
128
            (Some(i), true) => format!("{}[{}]_{}", self.name, i, self.uuid.as_u128()),
9,757,878✔
129
            (Some(i), false) => format!("{}[{}]", self.name, i),
4,822,612✔
130
            (None, true) => format!("{}_{}", self.name, self.uuid.as_u128()),
140,860✔
131
            (None, false) => self.name.clone(),
610,906✔
132
        }
133
    }
15,332,256✔
134
}
135

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

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

160
impl<'a, 'py> FromPyObject<'a, 'py> for Value {
161
    type Error = PyErr;
162

163
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
4,555,044✔
164
        if let Ok(i) = ob.extract::<i64>() {
4,555,044✔
165
            Ok(Value::Int(i))
2,376,122✔
166
        } else if let Ok(r) = ob.extract::<f64>() {
2,178,922✔
167
            Ok(Value::Real(r))
897,992✔
168
        } else {
169
            ob.extract::<Complex64>().map(Value::Complex)
1,280,930✔
170
        }
171
    }
4,555,044✔
172
}
173

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

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

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

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

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

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

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

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

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

299
impl SymbolExpr {
300
    /// bind value to symbol node
301
    pub fn bind(&self, maps: &HashMap<&Symbol, Value>) -> SymbolExpr {
1,282,004✔
302
        match self {
1,282,004✔
303
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
570,232✔
304
                Some(v) => SymbolExpr::Value(*v),
567,578✔
305
                None => self.clone(),
2,654✔
306
            },
307
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
262,376✔
308
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
21,034✔
309
                op: op.clone(),
21,034✔
310
                expr: Arc::new(expr.bind(maps)),
21,034✔
311
            },
21,034✔
312
            SymbolExpr::Binary { op, lhs, rhs } => {
428,362✔
313
                let new_lhs = lhs.bind(maps);
428,362✔
314
                let new_rhs = rhs.bind(maps);
428,362✔
315
                match op {
428,362✔
316
                    BinaryOp::Add => new_lhs + new_rhs,
90,142✔
317
                    BinaryOp::Sub => new_lhs - new_rhs,
65,208✔
318
                    BinaryOp::Mul => new_lhs * new_rhs,
248,806✔
319
                    BinaryOp::Div => new_lhs / new_rhs,
9,194✔
320
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
15,012✔
321
                }
322
            }
323
        }
324
    }
1,282,004✔
325

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

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

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

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

575
    /// expand the equation
576
    pub fn expand(&self) -> SymbolExpr {
201,190✔
577
        match self {
201,190✔
578
            SymbolExpr::Symbol(_) => self.clone(),
27,096✔
579
            SymbolExpr::Value(_) => self.clone(),
3,436✔
580
            SymbolExpr::Unary { op, expr } => {
2,772✔
581
                let ex = expr.expand();
2,772✔
582
                match op {
2,772✔
583
                    UnaryOp::Neg => match ex.neg_opt() {
422✔
584
                        Some(ne) => ne,
×
585
                        None => _neg(ex),
422✔
586
                    },
587
                    _ => SymbolExpr::Unary {
2,350✔
588
                        op: op.clone(),
2,350✔
589
                        expr: Arc::new(ex),
2,350✔
590
                    },
2,350✔
591
                }
592
            }
593
            SymbolExpr::Binary { op, lhs, rhs } => {
167,886✔
594
                match op {
167,886✔
595
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
151,746✔
596
                        Some(e) => e,
2,402✔
597
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
149,344✔
598
                    },
599
                    BinaryOp::Div => match lhs.div_expand(rhs) {
142✔
600
                        Some(e) => e,
8✔
601
                        None => _div(lhs.as_ref().clone(), rhs.as_ref().clone()),
134✔
602
                    },
603
                    BinaryOp::Add => match lhs.add_opt(rhs, true) {
5,454✔
604
                        Some(e) => e,
180✔
605
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
5,274✔
606
                    },
607
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
7,412✔
608
                        Some(e) => e,
2,304✔
609
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
5,108✔
610
                    },
611
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
3,132✔
612
                }
613
            }
614
        }
615
    }
201,190✔
616

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

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

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

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

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

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

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

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

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

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

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

781
    /// check if evaluated result is 0
782
    pub fn is_zero(&self) -> bool {
9,767,834✔
783
        match self.eval(true) {
9,767,834✔
784
            Some(v) => v.is_zero(),
5,659,108✔
785
            None => false,
4,108,726✔
786
        }
787
    }
9,767,834✔
788

789
    /// check if evaluated result is 1
790
    pub fn is_one(&self) -> bool {
870,746✔
791
        match self.eval(true) {
870,746✔
792
            Some(v) => v.is_one(),
585,562✔
793
            None => false,
285,184✔
794
        }
795
    }
870,746✔
796

797
    /// check if evaluated result is -1
798
    pub fn is_minus_one(&self) -> bool {
592,702✔
799
        match self.eval(true) {
592,702✔
800
            Some(v) => v.is_minus_one(),
343,116✔
801
            None => false,
249,586✔
802
        }
803
    }
592,702✔
804

805
    /// check if evaluated result is negative
806
    fn is_negative(&self) -> bool {
474,130✔
807
        match self {
474,130✔
808
            SymbolExpr::Value(v) => v.is_negative(),
73,898✔
809
            SymbolExpr::Symbol(_) => false,
211,540✔
810
            SymbolExpr::Unary { op, expr } => match op {
18,758✔
811
                UnaryOp::Abs => false,
8✔
812
                UnaryOp::Neg => !expr.is_negative(),
16,640✔
813
                _ => false, // TO DO add heuristic determination
2,110✔
814
            },
815
            SymbolExpr::Binary { op, lhs, rhs } => match op {
169,934✔
816
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
141,738✔
817
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
18,356✔
818
                _ => false, // TO DO add heuristic determination for pow
9,840✔
819
            },
820
        }
821
    }
474,130✔
822

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

927
    pub fn string_id(&self) -> String {
9,543,146✔
928
        self.repr(true)
9,543,146✔
929
    }
9,543,146✔
930

931
    // Add with heuristic optimization
932
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,584,804✔
933
        if self.is_zero() {
2,584,804✔
934
            Some(rhs.clone())
1,366,164✔
935
        } else if rhs.is_zero() {
1,218,640✔
936
            Some(self.clone())
955,044✔
937
        } else {
938
            // if neg operation, call sub_opt
939
            if let SymbolExpr::Unary { op, expr } = rhs {
263,596✔
940
                if let UnaryOp::Neg = op {
17,584✔
941
                    return self.sub_opt(expr, recursive);
15,950✔
942
                }
1,634✔
943
            } else if recursive {
246,012✔
944
                if let SymbolExpr::Binary {
945
                    op,
71,374✔
946
                    lhs: r_lhs,
71,374✔
947
                    rhs: r_rhs,
71,374✔
948
                } = rhs
75,412✔
949
                {
950
                    // recursive optimization for add and sub
951
                    if let BinaryOp::Add = &op {
71,374✔
952
                        if let Some(e) = self.add_opt(r_lhs, true) {
6,142✔
953
                            return match e.add_opt(r_rhs, true) {
22✔
954
                                Some(ee) => Some(ee),
18✔
955
                                None => Some(_add(e, r_rhs.as_ref().clone())),
4✔
956
                            };
957
                        }
6,120✔
958
                        if let Some(e) = self.add_opt(r_rhs, true) {
6,120✔
959
                            return match e.add_opt(r_lhs, true) {
×
960
                                Some(ee) => Some(ee),
×
961
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
962
                            };
963
                        }
6,120✔
964
                    }
65,232✔
965
                    if let BinaryOp::Sub = &op {
71,352✔
966
                        if let Some(e) = self.add_opt(r_lhs, true) {
5,330✔
967
                            return match e.sub_opt(r_rhs, true) {
82✔
968
                                Some(ee) => Some(ee),
78✔
969
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
4✔
970
                            };
971
                        }
5,248✔
972
                        if let Some(e) = self.sub_opt(r_rhs, true) {
5,248✔
973
                            return match e.add_opt(r_lhs, true) {
×
974
                                Some(ee) => Some(ee),
×
975
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
976
                            };
977
                        }
5,248✔
978
                    }
66,022✔
979
                }
4,038✔
980
            }
170,600✔
981

982
            // optimization for each node type
983
            match self {
247,542✔
984
                SymbolExpr::Value(l) => match rhs {
85,938✔
985
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
71,228✔
986
                    SymbolExpr::Binary {
987
                        op,
6,036✔
988
                        lhs: r_lhs,
6,036✔
989
                        rhs: r_rhs,
6,036✔
990
                    } => {
991
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
6,036✔
992
                            let t = l + v;
4,538✔
993
                            match op {
4,538✔
994
                                BinaryOp::Add => {
995
                                    if t.is_zero() {
12✔
996
                                        Some(r_rhs.as_ref().clone())
×
997
                                    } else {
998
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
12✔
999
                                    }
1000
                                }
1001
                                BinaryOp::Sub => {
1002
                                    if t.is_zero() {
×
1003
                                        match r_rhs.neg_opt() {
×
1004
                                            Some(e) => Some(e),
×
1005
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1006
                                        }
1007
                                    } else {
1008
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1009
                                    }
1010
                                }
1011
                                _ => None,
4,526✔
1012
                            }
1013
                        } else {
1014
                            None
1,498✔
1015
                        }
1016
                    }
1017
                    _ => None,
8,674✔
1018
                },
1019
                SymbolExpr::Symbol(l) => match rhs {
17,090✔
1020
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
2,532✔
1021
                    SymbolExpr::Symbol(r) => {
11,008✔
1022
                        if r == l {
11,008✔
1023
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
232✔
1024
                        } else if r < l {
10,776✔
1025
                            Some(_add(rhs.clone(), self.clone()))
1,464✔
1026
                        } else {
1027
                            None
9,312✔
1028
                        }
1029
                    }
1030
                    SymbolExpr::Binary {
1031
                        op,
3,550✔
1032
                        lhs: r_lhs,
3,550✔
1033
                        rhs: r_rhs,
3,550✔
1034
                    } => {
1035
                        if let (
1036
                            BinaryOp::Mul | BinaryOp::Div,
1037
                            SymbolExpr::Value(v),
2,456✔
1038
                            SymbolExpr::Symbol(s),
2,456✔
1039
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,550✔
1040
                        {
1041
                            if l == s {
2,456✔
1042
                                let t = v + &Value::Int(1);
6✔
1043
                                if t.is_zero() {
6✔
1044
                                    Some(SymbolExpr::Value(Value::Int(0)))
2✔
1045
                                } else {
1046
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
4✔
1047
                                }
1048
                            } else {
1049
                                None
2,450✔
1050
                            }
1051
                        } else {
1052
                            None
1,094✔
1053
                        }
1054
                    }
1055
                    _ => None,
×
1056
                },
1057
                SymbolExpr::Unary { op, expr } => {
15,326✔
1058
                    if let UnaryOp::Neg = op {
15,326✔
1059
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
14,114✔
1060
                            return match e.neg_opt() {
5,206✔
1061
                                Some(ee) => Some(ee),
5,206✔
1062
                                None => Some(_neg(e)),
×
1063
                            };
1064
                        }
8,908✔
1065
                    } else if let SymbolExpr::Unary {
1066
                        op: rop,
576✔
1067
                        expr: rexpr,
576✔
1068
                    } = rhs
1,212✔
1069
                    {
1070
                        if op == rop {
576✔
1071
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
236✔
1072
                                if t.is_zero() {
12✔
1073
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1074
                                }
12✔
1075
                            }
224✔
1076
                        }
340✔
1077
                    }
636✔
1078

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

1200
                        if op == rop {
118,964✔
1201
                            if let Some(e) = rhs.neg_opt() {
52,974✔
1202
                                if self.expand().string_id() == e.expand().string_id() {
32,312✔
1203
                                    return Some(SymbolExpr::Value(Value::Int(0)));
4✔
1204
                                }
32,308✔
1205
                            }
20,662✔
1206
                        }
65,990✔
1207
                    } else if let SymbolExpr::Symbol(r) = rhs {
8,498✔
1208
                        if let (
1209
                            BinaryOp::Mul | BinaryOp::Div,
1210
                            SymbolExpr::Value(v),
1,536✔
1211
                            SymbolExpr::Symbol(s),
1,536✔
1212
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
4,936✔
1213
                        {
1214
                            if s == r {
1,536✔
1215
                                let t = v + &Value::Int(1);
×
1216
                                if t.is_zero() {
×
1217
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1218
                                } else {
1219
                                    return Some(_mul(
×
1220
                                        SymbolExpr::Value(t),
×
1221
                                        l_rhs.as_ref().clone(),
×
1222
                                    ));
×
1223
                                }
1224
                            }
1,536✔
1225
                        }
3,400✔
1226
                    }
3,562✔
1227
                    if recursive {
127,458✔
1228
                        if let BinaryOp::Add = op {
64,970✔
1229
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
8,032✔
1230
                                return match e.add_opt(l_rhs, true) {
350✔
1231
                                    Some(ee) => Some(ee),
264✔
1232
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
86✔
1233
                                };
1234
                            }
7,682✔
1235
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,682✔
1236
                                return match l_lhs.add_opt(&e, true) {
84✔
UNCOV
1237
                                    Some(ee) => Some(ee),
×
1238
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
84✔
1239
                                };
1240
                            }
7,598✔
1241
                        } else if let BinaryOp::Sub = op {
56,938✔
1242
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
10,462✔
1243
                                return match e.sub_opt(l_rhs, true) {
960✔
1244
                                    Some(ee) => Some(ee),
364✔
1245
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
596✔
1246
                                };
1247
                            }
9,502✔
1248
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
9,502✔
1249
                                return match l_lhs.sub_opt(&e, true) {
126✔
1250
                                    Some(ee) => Some(ee),
52✔
1251
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
74✔
1252
                                };
1253
                            }
9,376✔
1254
                        }
46,476✔
1255
                    }
62,488✔
1256
                    // swap nodes by sorting rule
1257
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
125,938✔
1258
                        match rhs {
60,754✔
1259
                            SymbolExpr::Binary { op: rop, .. } => {
57,634✔
1260
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
57,634✔
1261
                                    if self > rhs {
50,782✔
1262
                                        Some(_add(rhs.clone(), self.clone()))
388✔
1263
                                    } else {
1264
                                        None
50,394✔
1265
                                    }
1266
                                } else {
1267
                                    None
6,852✔
1268
                                }
1269
                            }
1270
                            _ => {
1271
                                if self > rhs {
3,120✔
1272
                                    Some(_add(rhs.clone(), self.clone()))
3,120✔
1273
                                } else {
1274
                                    None
×
1275
                                }
1276
                            }
1277
                        }
1278
                    } else {
1279
                        None
65,184✔
1280
                    }
1281
                }
1282
            }
1283
        }
1284
    }
2,584,804✔
1285

1286
    /// Sub with heuristic optimization
1287
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
209,796✔
1288
        if self.is_zero() {
209,796✔
1289
            match rhs.neg_opt() {
6,808✔
1290
                Some(e) => Some(e),
5,434✔
1291
                None => Some(_neg(rhs.clone())),
1,374✔
1292
            }
1293
        } else if rhs.is_zero() {
202,988✔
1294
            Some(self.clone())
3,272✔
1295
        } else {
1296
            // if neg, call add_opt
1297
            if let SymbolExpr::Unary { op, expr } = rhs {
199,716✔
1298
                if let UnaryOp::Neg = op {
4,784✔
1299
                    return self.add_opt(expr, recursive);
2,800✔
1300
                }
1,984✔
1301
            } else if recursive {
194,932✔
1302
                if let SymbolExpr::Binary {
1303
                    op,
73,380✔
1304
                    lhs: r_lhs,
73,380✔
1305
                    rhs: r_rhs,
73,380✔
1306
                } = rhs
86,208✔
1307
                {
1308
                    // recursive optimization for add and sub
1309
                    if let BinaryOp::Add = &op {
73,380✔
1310
                        if let Some(e) = self.sub_opt(r_lhs, true) {
5,892✔
1311
                            return match e.sub_opt(r_rhs, true) {
726✔
1312
                                Some(ee) => Some(ee),
722✔
1313
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
4✔
1314
                            };
1315
                        }
5,166✔
1316
                        if let Some(e) = self.sub_opt(r_rhs, true) {
5,166✔
1317
                            return match e.sub_opt(r_lhs, true) {
×
1318
                                Some(ee) => Some(ee),
×
1319
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
×
1320
                            };
1321
                        }
5,166✔
1322
                    }
67,488✔
1323
                    if let BinaryOp::Sub = &op {
72,654✔
1324
                        if let Some(e) = self.sub_opt(r_lhs, true) {
6,396✔
1325
                            return match e.add_opt(r_rhs, true) {
626✔
1326
                                Some(ee) => Some(ee),
614✔
1327
                                None => Some(_add(e, r_rhs.as_ref().clone())),
12✔
1328
                            };
1329
                        }
5,770✔
1330
                        if let Some(e) = self.add_opt(r_rhs, true) {
5,770✔
1331
                            return match e.sub_opt(r_lhs, true) {
×
1332
                                Some(ee) => Some(ee),
×
1333
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
×
1334
                            };
1335
                        }
5,770✔
1336
                    }
66,258✔
1337
                }
12,828✔
1338
            }
108,724✔
1339

1340
            // optimization for each type
1341
            match self {
195,564✔
1342
                SymbolExpr::Value(l) => match &rhs {
68,432✔
1343
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
58,080✔
1344
                    SymbolExpr::Binary {
1345
                        op,
5,898✔
1346
                        lhs: r_lhs,
5,898✔
1347
                        rhs: r_rhs,
5,898✔
1348
                    } => {
1349
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,898✔
1350
                            let t = l - v;
3,292✔
1351
                            match op {
3,292✔
1352
                                BinaryOp::Add => {
1353
                                    if t.is_zero() {
×
1354
                                        match r_rhs.neg_opt() {
×
1355
                                            Some(e) => Some(e),
×
1356
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1357
                                        }
1358
                                    } else {
1359
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1360
                                    }
1361
                                }
1362
                                BinaryOp::Sub => {
1363
                                    if t.is_zero() {
×
1364
                                        Some(r_rhs.as_ref().clone())
×
1365
                                    } else {
1366
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1367
                                    }
1368
                                }
1369
                                _ => None,
3,292✔
1370
                            }
1371
                        } else {
1372
                            None
2,606✔
1373
                        }
1374
                    }
1375
                    _ => None,
4,454✔
1376
                },
1377
                SymbolExpr::Symbol(l) => match &rhs {
27,810✔
1378
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
3,210✔
1379
                    SymbolExpr::Symbol(r) => {
19,864✔
1380
                        if r == l {
19,864✔
1381
                            Some(SymbolExpr::Value(Value::Int(0)))
12,420✔
1382
                        } else if r < l {
7,444✔
1383
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,184✔
1384
                        } else {
1385
                            None
6,260✔
1386
                        }
1387
                    }
1388
                    SymbolExpr::Binary {
1389
                        op,
4,736✔
1390
                        lhs: r_lhs,
4,736✔
1391
                        rhs: r_rhs,
4,736✔
1392
                    } => {
1393
                        if let (
1394
                            BinaryOp::Mul | BinaryOp::Div,
1395
                            SymbolExpr::Value(v),
2,752✔
1396
                            SymbolExpr::Symbol(s),
2,752✔
1397
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
4,736✔
1398
                        {
1399
                            if l == s {
2,752✔
1400
                                let t = &Value::Int(1) - v;
10✔
1401
                                if t.is_zero() {
10✔
1402
                                    Some(SymbolExpr::Value(Value::Int(0)))
×
1403
                                } else {
1404
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
10✔
1405
                                }
1406
                            } else {
1407
                                None
2,742✔
1408
                            }
1409
                        } else {
1410
                            None
1,984✔
1411
                        }
1412
                    }
1413
                    _ => None,
×
1414
                },
1415
                SymbolExpr::Unary { op, expr } => {
13,820✔
1416
                    if let UnaryOp::Neg = op {
13,820✔
1417
                        if let Some(e) = expr.add_opt(rhs, recursive) {
11,880✔
1418
                            return match e.neg_opt() {
5,004✔
1419
                                Some(ee) => Some(ee),
5,004✔
1420
                                None => Some(_neg(e)),
×
1421
                            };
1422
                        }
6,876✔
1423
                    }
1,940✔
1424
                    if let SymbolExpr::Unary {
1425
                        op: rop,
1,378✔
1426
                        expr: rexpr,
1,378✔
1427
                    } = rhs
8,816✔
1428
                    {
1429
                        if op == rop {
1,378✔
1430
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
940✔
1431
                                if t.is_zero() {
760✔
1432
                                    return Some(SymbolExpr::Value(Value::Int(0)));
760✔
UNCOV
1433
                                }
×
1434
                            }
180✔
1435
                        }
438✔
1436
                    }
7,438✔
1437

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

1565
                        if op == rop && self.expand().string_id() == rhs.expand().string_id() {
72,206✔
1566
                            return Some(SymbolExpr::Value(Value::Int(0)));
288✔
1567
                        }
71,918✔
1568
                    } else if let SymbolExpr::Symbol(r) = rhs {
12,072✔
1569
                        if let (
1570
                            BinaryOp::Mul | BinaryOp::Div,
1571
                            SymbolExpr::Value(v),
1,480✔
1572
                            SymbolExpr::Symbol(s),
1,480✔
1573
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,298✔
1574
                        {
1575
                            if s == r {
1,480✔
1576
                                let t = v - &Value::Int(1);
20✔
1577
                                if t.is_zero() {
20✔
1578
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1579
                                } else {
1580
                                    return Some(_mul(
20✔
1581
                                        SymbolExpr::Value(t),
20✔
1582
                                        l_rhs.as_ref().clone(),
20✔
1583
                                    ));
20✔
1584
                                }
1585
                            }
1,460✔
1586
                        }
3,818✔
1587
                    }
6,774✔
1588
                    if recursive {
83,970✔
1589
                        if let BinaryOp::Add = op {
66,662✔
1590
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
10,622✔
1591
                                return match e.add_opt(l_rhs, true) {
2,404✔
1592
                                    Some(ee) => Some(ee),
1,956✔
1593
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
448✔
1594
                                };
1595
                            }
8,218✔
1596
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
8,218✔
1597
                                return match l_lhs.add_opt(&e, true) {
874✔
1598
                                    Some(ee) => Some(ee),
784✔
1599
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
90✔
1600
                                };
1601
                            }
7,344✔
1602
                        }
56,040✔
1603
                        if let BinaryOp::Sub = op {
63,384✔
1604
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
11,486✔
1605
                                return match e.sub_opt(l_rhs, true) {
668✔
1606
                                    Some(ee) => Some(ee),
302✔
1607
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
366✔
1608
                                };
1609
                            }
10,818✔
1610
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
10,818✔
1611
                                return match l_lhs.sub_opt(&e, true) {
76✔
UNCOV
1612
                                    Some(ee) => Some(ee),
×
1613
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
76✔
1614
                                };
1615
                            }
10,742✔
1616
                        }
51,898✔
1617
                    }
17,308✔
1618
                    // swap nodes by sorting rule
1619
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
79,948✔
1620
                        match rhs {
50,452✔
1621
                            SymbolExpr::Binary { op: rop, .. } => {
46,350✔
1622
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
46,350✔
1623
                                    if self > rhs {
39,754✔
1624
                                        match rhs.neg_opt() {
118✔
UNCOV
1625
                                            Some(e) => Some(_add(e, self.clone())),
×
1626
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
118✔
1627
                                        }
1628
                                    } else {
1629
                                        None
39,636✔
1630
                                    }
1631
                                } else {
1632
                                    None
6,596✔
1633
                                }
1634
                            }
1635
                            _ => {
1636
                                if self > rhs {
4,102✔
1637
                                    match rhs.neg_opt() {
4,102✔
1638
                                        Some(e) => Some(_add(e, self.clone())),
1,654✔
1639
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
2,448✔
1640
                                    }
1641
                                } else {
1642
                                    None
×
1643
                                }
1644
                            }
1645
                        }
1646
                    } else {
1647
                        None
29,496✔
1648
                    }
1649
                }
1650
            }
1651
        }
1652
    }
209,796✔
1653

1654
    /// Mul with heuristic optimization
1655
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,764,444✔
1656
        if self.is_zero() {
2,764,444✔
1657
            Some(self.clone())
23,040✔
1658
        } else if rhs.is_zero() || self.is_one() {
2,741,404✔
1659
            Some(rhs.clone())
2,369,504✔
1660
        } else if rhs.is_one() {
371,900✔
1661
            Some(self.clone())
83,286✔
1662
        } else if self.is_minus_one() {
288,614✔
1663
            match rhs.neg_opt() {
3,422✔
1664
                Some(e) => Some(e),
1,634✔
1665
                None => Some(_neg(rhs.clone())),
1,788✔
1666
            }
1667
        } else if rhs.is_minus_one() {
285,192✔
1668
            match self.neg_opt() {
27,058✔
1669
                Some(e) => Some(e),
8,384✔
1670
                None => Some(_neg(self.clone())),
18,674✔
1671
            }
1672
        } else {
1673
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
258,134✔
1674
                if let SymbolExpr::Unary { .. } = self {
212,964✔
1675
                    return match rhs.mul_opt(self, recursive) {
4,946✔
1676
                        Some(e) => Some(e),
4,598✔
1677
                        None => Some(_mul(rhs.clone(), self.clone())),
348✔
1678
                    };
1679
                }
208,018✔
1680
            }
45,170✔
1681

1682
            match self {
253,188✔
1683
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
168,850✔
1684
                SymbolExpr::Symbol(e) => match rhs {
33,776✔
1685
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
15,672✔
1686
                    SymbolExpr::Symbol(r) => {
11,298✔
1687
                        if r < e {
11,298✔
1688
                            Some(_mul(rhs.clone(), self.clone()))
3,054✔
1689
                        } else {
1690
                            None
8,244✔
1691
                        }
1692
                    }
1693
                    SymbolExpr::Unary {
1694
                        op: UnaryOp::Neg,
1695
                        expr,
1,798✔
1696
                    } => match expr.as_ref() {
1,798✔
1697
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1698
                        SymbolExpr::Symbol(s) => {
1,798✔
1699
                            if s < e {
1,798✔
1700
                                Some(_neg(_mul(expr.as_ref().clone(), self.clone())))
1,088✔
1701
                            } else {
1702
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
710✔
1703
                            }
1704
                        }
1705
                        SymbolExpr::Binary { .. } => match self.mul_opt(expr, recursive) {
×
1706
                            Some(e) => match e.neg_opt() {
×
1707
                                Some(ee) => Some(ee),
×
1708
                                None => Some(_neg(e)),
×
1709
                            },
1710
                            None => None,
×
1711
                        },
1712
                        _ => None,
×
1713
                    },
1714
                    _ => None,
5,008✔
1715
                },
1716
                SymbolExpr::Unary { op, expr } => match op {
1,958✔
1717
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
1,948✔
1718
                        Some(e) => match e.neg_opt() {
296✔
1719
                            Some(ee) => Some(ee),
296✔
1720
                            None => Some(_neg(e)),
×
1721
                        },
1722
                        None => None,
1,652✔
1723
                    },
1724
                    UnaryOp::Abs => match rhs {
2✔
1725
                        SymbolExpr::Unary {
1726
                            op: UnaryOp::Abs,
1727
                            expr: rexpr,
2✔
1728
                        } => match expr.mul_opt(rexpr, recursive) {
2✔
1729
                            Some(e) => Some(SymbolExpr::Unary {
×
1730
                                op: UnaryOp::Abs,
×
1731
                                expr: Arc::new(e),
×
1732
                            }),
×
1733
                            None => Some(SymbolExpr::Unary {
2✔
1734
                                op: UnaryOp::Abs,
2✔
1735
                                expr: Arc::new(_mul(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
1736
                            }),
2✔
1737
                        },
1738
                        _ => None,
×
1739
                    },
1740
                    _ => None,
8✔
1741
                },
1742
                SymbolExpr::Binary {
1743
                    op,
48,604✔
1744
                    lhs: l_lhs,
48,604✔
1745
                    rhs: l_rhs,
48,604✔
1746
                } => {
1747
                    if recursive {
48,604✔
1748
                        if let SymbolExpr::Binary {
1749
                            op: rop,
220✔
1750
                            lhs: r_lhs,
220✔
1751
                            rhs: r_rhs,
220✔
1752
                        } = rhs
3,862✔
1753
                        {
1754
                            if let BinaryOp::Mul = &rop {
220✔
1755
                                if let Some(e) = self.mul_opt(r_lhs, true) {
212✔
1756
                                    return match e.mul_opt(r_rhs, true) {
212✔
1757
                                        Some(ee) => Some(ee),
144✔
1758
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
68✔
1759
                                    };
1760
                                }
×
1761
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
1762
                                    return match e.mul_opt(r_lhs, true) {
×
1763
                                        Some(ee) => Some(ee),
×
1764
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1765
                                    };
1766
                                }
×
1767
                            }
8✔
1768
                            if let BinaryOp::Div = &rop {
8✔
1769
                                if let Some(e) = self.mul_opt(r_lhs, true) {
×
1770
                                    return match e.div_opt(r_rhs, true) {
×
1771
                                        Some(ee) => Some(ee),
×
1772
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
1773
                                    };
1774
                                }
×
1775
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
1776
                                    return match e.mul_opt(r_lhs, true) {
×
1777
                                        Some(ee) => Some(ee),
×
1778
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1779
                                    };
1780
                                }
×
1781
                            }
8✔
1782
                        }
3,642✔
1783

1784
                        if let BinaryOp::Mul = &op {
3,650✔
1785
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
3,642✔
1786
                                return match e.mul_opt(l_rhs, true) {
1,072✔
1787
                                    Some(ee) => Some(ee),
928✔
1788
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1789
                                };
1790
                            }
2,570✔
1791
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
2,570✔
1792
                                return match l_lhs.mul_opt(&e, true) {
600✔
1793
                                    Some(ee) => Some(ee),
×
1794
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
600✔
1795
                                };
1796
                            }
1,970✔
1797
                        } else if let BinaryOp::Div = &op {
8✔
1798
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
8✔
1799
                                return match e.div_opt(l_rhs, true) {
×
1800
                                    Some(ee) => Some(ee),
×
1801
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
1802
                                };
1803
                            }
8✔
1804
                            if let Some(e) = rhs.div_opt(l_rhs, true) {
8✔
1805
                                return match l_lhs.mul_opt(&e, true) {
×
1806
                                    Some(ee) => Some(ee),
×
1807
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1808
                                };
1809
                            }
8✔
1810
                        }
×
1811
                        None
1,978✔
1812
                    } else {
1813
                        match rhs {
44,742✔
1814
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
29,094✔
1815
                                SymbolExpr::Value(lv) => match op {
10,414✔
1816
                                    BinaryOp::Mul => Some(_mul(
9,718✔
1817
                                        SymbolExpr::Value(lv * v),
9,718✔
1818
                                        l_rhs.as_ref().clone(),
9,718✔
1819
                                    )),
9,718✔
1820
                                    BinaryOp::Div => Some(_div(
×
1821
                                        SymbolExpr::Value(lv * v),
×
1822
                                        l_rhs.as_ref().clone(),
×
1823
                                    )),
×
1824
                                    _ => None,
696✔
1825
                                },
1826
                                _ => match l_rhs.as_ref() {
18,680✔
1827
                                    SymbolExpr::Value(rv) => match op {
576✔
1828
                                        BinaryOp::Mul => Some(_mul(
×
1829
                                            SymbolExpr::Value(rv * v),
×
1830
                                            l_lhs.as_ref().clone(),
×
1831
                                        )),
×
1832
                                        BinaryOp::Div => Some(_mul(
×
1833
                                            SymbolExpr::Value(v / rv),
×
1834
                                            l_lhs.as_ref().clone(),
×
1835
                                        )),
×
1836
                                        _ => None,
576✔
1837
                                    },
1838
                                    _ => None,
18,104✔
1839
                                },
1840
                            },
1841
                            SymbolExpr::Binary {
1842
                                op: rop,
11,304✔
1843
                                lhs: r_lhs,
11,304✔
1844
                                rhs: r_rhs,
11,304✔
1845
                            } => match (op, rop) {
11,304✔
1846
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1847
                                    l_lhs.as_ref(),
1,816✔
1848
                                    l_rhs.as_ref(),
1,816✔
1849
                                    r_lhs.as_ref(),
1,816✔
1850
                                    r_rhs.as_ref(),
1,816✔
1851
                                ) {
1852
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
1,816✔
1853
                                        Some(_mul(
1,816✔
1854
                                            SymbolExpr::Value(lv * rv),
1,816✔
1855
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
1,816✔
1856
                                        ))
1,816✔
1857
                                    }
1858
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1859
                                        Some(_mul(
×
1860
                                            SymbolExpr::Value(lv * rv),
×
1861
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1862
                                        ))
×
1863
                                    }
1864
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1865
                                        Some(_mul(
×
1866
                                            SymbolExpr::Value(lv * rv),
×
1867
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1868
                                        ))
×
1869
                                    }
1870
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1871
                                        Some(_mul(
×
1872
                                            SymbolExpr::Value(lv * rv),
×
1873
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1874
                                        ))
×
1875
                                    }
1876
                                    (_, _, _, _) => None,
×
1877
                                },
1878
                                (BinaryOp::Mul, BinaryOp::Div) => match (
1879
                                    l_lhs.as_ref(),
×
1880
                                    l_rhs.as_ref(),
×
1881
                                    r_lhs.as_ref(),
×
1882
                                    r_rhs.as_ref(),
×
1883
                                ) {
1884
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1885
                                        Some(_mul(
×
1886
                                            SymbolExpr::Value(lv * rv),
×
1887
                                            _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1888
                                        ))
×
1889
                                    }
1890
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1891
                                        Some(_mul(
×
1892
                                            SymbolExpr::Value(lv / rv),
×
1893
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1894
                                        ))
×
1895
                                    }
1896
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1897
                                        Some(_mul(
×
1898
                                            SymbolExpr::Value(lv * rv),
×
1899
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1900
                                        ))
×
1901
                                    }
1902
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1903
                                        Some(_mul(
×
1904
                                            SymbolExpr::Value(lv / rv),
×
1905
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1906
                                        ))
×
1907
                                    }
1908
                                    (_, _, _, _) => None,
×
1909
                                },
1910
                                (BinaryOp::Div, BinaryOp::Mul) => match (
1911
                                    l_lhs.as_ref(),
×
1912
                                    l_rhs.as_ref(),
×
1913
                                    r_lhs.as_ref(),
×
1914
                                    r_rhs.as_ref(),
×
1915
                                ) {
1916
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1917
                                        Some(_mul(
×
1918
                                            SymbolExpr::Value(lv * rv),
×
1919
                                            _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1920
                                        ))
×
1921
                                    }
1922
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1923
                                        Some(_mul(
×
1924
                                            SymbolExpr::Value(lv * rv),
×
1925
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1926
                                        ))
×
1927
                                    }
1928
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1929
                                        Some(_mul(
×
1930
                                            SymbolExpr::Value(rv / lv),
×
1931
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1932
                                        ))
×
1933
                                    }
1934
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1935
                                        Some(_mul(
×
1936
                                            SymbolExpr::Value(rv / lv),
×
1937
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1938
                                        ))
×
1939
                                    }
1940
                                    (_, _, _, _) => None,
×
1941
                                },
1942
                                (BinaryOp::Div, BinaryOp::Div) => match (
1943
                                    l_lhs.as_ref(),
2✔
1944
                                    l_rhs.as_ref(),
2✔
1945
                                    r_lhs.as_ref(),
2✔
1946
                                    r_rhs.as_ref(),
2✔
1947
                                ) {
1948
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1949
                                        Some(_div(
×
1950
                                            SymbolExpr::Value(lv * rv),
×
1951
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1952
                                        ))
×
1953
                                    }
1954
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1955
                                        Some(_mul(
×
1956
                                            SymbolExpr::Value(lv / rv),
×
1957
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1958
                                        ))
×
1959
                                    }
1960
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1961
                                        Some(_mul(
×
1962
                                            SymbolExpr::Value(rv / lv),
×
1963
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1964
                                        ))
×
1965
                                    }
1966
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2✔
1967
                                        Some(_div(
2✔
1968
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
2✔
1969
                                            SymbolExpr::Value(lv * rv),
2✔
1970
                                        ))
2✔
1971
                                    }
1972
                                    (_, _, _, _) => None,
×
1973
                                },
1974
                                (_, _) => None,
9,486✔
1975
                            },
1976
                            _ => None,
4,344✔
1977
                        }
1978
                    }
1979
                }
1980
            }
1981
        }
1982
    }
2,764,444✔
1983
    /// expand with optimization for mul operation
1984
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
326,148✔
1985
        if let SymbolExpr::Binary {
1986
            op: rop,
22,104✔
1987
            lhs: r_lhs,
22,104✔
1988
            rhs: r_rhs,
22,104✔
1989
        } = rhs
326,148✔
1990
        {
1991
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
22,104✔
1992
                let el = match self.mul_expand(r_lhs) {
2,674✔
1993
                    Some(e) => e,
1,626✔
1994
                    None => match self.mul_opt(r_lhs, true) {
1,048✔
1995
                        Some(e) => e,
608✔
1996
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
440✔
1997
                    },
1998
                };
1999
                let er = match self.mul_expand(r_rhs) {
2,674✔
2000
                    Some(e) => e,
1,368✔
2001
                    None => match self.mul_opt(r_rhs, true) {
1,306✔
2002
                        Some(e) => e,
370✔
2003
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
936✔
2004
                    },
2005
                };
2006
                return match &rop {
2,674✔
2007
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
1,244✔
2008
                        Some(e) => Some(e),
26✔
2009
                        None => Some(_sub(el, er)),
1,218✔
2010
                    },
2011
                    _ => match el.add_opt(&er, true) {
1,430✔
2012
                        Some(e) => Some(e),
38✔
2013
                        None => Some(_add(el, er)),
1,392✔
2014
                    },
2015
                };
2016
            }
19,430✔
2017
            if let BinaryOp::Mul = &rop {
19,430✔
2018
                return match self.mul_expand(r_lhs) {
19,382✔
2019
                    Some(e) => match e.mul_expand(r_rhs) {
1,102✔
2020
                        Some(ee) => Some(ee),
932✔
2021
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
170✔
2022
                    },
2023
                    None => self
18,280✔
2024
                        .mul_expand(r_rhs)
18,280✔
2025
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
18,280✔
2026
                };
2027
            }
48✔
2028
            if let BinaryOp::Div = &rop {
48✔
2029
                return match self.mul_expand(r_lhs) {
×
2030
                    Some(e) => match e.mul_expand(r_rhs) {
×
2031
                        Some(ee) => Some(ee),
×
2032
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2033
                    },
2034
                    None => self
×
2035
                        .div_expand(r_rhs)
×
2036
                        .map(|e| _div(e, r_lhs.as_ref().clone())),
×
2037
                };
2038
            }
48✔
2039
        }
304,044✔
2040
        if let SymbolExpr::Unary {
2041
            op: UnaryOp::Neg,
2042
            expr: rexpr,
580✔
2043
        } = rhs
1,524✔
2044
        {
2045
            return match self.mul_expand(rexpr) {
580✔
2046
                Some(e) => match e.neg_opt() {
326✔
2047
                    Some(ee) => Some(ee),
326✔
2048
                    None => Some(_neg(e)),
×
2049
                },
2050
                None => match self.mul_opt(rexpr, true) {
254✔
2051
                    Some(e) => match e.neg_opt() {
114✔
2052
                        Some(ee) => Some(ee),
42✔
2053
                        None => Some(_neg(e)),
72✔
2054
                    },
2055
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
140✔
2056
                },
2057
            };
2058
        }
303,512✔
2059

2060
        match self {
1,306✔
2061
            SymbolExpr::Unary {
2062
                op: UnaryOp::Neg,
2063
                expr,
1,306✔
2064
            } => match expr.mul_expand(rhs) {
1,306✔
2065
                Some(e) => match e.neg_opt() {
×
2066
                    Some(ee) => Some(ee),
×
2067
                    None => Some(_neg(e)),
×
2068
                },
2069
                None => match expr.mul_opt(rhs, true) {
1,306✔
2070
                    Some(e) => match e.neg_opt() {
766✔
2071
                        Some(ee) => Some(ee),
520✔
2072
                        None => Some(_neg(e)),
246✔
2073
                    },
2074
                    None => None,
540✔
2075
                },
2076
            },
2077
            SymbolExpr::Binary {
2078
                op,
64,210✔
2079
                lhs: l_lhs,
64,210✔
2080
                rhs: l_rhs,
64,210✔
2081
            } => match &op {
64,210✔
2082
                BinaryOp::Add | BinaryOp::Sub => {
2083
                    let l = match l_lhs.mul_expand(rhs) {
4,110✔
2084
                        Some(e) => e,
1,312✔
2085
                        None => match l_lhs.mul_opt(rhs, true) {
2,798✔
2086
                            Some(e) => e,
1,520✔
2087
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
1,278✔
2088
                        },
2089
                    };
2090
                    let r = match l_rhs.mul_expand(rhs) {
4,110✔
2091
                        Some(e) => e,
52✔
2092
                        None => match l_rhs.mul_opt(rhs, true) {
4,058✔
2093
                            Some(e) => e,
2,036✔
2094
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
2,022✔
2095
                        },
2096
                    };
2097
                    match &op {
4,110✔
2098
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
1,960✔
2099
                            Some(e) => Some(e),
118✔
2100
                            None => Some(_sub(l, r)),
1,842✔
2101
                        },
2102
                        _ => match l.add_opt(&r, true) {
2,150✔
2103
                            Some(e) => Some(e),
182✔
2104
                            None => Some(_add(l, r)),
1,968✔
2105
                        },
2106
                    }
2107
                }
2108
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
60,080✔
2109
                    Some(e) => match e.mul_expand(l_rhs) {
88✔
2110
                        Some(ee) => Some(ee),
88✔
2111
                        None => match e.mul_opt(l_rhs, true) {
×
2112
                            Some(ee) => Some(ee),
×
2113
                            None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2114
                        },
2115
                    },
2116
                    None => match l_rhs.mul_expand(rhs) {
59,992✔
2117
                        Some(e) => match l_lhs.mul_expand(&e) {
24✔
2118
                            Some(ee) => Some(ee),
24✔
2119
                            None => match l_lhs.mul_opt(&e, true) {
×
2120
                                Some(ee) => Some(ee),
×
2121
                                None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2122
                            },
2123
                        },
2124
                        None => None,
59,968✔
2125
                    },
2126
                },
2127
                BinaryOp::Div => match l_lhs.div_expand(rhs) {
20✔
2128
                    Some(e) => Some(_div(e, l_rhs.as_ref().clone())),
×
2129
                    None => l_rhs
20✔
2130
                        .div_expand(rhs)
20✔
2131
                        .map(|e| _div(l_lhs.as_ref().clone(), e)),
20✔
2132
                },
2133
                _ => None,
×
2134
            },
2135
            _ => None,
237,996✔
2136
        }
2137
    }
326,148✔
2138

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

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

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

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

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

2399
    /// optimization for neg
2400
    fn neg_opt(&self) -> Option<SymbolExpr> {
400,690✔
2401
        match self {
19,392✔
2402
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
84,566✔
2403
            SymbolExpr::Unary {
2404
                op: UnaryOp::Neg,
2405
                expr,
17,884✔
2406
            } => Some(expr.as_ref().clone()),
17,884✔
2407
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
152,908✔
2408
                BinaryOp::Add => match lhs.neg_opt() {
4,642✔
2409
                    Some(ln) => match rhs.neg_opt() {
3,426✔
2410
                        Some(rn) => Some(_add(ln, rn)),
1,704✔
2411
                        None => Some(_sub(ln, rhs.as_ref().clone())),
1,722✔
2412
                    },
2413
                    None => match rhs.neg_opt() {
1,216✔
2414
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
460✔
2415
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
756✔
2416
                    },
2417
                },
2418
                BinaryOp::Sub => match lhs.neg_opt() {
4,298✔
2419
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
3,240✔
2420
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
1,058✔
2421
                },
2422
                BinaryOp::Mul => match lhs.neg_opt() {
141,812✔
2423
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
77,340✔
2424
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
64,472✔
2425
                },
2426
                BinaryOp::Div => match lhs.neg_opt() {
76✔
2427
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
16✔
2428
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
60✔
2429
                },
2430
                _ => None,
2,080✔
2431
            },
2432
            _ => None,
145,332✔
2433
        }
2434
    }
400,690✔
2435

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

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

2497
    fn repr(&self, with_uuid: bool) -> String {
11,147,076✔
2498
        match self {
11,147,076✔
2499
            SymbolExpr::Symbol(e) => e.repr(with_uuid),
10,076,392✔
2500
            SymbolExpr::Value(e) => e.to_string(),
336,720✔
2501
            SymbolExpr::Unary { op, expr } => {
7,872✔
2502
                let s = expr.repr(with_uuid);
7,872✔
2503
                match op {
7,872✔
2504
                    UnaryOp::Abs => format!("abs({s})"),
×
2505
                    UnaryOp::Neg => match expr.as_ref() {
4,112✔
2506
                        SymbolExpr::Value(e) => (-e).to_string(),
×
2507
                        SymbolExpr::Binary {
2508
                            op: BinaryOp::Add | BinaryOp::Sub,
2509
                            ..
2510
                        } => format!("-({s})"),
×
2511
                        _ => format!("-{s}"),
4,112✔
2512
                    },
2513
                    UnaryOp::Sin => format!("sin({s})"),
120✔
2514
                    UnaryOp::Asin => format!("asin({s})"),
108✔
2515
                    UnaryOp::Cos => format!("cos({s})"),
80✔
2516
                    UnaryOp::Acos => format!("acos({s})"),
92✔
2517
                    UnaryOp::Tan => format!("tan({s})"),
64✔
2518
                    UnaryOp::Atan => format!("atan({s})"),
76✔
2519
                    UnaryOp::Exp => format!("exp({s})"),
260✔
2520
                    UnaryOp::Log => format!("log({s})"),
×
2521
                    UnaryOp::Sign => format!("sign({s})"),
×
2522
                    UnaryOp::Conj => format!("conj({s})"),
2,960✔
2523
                }
2524
            }
2525
            SymbolExpr::Binary { op, lhs, rhs } => {
726,092✔
2526
                let s_lhs = lhs.repr(with_uuid);
726,092✔
2527
                let s_rhs = rhs.repr(with_uuid);
726,092✔
2528
                let op_lhs = match lhs.as_ref() {
726,092✔
2529
                    SymbolExpr::Binary { op: lop, .. } => {
197,430✔
2530
                        matches!(lop, BinaryOp::Add | BinaryOp::Sub)
197,430✔
2531
                    }
2532
                    SymbolExpr::Value(e) => match e {
225,564✔
2533
                        Value::Real(v) => *v < 0.0,
17,492✔
2534
                        Value::Int(v) => *v < 0,
64,546✔
2535
                        Value::Complex(_) => true,
143,526✔
2536
                    },
2537
                    _ => false,
303,098✔
2538
                };
2539
                let op_rhs = match rhs.as_ref() {
726,092✔
2540
                    SymbolExpr::Binary { op: rop, .. } => match rop {
42,174✔
2541
                        BinaryOp::Add | BinaryOp::Sub => true,
3,394✔
2542
                        _ => matches!(op, BinaryOp::Div),
38,780✔
2543
                    },
2544
                    SymbolExpr::Value(e) => match e {
110,868✔
2545
                        Value::Real(v) => *v < 0.0,
65,302✔
2546
                        Value::Int(v) => *v < 0,
32,046✔
2547
                        Value::Complex(_) => true,
13,520✔
2548
                    },
2549
                    _ => false,
573,050✔
2550
                };
2551

2552
                match op {
726,092✔
2553
                    BinaryOp::Add => match rhs.as_ref() {
59,734✔
2554
                        SymbolExpr::Unary {
2555
                            op: UnaryOp::Neg,
2556
                            expr: _,
2557
                        } => {
2558
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2559
                                format!("{s_lhs} {s_rhs}")
×
2560
                            } else {
2561
                                format!("{s_lhs} + {s_rhs}")
×
2562
                            }
2563
                        }
2564
                        _ => format!("{s_lhs} + {s_rhs}"),
59,734✔
2565
                    },
2566
                    BinaryOp::Sub => match rhs.as_ref() {
59,426✔
2567
                        SymbolExpr::Unary {
2568
                            op: UnaryOp::Neg,
2569
                            expr: _,
2570
                        } => {
2571
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2572
                                let st = s_rhs.char_indices().nth(0).unwrap().0;
×
2573
                                let ed = s_rhs.char_indices().nth(1).unwrap().0;
×
2574
                                let s_rhs_new: &str = &s_rhs.as_str()[st..ed];
×
2575
                                format!("{s_lhs} + {s_rhs_new}")
×
2576
                            } else if op_rhs {
×
2577
                                format!("{s_lhs} -({s_rhs})")
×
2578
                            } else {
2579
                                format!("{s_lhs} - {s_rhs}")
×
2580
                            }
2581
                        }
2582
                        _ => {
2583
                            if op_rhs {
59,426✔
2584
                                format!("{s_lhs} -({s_rhs})")
882✔
2585
                            } else {
2586
                                format!("{s_lhs} - {s_rhs}")
58,544✔
2587
                            }
2588
                        }
2589
                    },
2590
                    BinaryOp::Mul => {
2591
                        if op_lhs {
541,220✔
2592
                            if op_rhs {
150,598✔
2593
                                format!("({s_lhs})*({s_rhs})")
486✔
2594
                            } else {
2595
                                format!("({s_lhs})*{s_rhs}")
150,112✔
2596
                            }
2597
                        } else if op_rhs {
390,622✔
2598
                            format!("{s_lhs}*({s_rhs})")
14,566✔
2599
                        } else {
2600
                            format!("{s_lhs}*{s_rhs}")
376,056✔
2601
                        }
2602
                    }
2603
                    BinaryOp::Div => {
2604
                        if op_lhs {
404✔
2605
                            if op_rhs {
40✔
2606
                                format!("({s_lhs})/({s_rhs})")
×
2607
                            } else {
2608
                                format!("({s_lhs})/{s_rhs}")
40✔
2609
                            }
2610
                        } else if op_rhs {
364✔
2611
                            format!("{s_lhs}/({s_rhs})")
8✔
2612
                        } else {
2613
                            format!("{s_lhs}/{s_rhs}")
356✔
2614
                        }
2615
                    }
2616
                    BinaryOp::Pow => match lhs.as_ref() {
65,308✔
2617
                        SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2618
                            match rhs.as_ref() {
4✔
2619
                                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2620
                                    format!("({s_lhs})**({s_rhs})")
×
2621
                                }
2622
                                SymbolExpr::Value(r) => {
×
2623
                                    if r.as_real() < 0.0 {
×
2624
                                        format!("({s_lhs})**({s_rhs})")
×
2625
                                    } else {
2626
                                        format!("({s_lhs})**{s_rhs}")
×
2627
                                    }
2628
                                }
2629
                                _ => format!("({s_lhs})**{s_rhs}"),
4✔
2630
                            }
2631
                        }
2632
                        SymbolExpr::Value(l) => {
4✔
2633
                            if l.as_real() < 0.0 {
4✔
2634
                                match rhs.as_ref() {
×
2635
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2636
                                        format!("({s_lhs})**({s_rhs})")
×
2637
                                    }
2638
                                    _ => format!("({s_lhs})**{s_rhs}"),
×
2639
                                }
2640
                            } else {
2641
                                match rhs.as_ref() {
4✔
2642
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2643
                                        format!("{s_lhs}**({s_rhs})")
×
2644
                                    }
2645
                                    _ => format!("{s_lhs}**{s_rhs}"),
4✔
2646
                                }
2647
                            }
2648
                        }
2649
                        _ => match rhs.as_ref() {
65,300✔
2650
                            SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2651
                                format!("{s_lhs}**({s_rhs})")
×
2652
                            }
2653
                            SymbolExpr::Value(r) => {
65,300✔
2654
                                if r.as_real() < 0.0 {
65,300✔
2655
                                    format!("{s_lhs}**({s_rhs})")
×
2656
                                } else {
2657
                                    format!("{s_lhs}**{s_rhs}")
65,300✔
2658
                                }
2659
                            }
2660
                            _ => format!("{s_lhs}**{s_rhs}"),
×
2661
                        },
2662
                    },
2663
                }
2664
            }
2665
        }
2666
    }
11,147,076✔
2667
}
2668

2669
impl Add for SymbolExpr {
2670
    type Output = SymbolExpr;
2671
    fn add(self, rhs: Self) -> SymbolExpr {
105,680✔
2672
        match self.add_opt(&rhs, false) {
105,680✔
2673
            Some(e) => e,
88,036✔
2674
            None => _add(self, rhs),
17,644✔
2675
        }
2676
    }
105,680✔
2677
}
2678

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

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

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

2709
impl Mul for SymbolExpr {
2710
    type Output = SymbolExpr;
2711
    fn mul(self, rhs: Self) -> SymbolExpr {
318,736✔
2712
        match self.mul_opt(&rhs, false) {
318,736✔
2713
            Some(e) => e,
247,922✔
2714
            None => _mul(self, rhs),
70,814✔
2715
        }
2716
    }
318,736✔
2717
}
2718

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

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

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

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

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

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

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

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

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

2835
// comparison rules for sorting equation
2836
impl PartialOrd for SymbolExpr {
2837
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
131,590✔
2838
        match self {
131,590✔
2839
            SymbolExpr::Value(l) => match rhs {
302✔
2840
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2841
                _ => Some(Ordering::Less),
290✔
2842
            },
2843
            SymbolExpr::Symbol(l) => match rhs {
7,224✔
2844
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2845
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
4,088✔
2846
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2847
                _ => Some(Ordering::Less),
3,136✔
2848
            },
2849
            SymbolExpr::Unary { op: _, expr } => match rhs {
17,092✔
2850
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2851
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,328✔
2852
                _ => (expr.as_ref()).partial_cmp(rhs),
15,762✔
2853
            },
2854
            SymbolExpr::Binary {
2855
                op,
106,972✔
2856
                lhs: ll,
106,972✔
2857
                rhs: lr,
106,972✔
2858
            } => match rhs {
106,972✔
2859
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
7,288✔
2860
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
7,280✔
2861
                    _ => Some(Ordering::Equal),
8✔
2862
                },
2863
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
236✔
2864
                SymbolExpr::Binary {
2865
                    op: _,
2866
                    lhs: rl,
99,448✔
2867
                    rhs: rr,
99,448✔
2868
                } => {
2869
                    let ls = match ll.as_ref() {
99,448✔
2870
                        SymbolExpr::Value(_) => lr.string_id(),
18,058✔
2871
                        _ => self.string_id(),
81,390✔
2872
                    };
2873
                    let rs = match rl.as_ref() {
99,448✔
2874
                        SymbolExpr::Value(_) => rr.string_id(),
18,252✔
2875
                        _ => rhs.string_id(),
81,196✔
2876
                    };
2877
                    if rs > ls && rs.len() > ls.len() {
99,448✔
2878
                        Some(Ordering::Less)
7,518✔
2879
                    } else if rs < ls && rs.len() < ls.len() {
91,930✔
2880
                        Some(Ordering::Greater)
510✔
2881
                    } else {
2882
                        Some(Ordering::Equal)
91,420✔
2883
                    }
2884
                }
2885
            },
2886
        }
2887
    }
131,590✔
2888
}
2889

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

2896
impl fmt::Display for Value {
2897
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336,904✔
2898
        write!(
336,904✔
2899
            f,
336,904✔
2900
            "{}",
336,904✔
2901
            match self {
336,904✔
2902
                Value::Real(e) => e.to_string(),
83,184✔
2903
                Value::Int(e) => e.to_string(),
96,662✔
2904
                Value::Complex(e) => {
157,058✔
2905
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
157,058✔
2906
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
156,466✔
2907
                            0.to_string()
×
2908
                        } else {
2909
                            format!("{}i", e.im)
156,466✔
2910
                        }
2911
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
592✔
2912
                        e.re.to_string()
×
2913
                    } else {
2914
                        e.to_string()
592✔
2915
                    }
2916
                }
2917
            }
2918
        )
2919
    }
336,904✔
2920
}
2921

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

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

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

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

3178
    pub fn is_zero(&self) -> bool {
5,659,156✔
3179
        match self {
5,659,156✔
3180
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,914,662✔
3181
            Value::Int(i) => *i == 0,
457,730✔
3182
            Value::Complex(c) => {
286,764✔
3183
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
286,764✔
3184
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
207,172✔
3185
            }
3186
        }
3187
    }
5,659,156✔
3188
    pub fn is_one(&self) -> bool {
585,562✔
3189
        match self {
585,562✔
3190
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
295,170✔
3191
            Value::Int(i) => *i == 1,
160,084✔
3192
            Value::Complex(c) => {
130,308✔
3193
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
130,308✔
3194
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
3,690✔
3195
            }
3196
        }
3197
    }
585,562✔
3198
    pub fn is_minus_one(&self) -> bool {
343,116✔
3199
        match self {
343,116✔
3200
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
245,674✔
3201
            Value::Int(i) => *i == -1,
15,604✔
3202
            Value::Complex(c) => {
81,838✔
3203
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
81,838✔
3204
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,018✔
3205
            }
3206
        }
3207
    }
343,116✔
3208

3209
    pub fn is_negative(&self) -> bool {
73,898✔
3210
        match self {
73,898✔
3211
            Value::Real(r) => *r < 0.0,
18,488✔
3212
            Value::Int(i) => *i < 0,
5,370✔
3213
            Value::Complex(c) => {
50,040✔
3214
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
50,040✔
3215
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
50,040✔
3216
            }
3217
        }
3218
    }
73,898✔
3219

3220
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
170,106✔
3221
        match rhs {
4,126✔
3222
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
80,242✔
3223
            SymbolExpr::Unary {
3224
                op: UnaryOp::Neg,
3225
                expr,
3,474✔
3226
            } => {
3227
                let l = SymbolExpr::Value(-self);
3,474✔
3228
                match l.mul_opt(expr, recursive) {
3,474✔
3229
                    Some(e) => Some(e),
8✔
3230
                    None => Some(_mul(l, expr.as_ref().clone())),
3,466✔
3231
                }
3232
            }
3233
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
19,572✔
3234
                if recursive {
19,572✔
3235
                    match op {
644✔
3236
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
644✔
3237
                            Some(e) => match e.mul_opt(r, recursive) {
32✔
3238
                                Some(ee) => Some(ee),
8✔
3239
                                None => Some(_mul(e, r.as_ref().clone())),
24✔
3240
                            },
3241
                            None => self
612✔
3242
                                .mul_opt(r, recursive)
612✔
3243
                                .map(|e| _mul(e, l.as_ref().clone())),
612✔
3244
                        },
3245
                        BinaryOp::Div => match self.mul_opt(l, recursive) {
×
3246
                            Some(e) => Some(_div(e, r.as_ref().clone())),
×
3247
                            None => self
×
3248
                                .div_opt(r, recursive)
×
3249
                                .map(|e| _mul(e, l.as_ref().clone())),
×
3250
                        },
3251
                        _ => None,
×
3252
                    }
3253
                } else {
3254
                    match l.as_ref() {
18,928✔
3255
                        SymbolExpr::Value(v) => match op {
4,274✔
3256
                            BinaryOp::Mul => {
3257
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
2,336✔
3258
                            }
3259
                            BinaryOp::Div => {
3260
                                Some(_div(SymbolExpr::Value(self * v), r.as_ref().clone()))
×
3261
                            }
3262
                            _ => None,
1,938✔
3263
                        },
3264
                        _ => match r.as_ref() {
14,654✔
3265
                            SymbolExpr::Value(v) => match op {
2,404✔
3266
                                BinaryOp::Mul => {
3267
                                    Some(_mul(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
3268
                                }
3269
                                BinaryOp::Div => {
3270
                                    Some(_mul(SymbolExpr::Value(self / v), l.as_ref().clone()))
8✔
3271
                                }
3272
                                _ => None,
2,396✔
3273
                            },
3274
                            _ => None,
12,250✔
3275
                        },
3276
                    }
3277
                }
3278
            }
3279
            _ => None,
66,818✔
3280
        }
3281
    }
170,106✔
3282

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

3319
    pub fn opt_complex(&self) -> Option<Value> {
255,374✔
3320
        match self {
255,374✔
3321
            Value::Complex(c) => {
122,018✔
3322
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
122,018✔
3323
                    Some(Value::Real(c.re))
25,250✔
3324
                } else {
3325
                    None
96,768✔
3326
                }
3327
            }
3328
            _ => None,
133,356✔
3329
        }
3330
    }
255,374✔
3331

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

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

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

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

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

3377
impl Add for Value {
3378
    type Output = Value;
3379
    fn add(self, rhs: Self) -> Value {
80,094✔
3380
        let t = match self {
80,094✔
3381
            Value::Real(l) => match rhs {
21,364✔
3382
                Value::Real(r) => Value::Real(l + r),
16,118✔
3383
                Value::Int(r) => Value::Real(l + r as f64),
2,856✔
3384
                Value::Complex(r) => Value::Complex(l + r),
2,390✔
3385
            },
3386
            Value::Int(l) => match rhs {
24,206✔
3387
                Value::Real(r) => Value::Real(l as f64 + r),
2,178✔
3388
                Value::Int(r) => Value::Int(l + r),
13,188✔
3389
                Value::Complex(r) => Value::Complex(l as f64 + r),
8,840✔
3390
            },
3391
            Value::Complex(l) => match rhs {
34,524✔
3392
                Value::Real(r) => Value::Complex(l + r),
922✔
3393
                Value::Int(r) => Value::Complex(l + r as f64),
15,434✔
3394
                Value::Complex(r) => Value::Complex(l + r),
18,168✔
3395
            },
3396
        };
3397
        match t.opt_complex() {
80,094✔
3398
            Some(v) => v,
4,216✔
3399
            None => t,
75,878✔
3400
        }
3401
    }
80,094✔
3402
}
3403

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

3411
impl Sub for Value {
3412
    type Output = Value;
3413
    fn sub(self, rhs: Self) -> Value {
63,486✔
3414
        let t = match self {
63,486✔
3415
            Value::Real(l) => match rhs {
12,872✔
3416
                Value::Real(r) => Value::Real(l - r),
7,348✔
3417
                Value::Int(r) => Value::Real(l - r as f64),
3,850✔
3418
                Value::Complex(r) => Value::Complex(l - r),
1,674✔
3419
            },
3420
            Value::Int(l) => match rhs {
19,270✔
3421
                Value::Real(r) => Value::Real(l as f64 - r),
358✔
3422
                Value::Int(r) => Value::Int(l - r),
11,852✔
3423
                Value::Complex(r) => Value::Complex(l as f64 - r),
7,060✔
3424
            },
3425
            Value::Complex(l) => match rhs {
31,344✔
3426
                Value::Real(r) => Value::Complex(l - r),
446✔
3427
                Value::Int(r) => Value::Complex(l - r as f64),
14,556✔
3428
                Value::Complex(r) => Value::Complex(l - r),
16,342✔
3429
            },
3430
        };
3431
        match t.opt_complex() {
63,486✔
3432
            Some(v) => v,
5,548✔
3433
            None => t,
57,938✔
3434
        }
3435
    }
63,486✔
3436
}
3437

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

3445
impl Mul for Value {
3446
    type Output = Value;
3447
    fn mul(self, rhs: Self) -> Value {
95,680✔
3448
        let t = match self {
95,680✔
3449
            Value::Real(l) => match rhs {
72,240✔
3450
                Value::Real(r) => Value::Real(l * r),
71,000✔
3451
                Value::Int(r) => Value::Real(l * r as f64),
646✔
3452
                Value::Complex(r) => Value::Complex(l * r),
594✔
3453
            },
3454
            Value::Int(l) => match rhs {
3,706✔
3455
                Value::Real(r) => Value::Real(l as f64 * r),
500✔
3456
                Value::Int(r) => Value::Int(l * r),
1,768✔
3457
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,438✔
3458
            },
3459
            Value::Complex(l) => match rhs {
19,734✔
3460
                Value::Real(r) => Value::Complex(l * r),
502✔
3461
                Value::Int(r) => Value::Complex(l * r as f64),
1,192✔
3462
                Value::Complex(r) => Value::Complex(l * r),
18,040✔
3463
            },
3464
        };
3465
        match t.opt_complex() {
95,680✔
3466
            Some(v) => v,
12,728✔
3467
            None => t,
82,952✔
3468
        }
3469
    }
95,680✔
3470
}
3471

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

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

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

3526
impl Neg for Value {
3527
    type Output = Value;
3528
    fn neg(self) -> Value {
113,898✔
3529
        match self {
113,898✔
3530
            Value::Real(v) => Value::Real(-v),
18,020✔
3531
            Value::Int(v) => Value::Int(-v),
28,146✔
3532
            Value::Complex(v) => Value::Complex(-v),
67,732✔
3533
        }
3534
    }
113,898✔
3535
}
3536

3537
impl PartialEq for Value {
3538
    fn eq(&self, r: &Self) -> bool {
10,102✔
3539
        match self {
10,102✔
3540
            Value::Real(e) => match r {
5,138✔
3541
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
3,530✔
3542
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
750✔
3543
                Value::Complex(rv) => {
858✔
3544
                    let t = Complex64::from(*e) - rv;
858✔
3545
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
858✔
3546
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
140✔
3547
                }
3548
            },
3549
            Value::Int(e) => match r {
2,748✔
3550
                Value::Int(rv) => e == rv,
1,682✔
3551
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
266✔
3552
                Value::Complex(rv) => {
800✔
3553
                    let t = Complex64::from(*e as f64) - rv;
800✔
3554
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
800✔
3555
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
58✔
3556
                }
3557
            },
3558
            Value::Complex(e) => match r {
2,216✔
3559
                Value::Real(rv) => {
254✔
3560
                    let t = *e - Complex64::from(rv);
254✔
3561
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
254✔
3562
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3563
                }
3564
                Value::Int(rv) => {
456✔
3565
                    let t = *e - Complex64::from(*rv as f64);
456✔
3566
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
456✔
3567
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3568
                }
3569
                Value::Complex(rv) => {
1,506✔
3570
                    let t = *e - rv;
1,506✔
3571
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
1,506✔
3572
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
926✔
3573
                }
3574
            },
3575
        }
3576
    }
10,102✔
3577
}
3578

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

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

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

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