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

Qiskit / qiskit / 16749316437

05 Aug 2025 11:55AM UTC coverage: 87.619% (-0.04%) from 87.654%
16749316437

Pull #14768

github

web-flow
Merge d130843eb into 1e49fbdd2
Pull Request #14768: Add GateDirection and CheckGateDirection to C API

173 of 218 new or added lines in 4 files covered. (79.36%)

19 existing lines in 6 files now uncovered.

81821 of 93383 relevant lines covered (87.62%)

540761.37 hits per line

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

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

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

27
// epsilon for SymbolExpr is heuristically defined
28
pub const SYMEXPR_EPSILON: f64 = f64::EPSILON * 8.0;
29

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

38
/// Custom implementations of Eq, PartialEq, PartialOrd and Hash to ignore the ``vector`` field
39
impl PartialEq for Symbol {
40
    fn eq(&self, other: &Self) -> bool {
1,864,042✔
41
        self.name() == other.name() && self.uuid == other.uuid && self.index == other.index
1,864,042✔
42
    }
1,864,042✔
43
}
44

45
impl Eq for Symbol {}
46

47
impl PartialOrd for Symbol {
48
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
31,134✔
49
        (&self.name, self.uuid, self.index).partial_cmp(&(&other.name, other.uuid, other.index))
31,134✔
50
    }
31,134✔
51
}
52

53
impl Hash for Symbol {
54
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
8,478,212✔
55
        (&self.name, self.uuid, self.index).hash(state);
8,478,212✔
56
    }
8,478,212✔
57
}
58

59
impl Symbol {
60
    pub fn new(name: &str, uuid: Option<Uuid>, index: Option<u32>) -> Self {
74,726✔
61
        Self {
74,726✔
62
            name: name.to_string(),
74,726✔
63
            uuid: uuid.unwrap_or(Uuid::new_v4()),
74,726✔
64
            index,
74,726✔
65
            vector: None, // Python only
74,726✔
66
        }
74,726✔
67
    }
74,726✔
68

69
    /// In addition to ``new``, this also takes a vector.
70
    pub fn py_new(
37,948✔
71
        name: &str,
37,948✔
72
        uuid: Option<u128>,
37,948✔
73
        index: Option<u32>,
37,948✔
74
        vector: Option<PyObject>,
37,948✔
75
    ) -> PyResult<Self> {
37,948✔
76
        if index.is_some() != vector.is_some() {
37,948✔
77
            return Err(PyValueError::new_err(
×
78
                "Either both of vector and index must be provided, or neither of them",
×
79
            ));
×
80
        }
37,948✔
81

82
        Ok(Self {
37,948✔
83
            name: name.to_string(),
37,948✔
84
            uuid: uuid.map_or_else(Uuid::new_v4, Uuid::from_u128),
37,948✔
85
            index,
37,948✔
86
            vector,
37,948✔
87
        })
37,948✔
88
    }
37,948✔
89

90
    pub fn name(&self) -> String {
7,211,830✔
91
        let base_name = &self.name;
7,211,830✔
92
        match self.index {
7,211,830✔
93
            Some(i) => format!("{base_name}[{i}]"),
5,864,894✔
94
            None => base_name.clone(),
1,346,936✔
95
        }
96
    }
7,211,830✔
97
}
98

99
/// node types of expression tree
100
#[derive(Debug, Clone)]
101
pub enum SymbolExpr {
102
    Symbol(Symbol),
103
    Value(Value),
104
    Unary {
105
        op: UnaryOp,
106
        expr: Arc<SymbolExpr>,
107
    },
108
    Binary {
109
        op: BinaryOp,
110
        lhs: Arc<SymbolExpr>,
111
        rhs: Arc<SymbolExpr>,
112
    },
113
}
114

115
/// Value type, can be integer, real or complex number
116
#[derive(Debug, Clone, Copy)]
117
pub enum Value {
118
    Real(f64),
119
    Int(i64),
120
    Complex(Complex64),
121
}
122

123
impl<'py> FromPyObject<'py> for Value {
124
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
534,582✔
125
        if let Ok(i) = ob.extract::<i64>() {
534,582✔
126
            Ok(Value::Int(i))
327,388✔
127
        } else if let Ok(r) = ob.extract::<f64>() {
207,194✔
128
            Ok(Value::Real(r))
180,998✔
129
        } else if let Ok(c) = ob.extract::<Complex64>() {
26,196✔
130
            Ok(Value::Complex(c))
26,196✔
131
        } else {
132
            Err(PyValueError::new_err(
×
133
                "Could not cast Bound<PyAny> to Value.",
×
134
            ))
×
135
        }
136
    }
534,582✔
137
}
138

139
/// definition of unary operations
140
#[derive(Debug, Clone, PartialEq)]
141
pub enum UnaryOp {
142
    Abs,
143
    Neg,
144
    Sin,
145
    Asin,
146
    Cos,
147
    Acos,
148
    Tan,
149
    Atan,
150
    Exp,
151
    Log,
152
    Sign,
153
    Conj,
154
}
155

156
/// definition of binary operations
157
#[derive(Debug, Clone, PartialEq)]
158
pub enum BinaryOp {
159
    Add,
160
    Sub,
161
    Mul,
162
    Div,
163
    Pow,
164
}
165

166
// functions to make new expr for add
167
#[inline(always)]
168
fn _add(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
121,980✔
169
    if rhs.is_negative() {
121,980✔
170
        match rhs.neg_opt() {
41,554✔
171
            Some(e) => SymbolExpr::Binary {
41,554✔
172
                op: BinaryOp::Sub,
41,554✔
173
                lhs: Arc::new(lhs),
41,554✔
174
                rhs: Arc::new(e),
41,554✔
175
            },
41,554✔
176
            None => SymbolExpr::Binary {
×
177
                op: BinaryOp::Sub,
×
178
                lhs: Arc::new(lhs),
×
179
                rhs: Arc::new(_neg(rhs)),
×
180
            },
×
181
        }
182
    } else {
183
        SymbolExpr::Binary {
80,426✔
184
            op: BinaryOp::Add,
80,426✔
185
            lhs: Arc::new(lhs),
80,426✔
186
            rhs: Arc::new(rhs),
80,426✔
187
        }
80,426✔
188
    }
189
}
121,980✔
190

191
// functions to make new expr for sub
192
#[inline(always)]
193
fn _sub(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
22,154✔
194
    if rhs.is_negative() {
22,154✔
195
        match rhs.neg_opt() {
720✔
196
            Some(e) => SymbolExpr::Binary {
720✔
197
                op: BinaryOp::Add,
720✔
198
                lhs: Arc::new(lhs),
720✔
199
                rhs: Arc::new(e),
720✔
200
            },
720✔
201
            None => SymbolExpr::Binary {
×
202
                op: BinaryOp::Add,
×
203
                lhs: Arc::new(lhs),
×
204
                rhs: Arc::new(_neg(rhs)),
×
205
            },
×
206
        }
207
    } else {
208
        SymbolExpr::Binary {
21,434✔
209
            op: BinaryOp::Sub,
21,434✔
210
            lhs: Arc::new(lhs),
21,434✔
211
            rhs: Arc::new(rhs),
21,434✔
212
        }
21,434✔
213
    }
214
}
22,154✔
215

216
// functions to make new expr for mul
217
#[inline(always)]
218
fn _mul(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
271,418✔
219
    SymbolExpr::Binary {
271,418✔
220
        op: BinaryOp::Mul,
271,418✔
221
        lhs: Arc::new(lhs),
271,418✔
222
        rhs: Arc::new(rhs),
271,418✔
223
    }
271,418✔
224
}
271,418✔
225

226
// functions to make new expr for div
227
#[inline(always)]
228
fn _div(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
27,090✔
229
    SymbolExpr::Binary {
27,090✔
230
        op: BinaryOp::Div,
27,090✔
231
        lhs: Arc::new(lhs),
27,090✔
232
        rhs: Arc::new(rhs),
27,090✔
233
    }
27,090✔
234
}
27,090✔
235

236
// functions to make new expr for pow
237
#[inline(always)]
238
fn _pow(lhs: SymbolExpr, rhs: SymbolExpr) -> SymbolExpr {
18,174✔
239
    SymbolExpr::Binary {
18,174✔
240
        op: BinaryOp::Pow,
18,174✔
241
        lhs: Arc::new(lhs),
18,174✔
242
        rhs: Arc::new(rhs),
18,174✔
243
    }
18,174✔
244
}
18,174✔
245

246
// functions to make new expr for neg
247
#[inline(always)]
248
fn _neg(expr: SymbolExpr) -> SymbolExpr {
35,154✔
249
    match expr.neg_opt() {
35,154✔
250
        Some(e) => e,
1,250✔
251
        None => SymbolExpr::Unary {
33,904✔
252
            op: UnaryOp::Neg,
33,904✔
253
            expr: Arc::new(expr),
33,904✔
254
        },
33,904✔
255
    }
256
}
35,154✔
257

258
impl fmt::Display for SymbolExpr {
259
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143,868✔
260
        write!(f, "{}", self.repr(false))
143,868✔
261
    }
143,868✔
262
}
263

264
impl SymbolExpr {
265
    /// bind value to symbol node
266
    pub fn bind(&self, maps: &HashMap<Symbol, Value>) -> SymbolExpr {
1,128,122✔
267
        match self {
1,128,122✔
268
            SymbolExpr::Symbol(e) => match maps.get(e) {
378,714✔
269
                Some(v) => SymbolExpr::Value(*v),
377,464✔
270
                None => self.clone(),
1,250✔
271
            },
272
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
259,522✔
273
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
59,938✔
274
                op: op.clone(),
59,938✔
275
                expr: Arc::new(expr.bind(maps)),
59,938✔
276
            },
59,938✔
277
            SymbolExpr::Binary { op, lhs, rhs } => {
429,948✔
278
                let new_lhs = lhs.bind(maps);
429,948✔
279
                let new_rhs = rhs.bind(maps);
429,948✔
280
                match op {
429,948✔
281
                    BinaryOp::Add => new_lhs + new_rhs,
86,960✔
282
                    BinaryOp::Sub => new_lhs - new_rhs,
65,904✔
283
                    BinaryOp::Mul => new_lhs * new_rhs,
182,864✔
284
                    BinaryOp::Div => new_lhs / new_rhs,
79,208✔
285
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
15,012✔
286
                }
287
            }
288
        }
289
    }
1,128,122✔
290

291
    /// substitute symbol node to other expression
292
    /// allows unknown expressions
293
    /// does not allow duplicate names with different UUID
294
    pub fn subs(&self, maps: &HashMap<Symbol, SymbolExpr>) -> SymbolExpr {
54,938✔
295
        match self {
54,938✔
296
            SymbolExpr::Symbol(e) => match maps.get(e) {
16,376✔
297
                Some(v) => v.clone(),
13,572✔
298
                None => self.clone(),
2,804✔
299
            },
300
            SymbolExpr::Value(e) => SymbolExpr::Value(*e),
14,994✔
301
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
5,760✔
302
                op: op.clone(),
5,760✔
303
                expr: Arc::new(expr.subs(maps)),
5,760✔
304
            },
5,760✔
305
            SymbolExpr::Binary { op, lhs, rhs } => {
17,808✔
306
                let new_lhs = lhs.subs(maps);
17,808✔
307
                let new_rhs = rhs.subs(maps);
17,808✔
308
                match op {
17,808✔
309
                    BinaryOp::Add => new_lhs + new_rhs,
3,548✔
310
                    BinaryOp::Sub => new_lhs - new_rhs,
2,498✔
311
                    BinaryOp::Mul => new_lhs * new_rhs,
2,234✔
312
                    BinaryOp::Div => new_lhs / new_rhs,
9,510✔
313
                    BinaryOp::Pow => _pow(new_lhs, new_rhs),
18✔
314
                }
315
            }
316
        }
317
    }
54,938✔
318

319
    /// evaluate the equation
320
    /// if recursive is false, only this node will be evaluated
321
    pub fn eval(&self, recurse: bool) -> Option<Value> {
51,700,836✔
322
        match self {
51,700,836✔
323
            SymbolExpr::Symbol(_) => None,
19,464,744✔
324
            SymbolExpr::Value(e) => Some(*e),
14,394,398✔
325
            SymbolExpr::Unary { op, expr } => {
664,884✔
326
                let val: Value;
327
                if recurse {
664,884✔
328
                    match expr.eval(recurse) {
664,884✔
329
                        Some(v) => val = v,
66,954✔
330
                        None => return None,
597,930✔
331
                    }
332
                } else {
333
                    match expr.as_ref() {
×
334
                        SymbolExpr::Value(e) => val = *e,
×
335
                        _ => return None,
×
336
                    }
337
                }
338
                let ret = match op {
66,954✔
339
                    UnaryOp::Abs => val.abs(),
462✔
340
                    UnaryOp::Neg => -val,
63,610✔
341
                    UnaryOp::Sin => val.sin(),
364✔
342
                    UnaryOp::Asin => val.asin(),
90✔
343
                    UnaryOp::Cos => val.cos(),
610✔
344
                    UnaryOp::Acos => val.acos(),
88✔
345
                    UnaryOp::Tan => val.tan(),
340✔
346
                    UnaryOp::Atan => val.atan(),
90✔
347
                    UnaryOp::Exp => val.exp(),
402✔
348
                    UnaryOp::Log => val.log(),
384✔
349
                    UnaryOp::Sign => val.sign(),
6✔
350
                    UnaryOp::Conj => match val {
508✔
351
                        Value::Complex(v) => Value::Complex(v.conj()),
186✔
352
                        _ => val,
322✔
353
                    },
354
                };
355
                match ret {
66,954✔
356
                    Value::Real(_) => Some(ret),
41,690✔
357
                    Value::Int(_) => Some(ret),
23,218✔
358
                    Value::Complex(c) => {
2,046✔
359
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
2,046✔
360
                            Some(Value::Real(c.re))
418✔
361
                        } else {
362
                            Some(ret)
1,628✔
363
                        }
364
                    }
365
                }
366
            }
367
            SymbolExpr::Binary { op, lhs, rhs } => {
17,176,810✔
368
                let lval: Value;
369
                let rval: Value;
370
                if recurse {
17,176,810✔
371
                    match (lhs.eval(true), rhs.eval(true)) {
17,176,810✔
372
                        (Some(left), Some(right)) => {
34,776✔
373
                            lval = left;
34,776✔
374
                            rval = right;
34,776✔
375
                        }
34,776✔
376
                        _ => return None,
17,142,034✔
377
                    }
378
                } else {
379
                    match (lhs.as_ref(), rhs.as_ref()) {
×
380
                        (SymbolExpr::Value(l), SymbolExpr::Value(r)) => {
×
381
                            lval = *l;
×
382
                            rval = *r;
×
383
                        }
×
384
                        _ => return None,
×
385
                    }
386
                }
387
                let ret = match op {
34,776✔
388
                    BinaryOp::Add => lval + rval,
2,600✔
389
                    BinaryOp::Sub => lval - rval,
876✔
390
                    BinaryOp::Mul => lval * rval,
1,560✔
391
                    BinaryOp::Div => lval / rval,
1,050✔
392
                    BinaryOp::Pow => lval.pow(&rval),
28,690✔
393
                };
394
                match ret {
34,776✔
395
                    Value::Real(_) => Some(ret),
13,464✔
396
                    Value::Int(_) => Some(ret),
10,086✔
397
                    Value::Complex(c) => {
11,226✔
398
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
11,226✔
399
                            Some(Value::Real(c.re))
×
400
                        } else {
401
                            Some(ret)
11,226✔
402
                        }
403
                    }
404
                }
405
            }
406
        }
407
    }
51,700,836✔
408

409
    /// calculate derivative of the equantion for a symbol passed by param
410
    pub fn derivative(&self, param: &Symbol) -> Result<SymbolExpr, String> {
174✔
411
        if let SymbolExpr::Symbol(s) = self {
174✔
412
            if s == param {
78✔
413
                return Ok(SymbolExpr::Value(Value::Real(1.0)));
64✔
414
            }
14✔
415
        }
96✔
416

417
        match self {
110✔
418
            SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => Ok(SymbolExpr::Value(Value::Real(0.0))),
22✔
419
            SymbolExpr::Unary { op, expr } => {
50✔
420
                let expr_d = expr.derivative(param)?;
50✔
421
                match op {
50✔
422
                    UnaryOp::Abs => Ok(&(expr.as_ref() * &expr_d)
4✔
423
                        / &SymbolExpr::Unary {
4✔
424
                            op: op.clone(),
4✔
425
                            expr: Arc::new(expr.as_ref().clone()),
4✔
426
                        }),
4✔
427
                    UnaryOp::Neg => Ok(SymbolExpr::Unary {
×
428
                        op: UnaryOp::Neg,
×
429
                        expr: Arc::new(expr_d),
×
430
                    }),
×
431
                    UnaryOp::Sin => {
432
                        let lhs = SymbolExpr::Unary {
10✔
433
                            op: UnaryOp::Cos,
10✔
434
                            expr: Arc::new(expr.as_ref().clone()),
10✔
435
                        };
10✔
436
                        Ok(lhs * expr_d)
10✔
437
                    }
438
                    UnaryOp::Asin => {
439
                        let d =
4✔
440
                            &SymbolExpr::Value(Value::Real(1.0)) - &(expr.as_ref() * expr.as_ref());
4✔
441
                        let rhs = match d {
4✔
442
                            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
443
                            _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
4✔
444
                        };
445
                        Ok(&expr_d / &rhs)
4✔
446
                    }
447
                    UnaryOp::Cos => {
448
                        let lhs = SymbolExpr::Unary {
4✔
449
                            op: UnaryOp::Sin,
4✔
450
                            expr: Arc::new(expr.as_ref().clone()),
4✔
451
                        };
4✔
452
                        Ok(&-&lhs * &expr_d)
4✔
453
                    }
454
                    UnaryOp::Acos => {
455
                        let d =
4✔
456
                            &SymbolExpr::Value(Value::Real(1.0)) - &(expr.as_ref() * expr.as_ref());
4✔
457
                        let rhs = match d {
4✔
458
                            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
459
                            _ => _pow(d, SymbolExpr::Value(Value::Real(0.5))),
4✔
460
                        };
461
                        Ok(&-&expr_d / &rhs)
4✔
462
                    }
463
                    UnaryOp::Tan => {
464
                        let d = SymbolExpr::Unary {
4✔
465
                            op: UnaryOp::Cos,
4✔
466
                            expr: Arc::new(expr.as_ref().clone()),
4✔
467
                        };
4✔
468
                        Ok(&(&expr_d / &d) / &d)
4✔
469
                    }
470
                    UnaryOp::Atan => {
471
                        let d =
4✔
472
                            &SymbolExpr::Value(Value::Real(1.0)) + &(expr.as_ref() * expr.as_ref());
4✔
473
                        Ok(&expr_d / &d)
4✔
474
                    }
475
                    UnaryOp::Exp => Ok(&SymbolExpr::Unary {
4✔
476
                        op: UnaryOp::Exp,
4✔
477
                        expr: Arc::new(expr.as_ref().clone()),
4✔
478
                    } * &expr_d),
4✔
479
                    UnaryOp::Log => Ok(&expr_d / expr.as_ref()),
4✔
480
                    UnaryOp::Sign => {
481
                        Err("SymbolExpr::derivative does not support sign function.".to_string())
4✔
482
                    }
483
                    UnaryOp::Conj => {
484
                        // we assume real parameters, hence Conj acts as identity
485
                        Ok(SymbolExpr::Value(Value::Real(1.0)))
4✔
486
                    }
487
                }
488
            }
489
            SymbolExpr::Binary { op, lhs, rhs } => match op {
38✔
490
                BinaryOp::Add => Ok(lhs.derivative(param)? + rhs.derivative(param)?),
10✔
491
                BinaryOp::Sub => Ok(lhs.derivative(param)? - rhs.derivative(param)?),
×
492
                BinaryOp::Mul => Ok(&(&lhs.derivative(param)? * rhs.as_ref())
20✔
493
                    + &(lhs.as_ref() * &rhs.derivative(param)?)),
20✔
494
                BinaryOp::Div => Ok(&(&(&(&lhs.derivative(param)? * rhs.as_ref())
2✔
495
                    - &(lhs.as_ref() * &rhs.derivative(param)?))
2✔
496
                    / rhs.as_ref())
2✔
497
                    / rhs.as_ref()),
2✔
498
                BinaryOp::Pow => {
499
                    if !lhs.has_symbol(param) {
6✔
500
                        if !rhs.has_symbol(param) {
6✔
501
                            Ok(SymbolExpr::Value(Value::Real(0.0)))
6✔
502
                        } else {
503
                            Ok(_mul(
×
504
                                SymbolExpr::Binary {
×
505
                                    op: BinaryOp::Pow,
×
506
                                    lhs: Arc::new(lhs.as_ref().clone()),
×
507
                                    rhs: Arc::new(rhs.as_ref().clone()),
×
508
                                },
×
509
                                SymbolExpr::Unary {
×
510
                                    op: UnaryOp::Log,
×
511
                                    expr: Arc::new(lhs.as_ref().clone()),
×
512
                                },
×
513
                            ))
×
514
                        }
515
                    } else if !rhs.has_symbol(param) {
×
516
                        Ok(rhs.as_ref()
×
517
                            * &SymbolExpr::Binary {
×
518
                                op: BinaryOp::Pow,
×
519
                                lhs: Arc::new(lhs.as_ref().clone()),
×
520
                                rhs: Arc::new(rhs.as_ref() - &SymbolExpr::Value(Value::Real(1.0))),
×
521
                            })
×
522
                    } else {
523
                        let new_expr = SymbolExpr::Unary {
×
524
                            op: UnaryOp::Exp,
×
525
                            expr: Arc::new(_mul(
×
526
                                SymbolExpr::Unary {
×
527
                                    op: UnaryOp::Log,
×
528
                                    expr: Arc::new(lhs.as_ref().clone()),
×
529
                                },
×
530
                                rhs.as_ref().clone(),
×
531
                            )),
×
532
                        };
×
533
                        new_expr.derivative(param)
×
534
                    }
535
                }
536
            },
537
        }
538
    }
174✔
539

540
    /// expand the equation
541
    pub fn expand(&self) -> SymbolExpr {
156,680✔
542
        match self {
156,680✔
543
            SymbolExpr::Symbol(_) => self.clone(),
29,684✔
544
            SymbolExpr::Value(_) => self.clone(),
3,440✔
545
            SymbolExpr::Unary { op, expr } => {
4,760✔
546
                let ex = expr.expand();
4,760✔
547
                match op {
4,760✔
548
                    UnaryOp::Neg => match ex.neg_opt() {
2,778✔
549
                        Some(ne) => ne,
×
550
                        None => _neg(ex),
2,778✔
551
                    },
552
                    _ => SymbolExpr::Unary {
1,982✔
553
                        op: op.clone(),
1,982✔
554
                        expr: Arc::new(ex),
1,982✔
555
                    },
1,982✔
556
                }
557
            }
558
            SymbolExpr::Binary { op, lhs, rhs } => {
118,796✔
559
                match op {
118,796✔
560
                    BinaryOp::Mul => match lhs.mul_expand(rhs) {
98,872✔
561
                        Some(e) => e,
2,672✔
562
                        None => _mul(lhs.as_ref().clone(), rhs.as_ref().clone()),
96,200✔
563
                    },
564
                    BinaryOp::Div => match lhs.div_expand(rhs) {
4,914✔
565
                        Some(e) => e,
494✔
566
                        None => _div(lhs.as_ref().clone(), rhs.as_ref().clone()),
4,420✔
567
                    },
568
                    BinaryOp::Add => match lhs.add_opt(rhs, true) {
5,436✔
569
                        Some(e) => e,
168✔
570
                        None => _add(lhs.as_ref().clone(), rhs.as_ref().clone()),
5,268✔
571
                    },
572
                    BinaryOp::Sub => match lhs.sub_opt(rhs, true) {
6,438✔
573
                        Some(e) => e,
2,866✔
574
                        None => _sub(lhs.as_ref().clone(), rhs.as_ref().clone()),
3,572✔
575
                    },
576
                    _ => _pow(lhs.expand(), rhs.expand()), // TO DO : add expand for pow
3,136✔
577
                }
578
            }
579
        }
580
    }
156,680✔
581

582
    /// sign operator
583
    pub fn sign(&self) -> SymbolExpr {
10✔
584
        SymbolExpr::Unary {
10✔
585
            op: UnaryOp::Sign,
10✔
586
            expr: Arc::new(self.clone()),
10✔
587
        }
10✔
588
    }
10✔
589

590
    /// return real number if equation can be evaluated
591
    pub fn real(&self) -> Option<f64> {
×
592
        match self.eval(true) {
×
593
            Some(v) => match v {
×
594
                Value::Real(r) => Some(r),
×
595
                Value::Int(r) => Some(r as f64),
×
596
                Value::Complex(c) => Some(c.re),
×
597
            },
598
            None => None,
×
599
        }
600
    }
×
601
    /// return imaginary part of the value if equation can be evaluated as complex number
602
    pub fn imag(&self) -> Option<f64> {
×
603
        match self.eval(true) {
×
604
            Some(v) => match v {
×
605
                Value::Real(_) => Some(0.0),
×
606
                Value::Int(_) => Some(0.0),
×
607
                Value::Complex(c) => Some(c.im),
×
608
            },
609
            None => None,
×
610
        }
611
    }
×
612
    /// return complex number if equation can be evaluated as complex
613
    pub fn complex(&self) -> Option<Complex64> {
×
614
        match self.eval(true) {
×
615
            Some(v) => match v {
×
616
                Value::Real(r) => Some(r.into()),
×
617
                Value::Int(i) => Some((i as f64).into()),
×
618
                Value::Complex(c) => Some(c),
×
619
            },
620
            None => None,
×
621
        }
622
    }
×
623

624
    /// Return hashset of all parameters this equation contains.
625
    pub fn parameters(&self) -> HashSet<Symbol> {
3,958,882✔
626
        match self {
3,958,882✔
627
            SymbolExpr::Symbol(e) => HashSet::from_iter([e.clone()]),
3,295,018✔
628
            SymbolExpr::Value(_) => HashSet::<Symbol>::new(),
192,438✔
629
            SymbolExpr::Unary { op: _, expr } => expr.parameters(),
75,686✔
630
            SymbolExpr::Binary { op: _, lhs, rhs } => {
395,740✔
631
                let mut parameters = HashSet::<Symbol>::new();
395,740✔
632
                for s in lhs.parameters().union(&rhs.parameters()) {
721,976✔
633
                    parameters.insert(s.clone());
721,976✔
634
                }
721,976✔
635
                parameters
395,740✔
636
            }
637
        }
638
    }
3,958,882✔
639

640
    /// Map of parameter name to the parameter.
641
    pub fn name_map(&self) -> HashMap<String, Symbol> {
796,772✔
642
        self.parameters()
796,772✔
643
            .iter()
796,772✔
644
            .map(|param| (param.name(), param.clone()))
796,772✔
645
            .collect()
796,772✔
646
    }
796,772✔
647

648
    /// return all numbers in the equation
649
    pub fn values(&self) -> Vec<Value> {
182✔
650
        match self {
182✔
651
            SymbolExpr::Symbol(_) => Vec::<Value>::new(),
86✔
652
            SymbolExpr::Value(v) => Vec::<Value>::from([*v]),
44✔
653
            SymbolExpr::Unary { op: _, expr } => expr.values(),
×
654
            SymbolExpr::Binary { op: _, lhs, rhs } => {
52✔
655
                let mut l = lhs.values();
52✔
656
                let r = rhs.values();
52✔
657
                l.extend(r);
52✔
658
                l
52✔
659
            }
660
        }
661
    }
182✔
662

663
    /// check if a symbol is in this equation
664
    pub fn has_symbol(&self, param: &Symbol) -> bool {
12✔
665
        match self {
12✔
666
            SymbolExpr::Symbol(e) => e.eq(param),
6✔
667
            SymbolExpr::Value(_) => false,
6✔
668
            SymbolExpr::Unary { op: _, expr } => expr.has_symbol(param),
×
669
            SymbolExpr::Binary { op: _, lhs, rhs } => lhs.has_symbol(param) | rhs.has_symbol(param),
×
670
        }
671
    }
12✔
672

673
    /// return reciprocal of the equation
674
    pub fn rcp(&self) -> SymbolExpr {
1,998✔
675
        match self {
1,998✔
676
            SymbolExpr::Symbol(e) => _div(
×
677
                SymbolExpr::Value(Value::Real(1.0)),
×
678
                SymbolExpr::Symbol(e.clone()),
×
679
            ),
680
            SymbolExpr::Value(e) => SymbolExpr::Value(e.rcp()),
1,998✔
681
            SymbolExpr::Unary { .. } => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
682
            SymbolExpr::Binary { op, lhs, rhs } => match op {
×
683
                BinaryOp::Div => SymbolExpr::Binary {
×
684
                    op: op.clone(),
×
685
                    lhs: rhs.clone(),
×
686
                    rhs: lhs.clone(),
×
687
                },
×
688
                _ => _div(SymbolExpr::Value(Value::Real(1.0)), self.clone()),
×
689
            },
690
        }
691
    }
1,998✔
692
    /// return square root of the equation
693
    pub fn sqrt(&self) -> SymbolExpr {
×
694
        match self {
×
695
            SymbolExpr::Value(v) => SymbolExpr::Value(v.sqrt()),
×
696
            _ => self.pow(&SymbolExpr::Value(Value::Real(0.5))),
×
697
        }
698
    }
×
699

700
    /// return conjugate of the equation
701
    pub fn conjugate(&self) -> SymbolExpr {
4,274✔
702
        match self {
4,274✔
703
            SymbolExpr::Symbol(_) => SymbolExpr::Unary {
1,864✔
704
                op: UnaryOp::Conj,
1,864✔
705
                expr: Arc::new(self.clone()),
1,864✔
706
            },
1,864✔
707
            SymbolExpr::Value(e) => match e {
1,034✔
708
                Value::Complex(c) => SymbolExpr::Value(Value::Complex(c.conj())),
482✔
709
                _ => SymbolExpr::Value(*e),
552✔
710
            },
711
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
310✔
712
                op: op.clone(),
310✔
713
                expr: Arc::new(expr.conjugate()),
310✔
714
            },
310✔
715
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
1,066✔
716
                op: op.clone(),
1,066✔
717
                lhs: Arc::new(lhs.conjugate()),
1,066✔
718
                rhs: Arc::new(rhs.conjugate()),
1,066✔
719
            },
1,066✔
720
        }
721
    }
4,274✔
722

723
    /// check if complex number or not
724
    pub fn is_complex(&self) -> Option<bool> {
×
725
        match self.eval(true) {
×
726
            Some(v) => match v {
×
727
                Value::Complex(c) => Some(!(-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
×
728
                _ => Some(false),
×
729
            },
730
            None => None,
×
731
        }
732
    }
×
733

734
    /// check if real number or not
735
    pub fn is_real(&self) -> Option<bool> {
270✔
736
        match self.eval(true) {
270✔
737
            Some(v) => match v {
182✔
738
                Value::Real(_) | Value::Int(_) => Some(true),
130✔
739
                Value::Complex(c) => Some((-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)),
52✔
740
            },
741
            None => None,
88✔
742
        }
743
    }
270✔
744

745
    /// check if integer or not
746
    pub fn is_int(&self) -> Option<bool> {
6,376✔
747
        match self.eval(true) {
6,376✔
748
            Some(v) => match v {
5,700✔
749
                Value::Int(_) => Some(true),
2,182✔
750
                _ => Some(false),
3,518✔
751
            },
752
            None => None,
676✔
753
        }
754
    }
6,376✔
755

756
    /// check if evaluated result is 0
757
    pub fn is_zero(&self) -> bool {
9,574,842✔
758
        match self.eval(true) {
9,574,842✔
759
            Some(v) => v.is_zero(),
5,592,130✔
760
            None => false,
3,982,712✔
761
        }
762
    }
9,574,842✔
763

764
    /// check if evaluated result is 1
765
    pub fn is_one(&self) -> bool {
740,340✔
766
        match self.eval(true) {
740,340✔
767
            Some(v) => v.is_one(),
521,976✔
768
            None => false,
218,364✔
769
        }
770
    }
740,340✔
771

772
    /// check if evaluated result is -1
773
    pub fn is_minus_one(&self) -> bool {
457,984✔
774
        match self.eval(true) {
457,984✔
775
            Some(v) => v.is_minus_one(),
272,162✔
776
            None => false,
185,822✔
777
        }
778
    }
457,984✔
779

780
    /// check if evaluated result is negative
781
    fn is_negative(&self) -> bool {
448,678✔
782
        match self {
448,678✔
783
            SymbolExpr::Value(v) => v.is_negative(),
71,866✔
784
            SymbolExpr::Symbol(_) => false,
196,782✔
785
            SymbolExpr::Unary { op, expr } => match op {
18,986✔
786
                UnaryOp::Abs => false,
6✔
787
                UnaryOp::Neg => !expr.is_negative(),
17,290✔
788
                _ => false, // TO DO add heuristic determination
1,690✔
789
            },
790
            SymbolExpr::Binary { op, lhs, rhs } => match op {
161,044✔
791
                BinaryOp::Mul | BinaryOp::Div => lhs.is_negative() ^ rhs.is_negative(),
136,050✔
792
                BinaryOp::Add | BinaryOp::Sub => lhs.is_negative(),
15,154✔
793
                _ => false, // TO DO add heuristic determination for pow
9,840✔
794
            },
795
        }
796
    }
448,678✔
797

798
    /// unary operations
799
    pub fn abs(&self) -> SymbolExpr {
378✔
800
        match self {
4✔
801
            SymbolExpr::Value(l) => SymbolExpr::Value(l.abs()),
6✔
802
            SymbolExpr::Unary {
803
                op: UnaryOp::Abs | UnaryOp::Neg,
804
                expr,
4✔
805
            } => expr.abs(),
4✔
806
            _ => SymbolExpr::Unary {
368✔
807
                op: UnaryOp::Abs,
368✔
808
                expr: Arc::new(self.clone()),
368✔
809
            },
368✔
810
        }
811
    }
378✔
812
    pub fn sin(&self) -> SymbolExpr {
362✔
813
        match self {
362✔
814
            SymbolExpr::Value(l) => SymbolExpr::Value(l.sin()),
×
815
            _ => SymbolExpr::Unary {
362✔
816
                op: UnaryOp::Sin,
362✔
817
                expr: Arc::new(self.clone()),
362✔
818
            },
362✔
819
        }
820
    }
362✔
821
    pub fn asin(&self) -> SymbolExpr {
100✔
822
        match self {
100✔
823
            SymbolExpr::Value(l) => SymbolExpr::Value(l.asin()),
×
824
            _ => SymbolExpr::Unary {
100✔
825
                op: UnaryOp::Asin,
100✔
826
                expr: Arc::new(self.clone()),
100✔
827
            },
100✔
828
        }
829
    }
100✔
830
    pub fn cos(&self) -> SymbolExpr {
352✔
831
        match self {
352✔
832
            SymbolExpr::Value(l) => SymbolExpr::Value(l.cos()),
×
833
            _ => SymbolExpr::Unary {
352✔
834
                op: UnaryOp::Cos,
352✔
835
                expr: Arc::new(self.clone()),
352✔
836
            },
352✔
837
        }
838
    }
352✔
839
    pub fn acos(&self) -> SymbolExpr {
100✔
840
        match self {
100✔
841
            SymbolExpr::Value(l) => SymbolExpr::Value(l.acos()),
×
842
            _ => SymbolExpr::Unary {
100✔
843
                op: UnaryOp::Acos,
100✔
844
                expr: Arc::new(self.clone()),
100✔
845
            },
100✔
846
        }
847
    }
100✔
848
    pub fn tan(&self) -> SymbolExpr {
352✔
849
        match self {
352✔
850
            SymbolExpr::Value(l) => SymbolExpr::Value(l.tan()),
×
851
            _ => SymbolExpr::Unary {
352✔
852
                op: UnaryOp::Tan,
352✔
853
                expr: Arc::new(self.clone()),
352✔
854
            },
352✔
855
        }
856
    }
352✔
857
    pub fn atan(&self) -> SymbolExpr {
100✔
858
        match self {
100✔
859
            SymbolExpr::Value(l) => SymbolExpr::Value(l.atan()),
×
860
            _ => SymbolExpr::Unary {
100✔
861
                op: UnaryOp::Atan,
100✔
862
                expr: Arc::new(self.clone()),
100✔
863
            },
100✔
864
        }
865
    }
100✔
866
    pub fn exp(&self) -> SymbolExpr {
350✔
867
        match self {
350✔
868
            SymbolExpr::Value(l) => SymbolExpr::Value(l.exp()),
×
869
            _ => SymbolExpr::Unary {
350✔
870
                op: UnaryOp::Exp,
350✔
871
                expr: Arc::new(self.clone()),
350✔
872
            },
350✔
873
        }
874
    }
350✔
875
    pub fn log(&self) -> SymbolExpr {
266✔
876
        match self {
266✔
877
            SymbolExpr::Value(l) => SymbolExpr::Value(l.log()),
×
878
            _ => SymbolExpr::Unary {
266✔
879
                op: UnaryOp::Log,
266✔
880
                expr: Arc::new(self.clone()),
266✔
881
            },
266✔
882
        }
883
    }
266✔
884
    pub fn pow(&self, rhs: &SymbolExpr) -> SymbolExpr {
3,016✔
885
        match self {
3,016✔
886
            SymbolExpr::Value(l) => match rhs {
1,030✔
887
                SymbolExpr::Value(r) => SymbolExpr::Value(l.pow(r)),
×
888
                _ => SymbolExpr::Binary {
1,030✔
889
                    op: BinaryOp::Pow,
1,030✔
890
                    lhs: Arc::new(SymbolExpr::Value(*l)),
1,030✔
891
                    rhs: Arc::new(rhs.clone()),
1,030✔
892
                },
1,030✔
893
            },
894
            _ => SymbolExpr::Binary {
1,986✔
895
                op: BinaryOp::Pow,
1,986✔
896
                lhs: Arc::new(self.clone()),
1,986✔
897
                rhs: Arc::new(rhs.clone()),
1,986✔
898
            },
1,986✔
899
        }
900
    }
3,016✔
901

902
    pub fn string_id(&self) -> String {
1,801,500✔
903
        self.repr(true)
1,801,500✔
904
    }
1,801,500✔
905

906
    // Add with heuristic optimization
907
    fn add_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,547,070✔
908
        if self.is_zero() {
2,547,070✔
909
            Some(rhs.clone())
1,304,726✔
910
        } else if rhs.is_zero() {
1,242,344✔
911
            Some(self.clone())
1,015,744✔
912
        } else {
913
            // if neg operation, call sub_opt
914
            if let SymbolExpr::Unary { op, expr } = rhs {
226,600✔
915
                if let UnaryOp::Neg = op {
15,038✔
916
                    return self.sub_opt(expr, recursive);
13,530✔
917
                }
1,508✔
918
            } else if recursive {
211,562✔
919
                if let SymbolExpr::Binary {
920
                    op,
39,526✔
921
                    lhs: r_lhs,
39,526✔
922
                    rhs: r_rhs,
39,526✔
923
                } = rhs
53,548✔
924
                {
925
                    // recursive optimization for add and sub
926
                    if let BinaryOp::Add = &op {
39,526✔
927
                        if let Some(e) = self.add_opt(r_lhs, true) {
2,720✔
928
                            return match e.add_opt(r_rhs, true) {
32✔
929
                                Some(ee) => Some(ee),
6✔
930
                                None => Some(_add(e, r_rhs.as_ref().clone())),
26✔
931
                            };
932
                        }
2,688✔
933
                        if let Some(e) = self.add_opt(r_rhs, true) {
2,688✔
934
                            return match e.add_opt(r_lhs, true) {
12✔
935
                                Some(ee) => Some(ee),
×
936
                                None => Some(_add(e, r_lhs.as_ref().clone())),
12✔
937
                            };
938
                        }
2,676✔
939
                    }
36,806✔
940
                    if let BinaryOp::Sub = &op {
39,482✔
941
                        if let Some(e) = self.add_opt(r_lhs, true) {
2,832✔
942
                            return match e.sub_opt(r_rhs, true) {
80✔
943
                                Some(ee) => Some(ee),
62✔
944
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
18✔
945
                            };
946
                        }
2,752✔
947
                        if let Some(e) = self.sub_opt(r_rhs, true) {
2,752✔
UNCOV
948
                            return match e.add_opt(r_lhs, true) {
×
949
                                Some(ee) => Some(ee),
×
UNCOV
950
                                None => Some(_add(e, r_lhs.as_ref().clone())),
×
951
                            };
952
                        }
2,752✔
953
                    }
36,650✔
954
                }
14,022✔
955
            }
158,014✔
956

957
            // optimization for each node type
958
            match self {
212,946✔
959
                SymbolExpr::Value(l) => match rhs {
82,844✔
960
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l + r)),
68,968✔
961
                    SymbolExpr::Binary {
962
                        op,
5,106✔
963
                        lhs: r_lhs,
5,106✔
964
                        rhs: r_rhs,
5,106✔
965
                    } => {
966
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,106✔
967
                            let t = l + v;
2,806✔
968
                            match op {
2,806✔
969
                                BinaryOp::Add => {
970
                                    if t.is_zero() {
12✔
971
                                        Some(r_rhs.as_ref().clone())
×
972
                                    } else {
973
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
12✔
974
                                    }
975
                                }
976
                                BinaryOp::Sub => {
977
                                    if t.is_zero() {
×
978
                                        match r_rhs.neg_opt() {
×
979
                                            Some(e) => Some(e),
×
980
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
981
                                        }
982
                                    } else {
983
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
984
                                    }
985
                                }
986
                                _ => None,
2,794✔
987
                            }
988
                        } else {
989
                            None
2,300✔
990
                        }
991
                    }
992
                    _ => None,
8,770✔
993
                },
994
                SymbolExpr::Symbol(l) => match rhs {
14,850✔
995
                    SymbolExpr::Value(_) => Some(_add(rhs.clone(), self.clone())),
3,506✔
996
                    SymbolExpr::Symbol(r) => {
8,470✔
997
                        if r == l {
8,470✔
998
                            Some(_mul(SymbolExpr::Value(Value::Int(2)), self.clone()))
228✔
999
                        } else if r < l {
8,242✔
1000
                            Some(_add(rhs.clone(), self.clone()))
1,318✔
1001
                        } else {
1002
                            None
6,924✔
1003
                        }
1004
                    }
1005
                    SymbolExpr::Binary {
1006
                        op,
2,874✔
1007
                        lhs: r_lhs,
2,874✔
1008
                        rhs: r_rhs,
2,874✔
1009
                    } => {
1010
                        if let (
1011
                            BinaryOp::Mul | BinaryOp::Div,
1012
                            SymbolExpr::Value(v),
2,002✔
1013
                            SymbolExpr::Symbol(s),
2,002✔
1014
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
2,874✔
1015
                        {
1016
                            if l == s {
2,002✔
1017
                                let t = v + &Value::Int(1);
10✔
1018
                                if t.is_zero() {
10✔
1019
                                    Some(SymbolExpr::Value(Value::Int(0)))
6✔
1020
                                } else {
1021
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
4✔
1022
                                }
1023
                            } else {
1024
                                None
1,992✔
1025
                            }
1026
                        } else {
1027
                            None
872✔
1028
                        }
1029
                    }
1030
                    _ => None,
×
1031
                },
1032
                SymbolExpr::Unary { op, expr } => {
14,692✔
1033
                    if let UnaryOp::Neg = op {
14,692✔
1034
                        if let Some(e) = expr.sub_opt(rhs, recursive) {
13,592✔
1035
                            return match e.neg_opt() {
6,544✔
1036
                                Some(ee) => Some(ee),
6,544✔
1037
                                None => Some(_neg(e)),
×
1038
                            };
1039
                        }
7,048✔
1040
                    } else if let SymbolExpr::Unary {
1041
                        op: rop,
656✔
1042
                        expr: rexpr,
656✔
1043
                    } = rhs
1,100✔
1044
                    {
1045
                        if op == rop {
656✔
1046
                            if let Some(t) = expr.expand().add_opt(&rexpr.expand(), true) {
316✔
1047
                                if t.is_zero() {
12✔
1048
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1049
                                }
12✔
1050
                            }
304✔
1051
                        }
340✔
1052
                    }
444✔
1053

1054
                    // swap nodes by sorting rule
1055
                    match rhs {
8,148✔
1056
                        SymbolExpr::Binary { op: rop, .. } => {
5,910✔
1057
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
5,910✔
1058
                                if self > rhs {
5,392✔
1059
                                    Some(_add(rhs.clone(), self.clone()))
×
1060
                                } else {
1061
                                    None
5,392✔
1062
                                }
1063
                            } else {
1064
                                None
518✔
1065
                            }
1066
                        }
1067
                        _ => {
1068
                            if self > rhs {
2,238✔
1069
                                Some(_add(rhs.clone(), self.clone()))
40✔
1070
                            } else {
1071
                                None
2,198✔
1072
                            }
1073
                        }
1074
                    }
1075
                }
1076
                SymbolExpr::Binary {
1077
                    op,
100,560✔
1078
                    lhs: l_lhs,
100,560✔
1079
                    rhs: l_rhs,
100,560✔
1080
                } => {
1081
                    if let SymbolExpr::Binary {
1082
                        op: rop,
91,712✔
1083
                        lhs: r_lhs,
91,712✔
1084
                        rhs: r_rhs,
91,712✔
1085
                    } = rhs
100,560✔
1086
                    {
1087
                        match (
1088
                            l_lhs.as_ref(),
91,712✔
1089
                            l_rhs.as_ref(),
91,712✔
1090
                            r_lhs.as_ref(),
91,712✔
1091
                            r_rhs.as_ref(),
91,712✔
1092
                        ) {
1093
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
8,202✔
1094
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
8,202✔
1095
                                    let t = SymbolExpr::Value(lv + rv);
754✔
1096
                                    if t.is_zero() {
754✔
1097
                                        return Some(SymbolExpr::Value(Value::Int(0)));
342✔
1098
                                    }
412✔
1099
                                    match (op, rop) {
412✔
1100
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1101
                                            return match t.mul_opt(l_rhs, recursive) {
316✔
1102
                                                Some(e) => Some(e),
8✔
1103
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
308✔
1104
                                            }
1105
                                        }
1106
                                        (BinaryOp::Div, BinaryOp::Div) => {
1107
                                            return match t.div_opt(l_rhs, recursive) {
×
1108
                                                Some(e) => Some(e),
×
1109
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1110
                                            }
1111
                                        }
1112
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1113
                                            return match t.pow_opt(l_rhs) {
96✔
1114
                                                Some(e) => Some(e),
96✔
1115
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1116
                                            }
1117
                                        }
1118
                                        (_, _) => (),
×
1119
                                    }
1120
                                }
7,448✔
1121
                            }
1122
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
4,822✔
1123
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
4,822✔
1124
                                    if l_lhs.expand().string_id() == r_lhs.expand().string_id()
1,130✔
1125
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
1,100✔
1126
                                            == r_lhs.expand().string_id()
1,100✔
1127
                                    {
1128
                                        let tl =
30✔
1129
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
30✔
1130
                                        let tr =
30✔
1131
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
30✔
1132
                                        let b = SymbolExpr::Value(lv * rv);
30✔
1133
                                        return match tl.add_opt(&tr, recursive) {
30✔
1134
                                            Some(e) => Some(_div(e, b)),
30✔
1135
                                            None => Some(_div(_add(tl, tr), b)),
×
1136
                                        };
1137
                                    }
1,100✔
1138
                                }
3,692✔
1139
                            }
1140
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
462✔
1141
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
462✔
1142
                                    if l_rhs.expand().string_id() == r_lhs.expand().string_id()
×
1143
                                        || _neg(l_rhs.as_ref().clone()).expand().string_id()
×
1144
                                            == r_lhs.expand().string_id()
×
1145
                                    {
1146
                                        let r = _mul(
×
1147
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
×
1148
                                            r_lhs.as_ref().clone(),
×
1149
                                        );
1150
                                        if let Some(e) = self.add_opt(&r, recursive) {
×
1151
                                            return Some(e);
×
1152
                                        }
×
1153
                                    }
×
1154
                                }
462✔
1155
                            }
1156
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
296✔
1157
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
296✔
1158
                                    if l_lhs.expand().string_id() == r_rhs.expand().string_id()
8✔
1159
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
4✔
1160
                                            == r_rhs.expand().string_id()
4✔
1161
                                    {
1162
                                        let l = _mul(
8✔
1163
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
8✔
1164
                                            l_lhs.as_ref().clone(),
8✔
1165
                                        );
1166
                                        if let Some(e) = l.add_opt(rhs, recursive) {
8✔
1167
                                            return Some(e);
8✔
1168
                                        }
×
1169
                                    }
×
1170
                                }
288✔
1171
                            }
1172
                            (_, _, _, _) => (),
77,930✔
1173
                        }
1174

1175
                        if op == rop {
90,920✔
1176
                            if let Some(e) = rhs.neg_opt() {
36,074✔
1177
                                if self.expand().string_id() == e.expand().string_id() {
24,936✔
1178
                                    return Some(SymbolExpr::Value(Value::Int(0)));
838✔
1179
                                }
24,098✔
1180
                            }
11,138✔
1181
                        }
54,846✔
1182
                    } else if let SymbolExpr::Symbol(r) = rhs {
8,848✔
1183
                        if let (
1184
                            BinaryOp::Mul | BinaryOp::Div,
1185
                            SymbolExpr::Value(v),
1,868✔
1186
                            SymbolExpr::Symbol(s),
1,868✔
1187
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
6,690✔
1188
                        {
1189
                            if s == r {
1,868✔
1190
                                let t = v + &Value::Int(1);
×
1191
                                if t.is_zero() {
×
1192
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1193
                                } else {
1194
                                    return Some(_mul(
×
1195
                                        SymbolExpr::Value(t),
×
1196
                                        l_rhs.as_ref().clone(),
×
1197
                                    ));
×
1198
                                }
1199
                            }
1,868✔
1200
                        }
4,822✔
1201
                    }
2,158✔
1202
                    if recursive {
98,930✔
1203
                        if let BinaryOp::Add = op {
37,208✔
1204
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
5,516✔
1205
                                return match e.add_opt(l_rhs, true) {
302✔
1206
                                    Some(ee) => Some(ee),
206✔
1207
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
96✔
1208
                                };
1209
                            }
5,214✔
1210
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
5,214✔
1211
                                return match l_lhs.add_opt(&e, true) {
96✔
1212
                                    Some(ee) => Some(ee),
×
1213
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
96✔
1214
                                };
1215
                            }
5,118✔
1216
                        } else if let BinaryOp::Sub = op {
31,692✔
1217
                            if let Some(e) = l_lhs.add_opt(rhs, true) {
6,066✔
1218
                                return match e.sub_opt(l_rhs, true) {
822✔
1219
                                    Some(ee) => Some(ee),
276✔
1220
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
546✔
1221
                                };
1222
                            }
5,244✔
1223
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
5,244✔
1224
                                return match l_lhs.sub_opt(&e, true) {
164✔
1225
                                    Some(ee) => Some(ee),
56✔
1226
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
108✔
1227
                                };
1228
                            }
5,080✔
1229
                        }
25,626✔
1230
                    }
61,722✔
1231
                    // swap nodes by sorting rule
1232
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
97,546✔
1233
                        match rhs {
41,306✔
1234
                            SymbolExpr::Binary { op: rop, .. } => {
37,958✔
1235
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
37,958✔
1236
                                    if self > rhs {
34,256✔
1237
                                        Some(_add(rhs.clone(), self.clone()))
344✔
1238
                                    } else {
1239
                                        None
33,912✔
1240
                                    }
1241
                                } else {
1242
                                    None
3,702✔
1243
                                }
1244
                            }
1245
                            _ => {
1246
                                if self > rhs {
3,348✔
1247
                                    Some(_add(rhs.clone(), self.clone()))
3,348✔
1248
                                } else {
1249
                                    None
×
1250
                                }
1251
                            }
1252
                        }
1253
                    } else {
1254
                        None
56,240✔
1255
                    }
1256
                }
1257
            }
1258
        }
1259
    }
2,547,070✔
1260

1261
    /// Sub with heuristic optimization
1262
    fn sub_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
189,810✔
1263
        if self.is_zero() {
189,810✔
1264
            match rhs.neg_opt() {
7,896✔
1265
                Some(e) => Some(e),
6,442✔
1266
                None => Some(_neg(rhs.clone())),
1,454✔
1267
            }
1268
        } else if rhs.is_zero() {
181,914✔
1269
            Some(self.clone())
2,808✔
1270
        } else {
1271
            // if neg, call add_opt
1272
            if let SymbolExpr::Unary { op, expr } = rhs {
179,106✔
1273
                if let UnaryOp::Neg = op {
3,892✔
1274
                    return self.add_opt(expr, recursive);
1,904✔
1275
                }
1,988✔
1276
            } else if recursive {
175,214✔
1277
                if let SymbolExpr::Binary {
1278
                    op,
44,074✔
1279
                    lhs: r_lhs,
44,074✔
1280
                    rhs: r_rhs,
44,074✔
1281
                } = rhs
69,576✔
1282
                {
1283
                    // recursive optimization for add and sub
1284
                    if let BinaryOp::Add = &op {
44,074✔
1285
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,590✔
1286
                            return match e.sub_opt(r_rhs, true) {
702✔
1287
                                Some(ee) => Some(ee),
686✔
1288
                                None => Some(_sub(e, r_rhs.as_ref().clone())),
16✔
1289
                            };
1290
                        }
2,888✔
1291
                        if let Some(e) = self.sub_opt(r_rhs, true) {
2,888✔
1292
                            return match e.sub_opt(r_lhs, true) {
2✔
1293
                                Some(ee) => Some(ee),
×
1294
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
2✔
1295
                            };
1296
                        }
2,886✔
1297
                    }
40,484✔
1298
                    if let BinaryOp::Sub = &op {
43,370✔
1299
                        if let Some(e) = self.sub_opt(r_lhs, true) {
3,764✔
1300
                            return match e.add_opt(r_rhs, true) {
530✔
1301
                                Some(ee) => Some(ee),
494✔
1302
                                None => Some(_add(e, r_rhs.as_ref().clone())),
36✔
1303
                            };
1304
                        }
3,234✔
1305
                        if let Some(e) = self.add_opt(r_rhs, true) {
3,234✔
1306
                            return match e.sub_opt(r_lhs, true) {
2✔
1307
                                Some(ee) => Some(ee),
×
1308
                                None => Some(_sub(e, r_lhs.as_ref().clone())),
2✔
1309
                            };
1310
                        }
3,232✔
1311
                    }
39,606✔
1312
                }
25,502✔
1313
            }
105,638✔
1314

1315
            // optimization for each type
1316
            match self {
175,966✔
1317
                SymbolExpr::Value(l) => match &rhs {
71,482✔
1318
                    SymbolExpr::Value(r) => Some(SymbolExpr::Value(l - r)),
61,076✔
1319
                    SymbolExpr::Binary {
1320
                        op,
5,542✔
1321
                        lhs: r_lhs,
5,542✔
1322
                        rhs: r_rhs,
5,542✔
1323
                    } => {
1324
                        if let SymbolExpr::Value(v) = r_lhs.as_ref() {
5,542✔
1325
                            let t = l - v;
2,526✔
1326
                            match op {
2,526✔
1327
                                BinaryOp::Add => {
1328
                                    if t.is_zero() {
×
1329
                                        match r_rhs.neg_opt() {
×
1330
                                            Some(e) => Some(e),
×
1331
                                            None => Some(_neg(r_rhs.as_ref().clone())),
×
1332
                                        }
1333
                                    } else {
1334
                                        Some(_sub(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1335
                                    }
1336
                                }
1337
                                BinaryOp::Sub => {
1338
                                    if t.is_zero() {
×
1339
                                        Some(r_rhs.as_ref().clone())
×
1340
                                    } else {
1341
                                        Some(_add(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
×
1342
                                    }
1343
                                }
1344
                                _ => None,
2,526✔
1345
                            }
1346
                        } else {
1347
                            None
3,016✔
1348
                        }
1349
                    }
1350
                    _ => None,
4,864✔
1351
                },
1352
                SymbolExpr::Symbol(l) => match &rhs {
26,398✔
1353
                    SymbolExpr::Value(r) => Some(_add(SymbolExpr::Value(-r), self.clone())),
3,866✔
1354
                    SymbolExpr::Symbol(r) => {
18,742✔
1355
                        if r == l {
18,742✔
1356
                            Some(SymbolExpr::Value(Value::Int(0)))
12,616✔
1357
                        } else if r < l {
6,126✔
1358
                            Some(_add(_neg(rhs.clone()), self.clone()))
1,088✔
1359
                        } else {
1360
                            None
5,038✔
1361
                        }
1362
                    }
1363
                    SymbolExpr::Binary {
1364
                        op,
3,790✔
1365
                        lhs: r_lhs,
3,790✔
1366
                        rhs: r_rhs,
3,790✔
1367
                    } => {
1368
                        if let (
1369
                            BinaryOp::Mul | BinaryOp::Div,
1370
                            SymbolExpr::Value(v),
1,960✔
1371
                            SymbolExpr::Symbol(s),
1,960✔
1372
                        ) = (op, r_lhs.as_ref(), r_rhs.as_ref())
3,790✔
1373
                        {
1374
                            if l == s {
1,960✔
1375
                                let t = &Value::Int(1) - v;
14✔
1376
                                if t.is_zero() {
14✔
1377
                                    Some(SymbolExpr::Value(Value::Int(0)))
4✔
1378
                                } else {
1379
                                    Some(_mul(SymbolExpr::Value(t), r_rhs.as_ref().clone()))
10✔
1380
                                }
1381
                            } else {
1382
                                None
1,946✔
1383
                            }
1384
                        } else {
1385
                            None
1,830✔
1386
                        }
1387
                    }
1388
                    _ => None,
×
1389
                },
1390
                SymbolExpr::Unary { op, expr } => {
13,518✔
1391
                    if let UnaryOp::Neg = op {
13,518✔
1392
                        if let Some(e) = expr.add_opt(rhs, recursive) {
11,642✔
1393
                            return match e.neg_opt() {
6,326✔
1394
                                Some(ee) => Some(ee),
6,326✔
1395
                                None => Some(_neg(e)),
×
1396
                            };
1397
                        }
5,316✔
1398
                    }
1,876✔
1399
                    if let SymbolExpr::Unary {
1400
                        op: rop,
1,534✔
1401
                        expr: rexpr,
1,534✔
1402
                    } = rhs
7,192✔
1403
                    {
1404
                        if op == rop {
1,534✔
1405
                            if let Some(t) = expr.expand().sub_opt(&rexpr.expand(), true) {
1,060✔
1406
                                if t.is_zero() {
896✔
1407
                                    return Some(SymbolExpr::Value(Value::Int(0)));
896✔
1408
                                }
×
1409
                            }
164✔
1410
                        }
474✔
1411
                    }
5,658✔
1412

1413
                    // swap nodes by sorting rule
1414
                    match rhs {
6,296✔
1415
                        SymbolExpr::Binary { op: rop, .. } => {
4,164✔
1416
                            if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
4,164✔
1417
                                if self > rhs {
3,606✔
1418
                                    match rhs.neg_opt() {
×
1419
                                        Some(e) => Some(_add(e, self.clone())),
×
1420
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
×
1421
                                    }
1422
                                } else {
1423
                                    None
3,606✔
1424
                                }
1425
                            } else {
1426
                                None
558✔
1427
                            }
1428
                        }
1429
                        _ => {
1430
                            if self > rhs {
2,132✔
1431
                                match rhs.neg_opt() {
28✔
1432
                                    Some(e) => Some(_add(e, self.clone())),
×
1433
                                    None => Some(_add(_neg(rhs.clone()), self.clone())),
28✔
1434
                                }
1435
                            } else {
1436
                                None
2,104✔
1437
                            }
1438
                        }
1439
                    }
1440
                }
1441
                SymbolExpr::Binary {
1442
                    op,
64,568✔
1443
                    lhs: l_lhs,
64,568✔
1444
                    rhs: l_rhs,
64,568✔
1445
                } => {
1446
                    if let SymbolExpr::Binary {
1447
                        op: rop,
46,374✔
1448
                        lhs: r_lhs,
46,374✔
1449
                        rhs: r_rhs,
46,374✔
1450
                    } = rhs
64,568✔
1451
                    {
1452
                        match (
1453
                            l_lhs.as_ref(),
46,374✔
1454
                            l_rhs.as_ref(),
46,374✔
1455
                            r_lhs.as_ref(),
46,374✔
1456
                            r_rhs.as_ref(),
46,374✔
1457
                        ) {
1458
                            (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
3,270✔
1459
                                if l_rhs.expand().string_id() == r_rhs.expand().string_id() {
3,270✔
1460
                                    let t = SymbolExpr::Value(lv - rv);
1,256✔
1461
                                    if t.is_zero() {
1,256✔
1462
                                        return Some(SymbolExpr::Value(Value::Int(0)));
1,256✔
1463
                                    }
×
1464
                                    match (op, rop) {
×
1465
                                        (BinaryOp::Mul, BinaryOp::Mul) => {
1466
                                            return match t.mul_opt(l_rhs, recursive) {
×
1467
                                                Some(e) => Some(e),
×
1468
                                                None => Some(_mul(t, l_rhs.as_ref().clone())),
×
1469
                                            }
1470
                                        }
1471
                                        (BinaryOp::Div, BinaryOp::Div) => {
1472
                                            return match t.div_opt(l_rhs, recursive) {
×
1473
                                                Some(e) => Some(e),
×
1474
                                                None => Some(_div(t, l_rhs.as_ref().clone())),
×
1475
                                            }
1476
                                        }
1477
                                        (BinaryOp::Pow, BinaryOp::Pow) => {
1478
                                            return match t.pow_opt(l_rhs) {
×
1479
                                                Some(e) => Some(e),
×
1480
                                                None => Some(_pow(t, l_rhs.as_ref().clone())),
×
1481
                                            }
1482
                                        }
1483
                                        (_, _) => (),
×
1484
                                    }
1485
                                }
2,014✔
1486
                            }
1487
                            (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
736✔
1488
                                if let (BinaryOp::Div, BinaryOp::Div) = (op, rop) {
736✔
1489
                                    if l_lhs.expand().string_id() == r_lhs.expand().string_id()
260✔
1490
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
204✔
1491
                                            == r_lhs.expand().string_id()
204✔
1492
                                    {
1493
                                        let tl =
60✔
1494
                                            _mul(SymbolExpr::Value(*rv), l_lhs.as_ref().clone());
60✔
1495
                                        let tr =
60✔
1496
                                            _mul(SymbolExpr::Value(*lv), r_lhs.as_ref().clone());
60✔
1497
                                        let b = SymbolExpr::Value(lv * rv);
60✔
1498
                                        return match tl.sub_opt(&tr, recursive) {
60✔
1499
                                            Some(e) => Some(_div(e, b)),
60✔
1500
                                            None => Some(_div(_sub(tl, tr), b)),
×
1501
                                        };
1502
                                    }
200✔
1503
                                }
476✔
1504
                            }
1505
                            (SymbolExpr::Value(_), _, _, SymbolExpr::Value(rv)) => {
330✔
1506
                                if let (BinaryOp::Mul, BinaryOp::Div) = (op, rop) {
330✔
1507
                                    if l_rhs.expand().string_id() == r_lhs.expand().string_id()
4✔
1508
                                        || _neg(l_rhs.as_ref().clone()).expand().string_id()
×
1509
                                            == r_lhs.expand().string_id()
×
1510
                                    {
1511
                                        let r = _mul(
4✔
1512
                                            SymbolExpr::Value(Value::Real(1.0) / *rv),
4✔
1513
                                            r_lhs.as_ref().clone(),
4✔
1514
                                        );
1515
                                        if let Some(e) = self.sub_opt(&r, recursive) {
4✔
1516
                                            return Some(e);
4✔
1517
                                        }
×
1518
                                    }
×
1519
                                }
326✔
1520
                            }
1521
                            (_, SymbolExpr::Value(lv), SymbolExpr::Value(_), _) => {
278✔
1522
                                if let (BinaryOp::Div, BinaryOp::Mul) = (op, rop) {
278✔
1523
                                    if l_lhs.expand().string_id() == r_rhs.expand().string_id()
54✔
1524
                                        || _neg(l_lhs.as_ref().clone()).expand().string_id()
24✔
1525
                                            == r_rhs.expand().string_id()
24✔
1526
                                    {
1527
                                        let l = _mul(
50✔
1528
                                            SymbolExpr::Value(Value::Real(1.0) / *lv),
50✔
1529
                                            l_lhs.as_ref().clone(),
50✔
1530
                                        );
1531
                                        if let Some(e) = l.sub_opt(rhs, recursive) {
50✔
1532
                                            return Some(e);
50✔
1533
                                        }
×
1534
                                    }
4✔
1535
                                }
224✔
1536
                            }
1537
                            (_, _, _, _) => (),
41,760✔
1538
                        }
1539

1540
                        if op == rop && self.expand().string_id() == rhs.expand().string_id() {
45,004✔
1541
                            return Some(SymbolExpr::Value(Value::Int(0)));
270✔
1542
                        }
44,734✔
1543
                    } else if let SymbolExpr::Symbol(r) = rhs {
18,194✔
1544
                        if let (
1545
                            BinaryOp::Mul | BinaryOp::Div,
1546
                            SymbolExpr::Value(v),
1,720✔
1547
                            SymbolExpr::Symbol(s),
1,720✔
1548
                        ) = (op, l_lhs.as_ref(), l_rhs.as_ref())
6,336✔
1549
                        {
1550
                            if s == r {
1,720✔
1551
                                let t = v - &Value::Int(1);
20✔
1552
                                if t.is_zero() {
20✔
1553
                                    return Some(SymbolExpr::Value(Value::Int(0)));
×
1554
                                } else {
1555
                                    return Some(_mul(
20✔
1556
                                        SymbolExpr::Value(t),
20✔
1557
                                        l_rhs.as_ref().clone(),
20✔
1558
                                    ));
20✔
1559
                                }
1560
                            }
1,700✔
1561
                        }
4,616✔
1562
                    }
11,858✔
1563
                    if recursive {
62,908✔
1564
                        if let BinaryOp::Add = op {
47,164✔
1565
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
10,638✔
1566
                                return match e.add_opt(l_rhs, true) {
5,894✔
1567
                                    Some(ee) => Some(ee),
1,974✔
1568
                                    None => Some(_add(e, l_rhs.as_ref().clone())),
3,920✔
1569
                                };
1570
                            }
4,744✔
1571
                            if let Some(e) = l_rhs.sub_opt(rhs, true) {
4,744✔
1572
                                return match l_lhs.add_opt(&e, true) {
896✔
1573
                                    Some(ee) => Some(ee),
768✔
1574
                                    None => Some(_add(l_lhs.as_ref().clone(), e)),
128✔
1575
                                };
1576
                            }
3,848✔
1577
                        }
36,526✔
1578
                        if let BinaryOp::Sub = op {
40,374✔
1579
                            if let Some(e) = l_lhs.sub_opt(rhs, true) {
9,250✔
1580
                                return match e.sub_opt(l_rhs, true) {
1,258✔
1581
                                    Some(ee) => Some(ee),
298✔
1582
                                    None => Some(_sub(e, l_rhs.as_ref().clone())),
960✔
1583
                                };
1584
                            }
7,992✔
1585
                            if let Some(e) = l_rhs.add_opt(rhs, true) {
7,992✔
1586
                                return match l_lhs.sub_opt(&e, true) {
100✔
1587
                                    Some(ee) => Some(ee),
8✔
1588
                                    None => Some(_sub(l_lhs.as_ref().clone(), e)),
92✔
1589
                                };
1590
                            }
7,892✔
1591
                        }
31,124✔
1592
                    }
15,744✔
1593
                    // swap nodes by sorting rule
1594
                    if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = op {
54,760✔
1595
                        match rhs {
33,372✔
1596
                            SymbolExpr::Binary { op: rop, .. } => {
26,868✔
1597
                                if let BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow = rop {
26,868✔
1598
                                    if self > rhs {
23,288✔
1599
                                        match rhs.neg_opt() {
112✔
1600
                                            Some(e) => Some(_add(e, self.clone())),
14✔
1601
                                            None => Some(_add(_neg(rhs.clone()), self.clone())),
98✔
1602
                                        }
1603
                                    } else {
1604
                                        None
23,176✔
1605
                                    }
1606
                                } else {
1607
                                    None
3,580✔
1608
                                }
1609
                            }
1610
                            _ => {
1611
                                if self > rhs {
6,504✔
1612
                                    match rhs.neg_opt() {
6,504✔
1613
                                        Some(e) => Some(_add(e, self.clone())),
3,880✔
1614
                                        None => Some(_add(_neg(rhs.clone()), self.clone())),
2,624✔
1615
                                    }
1616
                                } else {
1617
                                    None
×
1618
                                }
1619
                            }
1620
                        }
1621
                    } else {
1622
                        None
21,388✔
1623
                    }
1624
                }
1625
            }
1626
        }
1627
    }
189,810✔
1628

1629
    /// Mul with heuristic optimization
1630
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
2,629,026✔
1631
        if self.is_zero() {
2,629,026✔
1632
            Some(self.clone())
20,480✔
1633
        } else if rhs.is_zero() || self.is_one() {
2,608,546✔
1634
            Some(rhs.clone())
2,366,074✔
1635
        } else if rhs.is_one() {
242,472✔
1636
            Some(self.clone())
84,118✔
1637
        } else if self.is_minus_one() {
158,354✔
1638
            match rhs.neg_opt() {
3,268✔
1639
                Some(e) => Some(e),
1,378✔
1640
                None => Some(_neg(rhs.clone())),
1,890✔
1641
            }
1642
        } else if rhs.is_minus_one() {
155,086✔
1643
            match self.neg_opt() {
26,474✔
1644
                Some(e) => Some(e),
9,244✔
1645
                None => Some(_neg(self.clone())),
17,230✔
1646
            }
1647
        } else {
1648
            if let SymbolExpr::Value(_) | SymbolExpr::Symbol(_) = rhs {
128,612✔
1649
                if let SymbolExpr::Unary { .. } = self {
92,894✔
1650
                    return match rhs.mul_opt(self, recursive) {
5,462✔
1651
                        Some(e) => Some(e),
5,246✔
1652
                        None => Some(_mul(rhs.clone(), self.clone())),
216✔
1653
                    };
1654
                }
87,432✔
1655
            }
35,718✔
1656

1657
            match self {
123,150✔
1658
                SymbolExpr::Value(e) => e.mul_opt(rhs, recursive),
35,184✔
1659
                SymbolExpr::Symbol(e) => match rhs {
33,414✔
1660
                    SymbolExpr::Value(_) => Some(_mul(rhs.clone(), self.clone())),
15,506✔
1661
                    SymbolExpr::Symbol(r) => {
10,460✔
1662
                        if r < e {
10,460✔
1663
                            Some(_mul(rhs.clone(), self.clone()))
3,560✔
1664
                        } else {
1665
                            None
6,900✔
1666
                        }
1667
                    }
1668
                    SymbolExpr::Unary {
1669
                        op: UnaryOp::Neg,
1670
                        expr,
2,222✔
1671
                    } => match expr.as_ref() {
2,222✔
1672
                        SymbolExpr::Value(v) => Some(_mul(SymbolExpr::Value(-v), self.clone())),
×
1673
                        SymbolExpr::Symbol(s) => {
2,222✔
1674
                            if s < e {
2,222✔
1675
                                Some(_neg(_mul(expr.as_ref().clone(), self.clone())))
1,540✔
1676
                            } else {
1677
                                Some(_neg(_mul(self.clone(), expr.as_ref().clone())))
682✔
1678
                            }
1679
                        }
1680
                        SymbolExpr::Binary { .. } => match self.mul_opt(expr, recursive) {
×
1681
                            Some(e) => match e.neg_opt() {
×
1682
                                Some(ee) => Some(ee),
×
1683
                                None => Some(_neg(e)),
×
1684
                            },
1685
                            None => None,
×
1686
                        },
1687
                        _ => None,
×
1688
                    },
1689
                    _ => None,
5,226✔
1690
                },
1691
                SymbolExpr::Unary { op, expr } => match op {
1,882✔
1692
                    UnaryOp::Neg => match expr.mul_opt(rhs, recursive) {
1,872✔
1693
                        Some(e) => match e.neg_opt() {
482✔
1694
                            Some(ee) => Some(ee),
482✔
1695
                            None => Some(_neg(e)),
×
1696
                        },
1697
                        None => None,
1,390✔
1698
                    },
1699
                    UnaryOp::Abs => match rhs {
2✔
1700
                        SymbolExpr::Unary {
1701
                            op: UnaryOp::Abs,
1702
                            expr: rexpr,
2✔
1703
                        } => match expr.mul_opt(rexpr, recursive) {
2✔
1704
                            Some(e) => Some(SymbolExpr::Unary {
×
1705
                                op: UnaryOp::Abs,
×
1706
                                expr: Arc::new(e),
×
1707
                            }),
×
1708
                            None => Some(SymbolExpr::Unary {
2✔
1709
                                op: UnaryOp::Abs,
2✔
1710
                                expr: Arc::new(_mul(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
1711
                            }),
2✔
1712
                        },
1713
                        _ => None,
×
1714
                    },
1715
                    _ => None,
8✔
1716
                },
1717
                SymbolExpr::Binary {
1718
                    op,
52,670✔
1719
                    lhs: l_lhs,
52,670✔
1720
                    rhs: l_rhs,
52,670✔
1721
                } => {
1722
                    if recursive {
52,670✔
1723
                        if let SymbolExpr::Binary {
1724
                            op: rop,
248✔
1725
                            lhs: r_lhs,
248✔
1726
                            rhs: r_rhs,
248✔
1727
                        } = rhs
3,850✔
1728
                        {
1729
                            if let BinaryOp::Mul = &rop {
248✔
1730
                                if let Some(e) = self.mul_opt(r_lhs, true) {
240✔
1731
                                    return match e.mul_opt(r_rhs, true) {
240✔
1732
                                        Some(ee) => Some(ee),
194✔
1733
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
46✔
1734
                                    };
1735
                                }
×
1736
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
1737
                                    return match e.mul_opt(r_lhs, true) {
×
1738
                                        Some(ee) => Some(ee),
×
1739
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1740
                                    };
1741
                                }
×
1742
                            }
8✔
1743
                            if let BinaryOp::Div = &rop {
8✔
1744
                                if let Some(e) = self.mul_opt(r_lhs, true) {
×
1745
                                    return match e.div_opt(r_rhs, true) {
×
1746
                                        Some(ee) => Some(ee),
×
1747
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
1748
                                    };
1749
                                }
×
1750
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
1751
                                    return match e.mul_opt(r_lhs, true) {
×
1752
                                        Some(ee) => Some(ee),
×
1753
                                        None => Some(_mul(e, r_lhs.as_ref().clone())),
×
1754
                                    };
1755
                                }
×
1756
                            }
8✔
1757
                        }
3,602✔
1758

1759
                        if let BinaryOp::Mul = &op {
3,610✔
1760
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
3,602✔
1761
                                return match e.mul_opt(l_rhs, true) {
1,198✔
1762
                                    Some(ee) => Some(ee),
1,054✔
1763
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
144✔
1764
                                };
1765
                            }
2,404✔
1766
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
2,404✔
1767
                                return match l_lhs.mul_opt(&e, true) {
918✔
1768
                                    Some(ee) => Some(ee),
×
1769
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
918✔
1770
                                };
1771
                            }
1,486✔
1772
                        } else if let BinaryOp::Div = &op {
8✔
1773
                            if let Some(e) = l_lhs.mul_opt(rhs, true) {
8✔
1774
                                return match e.div_opt(l_rhs, true) {
×
1775
                                    Some(ee) => Some(ee),
×
1776
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
1777
                                };
1778
                            }
8✔
1779
                            if let Some(e) = rhs.div_opt(l_rhs, true) {
8✔
1780
                                return match l_lhs.mul_opt(&e, true) {
×
1781
                                    Some(ee) => Some(ee),
×
1782
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
1783
                                };
1784
                            }
8✔
1785
                        }
×
1786
                        None
1,494✔
1787
                    } else {
1788
                        match rhs {
48,820✔
1789
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
31,716✔
1790
                                SymbolExpr::Value(lv) => match op {
11,182✔
1791
                                    BinaryOp::Mul => Some(_mul(
10,466✔
1792
                                        SymbolExpr::Value(lv * v),
10,466✔
1793
                                        l_rhs.as_ref().clone(),
10,466✔
1794
                                    )),
10,466✔
1795
                                    BinaryOp::Div => Some(_div(
×
1796
                                        SymbolExpr::Value(lv * v),
×
1797
                                        l_rhs.as_ref().clone(),
×
1798
                                    )),
×
1799
                                    _ => None,
716✔
1800
                                },
1801
                                _ => match l_rhs.as_ref() {
20,534✔
1802
                                    SymbolExpr::Value(rv) => match op {
576✔
1803
                                        BinaryOp::Mul => Some(_mul(
×
1804
                                            SymbolExpr::Value(rv * v),
×
1805
                                            l_lhs.as_ref().clone(),
×
1806
                                        )),
×
1807
                                        BinaryOp::Div => Some(_mul(
×
1808
                                            SymbolExpr::Value(v / rv),
×
1809
                                            l_lhs.as_ref().clone(),
×
1810
                                        )),
×
1811
                                        _ => None,
576✔
1812
                                    },
1813
                                    _ => None,
19,958✔
1814
                                },
1815
                            },
1816
                            SymbolExpr::Binary {
1817
                                op: rop,
10,224✔
1818
                                lhs: r_lhs,
10,224✔
1819
                                rhs: r_rhs,
10,224✔
1820
                            } => match (op, rop) {
10,224✔
1821
                                (BinaryOp::Mul, BinaryOp::Mul) => match (
1822
                                    l_lhs.as_ref(),
1,256✔
1823
                                    l_rhs.as_ref(),
1,256✔
1824
                                    r_lhs.as_ref(),
1,256✔
1825
                                    r_rhs.as_ref(),
1,256✔
1826
                                ) {
1827
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
1,256✔
1828
                                        Some(_mul(
1,256✔
1829
                                            SymbolExpr::Value(lv * rv),
1,256✔
1830
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
1,256✔
1831
                                        ))
1,256✔
1832
                                    }
1833
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1834
                                        Some(_mul(
×
1835
                                            SymbolExpr::Value(lv * rv),
×
1836
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1837
                                        ))
×
1838
                                    }
1839
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1840
                                        Some(_mul(
×
1841
                                            SymbolExpr::Value(lv * rv),
×
1842
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1843
                                        ))
×
1844
                                    }
1845
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1846
                                        Some(_mul(
×
1847
                                            SymbolExpr::Value(lv * rv),
×
1848
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1849
                                        ))
×
1850
                                    }
1851
                                    (_, _, _, _) => None,
×
1852
                                },
1853
                                (BinaryOp::Mul, BinaryOp::Div) => match (
1854
                                    l_lhs.as_ref(),
×
1855
                                    l_rhs.as_ref(),
×
1856
                                    r_lhs.as_ref(),
×
1857
                                    r_rhs.as_ref(),
×
1858
                                ) {
1859
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1860
                                        Some(_mul(
×
1861
                                            SymbolExpr::Value(lv * rv),
×
1862
                                            _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1863
                                        ))
×
1864
                                    }
1865
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1866
                                        Some(_mul(
×
1867
                                            SymbolExpr::Value(lv / rv),
×
1868
                                            _mul(l_rhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1869
                                        ))
×
1870
                                    }
1871
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1872
                                        Some(_mul(
×
1873
                                            SymbolExpr::Value(lv * rv),
×
1874
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1875
                                        ))
×
1876
                                    }
1877
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1878
                                        Some(_mul(
×
1879
                                            SymbolExpr::Value(lv / rv),
×
1880
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1881
                                        ))
×
1882
                                    }
1883
                                    (_, _, _, _) => None,
×
1884
                                },
1885
                                (BinaryOp::Div, BinaryOp::Mul) => match (
1886
                                    l_lhs.as_ref(),
×
1887
                                    l_rhs.as_ref(),
×
1888
                                    r_lhs.as_ref(),
×
1889
                                    r_rhs.as_ref(),
×
1890
                                ) {
1891
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1892
                                        Some(_mul(
×
1893
                                            SymbolExpr::Value(lv * rv),
×
1894
                                            _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1895
                                        ))
×
1896
                                    }
1897
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1898
                                        Some(_mul(
×
1899
                                            SymbolExpr::Value(lv * rv),
×
1900
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1901
                                        ))
×
1902
                                    }
1903
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1904
                                        Some(_mul(
×
1905
                                            SymbolExpr::Value(rv / lv),
×
1906
                                            _mul(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1907
                                        ))
×
1908
                                    }
1909
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
×
1910
                                        Some(_mul(
×
1911
                                            SymbolExpr::Value(rv / lv),
×
1912
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
×
1913
                                        ))
×
1914
                                    }
1915
                                    (_, _, _, _) => None,
×
1916
                                },
1917
                                (BinaryOp::Div, BinaryOp::Div) => match (
1918
                                    l_lhs.as_ref(),
2✔
1919
                                    l_rhs.as_ref(),
2✔
1920
                                    r_lhs.as_ref(),
2✔
1921
                                    r_rhs.as_ref(),
2✔
1922
                                ) {
1923
                                    (SymbolExpr::Value(lv), _, SymbolExpr::Value(rv), _) => {
×
1924
                                        Some(_div(
×
1925
                                            SymbolExpr::Value(lv * rv),
×
1926
                                            _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1927
                                        ))
×
1928
                                    }
1929
                                    (SymbolExpr::Value(lv), _, _, SymbolExpr::Value(rv)) => {
×
1930
                                        Some(_mul(
×
1931
                                            SymbolExpr::Value(lv / rv),
×
1932
                                            _div(r_lhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
1933
                                        ))
×
1934
                                    }
1935
                                    (_, SymbolExpr::Value(lv), SymbolExpr::Value(rv), _) => {
×
1936
                                        Some(_mul(
×
1937
                                            SymbolExpr::Value(rv / lv),
×
1938
                                            _div(l_lhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
1939
                                        ))
×
1940
                                    }
1941
                                    (_, SymbolExpr::Value(lv), _, SymbolExpr::Value(rv)) => {
2✔
1942
                                        Some(_div(
2✔
1943
                                            _mul(l_lhs.as_ref().clone(), r_lhs.as_ref().clone()),
2✔
1944
                                            SymbolExpr::Value(lv * rv),
2✔
1945
                                        ))
2✔
1946
                                    }
1947
                                    (_, _, _, _) => None,
×
1948
                                },
1949
                                (_, _) => None,
8,966✔
1950
                            },
1951
                            _ => None,
6,880✔
1952
                        }
1953
                    }
1954
                }
1955
            }
1956
        }
1957
    }
2,629,026✔
1958
    /// expand with optimization for mul operation
1959
    fn mul_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
218,508✔
1960
        if let SymbolExpr::Binary {
1961
            op: rop,
11,878✔
1962
            lhs: r_lhs,
11,878✔
1963
            rhs: r_rhs,
11,878✔
1964
        } = rhs
218,508✔
1965
        {
1966
            if let BinaryOp::Add | BinaryOp::Sub = &rop {
11,878✔
1967
                let el = match self.mul_expand(r_lhs) {
1,256✔
1968
                    Some(e) => e,
922✔
1969
                    None => match self.mul_opt(r_lhs, true) {
334✔
1970
                        Some(e) => e,
236✔
1971
                        None => _mul(self.clone(), r_lhs.as_ref().clone()),
98✔
1972
                    },
1973
                };
1974
                let er = match self.mul_expand(r_rhs) {
1,256✔
1975
                    Some(e) => e,
576✔
1976
                    None => match self.mul_opt(r_rhs, true) {
680✔
1977
                        Some(e) => e,
332✔
1978
                        None => _mul(self.clone(), r_rhs.as_ref().clone()),
348✔
1979
                    },
1980
                };
1981
                return match &rop {
1,256✔
1982
                    BinaryOp::Sub => match el.sub_opt(&er, true) {
640✔
1983
                        Some(e) => Some(e),
30✔
1984
                        None => Some(_sub(el, er)),
610✔
1985
                    },
1986
                    _ => match el.add_opt(&er, true) {
616✔
1987
                        Some(e) => Some(e),
34✔
1988
                        None => Some(_add(el, er)),
582✔
1989
                    },
1990
                };
1991
            }
10,622✔
1992
            if let BinaryOp::Mul = &rop {
10,622✔
1993
                return match self.mul_expand(r_lhs) {
10,574✔
1994
                    Some(e) => match e.mul_expand(r_rhs) {
748✔
1995
                        Some(ee) => Some(ee),
700✔
1996
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
48✔
1997
                    },
1998
                    None => self
9,826✔
1999
                        .mul_expand(r_rhs)
9,826✔
2000
                        .map(|e| _mul(e, r_lhs.as_ref().clone())),
9,826✔
2001
                };
2002
            }
48✔
2003
            if let BinaryOp::Div = &rop {
48✔
2004
                return match self.mul_expand(r_lhs) {
×
2005
                    Some(e) => match e.mul_expand(r_rhs) {
×
2006
                        Some(ee) => Some(ee),
×
2007
                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2008
                    },
2009
                    None => self
×
2010
                        .div_expand(r_rhs)
×
2011
                        .map(|e| _div(e, r_lhs.as_ref().clone())),
×
2012
                };
2013
            }
48✔
2014
        }
206,630✔
2015
        if let SymbolExpr::Unary {
2016
            op: UnaryOp::Neg,
2017
            expr: rexpr,
1,436✔
2018
        } = rhs
2,092✔
2019
        {
2020
            return match self.mul_expand(rexpr) {
1,436✔
2021
                Some(e) => match e.neg_opt() {
288✔
2022
                    Some(ee) => Some(ee),
288✔
2023
                    None => Some(_neg(e)),
×
2024
                },
2025
                None => match self.mul_opt(rexpr, true) {
1,148✔
2026
                    Some(e) => match e.neg_opt() {
134✔
2027
                        Some(ee) => Some(ee),
102✔
2028
                        None => Some(_neg(e)),
32✔
2029
                    },
2030
                    None => Some(_neg(_mul(self.clone(), rexpr.as_ref().clone()))),
1,014✔
2031
                },
2032
            };
2033
        }
205,242✔
2034

2035
        match self {
876✔
2036
            SymbolExpr::Unary {
2037
                op: UnaryOp::Neg,
2038
                expr,
876✔
2039
            } => match expr.mul_expand(rhs) {
876✔
2040
                Some(e) => match e.neg_opt() {
×
2041
                    Some(ee) => Some(ee),
×
2042
                    None => Some(_neg(e)),
×
2043
                },
2044
                None => match expr.mul_opt(rhs, true) {
876✔
2045
                    Some(e) => match e.neg_opt() {
518✔
2046
                        Some(ee) => Some(ee),
248✔
2047
                        None => Some(_neg(e)),
270✔
2048
                    },
2049
                    None => None,
358✔
2050
                },
2051
            },
2052
            SymbolExpr::Binary {
2053
                op,
46,840✔
2054
                lhs: l_lhs,
46,840✔
2055
                rhs: l_rhs,
46,840✔
2056
            } => match &op {
46,840✔
2057
                BinaryOp::Add | BinaryOp::Sub => {
2058
                    let l = match l_lhs.mul_expand(rhs) {
3,274✔
2059
                        Some(e) => e,
1,174✔
2060
                        None => match l_lhs.mul_opt(rhs, true) {
2,100✔
2061
                            Some(e) => e,
1,308✔
2062
                            None => _mul(l_lhs.as_ref().clone(), rhs.clone()),
792✔
2063
                        },
2064
                    };
2065
                    let r = match l_rhs.mul_expand(rhs) {
3,274✔
2066
                        Some(e) => e,
84✔
2067
                        None => match l_rhs.mul_opt(rhs, true) {
3,190✔
2068
                            Some(e) => e,
1,930✔
2069
                            None => _mul(l_rhs.as_ref().clone(), rhs.clone()),
1,260✔
2070
                        },
2071
                    };
2072
                    match &op {
3,274✔
2073
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
1,448✔
2074
                            Some(e) => Some(e),
204✔
2075
                            None => Some(_sub(l, r)),
1,244✔
2076
                        },
2077
                        _ => match l.add_opt(&r, true) {
1,826✔
2078
                            Some(e) => Some(e),
334✔
2079
                            None => Some(_add(l, r)),
1,492✔
2080
                        },
2081
                    }
2082
                }
2083
                BinaryOp::Mul => match l_lhs.mul_expand(rhs) {
43,546✔
2084
                    Some(e) => match e.mul_expand(l_rhs) {
44✔
2085
                        Some(ee) => Some(ee),
44✔
2086
                        None => match e.mul_opt(l_rhs, true) {
×
2087
                            Some(ee) => Some(ee),
×
2088
                            None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2089
                        },
2090
                    },
2091
                    None => match l_rhs.mul_expand(rhs) {
43,502✔
2092
                        Some(e) => match l_lhs.mul_expand(&e) {
24✔
2093
                            Some(ee) => Some(ee),
24✔
2094
                            None => match l_lhs.mul_opt(&e, true) {
×
2095
                                Some(ee) => Some(ee),
×
2096
                                None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2097
                            },
2098
                        },
2099
                        None => None,
43,478✔
2100
                    },
2101
                },
2102
                BinaryOp::Div => match l_lhs.div_expand(rhs) {
20✔
2103
                    Some(e) => Some(_div(e, l_rhs.as_ref().clone())),
×
2104
                    None => l_rhs
20✔
2105
                        .div_expand(rhs)
20✔
2106
                        .map(|e| _div(l_lhs.as_ref().clone(), e)),
20✔
2107
                },
2108
                _ => None,
×
2109
            },
2110
            _ => None,
157,526✔
2111
        }
2112
    }
218,508✔
2113

2114
    /// Div with heuristic optimization
2115
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
147,084✔
2116
        if rhs.is_zero() {
147,084✔
2117
            // return inf to detect divide by zero without panic
2118
            Some(SymbolExpr::Value(Value::Real(f64::INFINITY)))
1,828✔
2119
        } else if rhs.is_one() {
145,256✔
2120
            Some(self.clone())
712✔
2121
        } else if rhs.is_minus_one() {
144,544✔
2122
            match self.neg_opt() {
684✔
2123
                Some(e) => Some(e),
168✔
2124
                None => Some(_neg(self.clone())),
516✔
2125
            }
2126
        } else if *self == *rhs {
143,860✔
2127
            let l_is_int = self.is_int().unwrap_or_default();
3,188✔
2128
            let r_is_int = rhs.is_int().unwrap_or_default();
3,188✔
2129
            if l_is_int || r_is_int {
3,188✔
2130
                Some(SymbolExpr::Value(Value::Int(1)))
1,206✔
2131
            } else {
2132
                Some(SymbolExpr::Value(Value::Real(1.0)))
1,982✔
2133
            }
2134
        } else {
2135
            if let SymbolExpr::Value(Value::Real(r)) = rhs {
132,586✔
2136
                let t = 1.0 / r;
1,222✔
2137
                if &(1.0 / t) == r {
1,222✔
2138
                    if recursive {
1,210✔
2139
                        return self.mul_opt(&SymbolExpr::Value(Value::Real(t)), recursive);
×
2140
                    } else {
2141
                        return Some(&SymbolExpr::Value(Value::Real(t)) * self);
1,210✔
2142
                    }
2143
                }
12✔
2144
            }
139,450✔
2145

2146
            match self {
139,462✔
2147
                SymbolExpr::Value(e) => e.div_opt(rhs, recursive),
76,738✔
2148
                SymbolExpr::Symbol(_) => None,
15,680✔
2149
                SymbolExpr::Unary { op, expr } => match op {
39,032✔
2150
                    UnaryOp::Neg => match expr.div_opt(rhs, recursive) {
39,000✔
2151
                        Some(e) => match e.neg_opt() {
35,420✔
2152
                            Some(ee) => Some(ee),
35,420✔
2153
                            None => Some(_neg(e)),
×
2154
                        },
2155
                        None => None,
3,580✔
2156
                    },
2157
                    UnaryOp::Abs => match rhs {
2✔
2158
                        SymbolExpr::Unary {
2159
                            op: UnaryOp::Abs,
2160
                            expr: rexpr,
2✔
2161
                        } => match expr.div_opt(rexpr, recursive) {
2✔
2162
                            Some(e) => Some(SymbolExpr::Unary {
×
2163
                                op: UnaryOp::Abs,
×
2164
                                expr: Arc::new(e),
×
2165
                            }),
×
2166
                            None => Some(SymbolExpr::Unary {
2✔
2167
                                op: UnaryOp::Abs,
2✔
2168
                                expr: Arc::new(_div(expr.as_ref().clone(), rexpr.as_ref().clone())),
2✔
2169
                            }),
2✔
2170
                        },
2171
                        _ => None,
×
2172
                    },
2173
                    _ => None,
30✔
2174
                },
2175
                SymbolExpr::Binary {
2176
                    op,
8,012✔
2177
                    lhs: l_lhs,
8,012✔
2178
                    rhs: l_rhs,
8,012✔
2179
                } => {
2180
                    if recursive {
8,012✔
2181
                        if let SymbolExpr::Binary {
2182
                            op: rop,
×
2183
                            lhs: r_lhs,
×
2184
                            rhs: r_rhs,
×
2185
                        } = rhs
196✔
2186
                        {
2187
                            if let BinaryOp::Mul = &rop {
×
2188
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2189
                                    return match e.div_opt(r_rhs, true) {
×
2190
                                        Some(ee) => Some(ee),
×
2191
                                        None => Some(_div(e, r_rhs.as_ref().clone())),
×
2192
                                    };
2193
                                }
×
2194
                                if let Some(e) = self.div_opt(r_rhs, true) {
×
2195
                                    return match e.div_opt(r_lhs, true) {
×
2196
                                        Some(ee) => Some(ee),
×
2197
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2198
                                    };
2199
                                }
×
2200
                            }
×
2201
                            if let BinaryOp::Div = &rop {
×
2202
                                if let Some(e) = self.mul_opt(r_rhs, true) {
×
2203
                                    return match e.div_opt(r_lhs, true) {
×
2204
                                        Some(ee) => Some(ee),
×
2205
                                        None => Some(_div(e, r_lhs.as_ref().clone())),
×
2206
                                    };
2207
                                }
×
2208
                                if let Some(e) = self.div_opt(r_lhs, true) {
×
2209
                                    return match e.mul_opt(r_rhs, true) {
×
2210
                                        Some(ee) => Some(ee),
×
2211
                                        None => Some(_mul(e, r_rhs.as_ref().clone())),
×
2212
                                    };
2213
                                }
×
2214
                            }
×
2215
                        }
196✔
2216

2217
                        if let BinaryOp::Mul = &op {
196✔
2218
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2219
                                return match e.mul_opt(l_rhs, true) {
×
2220
                                    Some(ee) => Some(ee),
×
2221
                                    None => Some(_mul(e, l_rhs.as_ref().clone())),
×
2222
                                };
2223
                            }
×
2224
                            if let Some(e) = l_rhs.div_opt(rhs, true) {
×
2225
                                return match l_lhs.mul_opt(&e, true) {
×
2226
                                    Some(ee) => Some(ee),
×
2227
                                    None => Some(_mul(l_lhs.as_ref().clone(), e)),
×
2228
                                };
2229
                            }
×
2230
                        } else if let BinaryOp::Div = &op {
196✔
2231
                            if let Some(e) = l_rhs.mul_opt(rhs, true) {
94✔
2232
                                return match l_lhs.div_opt(&e, true) {
94✔
2233
                                    Some(ee) => Some(ee),
×
2234
                                    None => Some(_div(l_lhs.as_ref().clone(), e)),
94✔
2235
                                };
2236
                            }
×
2237
                            if let Some(e) = l_lhs.div_opt(rhs, true) {
×
2238
                                return match e.div_opt(l_rhs, true) {
×
2239
                                    Some(ee) => Some(ee),
×
2240
                                    None => Some(_div(e, l_rhs.as_ref().clone())),
×
2241
                                };
2242
                            }
×
2243
                        }
102✔
2244
                        None
102✔
2245
                    } else {
2246
                        match rhs {
7,816✔
2247
                            SymbolExpr::Value(v) => match l_lhs.as_ref() {
6,382✔
2248
                                SymbolExpr::Value(lv) => match op {
1,512✔
2249
                                    BinaryOp::Mul => Some(_mul(
340✔
2250
                                        SymbolExpr::Value(lv / v),
340✔
2251
                                        l_rhs.as_ref().clone(),
340✔
2252
                                    )),
340✔
2253
                                    BinaryOp::Div => Some(_div(
×
2254
                                        SymbolExpr::Value(lv / v),
×
2255
                                        l_rhs.as_ref().clone(),
×
2256
                                    )),
×
2257
                                    _ => None,
1,172✔
2258
                                },
2259
                                _ => match l_rhs.as_ref() {
4,870✔
2260
                                    SymbolExpr::Value(rv) => match op {
3,120✔
2261
                                        BinaryOp::Mul => Some(_mul(
8✔
2262
                                            SymbolExpr::Value(rv / v),
8✔
2263
                                            l_lhs.as_ref().clone(),
8✔
2264
                                        )),
8✔
2265
                                        BinaryOp::Div => Some(_mul(
1,998✔
2266
                                            SymbolExpr::Value(v * rv).rcp(),
1,998✔
2267
                                            l_lhs.as_ref().clone(),
1,998✔
2268
                                        )),
1,998✔
2269
                                        _ => None,
1,114✔
2270
                                    },
2271
                                    _ => None,
1,750✔
2272
                                },
2273
                            },
2274
                            SymbolExpr::Binary {
2275
                                op: rop,
512✔
2276
                                lhs: r_lhs,
512✔
2277
                                rhs: r_rhs,
512✔
2278
                            } => match (l_lhs.as_ref(), r_lhs.as_ref()) {
512✔
2279
                                (SymbolExpr::Value(lv), SymbolExpr::Value(rv)) => match (op, rop) {
×
2280
                                    (BinaryOp::Mul, BinaryOp::Mul) => Some(_mul(
×
2281
                                        SymbolExpr::Value(lv / rv),
×
2282
                                        _div(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2283
                                    )),
×
2284
                                    (BinaryOp::Mul, BinaryOp::Div) => Some(_mul(
×
2285
                                        SymbolExpr::Value(lv / rv),
×
2286
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2287
                                    )),
×
2288
                                    (BinaryOp::Div, BinaryOp::Mul) => Some(_div(
×
2289
                                        SymbolExpr::Value(lv / rv),
×
2290
                                        _div(r_rhs.as_ref().clone(), l_rhs.as_ref().clone()),
×
2291
                                    )),
×
2292
                                    (BinaryOp::Div, BinaryOp::Div) => Some(_div(
×
2293
                                        SymbolExpr::Value(lv / rv),
×
2294
                                        _mul(l_rhs.as_ref().clone(), r_rhs.as_ref().clone()),
×
2295
                                    )),
×
2296
                                    (_, _) => None,
×
2297
                                },
2298
                                (_, _) => None,
512✔
2299
                            },
2300
                            _ => None,
922✔
2301
                        }
2302
                    }
2303
                }
2304
            }
2305
        }
2306
    }
147,084✔
2307

2308
    /// expand with optimization for div operation
2309
    fn div_expand(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
7,078✔
2310
        match self {
7,078✔
2311
            SymbolExpr::Unary { op, expr } => match op {
1,216✔
2312
                UnaryOp::Neg => match expr.div_expand(rhs) {
1,112✔
2313
                    Some(e) => match e.neg_opt() {
4✔
2314
                        Some(ee) => Some(ee),
4✔
2315
                        None => Some(_neg(e)),
×
2316
                    },
2317
                    None => match expr.div_opt(rhs, true) {
1,108✔
2318
                        Some(e) => match e.neg_opt() {
×
2319
                            Some(ee) => Some(ee),
×
2320
                            None => Some(_neg(e)),
×
2321
                        },
2322
                        None => None,
1,108✔
2323
                    },
2324
                },
2325
                _ => None,
104✔
2326
            },
2327
            SymbolExpr::Binary {
2328
                op,
616✔
2329
                lhs: l_lhs,
616✔
2330
                rhs: l_rhs,
616✔
2331
            } => match &op {
616✔
2332
                BinaryOp::Add | BinaryOp::Sub => {
2333
                    let l = match l_lhs.div_expand(rhs) {
506✔
2334
                        Some(e) => e,
200✔
2335
                        None => match l_lhs.div_opt(rhs, true) {
306✔
2336
                            Some(e) => e,
×
2337
                            None => _div(l_lhs.as_ref().clone(), rhs.clone()),
306✔
2338
                        },
2339
                    };
2340
                    let r = match l_rhs.div_expand(rhs) {
506✔
2341
                        Some(e) => e,
×
2342
                        None => match l_rhs.div_opt(rhs, true) {
506✔
2343
                            Some(e) => e,
94✔
2344
                            None => _div(l_rhs.as_ref().clone(), rhs.clone()),
412✔
2345
                        },
2346
                    };
2347
                    match &op {
506✔
2348
                        BinaryOp::Sub => match l.sub_opt(&r, true) {
200✔
2349
                            Some(e) => Some(e),
4✔
2350
                            None => Some(_sub(l, r)),
196✔
2351
                        },
2352
                        _ => match l.add_opt(&r, true) {
306✔
2353
                            Some(e) => Some(e),
4✔
2354
                            None => Some(_add(l, r)),
302✔
2355
                        },
2356
                    }
2357
                }
2358
                _ => None,
110✔
2359
            },
2360
            _ => self.div_opt(rhs, true),
5,246✔
2361
        }
2362
    }
7,078✔
2363

2364
    /// pow with heuristic optimization
2365
    fn pow_opt(&self, rhs: &SymbolExpr) -> Option<SymbolExpr> {
96✔
2366
        if self.is_zero() || rhs.is_one() {
96✔
2367
            return Some(self.clone());
96✔
2368
        } else if rhs.is_zero() {
×
2369
            return Some(SymbolExpr::Value(Value::Int(1)));
×
2370
        }
×
2371
        None
×
2372
    }
96✔
2373

2374
    /// optimization for neg
2375
    fn neg_opt(&self) -> Option<SymbolExpr> {
405,854✔
2376
        match self {
19,482✔
2377
            SymbolExpr::Value(v) => Some(SymbolExpr::Value(-v)),
121,680✔
2378
            SymbolExpr::Unary {
2379
                op: UnaryOp::Neg,
2380
                expr,
17,614✔
2381
            } => Some(expr.as_ref().clone()),
17,614✔
2382
            SymbolExpr::Binary { op, lhs, rhs } => match &op {
133,144✔
2383
                BinaryOp::Add => match lhs.neg_opt() {
4,874✔
2384
                    Some(ln) => match rhs.neg_opt() {
3,620✔
2385
                        Some(rn) => Some(_add(ln, rn)),
1,508✔
2386
                        None => Some(_sub(ln, rhs.as_ref().clone())),
2,112✔
2387
                    },
2388
                    None => match rhs.neg_opt() {
1,254✔
2389
                        Some(rn) => Some(_add(_neg(lhs.as_ref().clone()), rn)),
584✔
2390
                        None => Some(_sub(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
670✔
2391
                    },
2392
                },
2393
                BinaryOp::Sub => match lhs.neg_opt() {
3,484✔
2394
                    Some(ln) => Some(_add(ln, rhs.as_ref().clone())),
2,826✔
2395
                    None => Some(_add(_neg(lhs.as_ref().clone()), rhs.as_ref().clone())),
658✔
2396
                },
2397
                BinaryOp::Mul => match lhs.neg_opt() {
119,928✔
2398
                    Some(ln) => Some(_mul(ln, rhs.as_ref().clone())),
62,852✔
2399
                    None => rhs.neg_opt().map(|rn| _mul(lhs.as_ref().clone(), rn)),
57,076✔
2400
                },
2401
                BinaryOp::Div => match lhs.neg_opt() {
2,782✔
2402
                    Some(ln) => Some(_div(ln, rhs.as_ref().clone())),
1,688✔
2403
                    None => rhs.neg_opt().map(|rn| _div(lhs.as_ref().clone(), rn)),
1,094✔
2404
                },
2405
                _ => None,
2,076✔
2406
            },
2407
            _ => None,
133,416✔
2408
        }
2409
    }
405,854✔
2410

2411
    /// optimize the equation
2412
    pub fn optimize(&self) -> SymbolExpr {
×
2413
        match self {
×
2414
            SymbolExpr::Value(_) => self.clone(),
×
2415
            SymbolExpr::Symbol(_) => self.clone(),
×
2416
            SymbolExpr::Unary { op, expr } => {
×
2417
                let opt = expr.optimize();
×
2418
                match op {
×
2419
                    UnaryOp::Neg => match opt.neg_opt() {
×
2420
                        Some(e) => e,
×
2421
                        None => _neg(opt),
×
2422
                    },
2423
                    _ => SymbolExpr::Unary {
×
2424
                        op: op.clone(),
×
2425
                        expr: Arc::new(opt),
×
2426
                    },
×
2427
                }
2428
            }
2429
            SymbolExpr::Binary { op, lhs, rhs } => {
×
2430
                let opt_lhs = lhs.optimize();
×
2431
                let opt_rhs = rhs.optimize();
×
2432
                match op {
×
2433
                    BinaryOp::Add => match opt_lhs.add_opt(&opt_rhs, true) {
×
2434
                        Some(e) => e,
×
2435
                        None => _add(opt_lhs, opt_rhs),
×
2436
                    },
2437
                    BinaryOp::Sub => match opt_lhs.sub_opt(&opt_rhs, true) {
×
2438
                        Some(e) => e,
×
2439
                        None => _sub(opt_lhs, opt_rhs),
×
2440
                    },
2441
                    BinaryOp::Mul => match opt_lhs.mul_opt(&opt_rhs, true) {
×
2442
                        Some(e) => e,
×
2443
                        None => _mul(opt_lhs, opt_rhs),
×
2444
                    },
2445
                    BinaryOp::Div => match opt_lhs.div_opt(&opt_rhs, true) {
×
2446
                        Some(e) => e,
×
2447
                        None => _div(opt_lhs, opt_rhs),
×
2448
                    },
2449
                    BinaryOp::Pow => _pow(opt_lhs, opt_rhs),
×
2450
                }
2451
            }
2452
        }
2453
    }
×
2454

2455
    // convert sympy compatible format
2456
    pub fn sympify(&self) -> SymbolExpr {
×
2457
        match self {
×
2458
            SymbolExpr::Symbol { .. } => self.clone(),
×
2459
            SymbolExpr::Value(e) => e.sympify(),
×
2460
            SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
×
2461
                op: op.clone(),
×
2462
                expr: Arc::new(expr.sympify()),
×
2463
            },
×
2464
            SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
×
2465
                op: op.clone(),
×
2466
                lhs: Arc::new(lhs.sympify()),
×
2467
                rhs: Arc::new(rhs.sympify()),
×
2468
            },
×
2469
        }
2470
    }
×
2471

2472
    fn repr(&self, with_uuid: bool) -> String {
3,033,964✔
2473
        match self {
3,033,964✔
2474
            SymbolExpr::Symbol(e) => match with_uuid {
2,197,518✔
2475
                true => format!("{}_{}", e.name(), e.uuid.as_u128()),
2,019,876✔
2476
                false => e.name(),
177,642✔
2477
            },
2478
            SymbolExpr::Value(e) => e.to_string(),
288,372✔
2479
            SymbolExpr::Unary { op, expr } => {
7,552✔
2480
                let s = expr.repr(with_uuid);
7,552✔
2481
                match op {
7,552✔
2482
                    UnaryOp::Abs => format!("abs({s})"),
×
2483
                    UnaryOp::Neg => match expr.as_ref() {
5,216✔
2484
                        SymbolExpr::Value(e) => (-e).to_string(),
×
2485
                        SymbolExpr::Binary {
2486
                            op: BinaryOp::Add | BinaryOp::Sub,
2487
                            ..
2488
                        } => format!("-({s})"),
×
2489
                        _ => format!("-{s}"),
5,216✔
2490
                    },
2491
                    UnaryOp::Sin => format!("sin({s})"),
120✔
2492
                    UnaryOp::Asin => format!("asin({s})"),
108✔
2493
                    UnaryOp::Cos => format!("cos({s})"),
80✔
2494
                    UnaryOp::Acos => format!("acos({s})"),
92✔
2495
                    UnaryOp::Tan => format!("tan({s})"),
64✔
2496
                    UnaryOp::Atan => format!("atan({s})"),
76✔
2497
                    UnaryOp::Exp => format!("exp({s})"),
260✔
2498
                    UnaryOp::Log => format!("log({s})"),
×
2499
                    UnaryOp::Sign => format!("sign({s})"),
×
2500
                    UnaryOp::Conj => format!("conj({s})"),
1,536✔
2501
                }
2502
            }
2503
            SymbolExpr::Binary { op, lhs, rhs } => {
540,522✔
2504
                let s_lhs = lhs.repr(with_uuid);
540,522✔
2505
                let s_rhs = rhs.repr(with_uuid);
540,522✔
2506
                let op_lhs = match lhs.as_ref() {
540,522✔
2507
                    SymbolExpr::Binary { op: lop, .. } => {
151,920✔
2508
                        matches!(lop, BinaryOp::Add | BinaryOp::Sub)
151,920✔
2509
                    }
2510
                    SymbolExpr::Value(e) => match e {
167,266✔
2511
                        Value::Real(v) => *v < 0.0,
16,342✔
2512
                        Value::Int(v) => *v < 0,
64,722✔
2513
                        Value::Complex(_) => true,
86,202✔
2514
                    },
2515
                    _ => false,
221,336✔
2516
                };
2517
                let op_rhs = match rhs.as_ref() {
540,522✔
2518
                    SymbolExpr::Binary { op: rop, .. } => match rop {
24,320✔
2519
                        BinaryOp::Add | BinaryOp::Sub => true,
1,864✔
2520
                        _ => matches!(op, BinaryOp::Div),
22,456✔
2521
                    },
2522
                    SymbolExpr::Value(e) => match e {
120,818✔
2523
                        Value::Real(v) => *v < 0.0,
65,112✔
2524
                        Value::Int(v) => *v < 0,
37,514✔
2525
                        Value::Complex(_) => true,
18,192✔
2526
                    },
2527
                    _ => false,
395,384✔
2528
                };
2529

2530
                match op {
540,522✔
2531
                    BinaryOp::Add => match rhs.as_ref() {
55,558✔
2532
                        SymbolExpr::Unary {
2533
                            op: UnaryOp::Neg,
2534
                            expr: _,
2535
                        } => {
2536
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2537
                                format!("{s_lhs} {s_rhs}")
×
2538
                            } else {
2539
                                format!("{s_lhs} + {s_rhs}")
×
2540
                            }
2541
                        }
2542
                        _ => format!("{s_lhs} + {s_rhs}"),
55,558✔
2543
                    },
2544
                    BinaryOp::Sub => match rhs.as_ref() {
55,412✔
2545
                        SymbolExpr::Unary {
2546
                            op: UnaryOp::Neg,
2547
                            expr: _,
2548
                        } => {
2549
                            if s_rhs.as_str().char_indices().nth(0).unwrap().1 == '-' {
×
2550
                                let st = s_rhs.char_indices().nth(0).unwrap().0;
×
2551
                                let ed = s_rhs.char_indices().nth(1).unwrap().0;
×
2552
                                let s_rhs_new: &str = &s_rhs.as_str()[st..ed];
×
2553
                                format!("{s_lhs} + {s_rhs_new}")
×
2554
                            } else if op_rhs {
×
2555
                                format!("{s_lhs} -({s_rhs})")
×
2556
                            } else {
2557
                                format!("{s_lhs} - {s_rhs}")
×
2558
                            }
2559
                        }
2560
                        _ => {
2561
                            if op_rhs {
55,412✔
2562
                                format!("{s_lhs} -({s_rhs})")
610✔
2563
                            } else {
2564
                                format!("{s_lhs} - {s_rhs}")
54,802✔
2565
                            }
2566
                        }
2567
                    },
2568
                    BinaryOp::Mul => {
2569
                        if op_lhs {
358,364✔
2570
                            if op_rhs {
94,118✔
2571
                                format!("({s_lhs})*({s_rhs})")
274✔
2572
                            } else {
2573
                                format!("({s_lhs})*{s_rhs}")
93,844✔
2574
                            }
2575
                        } else if op_rhs {
264,246✔
2576
                            format!("{s_lhs}*({s_rhs})")
18,620✔
2577
                        } else {
2578
                            format!("{s_lhs}*{s_rhs}")
245,626✔
2579
                        }
2580
                    }
2581
                    BinaryOp::Div => {
2582
                        if op_lhs {
5,872✔
2583
                            if op_rhs {
604✔
2584
                                format!("({s_lhs})/({s_rhs})")
×
2585
                            } else {
2586
                                format!("({s_lhs})/{s_rhs}")
604✔
2587
                            }
2588
                        } else if op_rhs {
5,268✔
2589
                            format!("{s_lhs}/({s_rhs})")
1,196✔
2590
                        } else {
2591
                            format!("{s_lhs}/{s_rhs}")
4,072✔
2592
                        }
2593
                    }
2594
                    BinaryOp::Pow => match lhs.as_ref() {
65,316✔
2595
                        SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2596
                            match rhs.as_ref() {
4✔
2597
                                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2598
                                    format!("({s_lhs})**({s_rhs})")
×
2599
                                }
2600
                                SymbolExpr::Value(r) => {
×
2601
                                    if r.as_real() < 0.0 {
×
2602
                                        format!("({s_lhs})**({s_rhs})")
×
2603
                                    } else {
2604
                                        format!("({s_lhs})**{s_rhs}")
×
2605
                                    }
2606
                                }
2607
                                _ => format!("({s_lhs})**{s_rhs}"),
4✔
2608
                            }
2609
                        }
2610
                        SymbolExpr::Value(l) => {
4✔
2611
                            if l.as_real() < 0.0 {
4✔
2612
                                match rhs.as_ref() {
×
2613
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2614
                                        format!("({s_lhs})**({s_rhs})")
×
2615
                                    }
2616
                                    _ => format!("({s_lhs})**{s_rhs}"),
×
2617
                                }
2618
                            } else {
2619
                                match rhs.as_ref() {
4✔
2620
                                    SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2621
                                        format!("{s_lhs}**({s_rhs})")
×
2622
                                    }
2623
                                    _ => format!("{s_lhs}**{s_rhs}"),
4✔
2624
                                }
2625
                            }
2626
                        }
2627
                        _ => match rhs.as_ref() {
65,308✔
2628
                            SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. } => {
2629
                                format!("{s_lhs}**({s_rhs})")
×
2630
                            }
2631
                            SymbolExpr::Value(r) => {
65,308✔
2632
                                if r.as_real() < 0.0 {
65,308✔
2633
                                    format!("{s_lhs}**({s_rhs})")
×
2634
                                } else {
2635
                                    format!("{s_lhs}**{s_rhs}")
65,308✔
2636
                                }
2637
                            }
2638
                            _ => format!("{s_lhs}**{s_rhs}"),
×
2639
                        },
2640
                    },
2641
                }
2642
            }
2643
        }
2644
    }
3,033,964✔
2645
}
2646

2647
impl Add for SymbolExpr {
2648
    type Output = SymbolExpr;
2649
    fn add(self, rhs: Self) -> SymbolExpr {
90,518✔
2650
        match self.add_opt(&rhs, false) {
90,518✔
2651
            Some(e) => e,
85,092✔
2652
            None => _add(self, rhs),
5,426✔
2653
        }
2654
    }
90,518✔
2655
}
2656

2657
impl Add for &SymbolExpr {
2658
    type Output = SymbolExpr;
2659
    fn add(self, rhs: Self) -> SymbolExpr {
2,390,444✔
2660
        match self.add_opt(rhs, false) {
2,390,444✔
2661
            Some(e) => e,
2,311,590✔
2662
            None => _add(self.clone(), rhs.clone()),
78,854✔
2663
        }
2664
    }
2,390,444✔
2665
}
2666

2667
impl Sub for SymbolExpr {
2668
    type Output = SymbolExpr;
2669
    fn sub(self, rhs: Self) -> SymbolExpr {
68,402✔
2670
        match self.sub_opt(&rhs, false) {
68,402✔
2671
            Some(e) => e,
65,264✔
2672
            None => _sub(self, rhs),
3,138✔
2673
        }
2674
    }
68,402✔
2675
}
2676

2677
impl Sub for &SymbolExpr {
2678
    type Output = SymbolExpr;
2679
    fn sub(self, rhs: Self) -> SymbolExpr {
25,430✔
2680
        match self.sub_opt(rhs, false) {
25,430✔
2681
            Some(e) => e,
16,562✔
2682
            None => _sub(self.clone(), rhs.clone()),
8,868✔
2683
        }
2684
    }
25,430✔
2685
}
2686

2687
impl Mul for SymbolExpr {
2688
    type Output = SymbolExpr;
2689
    fn mul(self, rhs: Self) -> SymbolExpr {
185,108✔
2690
        match self.mul_opt(&rhs, false) {
185,108✔
2691
            Some(e) => e,
181,250✔
2692
            None => _mul(self, rhs),
3,858✔
2693
        }
2694
    }
185,108✔
2695
}
2696

2697
impl Mul for &SymbolExpr {
2698
    type Output = SymbolExpr;
2699
    fn mul(self, rhs: Self) -> SymbolExpr {
2,415,080✔
2700
        match self.mul_opt(rhs, false) {
2,415,080✔
2701
            Some(e) => e,
2,364,760✔
2702
            None => _mul(self.clone(), rhs.clone()),
50,320✔
2703
        }
2704
    }
2,415,080✔
2705
}
2706

2707
impl Div for SymbolExpr {
2708
    type Output = SymbolExpr;
2709
    fn div(self, rhs: Self) -> SymbolExpr {
88,718✔
2710
        match self.div_opt(&rhs, false) {
88,718✔
2711
            Some(e) => e,
79,304✔
2712
            None => _div(self, rhs),
9,414✔
2713
        }
2714
    }
88,718✔
2715
}
2716

2717
impl Div for &SymbolExpr {
2718
    type Output = SymbolExpr;
2719
    fn div(self, rhs: Self) -> SymbolExpr {
12,096✔
2720
        match self.div_opt(rhs, false) {
12,096✔
2721
            Some(e) => e,
2,864✔
2722
            None => _div(self.clone(), rhs.clone()),
9,232✔
2723
        }
2724
    }
12,096✔
2725
}
2726

2727
impl Neg for SymbolExpr {
2728
    type Output = SymbolExpr;
2729
    fn neg(self) -> SymbolExpr {
×
2730
        match self.neg_opt() {
×
2731
            Some(e) => e,
×
2732
            None => _neg(self),
×
2733
        }
2734
    }
×
2735
}
2736

2737
impl Neg for &SymbolExpr {
2738
    type Output = SymbolExpr;
2739
    fn neg(self) -> SymbolExpr {
780✔
2740
        match self.neg_opt() {
780✔
2741
            Some(e) => e,
114✔
2742
            None => _neg(self.clone()),
666✔
2743
        }
2744
    }
780✔
2745
}
2746

2747
impl PartialEq for SymbolExpr {
2748
    fn eq(&self, rexpr: &Self) -> bool {
336,692✔
2749
        if let (Some(l), Some(r)) = (self.eval(true), rexpr.eval(true)) {
336,692✔
2750
            return l == r;
110,670✔
2751
        }
226,022✔
2752

2753
        match (self, rexpr) {
226,022✔
2754
            (SymbolExpr::Symbol(l), SymbolExpr::Symbol(r)) => l == r,
191,744✔
2755
            (SymbolExpr::Value(l), SymbolExpr::Value(r)) => l == r,
×
2756
            (
2757
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2758
                SymbolExpr::Binary { .. } | SymbolExpr::Unary { .. },
2759
            ) => {
2760
                let ex_lhs = self.expand();
2,972✔
2761
                let ex_rhs = rexpr.expand();
2,972✔
2762
                match ex_lhs.sub_opt(&ex_rhs, true) {
2,972✔
2763
                    Some(e) => e.is_zero(),
2,626✔
2764
                    None => {
2765
                        let t = &ex_lhs - &ex_rhs;
346✔
2766
                        t.is_zero()
346✔
2767
                    }
2768
                }
2769
            }
2770
            (SymbolExpr::Binary { .. }, _) => {
2771
                let ex_lhs = self.expand();
7,320✔
2772
                match ex_lhs.sub_opt(rexpr, true) {
7,320✔
2773
                    Some(e) => e.is_zero(),
7,208✔
2774
                    None => {
2775
                        let t = &ex_lhs - rexpr;
112✔
2776
                        t.is_zero()
112✔
2777
                    }
2778
                }
2779
            }
2780
            (_, SymbolExpr::Binary { .. }) => {
2781
                let ex_rhs = rexpr.expand();
2,664✔
2782
                match self.sub_opt(&ex_rhs, true) {
2,664✔
2783
                    Some(e) => e.is_zero(),
558✔
2784
                    None => {
2785
                        let t = self - &ex_rhs;
2,106✔
2786
                        t.is_zero()
2,106✔
2787
                    }
2788
                }
2789
            }
2790
            (_, _) => false,
21,322✔
2791
        }
2792
    }
336,692✔
2793
}
2794

2795
impl PartialEq<f64> for SymbolExpr {
2796
    fn eq(&self, r: &f64) -> bool {
×
2797
        match self.eval(true) {
×
2798
            Some(v) => v == *r,
×
2799
            None => false,
×
2800
        }
2801
    }
×
2802
}
2803

2804
impl PartialEq<Complex64> for SymbolExpr {
2805
    fn eq(&self, r: &Complex64) -> bool {
×
2806
        match self.eval(true) {
×
2807
            Some(v) => v == *r,
×
2808
            None => false,
×
2809
        }
2810
    }
×
2811
}
2812

2813
// comparison rules for sorting equation
2814
impl PartialOrd for SymbolExpr {
2815
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
94,640✔
2816
        match self {
94,640✔
2817
            SymbolExpr::Value(l) => match rhs {
300✔
2818
                SymbolExpr::Value(r) => l.partial_cmp(r),
12✔
2819
                _ => Some(Ordering::Less),
288✔
2820
            },
2821
            SymbolExpr::Symbol(l) => match rhs {
6,168✔
2822
                SymbolExpr::Value(_) => Some(Ordering::Greater),
×
2823
                SymbolExpr::Symbol(r) => l.partial_cmp(r),
4,084✔
2824
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
×
2825
                _ => Some(Ordering::Less),
2,084✔
2826
            },
2827
            SymbolExpr::Unary { op: _, expr } => match rhs {
13,770✔
2828
                SymbolExpr::Value(_) => Some(Ordering::Greater),
2✔
2829
                SymbolExpr::Unary { op: _, expr: rexpr } => expr.partial_cmp(rexpr),
1,368✔
2830
                _ => (expr.as_ref()).partial_cmp(rhs),
12,400✔
2831
            },
2832
            SymbolExpr::Binary {
2833
                op,
74,402✔
2834
                lhs: ll,
74,402✔
2835
                rhs: lr,
74,402✔
2836
            } => match rhs {
74,402✔
2837
                SymbolExpr::Value(_) | SymbolExpr::Symbol(_) => match op {
9,918✔
2838
                    BinaryOp::Mul | BinaryOp::Div | BinaryOp::Pow => Some(Ordering::Greater),
9,910✔
2839
                    _ => Some(Ordering::Equal),
8✔
2840
                },
2841
                SymbolExpr::Unary { op: _, expr } => self.partial_cmp(expr),
108✔
2842
                SymbolExpr::Binary {
2843
                    op: _,
2844
                    lhs: rl,
64,376✔
2845
                    rhs: rr,
64,376✔
2846
                } => {
2847
                    let ls = match ll.as_ref() {
64,376✔
2848
                        SymbolExpr::Value(_) => lr.string_id(),
10,752✔
2849
                        _ => self.string_id(),
53,624✔
2850
                    };
2851
                    let rs = match rl.as_ref() {
64,376✔
2852
                        SymbolExpr::Value(_) => rr.string_id(),
13,426✔
2853
                        _ => rhs.string_id(),
50,950✔
2854
                    };
2855
                    if rs > ls && rs.len() > ls.len() {
64,376✔
2856
                        Some(Ordering::Less)
5,802✔
2857
                    } else if rs < ls && rs.len() < ls.len() {
58,574✔
2858
                        Some(Ordering::Greater)
460✔
2859
                    } else {
2860
                        Some(Ordering::Equal)
58,114✔
2861
                    }
2862
                }
2863
            },
2864
        }
2865
    }
94,640✔
2866
}
2867

2868
impl From<&str> for SymbolExpr {
2869
    fn from(v: &str) -> Self {
×
2870
        SymbolExpr::Symbol(Symbol::new(v, None, None))
×
2871
    }
×
2872
}
2873

2874
impl fmt::Display for Value {
2875
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288,552✔
2876
        write!(
288,552✔
2877
            f,
288,552✔
2878
            "{}",
288,552✔
2879
            match self {
288,552✔
2880
                Value::Real(e) => e.to_string(),
81,844✔
2881
                Value::Int(e) => e.to_string(),
102,302✔
2882
                Value::Complex(e) => {
104,406✔
2883
                    if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.re) {
104,406✔
2884
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
103,750✔
2885
                            0.to_string()
×
2886
                        } else {
2887
                            format!("{}i", e.im)
103,750✔
2888
                        }
2889
                    } else if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&e.im) {
656✔
2890
                        e.re.to_string()
×
2891
                    } else {
2892
                        e.to_string()
656✔
2893
                    }
2894
                }
2895
            }
2896
        )
2897
    }
288,552✔
2898
}
2899

2900
// ===============================================================
2901
//  implementations for Value
2902
// ===============================================================
2903
impl Value {
2904
    pub fn as_real(&self) -> f64 {
65,312✔
2905
        match self {
65,312✔
2906
            Value::Real(e) => *e,
65,116✔
2907
            Value::Int(e) => *e as f64,
196✔
2908
            Value::Complex(e) => e.re,
×
2909
        }
2910
    }
65,312✔
2911

2912
    pub fn abs(&self) -> Value {
468✔
2913
        match self {
468✔
2914
            Value::Real(e) => Value::Real(e.abs()),
218✔
2915
            Value::Int(e) => Value::Int(e.abs()),
134✔
2916
            Value::Complex(e) => Value::Real((e.re * e.re + e.im * e.im).sqrt()),
116✔
2917
        }
2918
    }
468✔
2919

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

3149
    pub fn is_zero(&self) -> bool {
5,592,186✔
3150
        match self {
5,592,186✔
3151
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(r),
4,697,214✔
3152
            Value::Int(i) => *i == 0,
593,616✔
3153
            Value::Complex(c) => {
301,356✔
3154
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.re)
301,356✔
3155
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
223,850✔
3156
            }
3157
        }
3158
    }
5,592,186✔
3159
    pub fn is_one(&self) -> bool {
521,976✔
3160
        match self {
521,976✔
3161
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r - 1.0)),
88,674✔
3162
            Value::Int(i) => *i == 1,
293,032✔
3163
            Value::Complex(c) => {
140,270✔
3164
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re - 1.0))
140,270✔
3165
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,940✔
3166
            }
3167
        }
3168
    }
521,976✔
3169
    pub fn is_minus_one(&self) -> bool {
272,162✔
3170
        match self {
272,162✔
3171
            Value::Real(r) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*r + 1.0)),
42,638✔
3172
            Value::Int(i) => *i == -1,
142,410✔
3173
            Value::Complex(c) => {
87,114✔
3174
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(c.re + 1.0))
87,114✔
3175
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im)
4,306✔
3176
            }
3177
        }
3178
    }
272,162✔
3179

3180
    pub fn is_negative(&self) -> bool {
71,866✔
3181
        match self {
71,866✔
3182
            Value::Real(r) => *r < 0.0,
12,704✔
3183
            Value::Int(i) => *i < 0,
9,956✔
3184
            Value::Complex(c) => {
49,206✔
3185
                (c.re < 0.0 && c.im < SYMEXPR_EPSILON && c.im > -SYMEXPR_EPSILON)
49,206✔
3186
                    || (c.im < 0.0 && c.re < SYMEXPR_EPSILON && c.re > -SYMEXPR_EPSILON)
49,206✔
3187
            }
3188
        }
3189
    }
71,866✔
3190

3191
    fn mul_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
37,092✔
3192
        match rhs {
4,638✔
3193
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self * r)),
13,538✔
3194
            SymbolExpr::Unary {
3195
                op: UnaryOp::Neg,
3196
                expr,
4,122✔
3197
            } => {
3198
                let l = SymbolExpr::Value(-self);
4,122✔
3199
                match l.mul_opt(expr, recursive) {
4,122✔
3200
                    Some(e) => Some(e),
2✔
3201
                    None => Some(_mul(l, expr.as_ref().clone())),
4,120✔
3202
                }
3203
            }
3204
            SymbolExpr::Binary { op, lhs: l, rhs: r } => {
8,792✔
3205
                if recursive {
8,792✔
3206
                    match op {
970✔
3207
                        BinaryOp::Mul => match self.mul_opt(l, recursive) {
970✔
3208
                            Some(e) => match e.mul_opt(r, recursive) {
32✔
3209
                                Some(ee) => Some(ee),
8✔
3210
                                None => Some(_mul(e, r.as_ref().clone())),
24✔
3211
                            },
3212
                            None => self
938✔
3213
                                .mul_opt(r, recursive)
938✔
3214
                                .map(|e| _mul(e, l.as_ref().clone())),
938✔
3215
                        },
3216
                        BinaryOp::Div => match self.mul_opt(l, recursive) {
×
3217
                            Some(e) => Some(_div(e, r.as_ref().clone())),
×
3218
                            None => self
×
3219
                                .div_opt(r, recursive)
×
3220
                                .map(|e| _mul(e, l.as_ref().clone())),
×
3221
                        },
3222
                        _ => None,
×
3223
                    }
3224
                } else {
3225
                    match l.as_ref() {
7,822✔
3226
                        SymbolExpr::Value(v) => match op {
1,316✔
3227
                            BinaryOp::Mul => {
3228
                                Some(_mul(SymbolExpr::Value(self * v), r.as_ref().clone()))
496✔
3229
                            }
3230
                            BinaryOp::Div => {
3231
                                Some(_div(SymbolExpr::Value(self * v), r.as_ref().clone()))
×
3232
                            }
3233
                            _ => None,
820✔
3234
                        },
3235
                        _ => match r.as_ref() {
6,506✔
3236
                            SymbolExpr::Value(v) => match op {
700✔
3237
                                BinaryOp::Mul => {
3238
                                    Some(_mul(SymbolExpr::Value(self * v), l.as_ref().clone()))
20✔
3239
                                }
3240
                                BinaryOp::Div => {
3241
                                    Some(_mul(SymbolExpr::Value(self / v), l.as_ref().clone()))
8✔
3242
                                }
3243
                                _ => None,
672✔
3244
                            },
3245
                            _ => None,
5,806✔
3246
                        },
3247
                    }
3248
                }
3249
            }
3250
            _ => None,
10,640✔
3251
        }
3252
    }
37,092✔
3253

3254
    fn div_opt(&self, rhs: &SymbolExpr, recursive: bool) -> Option<SymbolExpr> {
76,738✔
3255
        match rhs {
40✔
3256
            SymbolExpr::Value(r) => Some(SymbolExpr::Value(self / r)),
72,002✔
3257
            SymbolExpr::Unary {
3258
                op: UnaryOp::Neg,
3259
                expr,
×
3260
            } => {
3261
                if recursive {
×
3262
                    self.div_opt(expr, recursive).map(_neg)
×
3263
                } else {
3264
                    None
×
3265
                }
3266
            }
3267
            SymbolExpr::Binary { op, lhs: l, rhs: r } => match l.as_ref() {
2,360✔
3268
                SymbolExpr::Value(v) => match op {
980✔
3269
                    BinaryOp::Mul => Some(_div(SymbolExpr::Value(self / v), r.as_ref().clone())),
384✔
3270
                    BinaryOp::Div => Some(_mul(SymbolExpr::Value(self / v), r.as_ref().clone())),
×
3271
                    _ => None,
596✔
3272
                },
3273
                _ => match r.as_ref() {
1,380✔
3274
                    SymbolExpr::Value(v) => match op {
1,180✔
3275
                        BinaryOp::Mul => {
3276
                            Some(_div(SymbolExpr::Value(self / v), l.as_ref().clone()))
×
3277
                        }
3278
                        BinaryOp::Div => {
3279
                            Some(_div(SymbolExpr::Value(self * v), l.as_ref().clone()))
×
3280
                        }
3281
                        _ => None,
1,180✔
3282
                    },
3283
                    _ => None,
200✔
3284
                },
3285
            },
3286
            _ => None,
2,376✔
3287
        }
3288
    }
76,738✔
3289

3290
    pub fn opt_complex(&self) -> Option<Value> {
255,652✔
3291
        match self {
255,652✔
3292
            Value::Complex(c) => {
120,282✔
3293
                if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&c.im) {
120,282✔
3294
                    Some(Value::Real(c.re))
26,942✔
3295
                } else {
3296
                    None
93,340✔
3297
                }
3298
            }
3299
            _ => None,
135,370✔
3300
        }
3301
    }
255,652✔
3302

3303
    // convert sympy compatible format
3304
    pub fn sympify(&self) -> SymbolExpr {
×
3305
        match self {
×
3306
            // imaginary number is comverted to value * symbol 'I'
3307
            Value::Complex(c) => _add(
×
3308
                SymbolExpr::Value(Value::Real(c.re)),
×
3309
                _mul(
×
3310
                    SymbolExpr::Value(Value::Real(c.im)),
×
3311
                    SymbolExpr::Symbol(Symbol::new("I", None, None)),
×
3312
                ),
3313
            ),
3314
            _ => SymbolExpr::Value(*self),
×
3315
        }
3316
    }
×
3317
}
3318

3319
impl From<f64> for Value {
3320
    fn from(v: f64) -> Self {
×
3321
        Value::Real(v)
×
3322
    }
×
3323
}
3324

3325
impl From<i64> for Value {
3326
    fn from(v: i64) -> Self {
72,848✔
3327
        Value::Int(v)
72,848✔
3328
    }
72,848✔
3329
}
3330

3331
impl From<Complex64> for Value {
3332
    fn from(v: Complex64) -> Self {
4,772,550✔
3333
        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&v.im) {
4,772,550✔
3334
            Value::Real(v.re)
4,713,394✔
3335
        } else {
3336
            Value::Complex(v)
59,156✔
3337
        }
3338
    }
4,772,550✔
3339
}
3340

3341
impl Add for &Value {
3342
    type Output = Value;
3343
    fn add(self, rhs: Self) -> Value {
72,538✔
3344
        *self + *rhs
72,538✔
3345
    }
72,538✔
3346
}
3347

3348
impl Add for Value {
3349
    type Output = Value;
3350
    fn add(self, rhs: Self) -> Value {
75,138✔
3351
        let t = match self {
75,138✔
3352
            Value::Real(l) => match rhs {
18,182✔
3353
                Value::Real(r) => Value::Real(l + r),
13,254✔
3354
                Value::Int(r) => Value::Real(l + r as f64),
2,386✔
3355
                Value::Complex(r) => Value::Complex(l + r),
2,542✔
3356
            },
3357
            Value::Int(l) => match rhs {
24,302✔
3358
                Value::Real(r) => Value::Real(l as f64 + r),
2,180✔
3359
                Value::Int(r) => Value::Int(l + r),
13,038✔
3360
                Value::Complex(r) => Value::Complex(l as f64 + r),
9,084✔
3361
            },
3362
            Value::Complex(l) => match rhs {
32,654✔
3363
                Value::Real(r) => Value::Complex(l + r),
1,054✔
3364
                Value::Int(r) => Value::Complex(l + r as f64),
12,186✔
3365
                Value::Complex(r) => Value::Complex(l + r),
19,414✔
3366
            },
3367
        };
3368
        match t.opt_complex() {
75,138✔
3369
            Some(v) => v,
5,226✔
3370
            None => t,
69,912✔
3371
        }
3372
    }
75,138✔
3373
}
3374

3375
impl Sub for &Value {
3376
    type Output = Value;
3377
    fn sub(self, rhs: Self) -> Value {
64,892✔
3378
        *self - *rhs
64,892✔
3379
    }
64,892✔
3380
}
3381

3382
impl Sub for Value {
3383
    type Output = Value;
3384
    fn sub(self, rhs: Self) -> Value {
65,768✔
3385
        let t = match self {
65,768✔
3386
            Value::Real(l) => match rhs {
13,356✔
3387
                Value::Real(r) => Value::Real(l - r),
6,672✔
3388
                Value::Int(r) => Value::Real(l - r as f64),
4,782✔
3389
                Value::Complex(r) => Value::Complex(l - r),
1,902✔
3390
            },
3391
            Value::Int(l) => match rhs {
21,094✔
3392
                Value::Real(r) => Value::Real(l as f64 - r),
362✔
3393
                Value::Int(r) => Value::Int(l - r),
13,554✔
3394
                Value::Complex(r) => Value::Complex(l as f64 - r),
7,178✔
3395
            },
3396
            Value::Complex(l) => match rhs {
31,318✔
3397
                Value::Real(r) => Value::Complex(l - r),
468✔
3398
                Value::Int(r) => Value::Complex(l - r as f64),
12,188✔
3399
                Value::Complex(r) => Value::Complex(l - r),
18,662✔
3400
            },
3401
        };
3402
        match t.opt_complex() {
65,768✔
3403
            Some(v) => v,
6,470✔
3404
            None => t,
59,298✔
3405
        }
3406
    }
65,768✔
3407
}
3408

3409
impl Mul for &Value {
3410
    type Output = Value;
3411
    fn mul(self, rhs: Self) -> Value {
27,866✔
3412
        *self * *rhs
27,866✔
3413
    }
27,866✔
3414
}
3415

3416
impl Mul for Value {
3417
    type Output = Value;
3418
    fn mul(self, rhs: Self) -> Value {
29,426✔
3419
        let t = match self {
29,426✔
3420
            Value::Real(l) => match rhs {
4,472✔
3421
                Value::Real(r) => Value::Real(l * r),
3,358✔
3422
                Value::Int(r) => Value::Real(l * r as f64),
584✔
3423
                Value::Complex(r) => Value::Complex(l * r),
530✔
3424
            },
3425
            Value::Int(l) => match rhs {
5,294✔
3426
                Value::Real(r) => Value::Real(l as f64 * r),
480✔
3427
                Value::Int(r) => Value::Int(l * r),
3,820✔
3428
                Value::Complex(r) => Value::Complex(l as f64 * r),
994✔
3429
            },
3430
            Value::Complex(l) => match rhs {
19,660✔
3431
                Value::Real(r) => Value::Complex(l * r),
550✔
3432
                Value::Int(r) => Value::Complex(l * r as f64),
1,440✔
3433
                Value::Complex(r) => Value::Complex(l * r),
17,670✔
3434
            },
3435
        };
3436
        match t.opt_complex() {
29,426✔
3437
            Some(v) => v,
12,466✔
3438
            None => t,
16,960✔
3439
        }
3440
    }
29,426✔
3441
}
3442

3443
impl Div for &Value {
3444
    type Output = Value;
3445
    fn div(self, rhs: Self) -> Value {
72,742✔
3446
        *self / *rhs
72,742✔
3447
    }
72,742✔
3448
}
3449

3450
impl Div for Value {
3451
    type Output = Value;
3452
    fn div(self, rhs: Self) -> Value {
73,854✔
3453
        let t = match self {
73,854✔
3454
            Value::Real(l) => match rhs {
71,064✔
3455
                Value::Real(r) => Value::Real(l / r),
212✔
3456
                Value::Int(r) => Value::Real(l / r as f64),
69,990✔
3457
                Value::Complex(r) => Value::Complex(l / r),
862✔
3458
            },
3459
            Value::Int(l) => {
1,484✔
3460
                if rhs == 0.0 {
1,484✔
3461
                    return Value::Real(f64::INFINITY);
×
3462
                }
1,484✔
3463
                match rhs {
1,484✔
3464
                    Value::Real(r) => Value::Real(l as f64 / r),
48✔
3465
                    Value::Int(r) => {
650✔
3466
                        let t = l as f64 / r as f64;
650✔
3467
                        let d = t.floor() - t;
650✔
3468
                        if (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&d) {
650✔
3469
                            Value::Int(t as i64)
586✔
3470
                        } else {
3471
                            Value::Real(t)
64✔
3472
                        }
3473
                    }
3474
                    Value::Complex(r) => Value::Complex(l as f64 / r),
786✔
3475
                }
3476
            }
3477
            Value::Complex(l) => match rhs {
1,306✔
3478
                Value::Real(r) => Value::Complex(l / r),
48✔
3479
                Value::Int(r) => Value::Complex(l / r as f64),
552✔
3480
                Value::Complex(r) => Value::Complex(l / r),
706✔
3481
            },
3482
        };
3483
        match t.opt_complex() {
73,854✔
3484
            Some(v) => v,
688✔
3485
            None => t,
73,166✔
3486
        }
3487
    }
73,854✔
3488
}
3489

3490
impl Neg for &Value {
3491
    type Output = Value;
3492
    fn neg(self) -> Value {
129,668✔
3493
        -*self
129,668✔
3494
    }
129,668✔
3495
}
3496

3497
impl Neg for Value {
3498
    type Output = Value;
3499
    fn neg(self) -> Value {
193,278✔
3500
        match self {
193,278✔
3501
            Value::Real(v) => Value::Real(-v),
91,668✔
3502
            Value::Int(v) => Value::Int(-v),
38,540✔
3503
            Value::Complex(v) => Value::Complex(-v),
63,070✔
3504
        }
3505
    }
193,278✔
3506
}
3507

3508
impl PartialEq for Value {
3509
    fn eq(&self, r: &Self) -> bool {
113,064✔
3510
        match self {
113,064✔
3511
            Value::Real(e) => match r {
108,208✔
3512
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - rv)),
3,338✔
3513
                Value::Int(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - *rv as f64)),
104,008✔
3514
                Value::Complex(rv) => {
862✔
3515
                    let t = Complex64::from(*e) - rv;
862✔
3516
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
862✔
3517
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
132✔
3518
                }
3519
            },
3520
            Value::Int(e) => match r {
2,648✔
3521
                Value::Int(rv) => e == rv,
1,678✔
3522
                Value::Real(rv) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - rv)),
268✔
3523
                Value::Complex(rv) => {
702✔
3524
                    let t = Complex64::from(*e as f64) - rv;
702✔
3525
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
702✔
3526
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
50✔
3527
                }
3528
            },
3529
            Value::Complex(e) => match r {
2,208✔
3530
                Value::Real(rv) => {
254✔
3531
                    let t = *e - Complex64::from(rv);
254✔
3532
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
254✔
3533
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3534
                }
3535
                Value::Int(rv) => {
456✔
3536
                    let t = *e - Complex64::from(*rv as f64);
456✔
3537
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
456✔
3538
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3539
                }
3540
                Value::Complex(rv) => {
1,498✔
3541
                    let t = *e - rv;
1,498✔
3542
                    (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
1,498✔
3543
                        && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
926✔
3544
                }
3545
            },
3546
        }
3547
    }
113,064✔
3548
}
3549

3550
impl PartialEq<f64> for Value {
3551
    fn eq(&self, r: &f64) -> bool {
1,484✔
3552
        match self {
1,484✔
3553
            Value::Real(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(e - r)),
48✔
3554
            Value::Int(e) => (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&(*e as f64 - r)),
650✔
3555
            Value::Complex(e) => {
786✔
3556
                let t = *e - Complex64::from(r);
786✔
3557
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
786✔
3558
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
206✔
3559
            }
3560
        }
3561
    }
1,484✔
3562
}
3563

3564
impl PartialEq<Complex64> for Value {
3565
    fn eq(&self, r: &Complex64) -> bool {
×
3566
        match self {
×
3567
            Value::Real(e) => {
×
3568
                let t = Complex64::from(*e) - r;
×
3569
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3570
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3571
            }
3572
            Value::Int(e) => {
×
3573
                let t = Complex64::from(*e as f64) - r;
×
3574
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3575
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3576
            }
3577
            Value::Complex(e) => {
×
3578
                let t = *e - r;
×
3579
                (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.re)
×
3580
                    && (-SYMEXPR_EPSILON..SYMEXPR_EPSILON).contains(&t.im)
×
3581
            }
3582
        }
3583
    }
×
3584
}
3585

3586
impl PartialOrd for Value {
3587
    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
12✔
3588
        match self {
12✔
3589
            Value::Real(l) => match rhs {
4✔
3590
                Value::Real(r) => l.partial_cmp(r),
4✔
3591
                Value::Int(r) => l.partial_cmp(&(*r as f64)),
×
3592
                Value::Complex(_) => None,
×
3593
            },
3594
            Value::Int(l) => match rhs {
4✔
3595
                Value::Real(r) => (*l as f64).partial_cmp(r),
×
3596
                Value::Int(r) => l.partial_cmp(r),
4✔
3597
                Value::Complex(_) => None,
×
3598
            },
3599
            Value::Complex(_) => None,
4✔
3600
        }
3601
    }
12✔
3602
}
3603

3604
/// Replace [Symbol]s in a [SymbolExpr] according to the name map. This
3605
/// is used to reconstruct a parameter expression from a string.
3606
pub fn replace_symbol(symbol_expr: &SymbolExpr, name_map: &HashMap<String, Symbol>) -> SymbolExpr {
116✔
3607
    match symbol_expr {
116✔
3608
        SymbolExpr::Symbol(existing_symbol) => {
36✔
3609
            let name = existing_symbol.name();
36✔
3610
            if let Some(new_symbol) = name_map.get(&name) {
36✔
3611
                SymbolExpr::Symbol(new_symbol.clone())
36✔
3612
            } else {
3613
                symbol_expr.clone()
×
3614
            }
3615
        }
3616
        SymbolExpr::Value(_) => symbol_expr.clone(), // nothing to do
56✔
3617
        SymbolExpr::Binary { op, lhs, rhs } => SymbolExpr::Binary {
22✔
3618
            op: op.clone(),
22✔
3619
            lhs: Arc::new(replace_symbol(lhs, name_map)),
22✔
3620
            rhs: Arc::new(replace_symbol(rhs, name_map)),
22✔
3621
        },
22✔
3622
        SymbolExpr::Unary { op, expr } => SymbolExpr::Unary {
2✔
3623
            op: op.clone(),
2✔
3624
            expr: Arc::new(replace_symbol(expr, name_map)),
2✔
3625
        },
2✔
3626
    }
3627
}
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