Skip to content

Conversation

@github-actions
Copy link
Contributor

Summary

This PR adds comprehensive test coverage for the Exponential distribution in FSharp.Stats.Distributions.Continuous. The tests significantly improve coverage of this previously untested module.

Problems Found

The Exponential.fs source file had 0% test coverage before this PR. This meant that:

  • No validation of statistical properties (mean, variance, mode)
  • No testing of PDF and CDF functions
  • No verification of parameter validation
  • No testing of sampling functionality
  • No verification of the Fit/Estimate methods

Additionally, during testing, I discovered what appears to be a potential bug in the Estimate method: it passes the sample mean directly to Init which expects a lambda parameter, but the correct lambda should be 1/mean. The Fit method correctly returns 1/mean as lambda. The test documents this behavior rather than "fixing" it, as I'm not 100% certain this is a bug without more context.

Actions Taken

Tests Added

Created a new test file DistributionsExponential.fs with 29 comprehensive tests covering:

  1. Statistical Properties (4 tests)

    • Mean calculation
    • Variance calculation
    • Standard deviation calculation
    • Mode (always 0 for exponential distribution)
  2. Probability Density Function (PDF) (4 tests)

    • PDF at x=0 (should equal lambda)
    • PDF at various positive values
    • PDF for negative values (should be 0)
    • PDF monotonicity (decreases as x increases)
  3. Cumulative Distribution Function (CDF) (4 tests)

    • CDF at x=0 (should be 0)
    • CDF at mean (should be 1-1/e ≈ 0.632)
    • CDF for negative values (should be 0)
    • CDF monotonicity and convergence to 1
  4. Support and Parameter Validation (4 tests)

    • Support interval validation [0, +∞)
    • CheckParam rejects zero
    • CheckParam rejects negative values
    • CheckParam accepts positive values
  5. Distribution Parameters and String Representation (2 tests)

    • Parameters property validation
    • ToString format verification
  6. Fitting and Estimation (3 tests)

    • Fit with unweighted observations
    • Fit with weighted observations
    • Estimate creates valid distribution
  7. Sampling (2 tests)

    • Samples are non-negative
    • Sample mean approximates theoretical mean
  8. Mathematical Properties (3 tests)

    • Memoryless property: P(X > s+t | X > s) = P(X > t)
    • PDF is the derivative of CDF
    • PDF integrates to approximately 1
  9. Parameter Effects (2 tests)

    • Larger lambda means smaller mean
    • Larger lambda means faster probability accumulation
  10. Distribution Initialization (1 test, through Init method)

    • All distribution interface methods work correctly

Test Coverage Results

Exponential.fs Coverage

Metric Before After Change
Sequence Points 48 48 -
Covered 0 36 +36
Coverage 0.00% 75.00% +75.00%

Test File Coverage

The test file itself (DistributionsExponential.fs) has 97.81% coverage (134/137 sequence points covered).

Replicating the Test Coverage Measurements

To replicate these measurements:

# 1. Restore dependencies
cd tests/FSharp.Stats.Tests
dotnet restore

# 2. Build the test project
dotnet build --configuration Release

# 3. Run tests with coverage (using AltCover)
dotnet test --configuration Release --no-restore \
  /p:AltCover=true \
  /p:AltCoverForce=true \
  /p:AltCoverReportFormat=OpenCover \
  /p:AltCoverShowStatic=-

# 4. Coverage report will be in tests/FSharp.Stats.Tests/coverage.xml

# 5. To check just the Exponential tests:
dotnet test --configuration Release --no-build \
  --filter "FullyQualifiedName~Exponential"

Expected output: Passed: 29, Failed: 0, Total: 29

Analyzing Coverage

To extract coverage for Exponential.fs from the OpenCover XML:

import xml.etree.ElementTree as ET

tree = ET.parse('tests/FSharp.Stats.Tests/coverage.xml')
root = tree.getroot()

# Find Exponential.fs file uid
for file_elem in root.findall('.//File'):
    if 'Exponential.fs' in file_elem.get('fullPath', ''):
        file_uid = file_elem.get('uid')
        
        # Count covered sequence points
        total = covered = 0
        for seqpoint in root.findall('.//SequencePoint'):
            if seqpoint.get('fileid') == file_uid:
                total += 1
                if int(seqpoint.get('vc', 0)) > 0:
                    covered += 1
        
        print(f"Coverage: {covered}/{total} = {100*covered/total:.2f}%")

Possible Future Improvements

  1. InvCDF Method: Currently not implemented (throws failwithf). Could add implementation and tests for the inverse CDF (quantile function).

  2. Additional Edge Cases: Test extreme lambda values (very small, very large) to ensure numerical stability.

  3. Fix Estimate Method: If the behavior I observed is indeed a bug, the Estimate method should return a distribution with lambda = 1.0 / Array.average observations instead of passing the average directly to Init.

  4. Other Untested Distributions: Apply similar testing approach to other distributions with low coverage:

    • StudentizedRange.fs (0% coverage, 82 lines)
    • Uniform.fs (0% coverage, 70 lines)
    • Chi.fs (potentially low coverage)
    • LogNormal.fs (potentially low coverage)
  5. Performance Tests: Add tests for sampling performance with large sample sizes.

  6. Property-Based Tests: Use FsCheck to generate random valid inputs and verify properties hold universally.


Commands and Research

Bash Commands Run

# Coverage analysis
cat .github/actions/daily-test-improver/coverage-steps/action.yml
dotnet test ... /p:AltCover=true ...

# Code analysis
find src -name "Exponential.fs" -type f
python3 << 'EOF' [coverage analysis scripts]

# Build and test
git checkout -b test-coverage/exponential-1760717718
dotnet build tests/FSharp.Stats.Tests/FSharp.Stats.Tests.fsproj -c Release
dotnet test ... --filter "FullyQualifiedName~Exponential"

# Git operations
git add tests/FSharp.Stats.Tests/DistributionsExponential.fs
git add tests/FSharp.Stats.Tests/FSharp.Stats.Tests.fsproj
git commit -m "..."

Web Pages Fetched

None - all work was done using local repository analysis.

Web Searches Performed

None - relied on existing test patterns in the repository and mathematical knowledge of the exponential distribution.

AI generated by Daily Test Coverage Improver

- Added 29 new tests covering all static methods
- Tests cover: Mean, Variance, StandardDeviation, Mode, PDF, CDF
- Tests cover: CheckParam validation, Support interval, Fit, Estimate
- Tests cover: Sampling, memoryless property, PDF/CDF relationship
- Increases Exponential.fs coverage from 0% to 75%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant