-
Notifications
You must be signed in to change notification settings - Fork 37
Find closest convex function for piecewise linear data #513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Find closest convex function for piecewise linear data #513
Conversation
Implement make_convex and make_concave functions using the Pool Adjacent Violators Algorithm (PAVA) for isotonic regression. This provides an optimal O(n) solution for finding the closest convex/concave approximation to non-convex PiecewiseLinearData and PiecewiseStepData. New functions: - isotonic_regression / antitonic_regression: Core PAVA implementation - make_convex / make_concave: Convert piecewise data to convex/concave form - convexity_violations: Find indices where convexity is violated - convexity_gap: Measure the maximum convexity violation - approximation_error: Compute error between original and approximated data Features: - Multiple weighting schemes (:uniform, :length, custom) - Multiple anchor options for PiecewiseLinearData (:first, :last, :centroid) - Support for L1, L2, and Linf error metrics
Remove antitonic_regression, make_concave for PiecewiseStepData and PiecewiseLinearData, and related tests. The library only needs conversion from concave to convex (make_convex), not the reverse.
| return _get_x_lengths(x_coords) | ||
| elseif weights isa Vector{Float64} | ||
| length(weights) == n_segments || | ||
| throw(ArgumentError("Custom weights must have length $n_segments, got $(length(weights))")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶
| throw(ArgumentError("Custom weights must have length $n_segments, got $(length(weights))")) | |
| throw( | |
| ArgumentError( | |
| "Custom weights must have length $n_segments, got $(length(weights))", | |
| ), | |
| ) |
| approximated = IS.PiecewiseStepData([0.0, 1.0, 2.0, 3.0], [7.5, 7.5, 15.0]) | ||
|
|
||
| # L2 error with uniform weights | ||
| err_l2 = IS.approximation_error(original, approximated; metric = :L2, weights = :uniform) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶
| err_l2 = IS.approximation_error(original, approximated; metric = :L2, weights = :uniform) | |
| err_l2 = | |
| IS.approximation_error(original, approximated; metric = :L2, weights = :uniform) |
| @test err_l2 ≈ expected_l2 | ||
|
|
||
| # L1 error | ||
| err_l1 = IS.approximation_error(original, approximated; metric = :L1, weights = :uniform) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶
| err_l1 = IS.approximation_error(original, approximated; metric = :L1, weights = :uniform) | |
| err_l1 = | |
| IS.approximation_error(original, approximated; metric = :L1, weights = :uniform) |
| @test err_l1 ≈ expected_l1 | ||
|
|
||
| # Linf error | ||
| err_linf = IS.approximation_error(original, approximated; metric = :Linf, weights = :uniform) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶
| err_linf = IS.approximation_error(original, approximated; metric = :Linf, weights = :uniform) | |
| err_linf = | |
| IS.approximation_error(original, approximated; metric = :Linf, weights = :uniform) |
| @test err ≈ expected | ||
|
|
||
| # Test invalid metric | ||
| @test_throws ArgumentError IS.approximation_error(original, approximated; metric = :invalid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶
| @test_throws ArgumentError IS.approximation_error(original, approximated; metric = :invalid) | |
| @test_throws ArgumentError IS.approximation_error( | |
| original, | |
| approximated; | |
| metric = :invalid, | |
| ) |
Refactor approximation_error functions to use Julia's standard LinearAlgebra functions instead of manually implementing norms: - L2 norm: Use norm() with weighted scaling - L1 norm: Use dot() for weighted sum - L∞ norm: Use norm(diff, Inf) This makes the code more idiomatic and leverages optimized implementations from Julia's standard library.
Implement make_convex and make_concave functions using the Pool Adjacent Violators Algorithm (PAVA) for isotonic regression. This provides an optimal O(n) solution for finding the closest convex/concave approximation to non-convex PiecewiseLinearData and PiecewiseStepData.
New functions:
Features: