Skip to content

CSpline - Fix segment function and add utils to constrain parameter calculations #3593

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

eslickj
Copy link
Contributor

@eslickj eslickj commented May 3, 2025

Fixes

There was a bug in the segment function in the parameter class. The function is just used for testing and plotting cubic splines, so it is not likely to have affected anything. It's fixed and tests are added that would catch similar future issues.

Summary/Motivation:

This fixes a bug and adds parameter calculation options that allow you to impose certain properties on the cubic spline.

Changes proposed in this PR:

  • Fix bug in segments method in CsplineParameters class (use for plotting and testing)
  • Add option to extend the curve to extrapolate linearly from the endpoints using endpoint slope
  • Add function to add constraints to parameter calculation problem to encourage the cspline to be increasing
  • Add function to add constraints to parameter calculation problem to encourage the cspline to be decreasing
  • Add function to add constraints to parameter calculation problem to require the function to be convex
  • Add function to add constraints to parameter calculation problem to require the function to be concave

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

Copy link

codecov bot commented May 6, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.77%. Comparing base (86f5f05) to head (d16d1f7).
Report is 21 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3593      +/-   ##
==========================================
+ Coverage   88.75%   88.77%   +0.01%     
==========================================
  Files         890      890              
  Lines      102259   102398     +139     
==========================================
+ Hits        90762    90904     +142     
+ Misses      11497    11494       -3     
Flag Coverage Δ
builders 26.59% <7.74%> (-0.04%) ⬇️
default 84.89% <100.00%> (?)
expensive 33.97% <7.74%> (?)
linux 86.56% <100.00%> (-1.94%) ⬇️
linux_other 86.56% <100.00%> (+0.02%) ⬆️
osx 82.86% <100.00%> (+0.02%) ⬆️
win 84.76% <100.00%> (+0.02%) ⬆️
win_other 84.76% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +375 to +380
def yx_ineq(blk, k):
if k >= len(m.knt_idx):
s = k - 1
else:
s = k
return _fx_cubic(m.x[k], m.alpha, s) <= -tol
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good for these functions to be declared at the module scope so that they would be picklable. Given the use of the tol argument, maybe they should be functors:

class _yx_ineq(object):
    def __init__(self, tol):
        self.tol = tol

    def __call__(self, m, k):
        if k >= len(m.knt_idx):
            s = k - 1
        else:
            s = k
        return _fx_cubic(m.x[k], m.alpha, s) <= -self.tol

def add_decreasing_constraints(m, tol=0):
    m.yx_ineq = Constraint(m.knt_idx, rule=_yx_ineq(tol))

@@ -313,3 +359,71 @@ def yxx_endpoint_eqn(blk, s):
else:
j = s
return _fxx_cubic(m.x[j], m.alpha, s) == 0


def add_decreasing_constraints(m, tol=0):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions assume that m has a set knt_idx, and that they can create components with specific hardcoded names. This feels like these should be methods on a custom Block class that disallows users to create components so you don't have to worry about conflicts and know that the required attributes are present.

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.

4 participants