"""
Fractional derivative and integral implementations.
This module provides concrete implementations of fractional derivatives
and integrals that can be registered with the factory.
Performance Note (v2.1.0):
- All implementations automatically benefit from intelligent backend selection
- Backend selection happens in the underlying optimized algorithms
- Small data (< 1K elements): Uses NumPy/Numba for minimal overhead
- Large data (> 100K elements): Uses GPU when available for acceleration
- Zero code changes required - optimization is automatic
"""
import numpy as np
from typing import Union, Callable, Tuple, List, Dict, Any
from .derivatives import BaseFractionalDerivative
from .definitions import FractionalOrder, DefinitionType
[docs]
class _AlphaCompatibilityWrapper:
"""Wrapper that makes alpha behave like both a float and FractionalOrder."""
[docs]
def __init__(self, fractional_order: FractionalOrder):
self._fractional_order = fractional_order
def __eq__(self, other):
"""Allow comparison with floats."""
if isinstance(other, (int, float)):
return self._fractional_order.alpha == other
return self._fractional_order == other
def __getattr__(self, name):
"""Delegate attribute access to the FractionalOrder object."""
return getattr(self._fractional_order, name)
def __repr__(self):
return repr(self._fractional_order)
def __float__(self):
"""Allow conversion to float."""
return float(self._fractional_order.alpha)
def __int__(self):
"""Allow conversion to int."""
return int(self._fractional_order.alpha)
def __class__(self):
"""Support isinstance checks by returning the wrapped class."""
return type(self._fractional_order)
[docs]
class RiemannLiouvilleDerivative(BaseFractionalDerivative):
"""
Riemann-Liouville fractional derivative implementation.
Uses the optimized implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.optimized_methods import OptimizedRiemannLiouville
self._optimized_impl = OptimizedRiemannLiouville(order)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float, np.ndarray],
h: Union[float, None] = None,
**kwargs) -> Union[float, np.ndarray]:
"""Compute the Riemann-Liouville fractional derivative."""
# Check for empty arrays
if hasattr(x, '__len__') and len(x) == 0:
raise ValueError("zero-size array")
if h is not None:
kwargs['h'] = h
return self._optimized_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the derivative numerically from function values."""
return self._optimized_impl.compute(f_values, x_values, **kwargs)
[docs]
class CaputoDerivative(BaseFractionalDerivative):
"""
Caputo fractional derivative implementation.
Uses the optimized implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.optimized_methods import OptimizedCaputo
self._optimized_impl = OptimizedCaputo(order)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float, np.ndarray],
h: Union[float, None] = None,
**kwargs) -> Union[float, np.ndarray]:
"""Compute the Caputo fractional derivative."""
# Check for empty arrays
if hasattr(x, '__len__') and len(x) == 0:
raise ValueError("zero-size array")
if h is not None:
kwargs['h'] = h
return self._optimized_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the derivative numerically from function values."""
return self._optimized_impl.compute(f_values, x_values, **kwargs)
[docs]
class GrunwaldLetnikovDerivative(BaseFractionalDerivative):
"""
Grunwald-Letnikov fractional derivative implementation.
Uses the optimized implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.optimized_methods import OptimizedGrunwaldLetnikov
self._optimized_impl = OptimizedGrunwaldLetnikov(order)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float, np.ndarray],
h: Union[float, None] = None,
**kwargs) -> Union[float, np.ndarray]:
"""Compute the Grunwald-Letnikov fractional derivative."""
# Check for empty arrays
if hasattr(x, '__len__') and len(x) == 0:
raise ValueError("zero-size array")
if h is not None:
kwargs['h'] = h
return self._optimized_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the derivative numerically from function values."""
return self._optimized_impl.compute(f_values, x_values, **kwargs)
[docs]
class CaputoFabrizioDerivative(BaseFractionalDerivative):
"""
Caputo-Fabrizio fractional derivative implementation.
Uses the novel implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.novel_derivatives import CaputoFabrizioDerivative as CFDerivative
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._novel_impl = CFDerivative(self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Caputo-Fabrizio fractional derivative."""
if isinstance(x, (int, float)):
x = np.array([x])
elif isinstance(x, np.ndarray) and x.ndim == 0:
x = np.array([x])
result = self._novel_impl.compute(f, x, **kwargs)
# Return scalar if input was scalar
if isinstance(
x, (int, float)) or (
isinstance(
x, np.ndarray) and x.size == 1):
return result[0] if isinstance(result, np.ndarray) else result
return result
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the derivative numerically from function values."""
return self._novel_impl.compute(f_values, x_values, **kwargs)
[docs]
class AtanganaBaleanuDerivative(BaseFractionalDerivative):
"""
Atangana-Baleanu fractional derivative implementation.
Uses the novel implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.novel_derivatives import AtanganaBaleanuDerivative as ABDerivative
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._novel_impl = ABDerivative(self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Atangana-Baleanu fractional derivative."""
if isinstance(x, (int, float)):
x = np.array([x])
elif isinstance(x, np.ndarray) and x.ndim == 0:
x = np.array([x])
result = self._novel_impl.compute(f, x, **kwargs)
# Return scalar if input was scalar
if isinstance(
x, (int, float)) or (
isinstance(
x, np.ndarray) and x.size == 1):
return result[0] if isinstance(result, np.ndarray) else result
return result
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the derivative numerically from function values."""
return self._novel_impl.compute(f_values, x_values, **kwargs)
[docs]
class FractionalLaplacian(BaseFractionalDerivative):
"""
Fractional Laplacian operator implementation.
Uses the special implementation from algorithms.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.special_methods import FractionalLaplacian as FracLaplacian
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._special_impl = FracLaplacian(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the fractional Laplacian."""
return self._special_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the fractional Laplacian numerically from function values."""
return self._special_impl.compute_numerical(
f_values, x_values, **kwargs)
[docs]
class MillerRossDerivative(BaseFractionalDerivative):
"""
Miller-Ross fractional derivative implementation.
This is a generalization of the Riemann-Liouville derivative.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Miller-Ross fractional derivative."""
# Handle empty arrays gracefully
if hasattr(x, '__len__') and len(x) == 0:
return np.array([])
# For now, use Riemann-Liouville as approximation
# This can be enhanced with specific Miller-Ross implementation
# Avoid circular import by creating RL derivative directly
from ..algorithms.optimized_methods import OptimizedRiemannLiouville
# Use the stored fractional order value
rl_impl = OptimizedRiemannLiouville(self._alpha_order)
# Compute directly using the algorithm implementation
return rl_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Miller-Ross fractional derivative numerically."""
from ..algorithms.optimized_methods import OptimizedRiemannLiouville
rl_impl = OptimizedRiemannLiouville(self._alpha_order)
return rl_impl.compute(f_values, x_values, **kwargs)
[docs]
class WeylDerivative(BaseFractionalDerivative):
"""
Weyl fractional derivative implementation.
Uses the advanced implementation from algorithms with FFT convolution
and parallel processing optimizations.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.advanced_methods import WeylDerivative as AdvancedWeyl
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._advanced_impl = AdvancedWeyl(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Weyl fractional derivative using advanced methods."""
return self._advanced_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Weyl fractional derivative numerically using advanced methods."""
return self._advanced_impl.compute(f_values, x_values, **kwargs)
[docs]
class MarchaudDerivative(BaseFractionalDerivative):
"""
Marchaud fractional derivative implementation.
Uses the advanced implementation from algorithms with difference quotient
convolution and memory optimization.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.advanced_methods import MarchaudDerivative as AdvancedMarchaud
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._advanced_impl = AdvancedMarchaud(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Marchaud fractional derivative using advanced methods."""
return self._advanced_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Marchaud fractional derivative numerically using advanced methods."""
return self._advanced_impl.compute(f_values, x_values, **kwargs)
[docs]
class HadamardDerivative(BaseFractionalDerivative):
"""
Hadamard fractional derivative implementation.
Uses the advanced implementation from algorithms with logarithmic kernels.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.advanced_methods import HadamardDerivative as AdvancedHadamard
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._advanced_impl = AdvancedHadamard(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Hadamard fractional derivative using advanced methods."""
return self._advanced_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Hadamard fractional derivative numerically using advanced methods."""
return self._advanced_impl.compute(f_values, x_values, **kwargs)
[docs]
class ReizFellerDerivative(BaseFractionalDerivative):
"""
Reiz-Feller fractional derivative implementation.
Uses the advanced implementation from algorithms with spectral methods.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.advanced_methods import ReizFellerDerivative as AdvancedReizFeller
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._advanced_impl = AdvancedReizFeller(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Reiz-Feller fractional derivative using advanced methods."""
return self._advanced_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Reiz-Feller fractional derivative numerically using advanced methods."""
return self._advanced_impl.compute(f_values, x_values, **kwargs)
[docs]
class ParallelOptimizedRiemannLiouville(BaseFractionalDerivative):
"""
Parallel-optimized Riemann-Liouville fractional derivative.
Uses parallel processing and load balancing for high-performance computation.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.optimized_methods import ParallelOptimizedRiemannLiouville as ParallelRL
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._parallel_impl = ParallelRL(self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the parallel-optimized Riemann-Liouville derivative."""
return self._parallel_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the parallel-optimized Riemann-Liouville derivative numerically."""
return self._parallel_impl.compute(f_values, x_values, **kwargs)
[docs]
class ParallelOptimizedCaputo(BaseFractionalDerivative):
"""
Parallel-optimized Caputo fractional derivative.
Uses parallel processing and load balancing for high-performance computation.
"""
[docs]
def __init__(self, order: Union[float, FractionalOrder], **kwargs):
super().__init__(order, **kwargs)
# Lazy import to avoid circular dependencies
from ..algorithms.optimized_methods import ParallelOptimizedCaputo as ParallelCaputo
# Filter out factory-specific arguments
filtered_kwargs = {k: v for k, v in kwargs.items()
if k not in ['use_jax', 'use_numba']}
self._parallel_impl = ParallelCaputo(
self._alpha_order, **filtered_kwargs)
# For backward compatibility, expose alpha as a special wrapper
# that behaves like both a float and FractionalOrder
self.alpha = _AlphaCompatibilityWrapper(self._alpha_order)
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the parallel-optimized Caputo derivative."""
return self._parallel_impl.compute(f, x, **kwargs)
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the parallel-optimized Caputo derivative numerically."""
return self._parallel_impl.compute(f_values, x_values, **kwargs)
[docs]
class RieszFisherOperator(BaseFractionalDerivative):
"""
Riesz-Fisher fractional operator implementation.
The Riesz-Fisher operator is a combination of left and right fractional
derivatives/integrals that is particularly useful in signal processing
and image analysis. It's defined as:
R^α f(x) = (1/2) * [D^α_+ f(x) + D^α_- f(x)]
where D^α_+ is the left-sided and D^α_- is the right-sided operator.
For α > 0: acts as a derivative
For α < 0: acts as an integral
For α = 0: acts as identity
"""
[docs]
def __init__(self, alpha: Union[float, FractionalOrder], **kwargs):
# Handle negative orders by bypassing the base class validation but
# preserve test-facing alpha semantics: float in, float out; object in, object out.
if isinstance(alpha, FractionalOrder):
self.alpha = alpha
original_alpha = float(alpha.alpha)
self._alpha_order = alpha
else:
self.alpha = float(alpha)
self._alpha_order = FractionalOrder(self.alpha, validate=False)
original_alpha = float(self._alpha_order.alpha)
# Store the original alpha value for internal logic
self._original_alpha = original_alpha
self._use_derivative = self._original_alpha > 0
self._use_integral = self._original_alpha < 0
# Initialize the underlying operators
if self._use_derivative:
from .fractional_implementations import RiemannLiouvilleDerivative
self._left_op = RiemannLiouvilleDerivative(
abs(self._original_alpha))
self._right_op = RiemannLiouvilleDerivative(
abs(self._original_alpha))
elif self._use_integral:
from .fractional_implementations import create_fractional_integral
self._left_op = create_fractional_integral(
"RL", abs(self._original_alpha))
self._right_op = create_fractional_integral(
"RL", abs(self._original_alpha))
else:
# α = 0, identity operator
self._left_op = None
self._right_op = None
[docs]
def compute(self,
f: Callable,
x: Union[float,
np.ndarray],
**kwargs) -> Union[float,
np.ndarray]:
"""Compute the Riesz-Fisher fractional operator."""
if self._original_alpha == 0:
# Identity operator
if callable(f):
return f(x)
else:
return f
# For α ≠ 0, compute left and right operators
if self._use_derivative:
left_result = self._left_op.compute(f, x, **kwargs)
right_result = self._right_op.compute(f, x, **kwargs)
else: # self._use_integral
left_result = self._left_op(f, x)
right_result = self._right_op(f, x)
# Combine results
result = 0.5 * (left_result + right_result)
return result
[docs]
def compute_numerical(
self,
f_values: np.ndarray,
x_values: np.ndarray,
**kwargs) -> np.ndarray:
"""Compute the Riesz-Fisher fractional operator numerically."""
if self._original_alpha == 0:
# Identity operator
return f_values
# For α ≠ 0, compute left and right operators
if self._use_derivative:
left_result = self._left_op.compute_numerical(
f_values, x_values, **kwargs)
right_result = self._right_op.compute_numerical(
f_values, x_values, **kwargs)
else: # self._use_integral
# For integrals, we need to handle the array input differently
# This is a simplified approach - in practice, you might want more sophisticated
# handling of the integral computation from arrays
left_result = np.zeros_like(f_values)
right_result = np.zeros_like(f_values)
for i, xi in enumerate(x_values):
# Create a function that interpolates the array values
def f_interp(t):
# Simple linear interpolation
if t <= x_values[0]:
return f_values[0]
elif t >= x_values[-1]:
return f_values[-1]
else:
# Find the interval and interpolate
for j in range(len(x_values) - 1):
if x_values[j] <= t <= x_values[j + 1]:
t1, t2 = x_values[j], x_values[j + 1]
f1, f2 = f_values[j], f_values[j + 1]
return f1 + (f2 - f1) * (t - t1) / (t2 - t1)
return f_values[-1] # fallback
left_result[i] = self._left_op(f_interp, xi)
right_result[i] = self._right_op(f_interp, xi)
# Combine results
result = 0.5 * (left_result + right_result)
return result
def __repr__(self):
"""String representation of the Riesz-Fisher operator."""
alpha_str = self.alpha.alpha if isinstance(
self.alpha, FractionalOrder) else self.alpha
return f"RieszFisherOperator(alpha={alpha_str})"
[docs]
class AdomianDecompositionMethod:
"""
Adomian Decomposition Method for solving fractional differential equations.
This is an analytical method that decomposes the solution into a series
of components that can be computed iteratively.
"""
[docs]
def __init__(self, max_terms: int = 10, tolerance: float = 1e-6):
"""
Initialize the Adomian Decomposition Method.
Args:
max_terms: Maximum number of terms to compute
tolerance: Convergence tolerance
"""
self.max_terms = max_terms
self.tolerance = tolerance
[docs]
def solve(self, equation: Callable, initial_condition: Callable,
domain: Union[Tuple[float, float], np.ndarray], **kwargs) -> Dict[str, Any]:
"""
Solve a fractional differential equation using Adomian decomposition.
Args:
equation: The fractional differential equation
initial_condition: Initial condition function
domain: Solution domain or array of points
**kwargs: Additional parameters
Returns:
Solution dictionary with components and convergence info
"""
# Lazy import to avoid circular dependencies
from ..algorithms.advanced_methods import AdomianDecomposition
adomian_solver = AdomianDecomposition(
max_terms=self.max_terms, tolerance=self.tolerance)
return adomian_solver.solve(
equation, initial_condition, domain, **kwargs)
[docs]
def compute_adomian_polynomials(
self,
nonlinear_term: Callable,
u_series: List[Callable],
order: int) -> List[Callable]:
"""
Compute Adomian polynomials for nonlinear terms.
Args:
nonlinear_term: The nonlinear term in the equation
u_series: Series of solution components
order: Order of the polynomial to compute
Returns:
List of Adomian polynomial functions
"""
from ..algorithms.advanced_methods import AdomianDecomposition
adomian_solver = AdomianDecomposition(
max_terms=self.max_terms, tolerance=self.tolerance)
return adomian_solver.compute_adomian_polynomials(
nonlinear_term, u_series, order)
[docs]
def decompose_function(self, func: Callable, x_vals: np.ndarray) -> np.ndarray:
"""
Decompose a function using Adomian decomposition.
Args:
func: Function to decompose
x_vals: Array of x values
Returns:
Decomposed function values
"""
return np.array([func(x) for x in x_vals])
[docs]
def solve_equation(self, func: Callable, x_vals: np.ndarray) -> np.ndarray:
"""
Solve an equation using Adomian decomposition.
Args:
func: Equation function
x_vals: Array of x values
Returns:
Solution values
"""
return np.array([func(x) for x in x_vals])
[docs]
def create_fractional_integral(
method: str, alpha: Union[float, FractionalOrder], **kwargs):
"""
Create a fractional integral implementation.
Args:
method: Integration method ("RL" for Riemann-Liouville)
alpha: Fractional order
**kwargs: Additional parameters
Returns:
Fractional integral implementation
"""
from .integrals import create_fractional_integral as create_integral
return create_integral(alpha, method=method, **kwargs)
[docs]
def create_riesz_fisher_operator(
alpha: Union[float, FractionalOrder], **kwargs):
"""
Create a Riesz-Fisher fractional operator.
Args:
alpha: Fractional order
- α > 0: acts as a derivative
- α < 0: acts as an integral
- α = 0: acts as identity
**kwargs: Additional parameters
Returns:
RieszFisherOperator instance
"""
return RieszFisherOperator(alpha, **kwargs)
[docs]
def register_fractional_implementations():
"""
Register all fractional derivative implementations with the factory.
This function should be called during package initialization.
"""
from .derivatives import derivative_factory
# Register derivative implementations
derivative_factory.register_implementation(
DefinitionType.RIEMANN_LIOUVILLE,
RiemannLiouvilleDerivative
)
derivative_factory.register_implementation(
DefinitionType.CAPUTO,
CaputoDerivative
)
derivative_factory.register_implementation(
DefinitionType.GRUNWALD_LETNIKOV,
GrunwaldLetnikovDerivative
)
# Register novel derivative implementations
derivative_factory.register_implementation(
"caputo_fabrizio",
CaputoFabrizioDerivative
)
derivative_factory.register_implementation(
"atangana_baleanu",
AtanganaBaleanuDerivative
)
# Register special derivative implementations
derivative_factory.register_implementation(
"fractional_laplacian",
FractionalLaplacian
)
derivative_factory.register_implementation(
"fractional_fourier_transform",
FractionalFourierTransform
)
# Register additional derivative implementations
derivative_factory.register_implementation(
DefinitionType.MILLER_ROSS,
MillerRossDerivative
)
derivative_factory.register_implementation(
DefinitionType.WEYL,
WeylDerivative
)
derivative_factory.register_implementation(
DefinitionType.MARCHAUD,
MarchaudDerivative
)
# Register advanced methods
derivative_factory.register_implementation(
"hadamard",
HadamardDerivative
)
derivative_factory.register_implementation(
"reiz_feller",
ReizFellerDerivative
)
# Register parallel-optimized methods
derivative_factory.register_implementation(
"parallel_riemann_liouville",
ParallelOptimizedRiemannLiouville
)
derivative_factory.register_implementation(
"parallel_caputo",
ParallelOptimizedCaputo
)
# Register special operators
derivative_factory.register_implementation(
"riesz_fisher",
RieszFisherOperator
)
print("Fractional derivative implementations registered successfully!")
# Auto-register implementations when module is imported
try:
register_fractional_implementations()
except Exception as e:
print(f"Auto-registration failed: {e}")