mathhook-core 0.2.0

Core mathematical engine for MathHook - expressions, algebra, and solving
Documentation
//! Pole finding for rational and transcendental functions
//!
//! Implements algorithms to find poles of various types of functions using
//! the Universal Function Intelligence Registry.

use crate::core::{Expression, Symbol};
use crate::functions::intelligence::get_universal_registry;
use crate::functions::properties::FunctionProperties;

fn get_singularities_from_props(props: &FunctionProperties) -> Vec<Expression> {
    match props {
        FunctionProperties::Elementary(elem_props) => elem_props.domain_range.singularities.clone(),
        _ => vec![],
    }
}

/// Parse reciprocal function name (e.g., "1/sin" -> Some("sin"))
///
/// # Arguments
///
/// * `name` - Function name to parse
///
/// # Returns
///
/// The base function name if this is a reciprocal, None otherwise
fn parse_reciprocal_function(name: &str) -> Option<&str> {
    name.strip_prefix("1/")
}

/// Find poles of rational functions by solving denominator = 0
///
/// # Arguments
///
/// * `_numerator` - The numerator expression (currently unused, for future enhancements)
/// * `denominator` - The denominator expression
/// * `variable` - The variable to solve for
///
/// # Returns
///
/// Vector of pole locations
///
/// # Examples
///
/// ```rust,ignore
/// use mathhook_core::{expr, symbol};
/// use mathhook_core::calculus::residues::pole_finding::find_rational_poles;
///
/// let x = symbol!(x);
/// let numerator = expr!(1);
/// let denominator = expr!(x - 2);
/// let poles = find_rational_poles(&numerator, &denominator, &x);
/// ```
pub fn find_rational_poles(
    _numerator: &Expression,
    denominator: &Expression,
    variable: &Symbol,
) -> Vec<Expression> {
    Expression::function("solve", vec![denominator.clone(), variable.clone().into()])
        .into_vec()
        .unwrap_or_default()
}

/// Find poles of transcendental functions using Function Intelligence Registry
///
/// Retrieves pole information from the Universal Function Intelligence Registry
/// instead of hardcoding function names. This architectural pattern enables:
/// - O(1) registry lookup instead of O(n) match statements
/// - Extensibility: new functions auto-register their poles
/// - Single source of truth: poles defined with function properties
///
/// # Mathematical Background
///
/// **SymPy Validated: 2025-01-16**
///
/// Pole locations confirmed via SymPy limit analysis:
/// - `tan(x)`: poles at x = π/2 + nπ (principal pole: π/2)
///   - Validation: `lim(tan(x), x→π/2±) = ±∞`
/// - `cot(x)`: poles at x = nπ (principal pole: 0)
///   - Validation: `lim(cot(x), x→0±) = ±∞`
/// - `sec(x)`: poles at x = π/2 + nπ (principal pole: π/2)
///   - Validation: `lim(sec(x), x→π/2±) = ±∞`
/// - `csc(x)`: poles at x = nπ (principal pole: 0)
///   - Validation: `lim(csc(x), x→0±) = ±∞`
///
/// Each function returns its principal pole only. Full pole families follow
/// the periodic pattern: `principal_pole + n·period` where `n ∈ ℤ`.
///
/// # Arguments
///
/// * `name` - Function name
/// * `args` - Function arguments
/// * `variable` - Variable to find poles with respect to
///
/// # Returns
///
/// Vector of pole locations (typically returns the principal pole)
///
/// # Examples
///
/// ```rust,ignore
/// use mathhook_core::{expr, symbol};
/// use mathhook_core::calculus::residues::pole_finding::find_transcendental_poles;
///
/// let x = symbol!(x);
/// let poles = find_transcendental_poles("tan", &[expr!(x)], &x);
/// assert!(!poles.is_empty());
/// ```
pub fn find_transcendental_poles(
    name: &str,
    args: &[Expression],
    variable: &Symbol,
) -> Vec<Expression> {
    if args.is_empty() {
        return vec![];
    }

    let arg = &args[0];

    let registry = get_universal_registry();

    if let Some(props) = registry.get_properties(name) {
        if arg.is_symbol_matching(variable) {
            return get_singularities_from_props(props);
        }
    }

    if let Some(func_name) = parse_reciprocal_function(name) {
        if let Some(props) = registry.get_properties(func_name) {
            return get_singularities_from_props(props);
        }
    }

    vec![]
}

/// Helper trait to convert function results to vectors
pub trait IntoVec {
    /// Convert expression to vector if it's a Set
    fn into_vec(self) -> Option<Vec<Expression>>;
}

impl IntoVec for Expression {
    fn into_vec(self) -> Option<Vec<Expression>> {
        match self {
            Expression::Set(elements) => Some(elements.as_ref().clone()),
            _ => None,
        }
    }
}