Manipulation of integrals using set operations on the integration domains

112 views
Skip to first unread message

Michael Gfrerer

unread,
Jun 4, 2024, 6:02:08 PM6/4/24
to sympy
I would be interested in doing symbolic manipulation of integrals involving unevaluated functions and symbolic integration domains. A simplified problem looks like:


I can "typeset" the left-hand-side by:

from sympy import *
x = Symbol('x')
u = Function('u')(x)
lhs = integrate(u, (x, 'Omega',)) + integrate(u, (x, Symbol(r'D \setminus \Omega'),))

Obviously, it is not possible to simplify the lhs. Is there a object in Sympy for D and \Omega to enable this?

Michael Gfrerer

unread,
Jun 5, 2024, 2:36:14 AM6/5/24
to sympy
One more try for the image:
setSimplify.png

Aaron Meurer

unread,
Jun 5, 2024, 3:20:51 PM6/5/24
to sy...@googlegroups.com
Not presently. There are objects representing sets in SymPy, but there isn't anything to represent an integral over a set. The current Integral class is hard-coded to support indefinite integrals or standard definite integrals over signed intervals.

You could make your own version of such a thing by making a custom subclass of Expr. The question is what sort of operations you'd want the object to support. 

Aaron Meurer

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/09620b17-56ea-4427-be28-7130887f243cn%40googlegroups.com.

Sangyub Lee

unread,
Jun 6, 2024, 9:19:40 AM6/6/24
to sympy
I think that there are other problems.
If we generalize the domain of integral to set, it gives incompatible definition that what we had done before.

For example, Integral(f(x), (x, a, b)) and Integral(f(x), (x, b, a)) should have same value if you represent the domain as set, because the set is unordered,
however, we lose the identity Integral(f(x), (x, a, b)) == -Integral(f(x), (x, b, a)) which had holded before

Aaron Meurer

unread,
Jun 6, 2024, 4:24:11 PM6/6/24
to sy...@googlegroups.com
I would make it a distinct object, so there isn't a relationship to the usual signed Integral. The object would represent something like a Lebesgue integral over a measurable set. There would also be expressions where the integral might not be well-defined, so it would have to make certain assumptions about the input. 

Of course, to actually compute things, it might need to convert the integral into a usual multidimensional signed Integral, since that is what SymPy knows how to work with. Although SymPy's ability to operate on multidimensional integrals is fairly limited and there might be better algorithms that can be implemented there anyways. 

Aaron Meurer

Michael Gfrerer

unread,
Jun 11, 2024, 8:01:48 AM6/11/24
to sympy
Thanks for your answers. I was thinking of making a custom class, but wanted to be sure I wasn't reinventing the wheel.
I made a first attempt to define a custom class, but I stumbled upon an issue with eval and simplify. If the integrand is 0 the whole integral can be set to 0.
So I tried the followiung code without success:

import sympy as sp
class LebesgueIntegral(sp.Expr):
    def _latex(self, printer, exp=1):
        m, n, l = self.args
        _m, _n, _l = printer._print(m), printer._print(n), printer._print(l)
        return r'\int_{%s} %s \,d%s' % (_m, _n, _l)

    @classmethod
    def eval(cls, m, n, l):
        if n == 0:
            return 0

    def _eval_simplify(self, **kwargs):
        if self.args[1] == 0:
            return 0
        return self

u = LebesgueIntegral(sp.Symbol('\Omega'), sp.sympify(0),sp.Symbol('x'))
print(sp.latex(u))
print(sp.simplify(u))
print(sp.simplify(2*u))

The above code gives me the output:
\int_{\Omega} 0 \,dx
0
2*LebesgueIntegral(\Omega, 0, x)

Why is the method eval not called in the first print statement?
I had a look at the simplify module but it is very hard for me to understand. Is it intended that the simplify method of the class is not called in the third print statement?

Michael Gfrerer

Aaron Meurer

unread,
Jun 11, 2024, 3:59:01 PM6/11/24
to sy...@googlegroups.com
eval() is only available for Function subclasses. For Expr subclasses,
you have to define __new__, which unfortunately isn't as convenient as
eval(). A basic version would look something like

def __new__(cls, m, n, l):
m, n, l = _sympify(m), _sympify(n), _sympify(l)
if n == 0:
return S.Zero
return Expr.__new__(cls, m, n, l)

Note that you need to manually handle making sure inputs and outputs
are SymPy types. I would suggest looking at the source code for
Integral.__new__ and ExprWithLimits.__new__.

Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/4f46ffe4-e4ca-4d14-bcb5-2402574af17dn%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages