Skip to content

Commit 422200c

Browse files
Add dedicated epsilon page and reorganize internal utilities
- Created comprehensive "Step Size Selection" page covering: - Mathematical theory of optimal step sizes - Error analysis (truncation vs round-off) - Adaptive step sizing algorithms - Special cases for complex step and sparse Jacobians - Renamed "Utilities" to "Internal Utilities" with complete coverage of: - Array utilities (_vec, _mat, setindex overloads) - Hessian utilities (_hessian_inplace, mutable_zeromatrix) - Sparse Jacobian internals (_make_Ji, _colorediteration!) - Performance optimizations and sparsity detection - Cache resize functions and error handling - Updated pages.jl navigation structure - Documentation builds cleanly with proper organization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 436cc25 commit 422200c

File tree

3 files changed

+133
-19
lines changed

3 files changed

+133
-19
lines changed

docs/pages.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ pages = [
88
"Jacobians" => "jacobians.md",
99
"Hessians" => "hessians.md",
1010
"Jacobian-Vector Products" => "jvp.md",
11-
"Utilities" => "utilities.md"
11+
"Step Size Selection" => "epsilons.md",
12+
"Internal Utilities" => "utilities.md"
1213
]

docs/src/epsilons.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Step Size Selection (Epsilons)
2+
3+
Functions and theory for computing optimal step sizes in finite difference approximations.
4+
5+
## Theory
6+
7+
The choice of step size (epsilon) in finite difference methods is critical for accuracy. Too large a step leads to truncation error, while too small a step leads to round-off error. The optimal step size balances these two sources of error.
8+
9+
### Error Analysis
10+
11+
For a function `f` with bounded derivatives, the total error in finite difference approximations consists of:
12+
13+
1. **Truncation Error**: Comes from the finite difference approximation itself
14+
- Forward differences: `O(h)` where `h` is the step size
15+
- Central differences: `O(h²)`
16+
- Hessian central differences: `O(h²)` for second derivatives
17+
18+
2. **Round-off Error**: Comes from floating-point arithmetic
19+
- Forward differences: `O(eps/h)` where `eps` is machine epsilon
20+
- Central differences: `O(eps/h)`
21+
22+
### Optimal Step Sizes
23+
24+
Minimizing the total error `truncation + round-off` gives optimal step sizes:
25+
26+
- **Forward differences**: `h* = sqrt(eps)` - balances `O(h)` truncation with `O(eps/h)` round-off
27+
- **Central differences**: `h* = eps^(1/3)` - balances `O(h²)` truncation with `O(eps/h)` round-off
28+
- **Hessian central**: `h* = eps^(1/4)` - balances `O(h²)` truncation for mixed derivatives
29+
- **Complex step**: `h* = eps` - no subtractive cancellation, only limited by machine precision
30+
31+
## Adaptive Step Sizing
32+
33+
The step size computation uses both relative and absolute components:
34+
35+
```julia
36+
epsilon = max(relstep * abs(x), absstep) * dir
37+
```
38+
39+
This ensures:
40+
- **Large values**: Use relative step `relstep * |x|` for scale-invariant accuracy
41+
- **Small values**: Use absolute step `absstep` to avoid underflow
42+
- **Direction**: Multiply by `dir` (±1) for forward differences
43+
44+
## Implementation
45+
46+
The step size computation is handled by internal functions:
47+
48+
- **`compute_epsilon(fdtype, x, relstep, absstep, dir)`**: Computes the actual step size for a given finite difference method and input value
49+
- **`default_relstep(fdtype, T)`**: Returns the optimal relative step size for a given method and numeric type
50+
51+
These functions are called automatically by all finite difference routines, but understanding their behavior can help with custom implementations or debugging numerical issues.
52+
53+
## Special Cases
54+
55+
### Complex Step Differentiation
56+
57+
For complex step differentiation, the step size is simply machine epsilon since this method avoids subtractive cancellation entirely:
58+
59+
⚠️ **Important**: The function `f` must be complex analytic when the input is complex!
60+
61+
### Sparse Jacobians
62+
63+
When computing sparse Jacobians with graph coloring, the step size is computed based on the norm of the perturbation vector to ensure balanced accuracy across all columns in the same color group.
64+
65+
## Practical Considerations
66+
67+
- **Default step sizes** are optimal for most smooth functions
68+
- **Custom step sizes** may be needed for functions with unusual scaling or near-discontinuities
69+
- **Relative steps** should scale with the magnitude of the input
70+
- **Absolute steps** provide a fallback for inputs near zero
71+
- **Direction parameter** allows for one-sided differences when needed (e.g., at domain boundaries)

docs/src/utilities.md

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,73 @@
1-
# Utilities
1+
# Internal Utilities
22

3-
Internal utility functions and types that may be useful for advanced users.
3+
Internal utility functions and algorithms used throughout FiniteDiff.jl. These functions are primarily for advanced users who need to understand or extend the library's functionality.
44

5-
## Step Size Computation
5+
## Array Utilities
66

7-
While these functions are primarily internal, they can be useful for understanding and customizing finite difference computations:
7+
Internal utilities for handling different array types and ensuring compatibility across the Julia ecosystem:
88

9-
### Default Step Sizes
9+
### Type Conversion Functions
1010

11-
Different finite difference methods use different optimal step sizes to balance truncation error and round-off error:
11+
These functions help FiniteDiff.jl work with various array types including `StaticArrays`, structured matrices, and GPU arrays:
1212

13-
- **Forward differences**: `sqrt(eps(T))` - balances O(h) truncation error with round-off
14-
- **Central differences**: `cbrt(eps(T))` - balances O(h²) truncation error with round-off
15-
- **Hessian central**: `eps(T)^(1/4)` - balances O(h²) truncation error for second derivatives
13+
- **`_vec(x)`**: Vectorizes arrays while preserving scalars unchanged
14+
- **`_mat(x)`**: Ensures matrix format, converting vectors to column matrices
15+
- **`setindex(x, v, i...)`**: Non-mutating setindex operations for immutable arrays
1616

17-
### Complex Step Differentiation
17+
### Hessian Utilities
1818

19-
Complex step differentiation uses machine epsilon since it avoids subtractive cancellation:
19+
Helper functions specifically for Hessian computation:
2020

21-
⚠️ **Important**: `f` must be a function of a real variable that is also complex analytic when the input is complex!
21+
- **`_hessian_inplace(x)`**: Determines whether to use in-place operations based on array mutability
22+
- **`__Symmetric(x)`**: Wraps matrices in `Symmetric` views for mathematical correctness
23+
- **`mutable_zeromatrix(x)`**: Creates mutable zero matrices compatible with input arrays
2224

23-
## Array Utilities
25+
## Sparse Jacobian Internals
26+
27+
Graph coloring and sparse matrix algorithms for efficient Jacobian computation:
28+
29+
### Matrix Construction
30+
31+
- **`_make_Ji(...)`**: Constructs Jacobian contribution matrices for both sparse and dense cases
32+
- **`_colorediteration!(...)`**: Core loop for sparse Jacobian assembly using graph coloring
33+
- **`_findstructralnz(A)`**: Finds structural non-zero patterns in dense matrices
34+
35+
### Sparsity Detection
36+
37+
- **`_use_findstructralnz(sparsity)`**: Determines when to use structural sparsity information
38+
- **`_use_sparseCSC_common_sparsity(J, sparsity)`**: Tests for common sparsity patterns between matrices
39+
40+
### Performance Optimizations
41+
42+
- **`fast_jacobian_setindex!(...)`**: Optimized index operations for sparse Jacobian assembly
43+
- **`void_setindex!(...)`**: Wrapper for setindex operations that discards return values
44+
45+
## JVP Utilities
46+
47+
- **`resize!(cache::JVPCache, i)`**: Resizes JVP cache arrays for dynamic problems
48+
- **`resize!(cache::JacobianCache, i)`**: Resizes Jacobian cache arrays for dynamic problems
49+
50+
## Error Handling
51+
52+
- **`fdtype_error(::Type{T})`**: Provides informative error messages for unsupported finite difference type combinations
53+
54+
## Design Philosophy
55+
56+
These internal utilities follow several design principles:
57+
58+
1. **Type Stability**: All functions are designed for type-stable operations
59+
2. **Zero Allocation**: Internal utilities avoid allocations when possible
60+
3. **Genericity**: Support for multiple array types (dense, sparse, static, GPU)
61+
4. **Performance**: Optimized for the specific needs of finite difference computation
62+
5. **Safety**: Proper error handling and bounds checking where needed
63+
64+
## Advanced Usage
2465

25-
Internal utilities for handling different array types and ensuring compatibility:
66+
These functions are primarily internal, but advanced users may find them useful for:
2667

27-
- `_vec(x)`: Vectorizes arrays while preserving scalars
28-
- `_mat(x)`: Ensures matrix format, converting vectors to column matrices
29-
- `setindex(x, v, i...)`: Non-mutating setindex for immutable arrays
68+
- **Custom finite difference implementations**
69+
- **Integration with other differentiation libraries**
70+
- **Performance optimization in specialized applications**
71+
- **Understanding the implementation details of FiniteDiff.jl**
3072

31-
These functions help FiniteDiff.jl work with various array types including `StaticArrays`, structured matrices, and GPU arrays.
73+
Most users should rely on the main API functions rather than calling these utilities directly.

0 commit comments

Comments
 (0)