Pattern Matching
Topic:
core.pattern-matching
Pattern matching is a powerful technique in MathHook for identifying, transforming, and simplifying mathematical expressions. MathHook combines Rust's native pattern matching with specialized mathematical pattern recognition to enable sophisticated symbolic manipulation including algebraic identities, calculus rules, and trigonometric transformations.
Mathematical Definition
Common Mathematical Patterns:
- Difference of Squares:
- Perfect Square:
- Power Rule:
- Chain Rule:
- Pythagorean Identity:
Examples
Rust Native Pattern Matching on Expressions
Using Rust's match statement to analyze expression structure
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; fn analyze_expression(expr: &Expression) -> String { match expr { Expression::Integer(n) => format!("Integer: {}", n), Expression::Symbol(s) => format!("Variable: {}", s.name()), Expression::Add(terms) => format!("Sum of {} terms", terms.len()), Expression::Mul(factors) => format!("Product of {} factors", factors.len()), Expression::Pow(base, exp) => format!("Power: ({})^({})", base, exp), Expression::Function { name, args } => { format!("Function {}: {} args", name, args.len()) } _ => "Other expression type".to_string(), } } let expr = expr!(x^2 + 2*x + 1); println!("{}", analyze_expression(&expr)); }
Python
from mathhook import Expression, expr
def analyze_expression(e):
if e.is_integer():
return f"Integer: {e.value()}"
elif e.is_symbol():
return f"Variable: {e.name()}"
elif e.is_add():
return f"Sum of {len(e.terms())} terms"
elif e.is_mul():
return f"Product of {len(e.factors())} factors"
elif e.is_pow():
return f"Power: ({e.base()})^({e.exponent()})"
elif e.is_function():
return f"Function {e.name()}: {len(e.args())} args"
else:
return "Other expression type"
expr_val = expr('x^2 + 2*x + 1')
print(analyze_expression(expr_val))
JavaScript
const { Expression, expr } = require('mathhook-node');
function analyzeExpression(e) {
if (e.isInteger()) {
return `Integer: ${e.value()}`;
} else if (e.isSymbol()) {
return `Variable: ${e.name()}`;
} else if (e.isAdd()) {
return `Sum of ${e.terms().length} terms`;
} else if (e.isMul()) {
return `Product of ${e.factors().length} factors`;
} else if (e.isPow()) {
return `Power: (${e.base()})^(${e.exponent()})`;
} else if (e.isFunction()) {
return `Function ${e.name()}: ${e.args().length} args`;
}
return 'Other expression type';
}
const exprVal = expr('x^2 + 2*x + 1');
console.log(analyzeExpression(exprVal));
Algebraic Pattern: Difference of Squares
Recognizing and factoring difference of squares pattern
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let a = symbol!(a); let b = symbol!(b); // Pattern: a² - b² = (a + b)(a - b) let diff_squares = expr!(a^2 - b^2); let factored = diff_squares.factor(); assert_eq!(factored, expr!((a + b) * (a - b))); // Recognizes in complex forms let x = symbol!(x); let example = expr!(x^4 - 16); let factored_example = example.factor(); // (x² + 4)(x² - 4) assert_eq!(factored_example, expr!((x^2 + 4) * (x^2 - 4))); }
Python
from mathhook import symbol, expr
a = symbol('a')
b = symbol('b')
# Pattern: a² - b² = (a + b)(a - b)
diff_squares = expr('a^2 - b^2')
factored = diff_squares.factor()
assert factored == expr('(a + b) * (a - b)')
# Complex forms
x = symbol('x')
example = expr('x^4 - 16')
factored_example = example.factor()
assert factored_example == expr('(x^2 + 4) * (x^2 - 4)')
JavaScript
const { symbol, expr } = require('mathhook-node');
const a = symbol('a');
const b = symbol('b');
// Pattern: a² - b² = (a + b)(a - b)
const diffSquares = expr('a^2 - b^2');
const factored = diffSquares.factor();
console.assert(factored.equals(expr('(a + b) * (a - b)')));
// Complex forms
const x = symbol('x');
const example = expr('x^4 - 16');
const factoredExample = example.factor();
console.assert(factoredExample.equals(expr('(x^2 + 4) * (x^2 - 4)')));
Calculus Pattern: Power Rule Derivative
Automatic pattern recognition for power rule differentiation
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let x = symbol!(x); // Pattern: d/dx(x^n) = n*x^(n-1) let f = expr!(x^5); let df = f.derivative(&x, 1); assert_eq!(df, expr!(5 * x^4)); // Works for any power let sqrt_x = expr!(x^(1/2)); let d_sqrt = sqrt_x.derivative(&x, 1); assert_eq!(d_sqrt, expr!((1/2) * x^(-1/2))); }
Python
from mathhook import symbol, expr
x = symbol('x')
# Pattern: d/dx(x^n) = n*x^(n-1)
f = expr('x^5')
df = f.derivative(x)
assert df == expr('5 * x^4')
# Works for any power
sqrt_x = expr('x^(1/2)')
d_sqrt = sqrt_x.derivative(x)
assert d_sqrt == expr('(1/2) * x^(-1/2)')
JavaScript
const { symbol, expr } = require('mathhook-node');
const x = symbol('x');
// Pattern: d/dx(x^n) = n*x^(n-1)
const f = expr('x^5');
const df = f.derivative(x);
console.assert(df.equals(expr('5 * x^4')));
// Works for any power
const sqrtX = expr('x^(1/2)');
const dSqrt = sqrtX.derivative(x);
console.assert(dSqrt.equals(expr('(1/2) * x^(-1/2)')));
Calculus Pattern: Chain Rule
Automatic chain rule application for composite functions
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let x = symbol!(x); // Pattern: d/dx f(g(x)) = f'(g(x)) * g'(x) let f = expr!(sin(x^2)); // sin(u) where u = x² // Derivative: cos(u) * du/dx = cos(x²) * 2x let df = f.derivative(&x, 1); assert_eq!(df, expr!(2*x*cos(x^2))); // Nested composition let nested = expr!(sin(cos(x))); let d_nested = nested.derivative(&x, 1); // cos(cos(x)) * (-sin(x)) assert_eq!(d_nested, expr!(-sin(x)*cos(cos(x)))); }
Python
from mathhook import symbol, expr
x = symbol('x')
# Pattern: chain rule
f = expr('sin(x^2)')
df = f.derivative(x)
assert df == expr('2*x*cos(x^2)')
# Nested composition
nested = expr('sin(cos(x))')
d_nested = nested.derivative(x)
assert d_nested == expr('-sin(x)*cos(cos(x))')
JavaScript
const { symbol, expr } = require('mathhook-node');
const x = symbol('x');
// Chain rule
const f = expr('sin(x^2)');
const df = f.derivative(x);
console.assert(df.equals(expr('2*x*cos(x^2)')));
// Nested composition
const nested = expr('sin(cos(x))');
const dNested = nested.derivative(x);
console.assert(dNested.equals(expr('-sin(x)*cos(cos(x))')));
Trigonometric Pattern: Pythagorean Identity
Automatic simplification using trigonometric identities
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let x = symbol!(x); // Pattern: sin²(x) + cos²(x) = 1 let identity = expr!(sin(x)^2 + cos(x)^2); assert_eq!(identity.simplify(), expr!(1)); // Pattern: 1 + tan²(x) = sec²(x) let tan_identity = expr!(1 + tan(x)^2); assert_eq!(tan_identity.simplify(), expr!(sec(x)^2)); // Pattern: 1 + cot²(x) = csc²(x) let cot_identity = expr!(1 + cot(x)^2); assert_eq!(cot_identity.simplify(), expr!(csc(x)^2)); }
Python
from mathhook import symbol, expr
x = symbol('x')
# Pythagorean identities
identity = expr('sin(x)^2 + cos(x)^2')
assert identity.simplify() == 1
tan_identity = expr('1 + tan(x)^2')
assert tan_identity.simplify() == expr('sec(x)^2')
cot_identity = expr('1 + cot(x)^2')
assert cot_identity.simplify() == expr('csc(x)^2')
JavaScript
const { symbol, expr } = require('mathhook-node');
const x = symbol('x');
// Pythagorean identities
const identity = expr('sin(x)^2 + cos(x)^2');
console.assert(identity.simplify().equals(1));
const tanIdentity = expr('1 + tan(x)^2');
console.assert(tanIdentity.simplify().equals(expr('sec(x)^2')));
const cotIdentity = expr('1 + cot(x)^2');
console.assert(cotIdentity.simplify().equals(expr('csc(x)^2')));
Logarithm Pattern: Log Laws
Automatic application of logarithm expansion and combination rules
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; let a = symbol!(a); let b = symbol!(b); let n = symbol!(n); // Pattern: ln(a*b) = ln(a) + ln(b) let log_product = expr!(ln(a*b)); assert_eq!(log_product.expand(), expr!(ln(a) + ln(b))); // Pattern: ln(a/b) = ln(a) - ln(b) let log_quotient = expr!(ln(a/b)); assert_eq!(log_quotient.expand(), expr!(ln(a) - ln(b))); // Pattern: ln(a^n) = n*ln(a) let log_power = expr!(ln(a^n)); assert_eq!(log_power.expand(), expr!(n*ln(a))); }
Python
from mathhook import symbol, expr
a = symbol('a')
b = symbol('b')
n = symbol('n')
# Log laws
log_product = expr('ln(a*b)')
assert log_product.expand() == expr('ln(a) + ln(b)')
log_quotient = expr('ln(a/b)')
assert log_quotient.expand() == expr('ln(a) - ln(b)')
log_power = expr('ln(a^n)')
assert log_power.expand() == expr('n*ln(a)')
JavaScript
const { symbol, expr } = require('mathhook-node');
const a = symbol('a');
const b = symbol('b');
const n = symbol('n');
// Log laws
const logProduct = expr('ln(a*b)');
console.assert(logProduct.expand().equals(expr('ln(a) + ln(b)')));
const logQuotient = expr('ln(a/b)');
console.assert(logQuotient.expand().equals(expr('ln(a) - ln(b)')));
const logPower = expr('ln(a^n)');
console.assert(logPower.expand().equals(expr('n*ln(a)')));
Custom Pattern Matcher: Polynomial Detection
Implementing custom pattern recognition for polynomial expressions
Rust
#![allow(unused)] fn main() { use mathhook::prelude::*; /// Pattern matcher for polynomial expressions fn is_polynomial(expr: &Expression, var: &Symbol) -> bool { match expr { // Constant term Expression::Integer(_) | Expression::Rational(_) => true, // Variable itself Expression::Symbol(s) if s == var => true, // Power of variable Expression::Pow(base, exp) => { matches!(**base, Expression::Symbol(ref s) if s == var) && matches!(**exp, Expression::Integer(n) if n >= 0) } // Sum or product of polynomials Expression::Add(terms) | Expression::Mul(factors) => { terms.iter().all(|t| is_polynomial(t, var)) || factors.iter().all(|f| is_polynomial(f, var)) } _ => false, } } let x = symbol!(x); assert!(is_polynomial(&expr!(x^2 + 3*x + 1), &x)); assert!(!is_polynomial(&expr!(sin(x)), &x)); }
Python
from mathhook import Expression, symbol, expr
def is_polynomial(e, var):
if e.is_integer() or e.is_rational():
return True
elif e.is_symbol():
return e == var
elif e.is_pow():
base = e.base()
exp = e.exponent()
return (base.is_symbol() and base == var and
exp.is_integer() and exp.value() >= 0)
elif e.is_add() or e.is_mul():
terms = e.terms() if e.is_add() else e.factors()
return all(is_polynomial(t, var) for t in terms)
return False
x = symbol('x')
assert is_polynomial(expr('x^2 + 3*x + 1'), x)
assert not is_polynomial(expr('sin(x)'), x)
JavaScript
const { Expression, symbol, expr } = require('mathhook-node');
function isPolynomial(e, varSym) {
if (e.isInteger() || e.isRational()) {
return true;
} else if (e.isSymbol()) {
return e.equals(varSym);
} else if (e.isPow()) {
const base = e.base();
const exp = e.exponent();
return base.isSymbol() && base.equals(varSym) &&
exp.isInteger() && exp.value() >= 0;
} else if (e.isAdd() || e.isMul()) {
const terms = e.isAdd() ? e.terms() : e.factors();
return terms.every(t => isPolynomial(t, varSym));
}
return false;
}
const x = symbol('x');
console.assert(isPolynomial(expr('x^2 + 3*x + 1'), x));
console.assert(!isPolynomial(expr('sin(x)'), x));
Performance
Time Complexity: O(n) for pattern matching on expression tree of size n
API Reference
- Rust:
mathhook_core::pattern - Python:
mathhook.pattern - JavaScript:
mathhook-node.pattern