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

Qiskit / qiskit / 20059263813

09 Dec 2025 09:31AM UTC coverage: 88.333% (-0.01%) from 88.343%
20059263813

push

github

web-flow
Add deprecation system to C API (#15369)

* Add deprecation system to C API

This adds infrastructure to apply deprecations to C API functions, which
causes them to raise warnings when user code is compiled against them
(with gcc/clang/MSVC, at least).  We also introduce a custom Doxygen
function that can be used to add deprecation information to the
docstring in a way that Sphinx will understand it.

To illustrate the use (and to follow, at least partially, the spirit of
our deprecation policies), this re-introduces the C API function
`qk_transpiler_pass_standalone_vf2_layout` function, which was removed
by the VF2-pruning PR chain.  We leave it with the Qiskit 2.2 API,
marking it as deprecated.

* Fix typos in documentation

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Comment on deprecation-warning location style

---------

Co-authored-by: Julien Gacon <gaconju@gmail.com>

0 of 21 new or added lines in 1 file covered. (0.0%)

7 existing lines in 3 files now uncovered.

96201 of 108907 relevant lines covered (88.33%)

1202836.04 hits per line

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

73.27
/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,161,522✔
45
        self.name == other.name && self.uuid == other.uuid && self.index == other.index
15,161,522✔
46
    }
15,161,522✔
47
}
48

49
impl Eq for Symbol {}
50

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

57
impl Hash for Symbol {
58
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46,289,502✔
59
        (&self.name, self.uuid, self.index).hash(state);
46,289,502✔
60
    }
46,289,502✔
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,758✔
67
        if let Ok(py_vector_element) = ob.extract::<PyParameterVectorElement>() {
18,758✔
68
            Ok(py_vector_element.symbol().clone())
16,460✔
69
        } else {
70
            ob.extract::<PyParameter>()
2,298✔
71
                .map(|ob| ob.symbol().clone())
2,298✔
72
                .map_err(PyErr::from)
2,298✔
73
        }
74
    }
18,758✔
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,250✔
83
        match (&self.index, &self.vector) {
58,250✔
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,578✔
87
        }
88
    }
58,250✔
89
}
90

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

126
    pub fn repr(&self, with_uuid: bool) -> String {
15,127,940✔
127
        match (self.index, with_uuid) {
15,127,940✔
128
            (Some(i), true) => format!("{}[{}]_{}", self.name, i, self.uuid.as_u128()),
9,532,832✔
129
            (Some(i), false) => format!("{}[{}]", self.name, i),
4,823,264✔
130
            (None, true) => format!("{}_{}", self.name, self.uuid.as_u128()),
141,100✔
131
            (None, false) => self.name.clone(),
630,744✔
132
        }
133
    }
15,127,940✔
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,054✔
164
        if let Ok(i) = ob.extract::<i64>() {
4,555,054✔
165
            Ok(Value::Int(i))
2,376,122✔
166
        } else if let Ok(r) = ob.extract::<f64>() {
2,178,932✔
167
            Ok(Value::Real(r))
898,002✔
168
        } else {
169
            ob.extract::<Complex64>().map(Value::Complex)
1,280,930✔
170
        }
171
    }
4,555,054✔
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 {
130,464✔
204
    if rhs.is_negative() {
130,464✔
205
        match rhs.neg_opt() {
40,508✔
206
            Some(e) => SymbolExpr::Binary {
40,508✔
207
                op: BinaryOp::Sub,
40,508✔
208
                lhs: Arc::new(lhs),
40,508✔
209
                rhs: Arc::new(e),
40,508✔
210
            },
40,508✔
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,956✔
219
            op: BinaryOp::Add,
89,956✔
220
            lhs: Arc::new(lhs),
89,956✔
221
            rhs: Arc::new(rhs),
89,956✔
222
        }
89,956✔
223
    }
224
}
130,464✔
225

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

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

261
// functions to make new expr for div
262
#[inline(always)]
263
fn _div(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
10,424✔
264
    SymbolExpr::Binary {
10,424✔
265
        op: BinaryOp::Div,
10,424✔
266
        lhs: Arc::new(lhs),
10,424✔
267
        rhs: Arc::new(rhs),
10,424✔
268
    }
10,424✔
269
}
10,424✔
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,512✔
284
    match expr.neg_opt() {
31,512✔
285
        Some(e) => e,
64✔
286
        None => SymbolExpr::Unary {
31,448✔
287
            op: UnaryOp::Neg,
31,448✔
288
            expr: Arc::new(expr),
31,448✔
289
        },
31,448✔
290
    }
291
}
31,512✔
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,306,316✔
302
        match self {
1,306,316✔
303
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
581,986✔
304
                Some(v) => SymbolExpr::Value(*v),
579,252✔
305
                None => self.clone(),
2,734✔
306
            },
307
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
267,166✔
308
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
22,168✔
309
                op: op.clone(),
22,168✔
310
                expr: Arc::new(expr.bind(maps)),
22,168✔
311
            },
22,168✔
312
            SymbolExpr::Binary { op, lhs, rhs } => {
434,996✔
313
                let new_lhs = lhs.bind(maps);
434,996✔
314
                let new_rhs = rhs.bind(maps);
434,996✔
315
                match op {
434,996✔
316
                    BinaryOp::Add => new_lhs + new_rhs,
89,984✔
317
                    BinaryOp::Sub => new_lhs - new_rhs,
64,760✔
318
                    BinaryOp::Mul => new_lhs * new_rhs,
255,930✔
319
                    BinaryOp::Div => new_lhs / new_rhs,
9,310✔
320
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
15,012✔
321
                }
322
            }
323
        }
324
    }
1,306,316✔
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 {
428,546✔
330
        match self {
428,546✔
331
            SymbolExpr::Symbol(e) => match maps.get(e.as_ref()) {
251,140✔
332
                Some(v) => v.clone(),
38,106✔
333
                None => self.clone(),
213,034✔
334
            },
335
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
83,080✔
336
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
2,046✔
337
                op: op.clone(),
2,046✔
338
                expr: Arc::new(expr.subs(maps)),
2,046✔
339
            },
2,046✔
340
            SymbolExpr::Binary { op, lhs, rhs } => {
92,280✔
341
                let new_lhs = lhs.subs(maps);
92,280✔
342
                let new_rhs = rhs.subs(maps);
92,280✔
343
                match op {
92,280✔
344
                    BinaryOp::Add => new_lhs + new_rhs,
16,046✔
345
                    BinaryOp::Sub => new_lhs - new_rhs,
4,334✔
346
                    BinaryOp::Mul => new_lhs * new_rhs,
71,866✔
347
                    BinaryOp::Div => new_lhs / new_rhs,
16✔
348
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
349
                }
350
            }
351
        }
352
    }
428,546✔
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> {
55,823,554✔
357
        match self {
55,823,554✔
358
            SymbolExpr::Symbol(_) => None,
26,144,268✔
359
            SymbolExpr::Value(e) => Some(*e),
12,304,266✔
360
            SymbolExpr::Unary { op, expr } => {
575,118✔
361
                let val: Value;
362
                if recurse {
575,118✔
363
                    match expr.eval(recurse) {
575,118✔
364
                        Some(v) => val = v,
27,462✔
365
                        None => return None,
547,656✔
366
                    }
367
                } else {
368
                    match expr.as_ref() {
×
369
                        SymbolExpr::Value(e) => val = *e,
×
370
                        _ => return None,
×
371
                    }
372
                }
373
                let ret = match op {
27,462✔
374
                    UnaryOp::Abs => val.abs(),
462✔
375
                    UnaryOp::Neg => -val,
24,118✔
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 {
27,462✔
391
                    Value::Real(_) => Some(ret),
5,168✔
392
                    Value::Int(_) => Some(ret),
20,250✔
393
                    Value::Complex(c) => {
2,044✔
394
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
2,044✔
395
                            Some(Value::Real(c.re))
416✔
396
                        } else {
397
                            Some(ret)
1,628✔
398
                        }
399
                    }
400
                }
401
            }
402
            SymbolExpr::Binary { op, lhs, rhs } => {
16,799,902✔
403
                let lval: Value;
404
                let rval: Value;
405
                if recurse {
16,799,902✔
406
                    match (lhs.eval(true), rhs.eval(true)) {
16,799,902✔
407
                        (Some(left), Some(right)) => {
34,700✔
408
                            lval = left;
34,700✔
409
                            rval = right;
34,700✔
410
                        }
34,700✔
411
                        _ => return None,
16,765,202✔
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
    }
55,823,554✔
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 {
157,142✔
577
        match self {
157,142✔
578
            SymbolExpr::Symbol(_) => self.clone(),
28,310✔
579
            SymbolExpr::Value(_) => self.clone(),
3,436✔
580
            SymbolExpr::Unary { op, expr } => {
3,806✔
581
                let ex = expr.expand();
3,806✔
582
                match op {
3,806✔
583
                    UnaryOp::Neg => match ex.neg_opt() {
208✔
584
                        Some(ne) => ne,
×
585
                        None => _neg(ex),
208✔
586
                    },
587
                    _ => SymbolExpr::Unary {
3,598✔
588
                        op: op.clone(),
3,598✔
589
                        expr: Arc::new(ex),
3,598✔
590
                    },
3,598✔
591
                }
592
            }
593
            SymbolExpr::Binary { op, lhs, rhs } => {
121,590✔
594
                match op {
121,590✔
595
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
108,174✔
596
                        Some(e) => e,
2,646✔
597
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
105,528✔
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) {
4,206✔
604
                        Some(e) => e,
180✔
605
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
4,026✔
606
                    },
607
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
5,936✔
608
                        Some(e) => e,
2,492✔
609
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,444✔
610
                    },
611
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
3,132✔
612
                }
613
            }
614
        }
615
    }
157,142✔
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,116,480✔
661
        // This could maybe be more elegantly resolved with a SymbolIter type>
662
        match self {
14,116,480✔
663
            SymbolExpr::Symbol(e) => Box::new(::std::iter::once(e.as_ref())),
14,024,674✔
664
            SymbolExpr::Value(_) => Box::new(::std::iter::empty()),
44,306✔
665
            SymbolExpr::Unary { op: _, expr } => expr.iter_symbols(),
2,470✔
666
            SymbolExpr::Binary { op: _, lhs, rhs } => {
45,030✔
667
                Box::new(lhs.iter_symbols().chain(rhs.iter_symbols()))
45,030✔
668
            }
669
        }
670
    }
14,116,480✔
671

672
    /// Map of parameter name to the parameter.
673
    pub fn name_map(&self) -> HashMap<String, Symbol> {
4,766,824✔
674
        self.iter_symbols()
4,766,824✔
675
            .map(|param| (param.repr(false), param.clone()))
4,766,824✔
676
            .collect()
4,766,824✔
677
    }
4,766,824✔
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 {
5,342✔
733
        match self {
5,342✔
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,614✔
739
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
806✔
740
                _ => SymbolExpr::Value(*e),
808✔
741
            },
742
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
218✔
743
                op: op.clone(),
218✔
744
                expr: Arc::new(expr.conjugate()),
218✔
745
            },
218✔
746
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
1,646✔
747
                op: op.clone(),
1,646✔
748
                lhs: Arc::new(lhs.conjugate()),
1,646✔
749
                rhs: Arc::new(rhs.conjugate()),
1,646✔
750
            },
1,646✔
751
        }
752
    }
5,342✔
753

754
    /// check if complex number or not
755
    pub fn is_complex(&self) -> Option<bool> {
23,136✔
756
        match self.eval(true) {
23,136✔
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,130✔
762
        }
763
    }
23,136✔
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,588✔
772
        match self.eval(true) {
91,588✔
773
            Some(v) => match v {
67,782✔
774
                Value::Int(_) => Some(true),
64,488✔
775
                _ => Some(false),
3,294✔
776
            },
777
            None => None,
23,806✔
778
        }
779
    }
91,588✔
780

781
    /// check if evaluated result is 0
782
    pub fn is_zero(&self) -> bool {
9,718,994✔
783
        match self.eval(true) {
9,718,994✔
784
            Some(v) => v.is_zero(),
5,688,302✔
785
            None => false,
4,030,692✔
786
        }
787
    }
9,718,994✔
788

789
    /// check if evaluated result is 1
790
    pub fn is_one(&self) -> bool {
902,406✔
791
        match self.eval(true) {
902,406✔
792
            Some(v) => v.is_one(),
606,838✔
793
            None => false,
295,568✔
794
        }
795
    }
902,406✔
796

797
    /// check if evaluated result is -1
798
    pub fn is_minus_one(&self) -> bool {
621,192✔
799
        match self.eval(true) {
621,192✔
800
            Some(v) => v.is_minus_one(),
359,506✔
801
            None => false,
261,686✔
802
        }
803
    }
621,192✔
804

805
    /// check if evaluated result is negative
806
    fn is_negative(&self) -> bool {
465,040✔
807
        match self {
465,040✔
808
            SymbolExpr::Value(v) => v.is_negative(),
76,120✔
809
            SymbolExpr::Symbol(_) => false,
204,968✔
810
            SymbolExpr::Unary { op, expr } => match op {
17,634✔
811
                UnaryOp::Abs => false,
8✔
812
                UnaryOp::Neg => !expr.is_negative(),
15,140✔
813
                _ => false, // TO DO add heuristic determination
2,486✔
814
            },
815
            SymbolExpr::Binary { op, lhs, rhs } => match op {
166,318✔
816
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
138,128✔
817
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
18,350✔
818
                _ => false, // TO DO add heuristic determination for pow
9,840✔
819
            },
820
        }
821
    }
465,040✔
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,438,566✔
928
        self.repr(true)
9,438,566✔
929
    }
9,438,566✔
930

931
    // Add with heuristic optimization
932
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,562,436✔
933
        if self.is_zero() {
2,562,436✔
934
            Some(rhs.clone())
1,353,972✔
935
        } else if rhs.is_zero() {
1,208,464✔
936
            Some(self.clone())
969,748✔
937
        } else {
938
            // if neg operation, call sub_opt
939
            if let SymbolExpr::Unary { op, expr } = rhs {
238,716✔
940
                if let UnaryOp::Neg = op {
15,648✔
941
                    return self.sub_opt(expr, recursive);
13,982✔
942
                }
1,666✔
943
            } else if recursive {
223,068✔
944
                if let SymbolExpr::Binary {
945
                    op,
46,868✔
946
                    lhs: r_lhs,
46,868✔
947
                    rhs: r_rhs,
46,868✔
948
                } = rhs
53,056✔
949
                {
950
                    // recursive optimization for add and sub
951
                    if let BinaryOp::Add = &op {
46,868✔
952
                        if let Some(e) = self.add_opt(r_lhs, true) {
4,094✔
953
                            return match e.add_opt(r_rhs, true) {
42✔
954
                                Some(ee) => Some(ee),
20✔
955
                                None => Some(_add(e, r_rhs.as_ref().clone())),
22✔
956
                            };
957
                        }
4,052✔
958
                        if let Some(e) = self.add_opt(r_rhs, true) {
4,052✔
959
                            return match e.add_opt(r_lhs, true) {
6✔
960
                                Some(ee) => Some(ee),
×
961
                                None => Some(_add(e, r_lhs.as_ref().clone())),
6✔
962
                            };
963
                        }
4,046✔
964
                    }
42,774✔
965
                    if let BinaryOp::Sub = &op {
46,820✔
966
                        if let Some(e) = self.add_opt(r_lhs, true) {
3,016✔
967
                            return match e.sub_opt(r_rhs, true) {
90✔
968
                                Some(ee) => Some(ee),
78✔
969
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
12✔
970
                            };
971
                        }
2,926✔
972
                        if let Some(e) = self.sub_opt(r_rhs, true) {
2,926✔
973
                            return match e.add_opt(r_lhs, true) {
4✔
974
                                Some(ee) => Some(ee),
×
975
                                None => Some(_add(e, r_lhs.as_ref().clone())),
4✔
976
                            };
977
                        }
2,922✔
978
                    }
43,804✔
979
                }
6,188✔
980
            }
170,012✔
981

982
            // optimization for each node type
983
            match self {
224,592✔
984
                SymbolExpr::Value(l) => match rhs {
85,088✔
985
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
68,892✔
986
                    SymbolExpr::Binary {
987
                        op,
6,050✔
988
                        lhs: r_lhs,
6,050✔
989
                        rhs: r_rhs,
6,050✔
990
                    } => {
991
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
6,050✔
992
                            let t = l + v;
4,550✔
993
                            match op {
4,550✔
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,538✔
1012
                            }
1013
                        } else {
1014
                            None
1,500✔
1015
                        }
1016
                    }
1017
                    _ => None,
10,146✔
1018
                },
1019
                SymbolExpr::Symbol(l) => match rhs {
17,644✔
1020
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
2,792✔
1021
                    SymbolExpr::Symbol(r) => {
11,850✔
1022
                        if r == l {
11,850✔
1023
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
232✔
1024
                        } else if r < l {
11,618✔
1025
                            Some(_add(rhs.clone(), self.clone()))
1,506✔
1026
                        } else {
1027
                            None
10,112✔
1028
                        }
1029
                    }
1030
                    SymbolExpr::Binary {
1031
                        op,
3,002✔
1032
                        lhs: r_lhs,
3,002✔
1033
                        rhs: r_rhs,
3,002✔
1034
                    } => {
1035
                        if let (
1036
                            BinaryOp::Mul | BinaryOp::Div,
1037
                            SymbolExpr::Value(v),
1,920✔
1038
                            SymbolExpr::Symbol(s),
1,920✔
1039
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,002✔
1040
                        {
1041
                            if l == s {
1,920✔
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
1,914✔
1050
                            }
1051
                        } else {
1052
                            None
1,082✔
1053
                        }
1054
                    }
1055
                    _ => None,
×
1056
                },
1057
                SymbolExpr::Unary { op, expr } => {
15,870✔
1058
                    if let UnaryOp::Neg = op {
15,870✔
1059
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
14,706✔
1060
                            return match e.neg_opt() {
6,078✔
1061
                                Some(ee) => Some(ee),
6,078✔
1062
                                None => Some(_neg(e)),
×
1063
                            };
1064
                        }
8,628✔
1065
                    } else if let SymbolExpr::Unary {
1066
                        op: rop,
516✔
1067
                        expr: rexpr,
516✔
1068
                    } = rhs
1,164✔
1069
                    {
1070
                        if op == rop {
516✔
1071
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
176✔
1072
                                if t.is_zero() {
12✔
1073
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1074
                                }
12✔
1075
                            }
164✔
1076
                        }
340✔
1077
                    }
648✔
1078

1079
                    // swap nodes by sorting rule
1080
                    match rhs {
9,792✔
1081
                        SymbolExpr::Binary { op: rop, .. } => {
7,154✔
1082
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
7,154✔
1083
                                if self > rhs {
6,404✔
1084
                                    Some(_add(rhs.clone(), self.clone()))
×
1085
                                } else {
1086
                                    None
6,404✔
1087
                                }
1088
                            } else {
1089
                                None
750✔
1090
                            }
1091
                        }
1092
                        _ => {
1093
                            if self > rhs {
2,638✔
1094
                                Some(_add(rhs.clone(), self.clone()))
40✔
1095
                            } else {
1096
                                None
2,598✔
1097
                            }
1098
                        }
1099
                    }
1100
                }
1101
                SymbolExpr::Binary {
1102
                    op,
105,990✔
1103
                    lhs: l_lhs,
105,990✔
1104
                    rhs: l_rhs,
105,990✔
1105
                } => {
1106
                    if let SymbolExpr::Binary {
1107
                        op: rop,
96,306✔
1108
                        lhs: r_lhs,
96,306✔
1109
                        rhs: r_rhs,
96,306✔
1110
                    } = rhs
105,990✔
1111
                    {
1112
                        match (
1113
                            l_lhs.as_ref(),
96,306✔
1114
                            l_rhs.as_ref(),
96,306✔
1115
                            r_lhs.as_ref(),
96,306✔
1116
                            r_rhs.as_ref(),
96,306✔
1117
                        ) {
1118
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
11,306✔
1119
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
11,306✔
1120
                                    let t = SymbolExpr::Value(lv + rv);
1,736✔
1121
                                    if t.is_zero() {
1,736✔
1122
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,408✔
1123
                                    }
328✔
1124
                                    match (op, rop) {
328✔
1125
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1126
                                            return match t.mul_opt(l_rhs, recursive) {
232✔
1127
                                                Some(e) => Some(e),
8✔
1128
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
224✔
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,570✔
1146
                            }
1147
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
3,680✔
1148
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
3,680✔
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
                                }
3,680✔
1164
                            }
1165
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
368✔
1166
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
368✔
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
                                }
368✔
1180
                            }
1181
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
292✔
1182
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
292✔
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
                                }
288✔
1196
                            }
1197
                            (_, _, _, _) => (),
80,660✔
1198
                        }
1199

1200
                        if op == rop {
94,566✔
1201
                            if let Some(e) = rhs.neg_opt() {
39,328✔
1202
                                if self.expand().string_id() == e.expand().string_id() {
26,798✔
1203
                                    return Some(SymbolExpr::Value(Value::Int(0)));
4✔
1204
                                }
26,794✔
1205
                            }
12,530✔
1206
                        }
55,238✔
1207
                    } else if let SymbolExpr::Symbol(r) = rhs {
9,684✔
1208
                        if let (
1209
                            BinaryOp::Mul | BinaryOp::Div,
1210
                            SymbolExpr::Value(v),
1,848✔
1211
                            SymbolExpr::Symbol(s),
1,848✔
1212
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
5,890✔
1213
                        {
1214
                            if s == r {
1,848✔
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,848✔
1225
                        }
4,042✔
1226
                    }
3,794✔
1227
                    if recursive {
104,246✔
1228
                        if let BinaryOp::Add = op {
42,256✔
1229
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
6,780✔
1230
                                return match e.add_opt(l_rhs, true) {
514✔
1231
                                    Some(ee) => Some(ee),
292✔
1232
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
222✔
1233
                                };
1234
                            }
6,266✔
1235
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
6,266✔
1236
                                return match l_lhs.add_opt(&e, true) {
118✔
1237
                                    Some(ee) => Some(ee),
×
1238
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
118✔
1239
                                };
1240
                            }
6,148✔
1241
                        } else if let BinaryOp::Sub = op {
35,476✔
1242
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
5,196✔
1243
                                return match e.sub_opt(l_rhs, true) {
1,108✔
1244
                                    Some(ee) => Some(ee),
420✔
1245
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
688✔
1246
                                };
1247
                            }
4,088✔
1248
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
4,088✔
1249
                                return match l_lhs.sub_opt(&e, true) {
144✔
1250
                                    Some(ee) => Some(ee),
44✔
1251
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
100✔
1252
                                };
1253
                            }
3,944✔
1254
                        }
30,280✔
1255
                    }
61,990✔
1256
                    // swap nodes by sorting rule
1257
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
102,362✔
1258
                        match rhs {
45,858✔
1259
                            SymbolExpr::Binary { op: rop, .. } => {
42,410✔
1260
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
42,410✔
1261
                                    if self > rhs {
38,038✔
1262
                                        Some(_add(rhs.clone(), self.clone()))
360✔
1263
                                    } else {
1264
                                        None
37,678✔
1265
                                    }
1266
                                } else {
1267
                                    None
4,372✔
1268
                                }
1269
                            }
1270
                            _ => {
1271
                                if self > rhs {
3,448✔
1272
                                    Some(_add(rhs.clone(), self.clone()))
3,448✔
1273
                                } else {
1274
                                    None
×
1275
                                }
1276
                            }
1277
                        }
1278
                    } else {
1279
                        None
56,504✔
1280
                    }
1281
                }
1282
            }
1283
        }
1284
    }
2,562,436✔
1285

1286
    /// Sub with heuristic optimization
1287
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
184,012✔
1288
        if self.is_zero() {
184,012✔
1289
            match rhs.neg_opt() {
7,412✔
1290
                Some(e) => Some(e),
5,974✔
1291
                None => Some(_neg(rhs.clone())),
1,438✔
1292
            }
1293
        } else if rhs.is_zero() {
176,600✔
1294
            Some(self.clone())
3,292✔
1295
        } else {
1296
            // if neg, call add_opt
1297
            if let SymbolExpr::Unary { op, expr } = rhs {
173,308✔
1298
                if let UnaryOp::Neg = op {
3,988✔
1299
                    return self.add_opt(expr, recursive);
2,104✔
1300
                }
1,884✔
1301
            } else if recursive {
169,320✔
1302
                if let SymbolExpr::Binary {
1303
                    op,
45,254✔
1304
                    lhs: r_lhs,
45,254✔
1305
                    rhs: r_rhs,
45,254✔
1306
                } = rhs
60,526✔
1307
                {
1308
                    // recursive optimization for add and sub
1309
                    if let BinaryOp::Add = &op {
45,254✔
1310
                        if let Some(e) = self.sub_opt(r_lhs, true) {
4,056✔
1311
                            return match e.sub_opt(r_rhs, true) {
866✔
1312
                                Some(ee) => Some(ee),
842✔
1313
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
24✔
1314
                            };
1315
                        }
3,190✔
1316
                        if let Some(e) = self.sub_opt(r_rhs, true) {
3,190✔
1317
                            return match e.sub_opt(r_lhs, true) {
6✔
1318
                                Some(ee) => Some(ee),
×
1319
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
6✔
1320
                            };
1321
                        }
3,184✔
1322
                    }
41,198✔
1323
                    if let BinaryOp::Sub = &op {
44,382✔
1324
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,398✔
1325
                            return match e.add_opt(r_rhs, true) {
770✔
1326
                                Some(ee) => Some(ee),
742✔
1327
                                None => Some(_add(e, r_rhs.as_ref().clone())),
28✔
1328
                            };
1329
                        }
2,628✔
1330
                        if let Some(e) = self.add_opt(r_rhs, true) {
2,628✔
1331
                            return match e.sub_opt(r_lhs, true) {
4✔
1332
                                Some(ee) => Some(ee),
×
1333
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
4✔
1334
                            };
1335
                        }
2,624✔
1336
                    }
40,984✔
1337
                }
15,272✔
1338
            }
108,794✔
1339

1340
            // optimization for each type
1341
            match self {
169,558✔
1342
                SymbolExpr::Value(l) => match &rhs {
69,432✔
1343
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
58,700✔
1344
                    SymbolExpr::Binary {
1345
                        op,
5,920✔
1346
                        lhs: r_lhs,
5,920✔
1347
                        rhs: r_rhs,
5,920✔
1348
                    } => {
1349
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,920✔
1350
                            let t = l - v;
3,312✔
1351
                            match op {
3,312✔
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,312✔
1370
                            }
1371
                        } else {
1372
                            None
2,608✔
1373
                        }
1374
                    }
1375
                    _ => None,
4,812✔
1376
                },
1377
                SymbolExpr::Symbol(l) => match &rhs {
28,116✔
1378
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
4,094✔
1379
                    SymbolExpr::Symbol(r) => {
19,838✔
1380
                        if r == l {
19,838✔
1381
                            Some(SymbolExpr::Value(Value::Int(0)))
12,250✔
1382
                        } else if r < l {
7,588✔
1383
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,184✔
1384
                        } else {
1385
                            None
6,404✔
1386
                        }
1387
                    }
1388
                    SymbolExpr::Binary {
1389
                        op,
4,184✔
1390
                        lhs: r_lhs,
4,184✔
1391
                        rhs: r_rhs,
4,184✔
1392
                    } => {
1393
                        if let (
1394
                            BinaryOp::Mul | BinaryOp::Div,
1395
                            SymbolExpr::Value(v),
2,222✔
1396
                            SymbolExpr::Symbol(s),
2,222✔
1397
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
4,184✔
1398
                        {
1399
                            if l == s {
2,222✔
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,212✔
1408
                            }
1409
                        } else {
1410
                            None
1,962✔
1411
                        }
1412
                    }
1413
                    _ => None,
×
1414
                },
1415
                SymbolExpr::Unary { op, expr } => {
11,974✔
1416
                    if let UnaryOp::Neg = op {
11,974✔
1417
                        if let Some(e) = expr.add_opt(rhs, recursive) {
10,254✔
1418
                            return match e.neg_opt() {
4,442✔
1419
                                Some(ee) => Some(ee),
4,442✔
1420
                                None => Some(_neg(e)),
×
1421
                            };
1422
                        }
5,812✔
1423
                    }
1,720✔
1424
                    if let SymbolExpr::Unary {
1425
                        op: rop,
1,090✔
1426
                        expr: rexpr,
1,090✔
1427
                    } = rhs
7,532✔
1428
                    {
1429
                        if op == rop {
1,090✔
1430
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
676✔
1431
                                if t.is_zero() {
572✔
1432
                                    return Some(SymbolExpr::Value(Value::Int(0)));
572✔
1433
                                }
×
1434
                            }
104✔
1435
                        }
414✔
1436
                    }
6,442✔
1437

1438
                    // swap nodes by sorting rule
1439
                    match rhs {
6,960✔
1440
                        SymbolExpr::Binary { op: rop, .. } => {
5,552✔
1441
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
5,552✔
1442
                                if self > rhs {
4,864✔
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
4,864✔
1449
                                }
1450
                            } else {
1451
                                None
688✔
1452
                            }
1453
                        }
1454
                        _ => {
1455
                            if self > rhs {
1,408✔
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,380✔
1462
                            }
1463
                        }
1464
                    }
1465
                }
1466
                SymbolExpr::Binary {
1467
                    op,
60,036✔
1468
                    lhs: l_lhs,
60,036✔
1469
                    rhs: l_rhs,
60,036✔
1470
                } => {
1471
                    if let SymbolExpr::Binary {
1472
                        op: rop,
45,558✔
1473
                        lhs: r_lhs,
45,558✔
1474
                        rhs: r_rhs,
45,558✔
1475
                    } = rhs
60,036✔
1476
                    {
1477
                        match (
1478
                            l_lhs.as_ref(),
45,558✔
1479
                            l_rhs.as_ref(),
45,558✔
1480
                            r_lhs.as_ref(),
45,558✔
1481
                            r_rhs.as_ref(),
45,558✔
1482
                        ) {
1483
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
5,130✔
1484
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
5,130✔
1485
                                    let t = SymbolExpr::Value(lv - rv);
1,394✔
1486
                                    if t.is_zero() {
1,394✔
1487
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,394✔
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,736✔
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
                            (_, _, _, _) => (),
39,486✔
1563
                        }
1564

1565
                        if op == rop && self.expand().string_id() == rhs.expand().string_id() {
44,148✔
1566
                            return Some(SymbolExpr::Value(Value::Int(0)));
288✔
1567
                        }
43,860✔
1568
                    } else if let SymbolExpr::Symbol(r) = rhs {
14,478✔
1569
                        if let (
1570
                            BinaryOp::Mul | BinaryOp::Div,
1571
                            SymbolExpr::Value(v),
1,918✔
1572
                            SymbolExpr::Symbol(s),
1,918✔
1573
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
6,276✔
1574
                        {
1575
                            if s == r {
1,918✔
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,898✔
1586
                        }
4,358✔
1587
                    }
8,202✔
1588
                    if recursive {
58,318✔
1589
                        if let BinaryOp::Add = op {
40,918✔
1590
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
8,216✔
1591
                                return match e.add_opt(l_rhs, true) {
3,348✔
1592
                                    Some(ee) => Some(ee),
2,030✔
1593
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
1,318✔
1594
                                };
1595
                            }
4,868✔
1596
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
4,868✔
1597
                                return match l_lhs.add_opt(&e, true) {
920✔
1598
                                    Some(ee) => Some(ee),
776✔
1599
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
144✔
1600
                                };
1601
                            }
3,948✔
1602
                        }
32,702✔
1603
                        if let BinaryOp::Sub = op {
36,650✔
1604
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
7,662✔
1605
                                return match e.sub_opt(l_rhs, true) {
1,036✔
1606
                                    Some(ee) => Some(ee),
374✔
1607
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
662✔
1608
                                };
1609
                            }
6,626✔
1610
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
6,626✔
1611
                                return match l_lhs.sub_opt(&e, true) {
94✔
1612
                                    Some(ee) => Some(ee),
×
1613
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
94✔
1614
                                };
1615
                            }
6,532✔
1616
                        }
28,988✔
1617
                    }
17,400✔
1618
                    // swap nodes by sorting rule
1619
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
52,920✔
1620
                        match rhs {
31,218✔
1621
                            SymbolExpr::Binary { op: rop, .. } => {
26,590✔
1622
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
26,590✔
1623
                                    if self > rhs {
23,184✔
1624
                                        match rhs.neg_opt() {
92✔
1625
                                            Some(e) => Some(_add(e, self.clone())),
10✔
1626
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
82✔
1627
                                        }
1628
                                    } else {
1629
                                        None
23,092✔
1630
                                    }
1631
                                } else {
1632
                                    None
3,406✔
1633
                                }
1634
                            }
1635
                            _ => {
1636
                                if self > rhs {
4,628✔
1637
                                    match rhs.neg_opt() {
4,628✔
1638
                                        Some(e) => Some(_add(e, self.clone())),
1,738✔
1639
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
2,890✔
1640
                                    }
1641
                                } else {
1642
                                    None
×
1643
                                }
1644
                            }
1645
                        }
1646
                    } else {
1647
                        None
21,702✔
1648
                    }
1649
                }
1650
            }
1651
        }
1652
    }
184,012✔
1653

1654
    /// Mul with heuristic optimization
1655
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,780,530✔
1656
        if self.is_zero() {
2,780,530✔
1657
            Some(self.clone())
21,946✔
1658
        } else if rhs.is_zero() || self.is_one() {
2,758,584✔
1659
            Some(rhs.clone())
2,371,572✔
1660
        } else if rhs.is_one() {
387,012✔
1661
            Some(self.clone())
84,624✔
1662
        } else if self.is_minus_one() {
302,388✔
1663
            match rhs.neg_opt() {
3,640✔
1664
                Some(e) => Some(e),
1,600✔
1665
                None => Some(_neg(rhs.clone())),
2,040✔
1666
            }
1667
        } else if rhs.is_minus_one() {
298,748✔
1668
            match self.neg_opt() {
27,566✔
1669
                Some(e) => Some(e),
9,326✔
1670
                None => Some(_neg(self.clone())),
18,240✔
1671
            }
1672
        } else {
1673
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
271,182✔
1674
                if let SymbolExpr::Unary { .. } = self {
221,396✔
1675
                    return match rhs.mul_opt(self, recursive) {
5,862✔
1676
                        Some(e) => Some(e),
5,450✔
1677
                        None => Some(_mul(rhs.clone(), self.clone())),
412✔
1678
                    };
1679
                }
215,534✔
1680
            }
49,786✔
1681

1682
            match self {
265,320✔
1683
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
177,652✔
1684
                SymbolExpr::Symbol(e) => match rhs {
34,976✔
1685
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
16,364✔
1686
                    SymbolExpr::Symbol(r) => {
11,684✔
1687
                        if r < e {
11,684✔
1688
                            Some(_mul(rhs.clone(), self.clone()))
4,332✔
1689
                        } else {
1690
                            None
7,352✔
1691
                        }
1692
                    }
1693
                    SymbolExpr::Unary {
1694
                        op: UnaryOp::Neg,
1695
                        expr,
1,672✔
1696
                    } => match expr.as_ref() {
1,672✔
1697
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1698
                        SymbolExpr::Symbol(s) => {
1,672✔
1699
                            if s < e {
1,672✔
1700
                                Some(_neg(_mul(expr.as_ref().clone(), self.clone())))
1,070✔
1701
                            } else {
1702
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
602✔
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,256✔
1715
                },
1716
                SymbolExpr::Unary { op, expr } => match op {
1,716✔
1717
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
1,706✔
1718
                        Some(e) => match e.neg_opt() {
256✔
1719
                            Some(ee) => Some(ee),
256✔
1720
                            None => Some(_neg(e)),
×
1721
                        },
1722
                        None => None,
1,450✔
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,
50,976✔
1744
                    lhs: l_lhs,
50,976✔
1745
                    rhs: l_rhs,
50,976✔
1746
                } => {
1747
                    if recursive {
50,976✔
1748
                        if let SymbolExpr::Binary {
1749
                            op: rop,
288✔
1750
                            lhs: r_lhs,
288✔
1751
                            rhs: r_rhs,
288✔
1752
                        } = rhs
4,782✔
1753
                        {
1754
                            if let BinaryOp::Mul = &rop {
288✔
1755
                                if let Some(e) = self.mul_opt(r_lhs, true) {
280✔
1756
                                    return match e.mul_opt(r_rhs, true) {
280✔
1757
                                        Some(ee) => Some(ee),
194✔
1758
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
86✔
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
                        }
4,494✔
1783

1784
                        if let BinaryOp::Mul = &op {
4,502✔
1785
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
4,494✔
1786
                                return match e.mul_opt(l_rhs, true) {
1,378✔
1787
                                    Some(ee) => Some(ee),
1,234✔
1788
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1789
                                };
1790
                            }
3,116✔
1791
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
3,116✔
1792
                                return match l_lhs.mul_opt(&e, true) {
1,510✔
1793
                                    Some(ee) => Some(ee),
×
1794
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
1,510✔
1795
                                };
1796
                            }
1,606✔
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,614✔
1812
                    } else {
1813
                        match rhs {
46,194✔
1814
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
30,234✔
1815
                                SymbolExpr::Value(lv) => match op {
10,306✔
1816
                                    BinaryOp::Mul => Some(_mul(
9,610✔
1817
                                        SymbolExpr::Value(lv * v),
9,610✔
1818
                                        l_rhs.as_ref().clone(),
9,610✔
1819
                                    )),
9,610✔
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() {
19,928✔
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,
19,352✔
1839
                                },
1840
                            },
1841
                            SymbolExpr::Binary {
1842
                                op: rop,
12,040✔
1843
                                lhs: r_lhs,
12,040✔
1844
                                rhs: r_rhs,
12,040✔
1845
                            } => match (op, rop) {
12,040✔
1846
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1847
                                    l_lhs.as_ref(),
1,384✔
1848
                                    l_rhs.as_ref(),
1,384✔
1849
                                    r_lhs.as_ref(),
1,384✔
1850
                                    r_rhs.as_ref(),
1,384✔
1851
                                ) {
1852
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
1,384✔
1853
                                        Some(_mul(
1,384✔
1854
                                            SymbolExpr::Value(lv * rv),
1,384✔
1855
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
1,384✔
1856
                                        ))
1,384✔
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,
10,654✔
1975
                            },
1976
                            _ => None,
3,920✔
1977
                        }
1978
                    }
1979
                }
1980
            }
1981
        }
1982
    }
2,780,530✔
1983
    /// expand with optimization for mul operation
1984
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
231,328✔
1985
        if let SymbolExpr::Binary {
1986
            op: rop,
18,218✔
1987
            lhs: r_lhs,
18,218✔
1988
            rhs: r_rhs,
18,218✔
1989
        } = rhs
231,328✔
1990
        {
1991
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
18,218✔
1992
                let el = match self.mul_expand(r_lhs) {
2,214✔
1993
                    Some(e) => e,
1,206✔
1994
                    None => match self.mul_opt(r_lhs, true) {
1,008✔
1995
                        Some(e) => e,
668✔
1996
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
340✔
1997
                    },
1998
                };
1999
                let er = match self.mul_expand(r_rhs) {
2,214✔
2000
                    Some(e) => e,
1,166✔
2001
                    None => match self.mul_opt(r_rhs, true) {
1,048✔
2002
                        Some(e) => e,
292✔
2003
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
756✔
2004
                    },
2005
                };
2006
                return match &rop {
2,214✔
2007
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
1,068✔
2008
                        Some(e) => Some(e),
32✔
2009
                        None => Some(_sub(el, er)),
1,036✔
2010
                    },
2011
                    _ => match el.add_opt(&er, true) {
1,146✔
2012
                        Some(e) => Some(e),
18✔
2013
                        None => Some(_add(el, er)),
1,128✔
2014
                    },
2015
                };
2016
            }
16,004✔
2017
            if let BinaryOp::Mul = &rop {
16,004✔
2018
                return match self.mul_expand(r_lhs) {
15,956✔
2019
                    Some(e) => match e.mul_expand(r_rhs) {
1,174✔
2020
                        Some(ee) => Some(ee),
1,044✔
2021
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
130✔
2022
                    },
2023
                    None => self
14,782✔
2024
                        .mul_expand(r_rhs)
14,782✔
2025
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
14,782✔
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
        }
213,110✔
2040
        if let SymbolExpr::Unary {
2041
            op: UnaryOp::Neg,
2042
            expr: rexpr,
588✔
2043
        } = rhs
2,628✔
2044
        {
2045
            return match self.mul_expand(rexpr) {
588✔
2046
                Some(e) => match e.neg_opt() {
356✔
2047
                    Some(ee) => Some(ee),
356✔
2048
                    None => Some(_neg(e)),
×
2049
                },
2050
                None => match self.mul_opt(rexpr, true) {
232✔
2051
                    Some(e) => match e.neg_opt() {
136✔
2052
                        Some(ee) => Some(ee),
104✔
2053
                        None => Some(_neg(e)),
32✔
2054
                    },
2055
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
96✔
2056
                },
2057
            };
2058
        }
212,570✔
2059

2060
        match self {
1,350✔
2061
            SymbolExpr::Unary {
2062
                op: UnaryOp::Neg,
2063
                expr,
1,350✔
2064
            } => match expr.mul_expand(rhs) {
1,350✔
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,350✔
2070
                    Some(e) => match e.neg_opt() {
886✔
2071
                        Some(ee) => Some(ee),
528✔
2072
                        None => Some(_neg(e)),
358✔
2073
                    },
2074
                    None => None,
464✔
2075
                },
2076
            },
2077
            SymbolExpr::Binary {
2078
                op,
42,446✔
2079
                lhs: l_lhs,
42,446✔
2080
                rhs: l_rhs,
42,446✔
2081
            } => match &op {
42,446✔
2082
                BinaryOp::Add | BinaryOp::Sub => {
2083
                    let l = match l_lhs.mul_expand(rhs) {
4,800✔
2084
                        Some(e) => e,
1,838✔
2085
                        None => match l_lhs.mul_opt(rhs, true) {
2,962✔
2086
                            Some(e) => e,
1,974✔
2087
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
988✔
2088
                        },
2089
                    };
2090
                    let r = match l_rhs.mul_expand(rhs) {
4,800✔
2091
                        Some(e) => e,
120✔
2092
                        None => match l_rhs.mul_opt(rhs, true) {
4,680✔
2093
                            Some(e) => e,
3,214✔
2094
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
1,466✔
2095
                        },
2096
                    };
2097
                    match &op {
4,800✔
2098
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
2,068✔
2099
                            Some(e) => Some(e),
280✔
2100
                            None => Some(_sub(l, r)),
1,788✔
2101
                        },
2102
                        _ => match l.add_opt(&r, true) {
2,732✔
2103
                            Some(e) => Some(e),
470✔
2104
                            None => Some(_add(l, r)),
2,262✔
2105
                        },
2106
                    }
2107
                }
2108
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
37,626✔
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) {
37,538✔
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,
37,514✔
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,
168,774✔
2136
        }
2137
    }
231,328✔
2138

2139
    /// Div with heuristic optimization
2140
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
22,596✔
2141
        if rhs.is_zero() {
22,596✔
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() {
20,768✔
2145
            Some(self.clone())
712✔
2146
        } else if rhs.is_minus_one() {
20,056✔
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 {
19,372✔
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 {
8,326✔
2161
                let t = 1.0 / r;
2,502✔
2162
                if &(1.0 / t) == r {
2,502✔
2163
                    if recursive {
2,490✔
2164
                        return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
2165
                    } else {
2166
                        return Some(&SymbolExpr::Value(Value::Real(t)) * self);
2,490✔
2167
                    }
2168
                }
12✔
2169
            }
13,910✔
2170

2171
            match self {
13,922✔
2172
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
7,888✔
2173
                SymbolExpr::Symbol(_) => None,
3,122✔
2174
                SymbolExpr::Unary { op, expr } => match op {
232✔
2175
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
200✔
2176
                        Some(e) => match e.neg_opt() {
114✔
2177
                            Some(ee) => Some(ee),
114✔
2178
                            None => Some(_neg(e)),
×
2179
                        },
2180
                        None => None,
86✔
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,680✔
2202
                    lhs: l_lhs,
2,680✔
2203
                    rhs: l_rhs,
2,680✔
2204
                } => {
2205
                    if recursive {
2,680✔
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,672✔
2272
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
1,238✔
2273
                                SymbolExpr::Value(lv) => match op {
580✔
2274
                                    BinaryOp::Mul => Some(_mul(
276✔
2275
                                        SymbolExpr::Value(lv / v),
276✔
2276
                                        l_rhs.as_ref().clone(),
276✔
2277
                                    )),
276✔
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() {
658✔
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,
170✔
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
    }
22,596✔
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> {
368,592✔
2401
        match self {
17,502✔
2402
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
83,528✔
2403
            SymbolExpr::Unary {
2404
                op: UnaryOp::Neg,
2405
                expr,
16,170✔
2406
            } => Some(expr.as_ref().clone()),
16,170✔
2407
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
136,424✔
2408
                BinaryOp::Add => match lhs.neg_opt() {
4,548✔
2409
                    Some(ln) => match rhs.neg_opt() {
3,078✔
2410
                        Some(rn) => Some(_add(ln, rn)),
1,628✔
2411
                        None => Some(_sub(ln, rhs.as_ref().clone())),
1,450✔
2412
                    },
2413
                    None => match rhs.neg_opt() {
1,470✔
2414
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
956✔
2415
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
514✔
2416
                    },
2417
                },
2418
                BinaryOp::Sub => match lhs.neg_opt() {
3,784✔
2419
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
2,976✔
2420
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
808✔
2421
                },
2422
                BinaryOp::Mul => match lhs.neg_opt() {
125,864✔
2423
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
65,864✔
2424
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
60,000✔
2425
                },
2426
                BinaryOp::Div => match lhs.neg_opt() {
148✔
2427
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
88✔
2428
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
60✔
2429
                },
2430
                _ => None,
2,080✔
2431
            },
2432
            _ => None,
132,470✔
2433
        }
2434
    }
368,592✔
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 {
10,690,608✔
2498
        match self {
10,690,608✔
2499
            SymbolExpr::Symbol(e) => e.repr(with_uuid),
9,851,586✔
2500
            SymbolExpr::Value(e) => e.to_string(),
279,316✔
2501
            SymbolExpr::Unary { op, expr } => {
11,244✔
2502
                let s = expr.repr(with_uuid);
11,244✔
2503
                match op {
11,244✔
2504
                    UnaryOp::Abs => format!("abs({s})"),
×
2505
                    UnaryOp::Neg => match expr.as_ref() {
3,772✔
2506
                        SymbolExpr::Value(e) => (-e).to_string(),
×
2507
                        SymbolExpr::Binary {
2508
                            op: BinaryOp::Add | BinaryOp::Sub,
2509
                            ..
2510
                        } => format!("-({s})"),
×
2511
                        _ => format!("-{s}"),
3,772✔
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})"),
6,672✔
2523
                }
2524
            }
2525
            SymbolExpr::Binary { op, lhs, rhs } => {
548,462✔
2526
                let s_lhs = lhs.repr(with_uuid);
548,462✔
2527
                let s_rhs = rhs.repr(with_uuid);
548,462✔
2528
                let op_lhs = match lhs.as_ref() {
548,462✔
2529
                    SymbolExpr::Binary { op: lop, .. } => {
137,196✔
2530
                        matches!(lop, BinaryOp::Add | BinaryOp::Sub)
137,196✔
2531
                    }
2532
                    SymbolExpr::Value(e) => match e {
162,880✔
2533
                        Value::Real(v) => *v < 0.0,
17,254✔
2534
                        Value::Int(v) => *v < 0,
64,386✔
2535
                        Value::Complex(_) => true,
81,240✔
2536
                    },
2537
                    _ => false,
248,386✔
2538
                };
2539
                let op_rhs = match rhs.as_ref() {
548,462✔
2540
                    SymbolExpr::Binary { op: rop, .. } => match rop {
33,844✔
2541
                        BinaryOp::Add | BinaryOp::Sub => true,
2,874✔
2542
                        _ => matches!(op, BinaryOp::Div),
30,970✔
2543
                    },
2544
                    SymbolExpr::Value(e) => match e {
116,148✔
2545
                        Value::Real(v) => *v < 0.0,
65,302✔
2546
                        Value::Int(v) => *v < 0,
32,046✔
2547
                        Value::Complex(_) => true,
18,800✔
2548
                    },
2549
                    _ => false,
398,470✔
2550
                };
2551

2552
                match op {
548,462✔
2553
                    BinaryOp::Add => match rhs.as_ref() {
57,792✔
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}"),
57,792✔
2565
                    },
2566
                    BinaryOp::Sub => match rhs.as_ref() {
56,220✔
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 {
56,220✔
2584
                                format!("{s_lhs} -({s_rhs})")
618✔
2585
                            } else {
2586
                                format!("{s_lhs} - {s_rhs}")
55,602✔
2587
                            }
2588
                        }
2589
                    },
2590
                    BinaryOp::Mul => {
2591
                        if op_lhs {
368,738✔
2592
                            if op_rhs {
88,484✔
2593
                                format!("({s_lhs})*({s_rhs})")
638✔
2594
                            } else {
2595
                                format!("({s_lhs})*{s_rhs}")
87,846✔
2596
                            }
2597
                        } else if op_rhs {
280,254✔
2598
                            format!("{s_lhs}*({s_rhs})")
19,736✔
2599
                        } else {
2600
                            format!("{s_lhs}*{s_rhs}")
260,518✔
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
    }
10,690,608✔
2667
}
2668

2669
impl Add for SymbolExpr {
2670
    type Output = SymbolExpr;
2671
    fn add(self, rhs: Self) -> SymbolExpr {
106,044✔
2672
        match self.add_opt(&rhs, false) {
106,044✔
2673
            Some(e) => e,
87,902✔
2674
            None => _add(self, rhs),
18,142✔
2675
        }
2676
    }
106,044✔
2677
}
2678

2679
impl Add for &SymbolExpr {
2680
    type Output = SymbolExpr;
2681
    fn add(self, rhs: Self) -> SymbolExpr {
2,391,378✔
2682
        match self.add_opt(rhs, false) {
2,391,378✔
2683
            Some(e) => e,
2,312,894✔
2684
            None => _add(self.clone(), rhs.clone()),
78,484✔
2685
        }
2686
    }
2,391,378✔
2687
}
2688

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

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

2709
impl Mul for SymbolExpr {
2710
    type Output = SymbolExpr;
2711
    fn mul(self, rhs: Self) -> SymbolExpr {
327,806✔
2712
        match self.mul_opt(&rhs, false) {
327,806✔
2713
            Some(e) => e,
255,010✔
2714
            None => _mul(self, rhs),
72,796✔
2715
        }
2716
    }
327,806✔
2717
}
2718

2719
impl Mul for &SymbolExpr {
2720
    type Output = SymbolExpr;
2721
    fn mul(self, rhs: Self) -> SymbolExpr {
2,417,906✔
2722
        match self.mul_opt(rhs, false) {
2,417,906✔
2723
            Some(e) => e,
2,368,922✔
2724
            None => _mul(self.clone(), rhs.clone()),
48,984✔
2725
        }
2726
    }
2,417,906✔
2727
}
2728

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

2739
impl Div for &SymbolExpr {
2740
    type Output = SymbolExpr;
2741
    fn div(self, rhs: Self) -> SymbolExpr {
12,938✔
2742
        match self.div_opt(rhs, false) {
12,938✔
2743
            Some(e) => e,
4,136✔
2744
            None => _div(self.clone(), rhs.clone()),
8,802✔
2745
        }
2746
    }
12,938✔
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 {
672✔
2762
        match self.neg_opt() {
672✔
2763
            Some(e) => e,
234✔
2764
            None => _neg(self.clone()),
438✔
2765
        }
2766
    }
672✔
2767
}
2768

2769
impl PartialEq for SymbolExpr {
2770
    fn eq(&self, rexpr: &Self) -> bool {
67,896✔
2771
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
67,896✔
2772
            return l == r;
7,696✔
2773
        }
60,200✔
2774

2775
        match (self, rexpr) {
60,200✔
2776
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
31,108✔
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,622✔
2783
                let ex_rhs = rexpr.expand();
2,622✔
2784
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,622✔
2785
                    Some(e) => e.is_zero(),
2,278✔
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,758✔
2794
                match ex_lhs.sub_opt(rexpr, true) {
2,758✔
2795
                    Some(e) => e.is_zero(),
2,646✔
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,666✔
2804
                match self.sub_opt(&ex_rhs, true) {
2,666✔
2805
                    Some(e) => e.is_zero(),
560✔
2806
                    None => {
2807
                        let t = self - &ex_rhs;
2,106✔
2808
                        t.is_zero()
2,106✔
2809
                    }
2810
                }
2811
            }
2812
            (_, _) => false,
21,046✔
2813
        }
2814
    }
67,896✔
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> {
100,694✔
2838
        match self {
100,694✔
2839
            SymbolExpr::Value(l) => match rhs {
300✔
2840
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2841
                _ => Some(Ordering::Less),
288✔
2842
            },
2843
            SymbolExpr::Symbol(l) => match rhs {
6,714✔
2844
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2845
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
3,760✔
2846
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2847
                _ => Some(Ordering::Less),
2,954✔
2848
            },
2849
            SymbolExpr::Unary { op: _, expr } => match rhs {
15,836✔
2850
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2851
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,088✔
2852
                _ => (expr.as_ref()).partial_cmp(rhs),
14,746✔
2853
            },
2854
            SymbolExpr::Binary {
2855
                op,
77,844✔
2856
                lhs: ll,
77,844✔
2857
                rhs: lr,
77,844✔
2858
            } => match rhs {
77,844✔
2859
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
8,142✔
2860
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
8,134✔
2861
                    _ => Some(Ordering::Equal),
8✔
2862
                },
2863
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
248✔
2864
                SymbolExpr::Binary {
2865
                    op: _,
2866
                    lhs: rl,
69,454✔
2867
                    rhs: rr,
69,454✔
2868
                } => {
2869
                    let ls = match ll.as_ref() {
69,454✔
2870
                        SymbolExpr::Value(_) => lr.string_id(),
16,540✔
2871
                        _ => self.string_id(),
52,914✔
2872
                    };
2873
                    let rs = match rl.as_ref() {
69,454✔
2874
                        SymbolExpr::Value(_) => rr.string_id(),
18,202✔
2875
                        _ => rhs.string_id(),
51,252✔
2876
                    };
2877
                    if rs > ls && rs.len() > ls.len() {
69,454✔
2878
                        Some(Ordering::Less)
8,170✔
2879
                    } else if rs < ls && rs.len() < ls.len() {
61,284✔
2880
                        Some(Ordering::Greater)
456✔
2881
                    } else {
2882
                        Some(Ordering::Equal)
60,828✔
2883
                    }
2884
                }
2885
            },
2886
        }
2887
    }
100,694✔
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 {
279,500✔
2898
        write!(
279,500✔
2899
            f,
279,500✔
2900
            "{}",
279,500✔
2901
            match self {
279,500✔
2902
                Value::Real(e) => e.to_string(),
82,946✔
2903
                Value::Int(e) => e.to_string(),
96,502✔
2904
                Value::Complex(e) => {
100,052✔
2905
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
100,052✔
2906
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
99,436✔
2907
                            0.to_string()
×
2908
                        } else {
2909
                            format!("{}i", e.im)
99,436✔
2910
                        }
2911
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
616✔
2912
                        e.re.to_string()
×
2913
                    } else {
2914
                        e.to_string()
616✔
2915
                    }
2916
                }
2917
            }
2918
        )
2919
    }
279,500✔
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,688,350✔
3179
        match self {
5,688,350✔
3180
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,930,268✔
3181
            Value::Int(i) => *i == 0,
460,180✔
3182
            Value::Complex(c) => {
297,902✔
3183
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
297,902✔
3184
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
222,394✔
3185
            }
3186
        }
3187
    }
5,688,350✔
3188
    pub fn is_one(&self) -> bool {
606,838✔
3189
        match self {
606,838✔
3190
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
301,344✔
3191
            Value::Int(i) => *i == 1,
164,832✔
3192
            Value::Complex(c) => {
140,662✔
3193
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
140,662✔
3194
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,584✔
3195
            }
3196
        }
3197
    }
606,838✔
3198
    pub fn is_minus_one(&self) -> bool {
359,506✔
3199
        match self {
359,506✔
3200
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
254,598✔
3201
            Value::Int(i) => *i == -1,
16,286✔
3202
            Value::Complex(c) => {
88,622✔
3203
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
88,622✔
3204
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,020✔
3205
            }
3206
        }
3207
    }
359,506✔
3208

3209
    pub fn is_negative(&self) -> bool {
76,120✔
3210
        match self {
76,120✔
3211
            Value::Real(r) => *r < 0.0,
18,336✔
3212
            Value::Int(i) => *i < 0,
5,258✔
3213
            Value::Complex(c) => {
52,526✔
3214
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
52,526✔
3215
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
52,526✔
3216
            }
3217
        }
3218
    }
76,120✔
3219

3220
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
180,728✔
3221
        match rhs {
5,478✔
3222
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
82,298✔
3223
            SymbolExpr::Unary {
3224
                op: UnaryOp::Neg,
3225
                expr,
4,638✔
3226
            } => {
3227
                let l = SymbolExpr::Value(-self);
4,638✔
3228
                match l.mul_opt(expr, recursive) {
4,638✔
UNCOV
3229
                    Some(e) => Some(e),
×
3230
                    None => Some(_mul(l, expr.as_ref().clone())),
4,638✔
3231
                }
3232
            }
3233
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
21,978✔
3234
                if recursive {
21,978✔
3235
                    match op {
1,554✔
3236
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
1,554✔
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
1,522✔
3242
                                .mul_opt(r, recursive)
1,522✔
3243
                                .map(|e| _mul(e, l.as_ref().clone())),
1,522✔
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() {
20,424✔
3255
                        SymbolExpr::Value(v) => match op {
4,414✔
3256
                            BinaryOp::Mul => {
3257
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
2,476✔
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() {
16,010✔
3265
                            SymbolExpr::Value(v) => match op {
2,664✔
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,656✔
3273
                            },
3274
                            _ => None,
13,346✔
3275
                        },
3276
                    }
3277
                }
3278
            }
3279
            _ => None,
71,814✔
3280
        }
3281
    }
180,728✔
3282

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

3319
    pub fn opt_complex(&self) -> Option<Value> {
255,714✔
3320
        match self {
255,714✔
3321
            Value::Complex(c) => {
117,638✔
3322
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
117,638✔
3323
                    Some(Value::Real(c.re))
27,080✔
3324
                } else {
3325
                    None
90,558✔
3326
                }
3327
            }
3328
            _ => None,
138,076✔
3329
        }
3330
    }
255,714✔
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,530✔
3350
        Value::Real(v)
13,530✔
3351
    }
13,530✔
3352
}
3353

3354
impl From<i64> for Value {
3355
    fn from(v: i64) -> Self {
134,224✔
3356
        Value::Int(v)
134,224✔
3357
    }
134,224✔
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,304,028✔
3364
        } else {
3365
            Value::Complex(v)
57,308✔
3366
        }
3367
    }
2,361,336✔
3368
}
3369

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

3377
impl Add for Value {
3378
    type Output = Value;
3379
    fn add(self, rhs: Self) -> Value {
77,784✔
3380
        let t = match self {
77,784✔
3381
            Value::Real(l) => match rhs {
21,518✔
3382
                Value::Real(r) => Value::Real(l + r),
16,664✔
3383
                Value::Int(r) => Value::Real(l + r as f64),
2,452✔
3384
                Value::Complex(r) => Value::Complex(l + r),
2,402✔
3385
            },
3386
            Value::Int(l) => match rhs {
23,874✔
3387
                Value::Real(r) => Value::Real(l as f64 + r),
2,194✔
3388
                Value::Int(r) => Value::Int(l + r),
13,400✔
3389
                Value::Complex(r) => Value::Complex(l as f64 + r),
8,280✔
3390
            },
3391
            Value::Complex(l) => match rhs {
32,392✔
3392
                Value::Real(r) => Value::Complex(l + r),
1,000✔
3393
                Value::Int(r) => Value::Complex(l + r as f64),
11,910✔
3394
                Value::Complex(r) => Value::Complex(l + r),
19,482✔
3395
            },
3396
        };
3397
        match t.opt_complex() {
77,784✔
3398
            Some(v) => v,
5,500✔
3399
            None => t,
72,284✔
3400
        }
3401
    }
77,784✔
3402
}
3403

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

3411
impl Sub for Value {
3412
    type Output = Value;
3413
    fn sub(self, rhs: Self) -> Value {
64,312✔
3414
        let t = match self {
64,312✔
3415
            Value::Real(l) => match rhs {
12,656✔
3416
                Value::Real(r) => Value::Real(l - r),
7,594✔
3417
                Value::Int(r) => Value::Real(l - r as f64),
3,372✔
3418
                Value::Complex(r) => Value::Complex(l - r),
1,690✔
3419
            },
3420
            Value::Int(l) => match rhs {
20,916✔
3421
                Value::Real(r) => Value::Real(l as f64 - r),
380✔
3422
                Value::Int(r) => Value::Int(l - r),
14,064✔
3423
                Value::Complex(r) => Value::Complex(l as f64 - r),
6,472✔
3424
            },
3425
            Value::Complex(l) => match rhs {
30,740✔
3426
                Value::Real(r) => Value::Complex(l - r),
472✔
3427
                Value::Int(r) => Value::Complex(l - r as f64),
11,826✔
3428
                Value::Complex(r) => Value::Complex(l - r),
18,442✔
3429
            },
3430
        };
3431
        match t.opt_complex() {
64,312✔
3432
            Some(v) => v,
6,782✔
3433
            None => t,
57,530✔
3434
        }
3435
    }
64,312✔
3436
}
3437

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

3445
impl Mul for Value {
3446
    type Output = Value;
3447
    fn mul(self, rhs: Self) -> Value {
97,336✔
3448
        let t = match self {
97,336✔
3449
            Value::Real(l) => match rhs {
74,492✔
3450
                Value::Real(r) => Value::Real(l * r),
73,300✔
3451
                Value::Int(r) => Value::Real(l * r as f64),
614✔
3452
                Value::Complex(r) => Value::Complex(l * r),
578✔
3453
            },
3454
            Value::Int(l) => match rhs {
3,604✔
3455
                Value::Real(r) => Value::Real(l as f64 * r),
488✔
3456
                Value::Int(r) => Value::Int(l * r),
1,692✔
3457
                Value::Complex(r) => Value::Complex(l as f64 * r),
1,424✔
3458
            },
3459
            Value::Complex(l) => match rhs {
19,240✔
3460
                Value::Real(r) => Value::Complex(l * r),
482✔
3461
                Value::Int(r) => Value::Complex(l * r as f64),
1,544✔
3462
                Value::Complex(r) => Value::Complex(l * r),
17,214✔
3463
            },
3464
        };
3465
        match t.opt_complex() {
97,336✔
3466
            Some(v) => v,
12,034✔
3467
            None => t,
85,302✔
3468
        }
3469
    }
97,336✔
3470
}
3471

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

3479
impl Div for Value {
3480
    type Output = Value;
3481
    fn div(self, rhs: Self) -> Value {
4,816✔
3482
        let t = match self {
4,816✔
3483
            Value::Real(l) => match rhs {
2,156✔
3484
                Value::Real(r) => Value::Real(l / r),
212✔
3485
                Value::Int(r) => Value::Real(l / r as f64),
1,082✔
3486
                Value::Complex(r) => Value::Complex(l / r),
862✔
3487
            },
3488
            Value::Int(l) => {
1,374✔
3489
                if rhs == 0.0 {
1,374✔
3490
                    return Value::Real(f64::INFINITY);
×
3491
                }
1,374✔
3492
                match rhs {
1,374✔
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),
806✔
3504
                }
3505
            }
3506
            Value::Complex(l) => match rhs {
1,286✔
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),
686✔
3510
            },
3511
        };
3512
        match t.opt_complex() {
4,816✔
3513
            Some(v) => v,
672✔
3514
            None => t,
4,144✔
3515
        }
3516
    }
4,816✔
3517
}
3518

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

3526
impl Neg for Value {
3527
    type Output = Value;
3528
    fn neg(self) -> Value {
116,378✔
3529
        match self {
116,378✔
3530
            Value::Real(v) => Value::Real(-v),
19,092✔
3531
            Value::Int(v) => Value::Int(-v),
30,138✔
3532
            Value::Complex(v) => Value::Complex(-v),
67,148✔
3533
        }
3534
    }
116,378✔
3535
}
3536

3537
impl PartialEq for Value {
3538
    fn eq(&self, r: &Self) -> bool {
10,478✔
3539
        match self {
10,478✔
3540
            Value::Real(e) => match r {
5,566✔
3541
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
3,738✔
3542
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
966✔
3543
                Value::Complex(rv) => {
862✔
3544
                    let t = Complex64::from(*e) - rv;
862✔
3545
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
862✔
3546
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
140✔
3547
                }
3548
            },
3549
            Value::Int(e) => match r {
2,692✔
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) => {
744✔
3553
                    let t = Complex64::from(*e as f64) - rv;
744✔
3554
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
744✔
3555
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
50✔
3556
                }
3557
            },
3558
            Value::Complex(e) => match r {
2,220✔
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,510✔
3570
                    let t = *e - rv;
1,510✔
3571
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
1,510✔
3572
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
930✔
3573
                }
3574
            },
3575
        }
3576
    }
10,478✔
3577
}
3578

3579
impl PartialEq<f64> for Value {
3580
    fn eq(&self, r: &f64) -> bool {
1,374✔
3581
        match self {
1,374✔
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) => {
806✔
3585
                let t = *e - Complex64::from(r);
806✔
3586
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
806✔
3587
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
226✔
3588
            }
3589
        }
3590
    }
1,374✔
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