Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@shokonaasti
Copy link

Description

Please include a short summary of the change.
Issue link (if applicable):
This PR creates the numerical_integration atom using discretization methods (trapezoidal, Simpson’s rule, and Monte Carlo) that numerically integrates a convex function of some parameters over a given domain. And is implemented as a wrapper around the existing sum atom. Unit test is included in the test_atoms.py file.

Type of change

  • [x ] New feature (backwards compatible)
  • New feature (breaking API changes)
  • Bug fix
  • Other (Documentation, CI, ...)

Contribution checklist

  • [x ] Add our license to new files.
  • [ x] Check that your code adheres to our coding style.
  • [x ] Write unittests.
  • [x ] Run the unittests and check that they’re passing.
  • [] Run the benchmarks to make sure your change doesn’t introduce a regression.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

from cvxpy.atoms.affine.sum import sum as cvx_sum


def numerical_integration(f_callable, w, ranges, g_list=None, num_points=100,
Copy link
Collaborator

Choose a reason for hiding this comment

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

all function arguments need types

Copy link
Author

Choose a reason for hiding this comment

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

should be good now!

Copy link
Author

@shokonaasti shokonaasti left a comment

Choose a reason for hiding this comment

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

sorry about that!

from cvxpy.atoms.affine.sum import sum as cvx_sum


def numerical_integration(f_callable, w, ranges, g_list=None, num_points=100,
Copy link
Author

Choose a reason for hiding this comment

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

should be good now!

@dberkens
Copy link
Contributor

dberkens commented Mar 7, 2025

Hey @shokonaasti - did you see the comments on Discord? Copied below for visibility. My sense is maybe we should change it to cp.integrate to be consistent with scipy numerical integration. Any thoughts on the other issues raised?

Hey thanks a lot for your PR.. I had a few comments open for discussion (hence why I didn't give a code review)

  • I believe we should stick with the scientific python API for these functions: simpson and trapezoid. So it would look something like cp.simpson(expr,...), what do you think?
  • I personally think passing the cvxpy expression directly (instead of using f_callable on data points) is more in line with our other atoms.. but open to hearing your thoughts on that also
  • can you add some documentation on the ND integration and the fractional volume grid? Are there numpy equivalent functions or wikipedia links to the algorithm? The code isn't so easy to understand. And it would help to know what they do.
  • We would need some improved documentation for the internal functions for maintainability
  • Finally, we need to add the atoms to the webpage.. I can help with that once necessary

@shokonaasti
Copy link
Author

I made the changes to to adhere to scientific notation as well as passing the cvxpy expression directly. Sorry for the delay and let me know if there are any questions.

Copy link
Collaborator

@PTNobel PTNobel left a comment

Choose a reason for hiding this comment

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

I think I'd prefer to have one file intergrate.py that contains both atoms than the subfolder. Any reason to not to do it this way? Are you planning to add a lot more integration methods in future PRs?

Also, just out of lay-curiosity can Forward Euler or Backward Euler be simulated with these atoms?

from cvxpy.atoms.stats import mean, std, var
from cvxpy.atoms.ptp import ptp

from . import integrate
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
from . import integrate
from cvxpy.atoms.integrate import trapz, simpson

from cvxpy.atoms.ptp import ptp

from . import integrate
from cvxpy.atoms import integrate
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
from cvxpy.atoms import integrate

@@ -0,0 +1,19 @@
"""
Copyright, the CVXPY Ashok Viswanathan
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Copyright, the CVXPY Ashok Viswanathan
Copyright, the CVXPY Project

Please sign the CLA.

@@ -0,0 +1,97 @@
"""
Copyright, the CVXPY Ashok Viswanathan
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Copyright, the CVXPY Ashok Viswanathan
Copyright, the CVXPY Project

Comment on lines +16 to +17
from .trapz import trapz
from .simpson import simpson
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
from .trapz import trapz
from .simpson import simpson
from cvxpy.atoms.integrate.trapz import trapz
from cvxpy.atoms.integrate.simpson import simpson

x: Optional[np.ndarray] = None,
dx: float = 1.0,
axis: int = -1,
even: str = "avg"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Which strategy does scipy implement? I notice that scipy.integrate.simpson doesn't have an even mode specification.

axis: int = -1
) -> Expression:
y_ndim = len(y.shape)
axis = axis % y_ndim
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same question as with simpson.

dxs = np.diff(x)
dxs_shape = [1] * y_ndim
dxs_shape[axis] = len(dxs)
dxs_broadcast = dxs.reshape(dxs_shape)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we use np.broadcast_to instead of .reshape

center = cvx_sum(y[slicer(1, n - 1)])
return dx * (edge + center)

# def trapz(
Copy link
Collaborator

Choose a reason for hiding this comment

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

We generally don't allow commented out code to be merged.

# The optimized result should be smaller than the naive result,
# where X of the naive result is I.
self.assertTrue(prob.value < naiveRes)
def test_trapz_atom(self) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
def test_trapz_atom(self) -> None:
def test_trapz_atom(self) -> None:

@PTNobel
Copy link
Collaborator

PTNobel commented Jun 23, 2025

@shokonaasti are you able to sign the CLA, so someone else can finish this PR? Will you be able to finish the PR soon?

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.

5 participants