Skip to content
299 changes: 178 additions & 121 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,180 +1,206 @@
# Copilot Instructions for Math_Foundations

## Project Architecture
## Project Overview

This is a **Julia scientific computing project** using DrWatson for reproducibility, focused on mathematical foundations with visualization capabilities. The codebase follows a **modular mathematical library pattern** with comprehensive testing and documentation.
**Julia scientific computing project** using DrWatson for reproducibility. Implements mathematical foundations (algebra, geometry, trigonometry) with visualization, comprehensive testing, and cross-repository documentation deployment.

### Core Components
### Core Architecture

- **`src/Math_Foundations.jl`**: Main module with smart environment detection for CI/interactive plotting
- **`src/basic_maths.jl`**: Mathematical functions (roots, polynomials, hyperbolas, financial calculations)
- **`test/`**: Comprehensive test suite with CI-compatible plotting tests (54 total tests)
- **`docs/`**: Documenter.jl setup with mathematical sections (Algebra, Geometry, etc.) and cross-repository deployment to math_tech_study
- **`src/Math_Foundations.jl`**: Main module with CI-aware plotting (auto-detects headless environments)
- **`src/basic_maths.jl`**: Mathematical library (roots, polynomials, hyperbolas, financial calculations)
- **`test/`**: 54 tests with separated computational/plotting logic for CI compatibility
- **`docs/`**: Documenter.jl deploying to `https://study.fourm.info/math_foundations/` (cross-repo to `math_tech_study`)
- **`notebooks/`**: Jupyter notebooks for exploration (not tested in CI)

## Critical Development Patterns

### Module Structure
### Module Structure & Exports

All code uses `@reexport` pattern and exports both computational + plotting functions:

```julia
# Main module uses @reexport for clean interface
# src/Math_Foundations.jl
using Reexport
@reexport using Symbolics, Nemo, Plots, Latexify, LaTeXStrings, Dates, AMRVW, Polynomials
# Comprehensive exports for all functions
export nth_root
export plot_parabola_roots_amrvw, plot_parabola_roots_polynomial, plot_parabola_roots_quadratic
# ...

# Export computational functions (no plotting)
export calculate_parabola_roots_quadratic, calculate_parabola_roots_polynomial, calculate_parabola_roots_amrvw

# Export integrated plotting functions (computation + visualization)
export plot_parabola_roots_quadratic, plot_hyperbola, plot_hyperbola_axes_direct

# Always export new functions in main module
```
### Environment-Aware Module Loading

### Automatic CI/Interactive Detection

Module auto-configures at load time - no manual intervention needed:

```julia
# The module automatically detects CI vs interactive environments
# src/Math_Foundations.jl - Runs on module load
if haskey(ENV, "CI") || get(ENV, "GKSwstype", "") == "100"
ENV["GKSwstype"] = "100" # Headless plotting
gr(show=false)
else
gr() # Interactive plotting
end
```

## Math_Foundations CI Testing Approach
## Testing Strategy (CI-Compatible)

The superior CI testing strategy consists of three components:
### Three-Layer Testing Approach

### 1. Module-Level Headless Detection
Configure plotting environment in the main module (`Math_Foundations.jl`) at load time:
**1. Module-Level Detection** - Automatic (in `Math_Foundations.jl`):
```julia
# Automatic CI detection and headless configuration
if haskey(ENV, "CI") || get(ENV, "GKSwstype", "") == "100"
ENV["GKSwstype"] = "100" # Force headless mode
gr(show=false) # Disable plot display
ENV["GKSwstype"] = "100"
gr(show=false)
end
```

### 2. Manual GKS Configuration in Tests
Set `ENV["GKSwstype"] = "100"` in test files before loading the module:
**2. Test-Level Configuration** - Manual (in `runtests.jl`):
```julia
# In runtests.jl - Configure headless mode before loading module
ENV["GKSwstype"] = "100" # Force headless plotting for CI
ENV["GKSwstype"] = "100" # Set BEFORE using Math_Foundations
using DrWatson, Test
@quickactivate "Math_Foundations"
using Math_Foundations
```

### 3. Separated Computational/Plotting Logic with Robust Testing
- **Pure computational functions** (`calculate_*`): Test mathematical logic directly, no try-catch
- **Plotting functions** (`plot_*`): Test with try-catch fallback for CI compatibility
- **Integration testing**: Verify both computation and visualization work together
**3. Separated Logic** - Design pattern for all new functions:

- **Computational functions** (`calculate_*`): Pure math, no plotting, test directly
- **Plotting functions** (`plot_*`): Computation + visualization, test with try-catch
- **Pattern Example**:

### Test Setup (Uses @quickactivate)
```julia
# Tests use DrWatson @quickactivate pattern
using DrWatson, Test
@quickactivate "Math_Foundations"
# Load the Math_Foundations package
using Math_Foundations
```
## Plotting Functions Pattern
All plotting functions auto-save with timestamps to `plots/` directory:
```julia
savefig("plots/"* Dates.format(now(),"yyyymmdd-HHMMSS") * "functionname.png"
# src/basic_maths.jl
function calculate_parabola_roots_quadratic(a₂, a₁=0.0, a₀=0.0)
discriminant = a₁^2 - 4 * a₂ * a₀
root1 = (-a₁ + sqrt(Complex(discriminant))) / (2 * a₂)
root2 = (-a₁ - sqrt(Complex(discriminant))) / (2 * a₂)
return [root1, root2] # Always returns ComplexF64
end

function plot_parabola_roots_quadratic(a₂, a₁=0.0, a₀=0.0)
all_roots = calculate_parabola_roots_quadratic(a₂, a₁, a₀) # Math always succeeds
try
@variables x
f = a₂ * x^2 + a₁ * x + a₀
plot_parabola(f, all_roots, a₂, a₁, a₀, "Quadratic")
catch e
!haskey(ENV, "CI") && @warn "Plotting failed: $e"
end
return [real(r) for r in all_roots if abs(imag(r)) < 1e-10] # Real roots only
end
```

## Julia Coding Standards
### Mathematical Functions
1. Use standard Julia mathematical conventions
2. Handle negative numbers appropriately (see `nth_root`)
3. Return complex numbers for even roots of negative numbers
4. Include comprehensive edge case testing
5. Always export new functions in main module
6. Use Unicode symbols (a₂, a₁, a₀) in function parameters

### Documentation & Comments
8. Include detailed comments explaining mathematical concepts
9. Use LaTeX math notation with Latexify.jl integration
10. Ensure all examples include explanatory text
11. Maintain the notebook-based structure with markdown explanations

### Testing Patterns
12. Include unit tests for all functions
13. Use Julia's built-in testing framework
14. Use `@test` for assertions in unit tests
15. Use `@testset` to group related tests by function
16. Use `@test_throws` to test for expected errors
17. Use `@test_broken` to mark tests that are known to fail
18. Group tests with comprehensive edge cases (54+ tests)
19. **CI-Compatible Testing Pattern**: Separate computational logic from plotting, test math directly without try-catch, only use try-catch for visualization:
### Testing Pattern

```julia
# Test computational logic directly (NO try-catch - mathematical errors should fail)
@testset "Pure Computational Tests" begin
# test/test_basic_maths.jl
@testset "Computational Tests" begin
# NO try-catch - math errors should fail
roots = calculate_parabola_roots_quadratic(1.0, 0.0, -4.0)
@test length(roots) == 2
@test typeof(roots) == Vector{ComplexF64}
# Test mathematical correctness without plotting dependencies
end

# Test integration (plotting + computation) with CI-safe fallback
@testset "Integration Tests" begin
# try-catch for CI-safe plotting
try
# Test the plotting function (includes computation + visualization)
result = plot_parabola_roots_quadratic(1.0, 0.0, -4.0)
@test typeof(result) == Vector{Float64} # Real roots only for backward compatibility
@test length(result) == 2
@test typeof(result) == Vector{Float64} # Real roots
catch e
# Graceful fallback for CI - test function exists and computational core works
@test hasmethod(plot_parabola_roots_quadratic, (Float64, Float64, Float64))
# Verify computational core still works via the separate computational function
computational_result = calculate_parabola_roots_quadratic(1.0, 0.0, -4.0)
@test typeof(computational_result) == Vector{ComplexF64}
@test typeof(calculate_parabola_roots_quadratic(1.0, 0.0, -4.0)) == Vector{ComplexF64}
end
end
```

### Code Organization
19. Follow the pattern of existing code in basic_maths.jl
20. Use consistent naming conventions for variables and functions
21. Ensure all code is well-documented and follows Julia's style guide
### Plotting Conventions

- All plots auto-save: `"plots/" * Dates.format(now(),"yyyymmdd-HHMMSS") * "functionname.png"`
- Ensure `plots/` directory exists before running tests
- Use LaTeX titles: `title!(L"Plot\ of\ %$a₂ * x^2 + %$a₁ * x + %$a₀\\")`

## Dependencies & Performance
## Coding Standards

**Heavy Dependencies** (main Project.toml): Nemo (~500MB), Makie, Symbolics, GLMakie
**Optimized Test Dependencies** (test/Project.toml): Only essential packages for CI speed
### Mathematical Functions

### Mathematical Libraries Used
- **Symbolics.jl**: For `@variables x` in hyperbola functions
- Pattern: Follow the @variables pattern seen in our notebooks
- Prefer simplify(expr, expand=true) for algebraic expressions
- **Polynomials.jl**: For polynomial root finding (`plot_parabola_roots_polynomial`)
- **AMRVW.jl**: Alternative root finding method
- **Nemo.jl**: Number theory (imported but verify usage before adding tests)
- Use polynomial_ring(ZZ, [vars]) for creating polynomial rings
- Prefer factor() over manual factorization
- Use Unicode symbols for coefficients: `a₂, a₁, a₀` (type `a\\_2<tab>` in Julia)
- Return `ComplexF64` for roots (even if imaginary part is zero)
- Handle negative numbers correctly (see `nth_root` - odd roots return negative reals, even roots return complex)
- Always export new functions in `src/Math_Foundations.jl`
- Follow pattern: `calculate_*` (pure math) + `plot_*` (integrated)

### Testing Requirements

- **@testset structure**: Group tests by function (54 total tests across all functions)
- **No try-catch for math**: Computational tests should fail on mathematical errors
- **try-catch for plots**: Only use for CI-safe visualization testing
- **Edge cases**: Test positive/negative, zero, special values
- Use `@test_throws` for expected errors, `@test_broken` for known failures

### Documentation Standards

- **Docstrings**: Required for all exported functions with signature and description
- **LaTeX math**: Use for equations in docs and plot titles
- **MathWorld links**: Add for new mathematical concepts (verify URL before adding)
- **Markdown docs**: Files in `docs/src/` organized by topic (Algebra, Geometry, Trigonometry)
- **Examples**: Include in docstrings showing typical usage

## Dependencies & Libraries

**Heavy Dependencies**: Nemo (~500MB), GLMakie, WGLMakie (main Project.toml)
**Optimized Tests**: Minimal dependencies in `test/Project.toml` for CI speed

### Key Mathematical Libraries

- **Symbolics.jl**: Symbolic variables (`@variables x`) for equation manipulation
- Create variables: `@variables x; f = a₂*x^2 + a₁*x + a₀`
- Simplify expressions: `simplify(expr, expand=true)`
- **Extract numeric values** (two methods):
1. **substitute + value**: `substitute(expr, x => π/4; fold=Val(true))` then `Symbolics.value(result)`
2. **build_function**: `f = build_function(expr, x, expression=Val{false})` creates callable Julia function
- Use `fold=Val(true)` with substitute to simplify after substitution
- Use `expression=Val{false}` with build_function to avoid eval requirement
- **Polynomials.jl**: Polynomial operations and root finding
- Create: `p = Polynomial([a₀, a₁, a₂])`
- Solve: `roots(p)`
- **AMRVW.jl**: Alternative root finding: `AMRVW.roots([a₀, a₁, a₂])`
- **Nemo.jl**: Number theory (verify usage patterns before adding new tests)
- **Plots.jl/GR**: Plotting with automatic CI headless mode

## Key Workflows

### Running Tests Locally
### Local Development

```bash
# Run tests
julia --project=. test/runtests.jl
```

### Running Tests in CI Mode
```bash
# CI mode (headless plotting)
CI=true julia --project=. test/runtests.jl
```

### Building Documentation
```bash
# Build documentation
julia --project=. docs/make.jl
```

### Julia Compilation Considerations
- **Be Patient with First Runs**: Julia often needs to precompile packages and rebuild project cache on first run. when running a Julia command in the CLI for the first time, it may take a while to precompile the packages and build the project cache, so you won't see the results of running the command for a while.
- **Typical First Run**: May take 15-30 seconds for precompilation before tests actually start
- **Example Expected Output**: `Precompiling DrWatson... 3 dependencies successfully precompiled in 17 seconds`
- **Subsequent Runs**: Much faster once cache is built
- **Don't Cancel Early**: Allow time for compilation phase to complete
- **IMPORTANT**: This applies to ALL Julia commands including CI testing with `CI=true julia --project=. test/runtests.jl`
### Julia Compilation

### CI Considerations
- Plots directory must exist for plotting tests to pass
- Configure headless mode before plotting in tests
- 54 comprehensive tests covering all mathematical functions
- Test execution includes edge cases and error handling
**CRITICAL**: First runs take 15-30 seconds for precompilation - DO NOT cancel early!

- **First Run**: `Precompiling DrWatson... 3 dependencies successfully precompiled in 17 seconds`
- **Subsequent Runs**: Near-instant once cache exists
- **Applies to**: ALL Julia commands including tests

### CI/CD Pipeline

- **Tests**: Run on all PRs (`.github/workflows/CI.yml`)
- **Docs Build**: Test on PR (no deploy)
- **Docs Deploy**: Auto-deploy to `https://study.fourm.info/math_foundations/` on merge to `main`
- **Cross-Repo**: Deploys to `FourMInfo/math_tech_study` subdirectory
- **Prerequisites**: `plots/` directory must exist for tests to pass

## Git Best Practices

Expand Down Expand Up @@ -251,16 +277,47 @@ triangle_area_perim(a::Float64, b::Float64, c::Float64) -> Tuple{Float64, Float6
```

## Documentation Patterns
- Use LaTeX for all mathematical notation
- Use LaTeX syntax for mathematical symbols not Unicode e.g. "^\circ" instead of "°"
- Use Markdown for explanations
- After creating or editing a markdown document always review and fix all linting issues, unless the document is a configuration file of some kind
- Follow the pattern of existing function documentation in src directory
- When a new mathematical concept is introduced, add an external link to [MathWorld](https://mathworld.wolfram.com/) for that specific concept.
- Compare multiple potential URLs to choose the most appropriate one
- Avoid replacing working links with inferior alternatives
- Always use fetch_webpage function to check the link is valid and points to the correct concept.
- use underscore not askterisk for markdown emphasis

### Structure for Mathematical Concept Documentation

Documentation in `docs/src/` explains general math concepts (not code). Follow these patterns:

**Document Organization:**
- Start with concept overview and [MathWorld](https://mathworld.wolfram.com/) link in opening paragraph
- Use hierarchical headings: `##` for major topics, `###` for subtopics
- Group related concepts (e.g., "By Side Length", "By Angle Measure")
- Include real-world applications section

**Content Style:**
- **Definitions first**: Clear, precise mathematical definitions with MathWorld links
- **Build progressively**: Simple concepts → complex relationships → applications
- **Multiple representations**: Equations, tables, visual aids (SVG diagrams when helpful)
- **Context matters**: Explain _why_ concepts are important, not just _what_ they are
- Example: "Arc length is crucial for engineering, navigation, physics..."
- **Derivations**: Show mathematical reasoning step-by-step (see Hyperbola derivation)

**Mathematical Notation:**
- Use LaTeX: `$$` for display equations, inline with `$...$`
- LaTeX syntax for symbols: `^\circ` not `°`, `\frac{}{}` for fractions
- Label variables clearly: "where: $r$ = radius, $θ$ = angle"
- Use aligned equations: `\begin{aligned}...\end{aligned}` for multi-step derivations

**MathWorld Links:**
- Link every new mathematical term on first mention
- Format: `[Term](https://mathworld.wolfram.com/Term.html)`
- Verify URLs before adding (use fetch_webpage)
- Compare multiple URLs to choose most appropriate

**Visual Elements:**
- SVG diagrams for geometric concepts (see Triangles, Polygons)
- Tables for reference data (degree/radian conversions, common values)
- Consistent styling in diagrams (colors, labels, annotations)

**Markdown Conventions:**
- _Underscore_ for emphasis (not asterisk)
- **Bold** for important terms and section labels
- Fix all linting issues after editing (except config files)
- Code blocks with language tags: ````julia` for Julia examples

## Communication Patterns

Expand Down
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ makedocs(;
"Geometry/01 Triangles.md",
"Geometry/02 Quadrilaterals.md",
"Geometry/03 Polygons.md",
"Geometry/04 Circles.md",
# "Geometry/04 Hyperbola.md" # TODO: Uncomment when ready to show
],
# "Linear Algebra" => [ # TODO: Uncomment when ready to show
Expand Down
Loading
Loading