Skip to Main Content Skip to Search
File Exchange
MATLAB Newsgroup
Link Exchange
  Blogs  
 Contest 
MathWorks.com

Loren on the Art of MATLAB

April 26th, 2006

Two-Dimensional Integration over a General Domain

There have been several requests on the MATLAB newsgroup to calculate the area of a function on a non-rectangular domain. MATLAB's function dblquad uses the technique that I am going to illustrate today for rectangular domains. And I just noticed this entry on the File Exchange for doing 2-dimensional quadrature over a non-rectangular domain. It sounds similar but I have not tried it out myself.

Contents

Do a little housekeeping first.

s = warning('off','MATLAB:quadl:MinStepSize');

Rectangular Area

To compute the area of a rectangle via integration, we can call dblquad as I mentioned earlier.

a = 4;
b = 3;
dblquad(@(x,y) ones(size(x)), 0, a, 0, b)

%
% and we see the result we expect: 3*4 = 12.
ans =
    12

Rectangular Domain

To integrate something more interesting over that rectangular region, we simply supply a different function. For example, let's have x*y be the integrand. We can do this analytically first.

Let's evaluate the integral numerically now with dblquad and compare the answer to the analytic one. I am using the default tolerance and the quadl method for integration.

tol = [];
qnumeric = dblquad(@(x,y) x*y, 0, a, 0, b, tol, @quadl)
qexact = (a^2 * b^2) / 4
qnumeric =
    36
qexact =
    36

Elliptical Domain

The equation for an ellipse can be written as:

and we can rewrite y as a function of x for the upper-right quadrant as

We can now write the equation for the ellipse's area by integrating the identity integrand from 0 to the right limit for each value of x.

and now we are ready to set up a function handle representing the inner integral. Let's plot the function.

fh = @(x) quadl(@(y) ones(size(y)), 0, b*sqrt(1-(x/a).^2));

x = 0:a/100:a;
ell = arrayfun(fh, x);
plot(x,ell); title('Ellipse boundary in first quadrant'); axis equal

The reason I used arrayfun to evaluate fh above is the same reason why I can't just use quadl for the outer integral. fh is not a vectorized function and I can't make it into one. To evaluate fh for each value of x, I am calculating an integral at each point and the limit of integration is a function of x. In addition, for each value of x, the integration method stops when the solution meets the correct numerical criteria and therefore each integration may not be performing the same number of function evaluations, nor will they necessarily evaluate the separate integrands at the same locations.

Simply calling quadl with the function defined by fh above won't work for the same reasons that I couldn't just vectorize my function evaluations of the integrand. Instead, we need an integration method that doesn't assume the integrand is vectorized. And that's what quadvec, the code I'm going to show you next, does (and it's similar to the inner workings of dblquad as well). You can also download quadvec here.

dbtype quadvec
1     function q = quadvec(f, varargin)
2     % QUADVEC calls quad but assumes you can't vectorize your input function.
3     %   QUADVEC has the same calling syntax as QUAD but doesn't require that
4     %   the integrand be vectorized.  This makes QUADVEC suitable to perform
5     %   double-, triple-, and higher order integrals over a non-rectangular
6     %   domain.
7     %   Q = QUADVEC(FUN,A,B) tries to approximate the integral of scalar-valued
8     %   function FUN from A to B to within an error of 1.e-6 using recursive
9     %   adaptive Simpson quadrature. FUN is a function handle. 
10    %
11    %   Example:
12    %   Compute area of ellipse by computing the result in one quadrant and
13    %   then multiplying by 4.  Note that the inner integrand has integration
14    %   limits that are a function of the semi-major and semi-minor ellipse
15    %   axes, a and b.  
16    %   First we set up the function handle to the inner integrand, fh.
17    %   a = 4; b = 3;
18    %   fh = @(x) quadl(@(y) ones(size(y)), 0, b*sqrt(1-(x/a).^2));
19    %   ea = 4 * quadvec(fh , 0, a);
20    %   ea-pi*a*b  % compare integration result to closed-form solution
21    
22      q = quadl(@g, varargin{:}); % like quadl, but supplies g as the argument
23      function y = g(X) % make f into a "vectorized" function
24        y = zeros(size(X));
25        for i = 1:numel(X)
26          y(i) = f(X(i)); % this f refers to the argument of quadvec
27        end
28      end
29    end

You can see that we make sure we call the integrand for each value separately and we achieve this by making our function handle "vectorized" by creating a function handle to a nested function, and using this new function, g as the integrand. Looking at g, you can see, starting on line 25, the we use a for loop to iterate over all the input values.

We're now ready to calculate the ellipse's area. Remember, since we are only working in one quadrant, we need to multiply the result by 4.

ellipseArea = 4 * quadvec(fh,0,a)
ellipseArea =
   37.6991

and we compare this to the analytic formula:

ellipseAreaAnalytic = pi*a*b
ellipseAreaAnalytic =
   37.6991

Do a little final housekeeping.

warning(s);

Summary

Today I showed you how to perform integration in higher dimensions in MATLAB with the introduction of quadvec. You can see that quadvec ensures that we call the integrand one element at a time to allow us to cover cases in which the integrand isn't vectorized. Note that you can use quadvec on an integrand in 1 dimension, but performance will probably be worse than using quadl, assuming the integrand is vectorized.


Published with MATLAB® 7.2

25 Responses to “Two-Dimensional Integration over a General Domain”

  1. Diego replied on :

    good

  2. Markus replied on :

    Hi!

    You are often making use of anonymous functions. Maybe you should state at some point that they are much slower than using a subfunction for the same task. Below I have put the code of a function that compares the cpu times in a simple example.

    Markus

    function testtime

    L = 2000;
    a = randn(L,10);

    time0 = cputime;
    for k=1:L
    x = arrayfun(@(x)sin(x), a(k,:));
    end
    disp(sprintf(’Elapsed time is %g seconds.’, cputime-time0))

    time0 = cputime;
    for k=1:L
    y = arrayfun(@subfun, a(k,:));
    end
    disp(sprintf(’Elapsed time is %g seconds.’, cputime-time0))

    function y = subfun(x)
    y = sin(x);

  3. Loren replied on :

    Performance of anonymous functions is sometimes less than for subfunctions currently. This is an area of performance (functions, nested functions, anonymous functions, and related) that we continue to work on. I find that for clariy and function signatures that show best the intent, nested and anonymous functions require less mental effort. The hope is that in future releases, the performance will continue to improve.

    For some functions, we strive to eke out the maximum performance, but if we do so at the expense of significantly reduced clarity, we must think hard. There tradeoffs are subjective.

  4. Ken Beard replied on :

    I’m a retired professor doing consulting on radar-raindrop relations. I have a choice of either resurrecting my decade-old Fortran programs or moving to a language like MatLab. My first hurdle in using Fortran is a call MSL to compute the surface area of a raindrop that is approximated as a triaxial ellipsoid. This allows me to explore possible normal modes of a raindrop having a given amount of oscillation energy that converts to surface energy at the oscillation end point of maximum area. Although I can find free Fortran compilers, the available IMSL seems to be unaffordable.

    If I convert to MatLab, then I would use your quadvec in three dimensions. Any suggestions?

    – Ken

  5. Loren replied on :

    triplequad ships as part of MATLAB. You might find that useful if you are integrating over fixed domains.

    –Loren

  6. Qi Chen replied on :

    Loren,

    This function is really useful.

    I have a little more complicated intergral problem:

    f(x,y) = x+y;

    I want to integrate f(x,y) with x varying from 0 to 1, and y varying from x to x+2;

    Could you please give me some hint how to use the function?

    This will solve a big problem for me!

    Thank you very much.

  7. Loren replied on :

    Qi Chen-

    Wouldn’t this do the trick?

    fh = @(x) quadl(@(y) x+y, x, x+2);
    % plot y as a function of x
    x = 0:1/100:1;
    y = arrayfun(fh, x);
    plot(x,y); title('x vs. y');
    triarea = quadvec(fh,0,1)
    

    –Loren

  8. Swadesh replied on :

    How do you multiply two anonymous functions with the same variable?The product has to go into the quad program.

  9. Loren replied on :

    Swadesh-

    I am not sure what you mean but here’s a way to multiply to anonymous functions.

    f = @(x) x;
    g = @(x) x+2;
    fg = @(x) f(x) * g(x)
    y = fg(3)
    
    OR
    
    y = f(3)*g(3)
    

    –Loren

  10. Diego replied on :

    Hi,
    I tried to apply your function when the 2-d integral depends on a third variable, that is to say:
    A=@(w) quadvec(fh,0,1);
    In this case the “vectorized” function depends on w,

    q =@(w)quadl(@(x)@g,varargin{:});
    function y =g(x,w)
    y = zeros(size(x));
    for i = 1:numel(x)
    y(i) = f{i}(x(i),w);(I wrote it like a cell array)
    end

    Unfortunately it doesn’t work…I can’t define q in an efficient way. May you give me any suggestion please?

  11. David Chi replied on :

    Dear Loren,

    I am not sure if this is a right place to post my question; however, my question is somehow related to this post.

    In my study, I need to numerically evaluate a quadruple integral. However, Matlab only offers built in functions up to triple integral. Can you offer me some suggestion, please?

  12. Loren replied on :

    David-

    Simply use the technique up above calling quadvec multiple times (i.e., have quadvec call quadvec, etc. up to your actual integrand).

    –Loren

  13. Ian replied on :

    Loren,

    How can I numerically integrate the function:

    exp(1/(|x|^2 - 1), where |x| is the length of x, and x is within R^N for N=1 and N=2

    I have been scratching my head trying to solve this problem and any help would be appreciated. Thanks

  14. Rajanikanth Jammalamadaka replied on :

    hi! Loren,
    In this post, theres a small typo:
    fh = @(x) quadl(@(y) x+y, x, x+2);
    % plot y as a function of x
    x = 0:1/100:1;
    y = arrayfun(fh, x);
    plot(x,y); title(’x vs. y’);
    triarea = quadvec(fh,0,1)

    I think the last line should be quadv(fh,0,1)
    Please let me know.

    Thanks

  15. Loren replied on :

    quadv does work. It was released after the original post. The quadvec code is available from the post itself. That last call is valid if you have made a copy of quadvec.

    –Loren

  16. Rajanikanth Jammalamadaka replied on :

    Sorry Loren. I should have paid more attention. Thank you.

  17. Thiri replied on :

    Hello,
    I am M.Res student in Yangon University.My thesis title is 2 dimension elliptic equations.I have one problem about the matlab program.My equation has constant no(a(x))and (u’(x,y))’.I cannot get a correct 2 dimension graph.I have boundary condition for constant “a”.N=4.h=1/N+1((0,1)*(0,1)),for j=1:(N+1)/2…..alpha(j)=1;
    for j=(N+1)/2+1:N+1…..alpha(j)=0.5;my equation is a’u'(x,y)+a(u’(x,y))’…..
    I hope you can give ur suggestion for me.
    I am waiting for your reply.
    your sincerely
    Thiri

  18. Kelly replied on :

    Hi Loren,

    Is there a way to perform double integration faster than using int(int(…)), where the limits of each integrand are different. I’m trying to perform double integration for a large array (2000×70), so by using the int(int(…)) approach, it is very time-consuming (~25min).

    Hope you can help.

    Best regards,
    Kelly

  19. Loren replied on :

    Kelly-

    int is for symbolic functions. You seem to have numeric values. I think there’s enough detail missing from your question that I can’t honestly help. I suggest you contact technical support with the entire M-file details.

    –Loren

  20. Shawn replied on :

    Loren,

    Is there a way to carry out integration without using the function commands?

    Thanks
    Shawn

  21. Loren replied on :

    Shawn-

    I don’t understand your question. I don’t know what a function command is.

    –Loren

  22. Angela replied on :

    Dear Loren,
    I want to numerically integrate a profit function with several integrales with the dblquad-command, therefore I ran two loops, and put the single variables from the loop as indices. The region I want to integrate is non-rectangular, that´s how I came to the quadvec-command. In the end I want to receive a big matrix of possible profits, where each element symbolizes a possible profit-outcome with the variables used from the loops. The variables from the loops are all integer and positives, but Matlab gives me the message: Subscript indices must either be real positive integers or logicals. I don´t really understand why. Therefore I tried to run my program with the quadvec-command which you posted here. But it gave the same error message. Do you have an idea, where I could have made a mistake?
    Thanks in advance
    Angela

  23. Loren replied on :

    Angela-

    I have no idea. You should use a debugger with your code to see if that helps. And if you are still stuck, you might work with technical support to sort out the issue.

    –Loren

  24. Vincent replied on :

    Dear Loren,

    I found some problems while using the quad function. For example, if I want to evaluate the expectation value of an exponential distributed variable, I approximately use the following:

    >> quadl(@(x) x.*exp(-x), 0, 100)

    ans =

    1.0000

    It works fine. However, 100 is just an approximation to infinity. So I wonder if I want a more precise answer, I should increase the upper limit. So I decide to use (0,1000). The answer is quite unexpected:

    >> quadl(@(x) x.*exp(-x), 0, 1000)

    ans =

    1.9164e-036

    Why does this happen?

    The same thing also happens when I use dblquad function:

    >> dblquad(@(x, y) y.*exp(-x).*exp(-y).*(y>a*x), 0, 100, 0, 100)

    ans =

    0.7500

    >> dblquad(@(x, y) y.*exp(-x).*exp(-y).*(y>a*x), 0, 1000, 0, 1000)

    ans =

    4.5183e-025

  25. Loren replied on :

    Vincent-

    I suspect it’s because the integration intervals widen when the integration limits widen, if the function is fairly flat, but might have some “peaks”, the peaks can be undersampled.

    You might to contact technical support for more detail.

    –Loren

Leave a Reply


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Ulla Vainio: That error bar width adjustment was extremely useful and I would never have figured it out myself....
  • Peter Perkins: Jessee, there is a property that you can use to tag variables with units. For example, >> load...
  • Jessee: I could potentially see myself using dataset for casually looking at data, but from an application standpoint...
  • Loren: Oktay- It very much depends on the details of the calculations you are doing. Vectorization can sometimes...
  • Oktay: Hello, Is there any significant difference between using: - Vectorization inside a subfunction - Benefiting...
  • Loren: Clare- Yes, sum can sum a double vector: x = [.3 .4 pi/3] y = sum(x) x = 0.3 0.4 1.0472 y = 1.7472 You must...
  • Clare J: R2007a - Student Version When I use sum to sum a vector of type double I get this error message: ???...
  • Sarah Zaranek: Hi Jacob, Sorry about the slow response. You are correct that the code would be slower without the...
  • Navaneethan Santhanam: Thanks a lot, Loren! That worked perfectly.
  • Mike N: Should it be OK to use “persistent 221; variables in a deployed application? What if I have two...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.

Related Topics