Common Patterns

Common patterns and best practices when using MathHook, including macro usage guidelines, polynomial construction, substitution patterns, function composition, matrix operations, error handling, performance patterns, and educational features. Includes detailed pitfalls to avoid.

Code Examples

Macro Usage - Correct Patterns

When to use macros vs explicit API

use mathhook::prelude::*;

// ALWAYS use macros for symbols
let x = symbol!(x);  // NOT Symbol::new("x")

// Simple expressions - use macros
let expr = expr!(x + y);
let expr = expr!(2 * x);
let expr = expr!(x ^ 2);

// Function calls - use macros
let expr = expr!(sin(x));

Runtime Variables - Explicit API Required

Why macros don't work with loop variables

use mathhook::prelude::*;

// WRONG - creates Symbol("i"), not integer value
for i in 0..10 {
    let expr = expr!(i);  // BAD!
}

// CORRECT - use explicit API for runtime variables
for i in 0..10 {
    let term = Expression::integer(i);  // GOOD!
}

// CORRECT - programmatic construction
let x = symbol!(x);
let coefficients = vec![1, 2, 3];
let mut terms = Vec::new();
for i in 0..coefficients.len() {
    let coeff = Expression::integer(coefficients[i]);
    let x_expr = Expression::from(x.clone());
    let power = Expression::integer(i as i64);
    terms.push(Expression::mul(vec![coeff, Expression::pow(x_expr, power)]));
}
let polynomial = Expression::add(terms);

Building Polynomials - Dynamic Degree

Construct polynomials with runtime coefficients

use mathhook::prelude::*;

fn build_polynomial(coefficients: &[i64], x: &Symbol) -> Expression {
    let mut terms = Vec::new();
    for (i, &coeff) in coefficients.iter().enumerate() {
        let coeff_expr = Expression::integer(coeff);
        let x_expr = Expression::from(x.clone());
        let power = Expression::integer(i as i64);
        let term = Expression::mul(vec![coeff_expr, Expression::pow(x_expr, power)]);
        terms.push(term);
    }
    Expression::add(terms)
}

let x = symbol!(x);
let poly = build_polynomial(&[1, -5, 6], &x);  // x^2 - 5x + 6

Substitution - Single and Multiple

Replace symbols with values

use mathhook::prelude::*;
use std::collections::HashMap;

let x = symbol!(x);
let y = symbol!(y);
let expr = expr!(add: (x * y), x, y);

// Single substitution
let mut vars = HashMap::new();
vars.insert("x".to_string(), Expression::integer(3));
let result = expr.substitute(&vars);

// Multiple substitutions
let mut vars = HashMap::new();
vars.insert("x".to_string(), Expression::integer(2));
vars.insert("y".to_string(), Expression::integer(3));
let result = expr.substitute(&vars);

Function Composition

Compose functions by nesting

use mathhook::prelude::*;

let x = symbol!(x);

// sin(cos(x)) - direct nesting
let composed = expr!(sin(cos(x)));

// Or build step by step
let inner = expr!(cos(x));
let composed_alt = function!(sin, inner);

println!("Composed function: {}", composed);

Performance - Bulk Operations

Efficient batch processing

use mathhook::prelude::*;

let x = symbol!(x);

// Simplify many expressions efficiently
let expressions = vec![
    expr!(x + x),
    expr!(x * 1),
    expr!(add: (x ^ 2), (-(x ^ 2))),
];

let simplified: Vec<_> = expressions
    .iter()
    .map(|e| e.simplify())
    .collect();

Performance - Caching Results

Cache frequently computed expressions

use mathhook::prelude::*;
use std::collections::HashMap;

let x = symbol!(x);
let mut cache: HashMap<String, Expression> = HashMap::new();

let expr = expr!(x ^ 2);
let key = format!("{}", expr);

if let Some(cached) = cache.get(&key) {
    println!("Using cached result");
} else {
    let result = expr.simplify();
    cache.insert(key, result.clone());
}

Common Pitfall - Float Equality

Never use == for approximate values

use mathhook::prelude::*;

// WRONG - comparing floats directly
let val1: f64 = 3.14;
let val2: f64 = 3.14000000001;
// if val1 == val2 { }  // BAD!

// CORRECT - use epsilon comparison
let tolerance: f64 = 1e-10;
if (val1 - val2).abs() < tolerance {
    println!("Values are approximately equal");
}

// OR use exact rationals for symbolic computation
let exact = Expression::rational(314, 100);  // Exact 3.14

🔗 Related Topics