6
\$\begingroup\$

Could the time complexity of this definite integral algorithm be improved?

import numpy as np
def integral(f, left, right, epsilon):
 w = int((right-left)/epsilon)
 domain = np.linspace(left, right, w)
 heights = [f(((a+b)*0.5)) for a, b in zip(domain[:-1], domain[1:])]
 return sum(heights)*epsilon
# Test an example
print('Result:', integral(lambda x: np.sin(x), 1, 10, 0.01))
Mast
13.8k12 gold badges56 silver badges127 bronze badges
asked Sep 28, 2017 at 17:20
\$\endgroup\$
2
  • \$\begingroup\$ Is there a reason you went for a lambda? \$\endgroup\$ Commented Sep 28, 2017 at 18:46
  • \$\begingroup\$ No, but that's just an input that the user gives me. I really only care about the efficiency of integral \$\endgroup\$ Commented Sep 28, 2017 at 18:50

2 Answers 2

4
\$\begingroup\$

By changing the start and end points to start+epsilon/2 and end-epsilon/2, we can simplify the calculation tremendously. This means that the domain is what we want to evaluate the function at, removing the zip and averaging logic, secondly, because we now have heights of the same length as domain, we can just call f(domain), to have it update in place. Finally, we can use np.sum() to return the answer. Put together, these changes result in simpler code, and roughly 100x faster (especially for small epsilon). The memory usage will also be reduced.

def integral1(f, left, right, epsilon):
 left += epsilon / 2
 right -= epsilon / 2
 domain = np.linspace(left, right, (right-left) // epsilon)
 return np.sum(f(domain), dtype = np.float128) * epsilon

Just for the record, I'm assuming that you aren't looking for general advice with numerical integration, and rather just using the midpoint rule. If you were, Simpson's rule or similar would be much more accurate, and would not take longer to compute.

It turns out that accumulating with a 128 bit float adds significant accuracy in some pathological cases, while only taking 10% longer.

Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
answered Sep 29, 2017 at 4:10
\$\endgroup\$
0
2
\$\begingroup\$

You might want to check out quadpy (a project of mine). It does the heavy lifting for all sorts of integration problems.

import numpy
import quadpy
val, error_estimate = quadpy.line_segment.integrate_adaptive(
 numpy.sin,
 [0.0, 1.0],
 1.0e-10
 )
answered Nov 18, 2017 at 11:29
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.