I'm CCing Tom Bachmann, since he wrote the original code.

+1 for exposing a function that can rewrite expressions to hyper or meijerg
as a public function (perhaps just expr.rewrite(hyper) and
expr.rewrite(meijerg)).

Aaron Meurer

On Wed, Jan 27, 2016 at 10:14 PM, Ondřej Čertík <ondrej.cer...@gmail.com>
wrote:

> On Wed, Jan 27, 2016 at 4:30 PM, Ondřej Čertík <ondrej.cer...@gmail.com>
> wrote:
> > On Wed, Jan 27, 2016 at 3:34 PM, Ondřej Čertík <ondrej.cer...@gmail.com>
> wrote:
> >> Hi,
> >>
> >> Our Meijer G-function integrator can find integrals (definite and
> >> indefinite) of any function that can be expressed as a Meijer
> >> G-function thanks to the formulas here:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/ShowAll.html
> >>
> >> I.e. an integral of a Meijer G-function is also a Meijer G-function.
> >> The definite integral has tons of conditions that SymPy checks, but
> >> the formula for the indefinite integral (i.e. the antiderivative)
> >> always holds.
> >>
> >> Then one converts the final Meijer G-function into elementary
> >> functions if possible, or leaves it as is if it is not possible. This
> >> part is robust.
> >>
> >> What is not robust is how to rewrite a given function into a Meijer
> >> G-function. This is done by the `meijerint._rewrite1` function (btw,
> >> we should expose it as a public function). For example:
> >>
> >> In [1]: meijerint._rewrite1((cos(x)/x), x)
> >> Out[1]: (1, 1/x, [(sqrt(pi), 0, meijerg(((), ()), ((0,), (1/2,)),
> >> x**2/4))], True)
> >>
> >> In [2]: meijerint._rewrite1((sin(x)/x), x)
> >> Out[2]: (1, 1/x, [(sqrt(pi), 0, meijerg(((), ()), ((1/2,), (0,)),
> >> x**2/4))], True)
> >>
> >> In [3]: meijerint._rewrite1((cos(x)/x)**2, x)
> >>
> >> In [4]: meijerint._rewrite1((sin(x)/x)**2, x)
> >> Out[4]:
> >> (1,
> >>  x**(-2),
> >>  [(sqrt(pi)/2, 0, meijerg(((0,), (1/2, 1/2, 1)), ((0, 1/2), ()),
> x**(-2)))],
> >>  True)
> >>
> >> In [3] it didn't find the solution, yet a similar expression involving
> >> sin(x) instead of cos(x) works in [4].
> >>
> >> Let's figure out a systematic algorithm. For that, you start with the
> >> elementary functions, that would be sin(x), cos(x) and "x" in the
> >> above expression, look their G-function representation, and then use
> >> the *, /, +, - and ** operations on the G-functions, that's it.
> >>
> >> Now the problem is, that there doesn't seem to be a formula for a
> >> product of two G functions, e.g. I didn't see one here:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/MeijerG/16/ShowAll.html
> >>
> >> the formula
> http://functions.wolfram.com/HypergeometricFunctions/MeijerG/16/02/01/0001/
> >> that you see there only seems to be using some even more generalized G
> >> function of two variables? It doesn't seem to be useful here. Can
> >> someone confirm that one cannot express a product of two G-functions
> >> as a G-function?
> >>
> >> So a solution is to simply have a robust method to rewrite any
> >> expression as a hypergeometric function and then use the formula here
> >> to convert the hypergeometric function to a G-function:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/HypergeometricPFQ/26/03/01/0001/
> >>
> >> There are just a few functions that can be expressed as a G-function
> >> but not as a hypergeometric function, some examples are: Bessel
> >> functions Y, K (for integer order), Whittaker function W, Legendre
> >> function Q_mu_nu and a few others. So for these functions we have to
> >> figure out something else, probably something that we do now.
> >>
> >> Also we can then use the integration formulas here for hypergeometric
> >> functions, so we don't even have to go via G-functions:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/HypergeometricPFQ/21/ShowAll.html
> >>
> >> It seems the conditions on definite integration are a lot simpler as
> well.
> >>
> >>
> >> So here is the algorithm for hypergeometric functions, I'll show it on
> >> the (sin(x)/x)**2 example above:
> >>
> >> 1) sin(x) = x * 0F1(3/2; -x^2/4)
> >>
> >> 2) sin(x) / x = 0F1(3/2; -x^2/4)
> >>
> >> 3) (sin(x)/x)**2 = 0F1(3/2; -x^2/4) * 0F1(3/2; -x^2/4) = 2F3(3/2,1;
> >> 3/2,3/2,2; -x^2)
> >>
> >> Where we used the formula for a product of two 0F1 functions:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/16/ShowAll.html
> >>
> >> 4) Finally, rewrite 2F3(3/2,1; 3/2,3/2,2; -x^2) as a G-function, or
> >> integrate directly.
> >>
> >>
> >> A general formula for multiplication of two hypergeometric series is
> here:
> >>
> >>
> http://functions.wolfram.com/HypergeometricFunctions/HypergeometricPFQ/16/ShowAll.html
> >>
> >> But I can see now that this only expresses the result as a Taylor
> >> series. So maybe I just got lucky that the multiplication of two 0F1
> >> functions exists (in terms of 2F3), but there is no such formula for a
> >> general PFQ function. Can someone confirm this?
> >>
> >> So then the other idea is that one can identify a hypergeometric
> >> function from the series expansion. Essentially, we expand into a
> >> series, calculate the ratio t_{k+1}/t_k of two successive terms, and
> >> if it is a rational function of "k", then it is a hypergeometric
> >> function and you read the coefficients directly. Let's do the same
> >> example again:
> >>
> >> 1) sin^2(x) = Sum(((-1)**(k - 1)* 2**(2* k - 1)*
> >> x**(2*k))/factorial(2*k), (k, 1, oo))
> >>
> >> 2) (sin(x)/x)**2 = sin^2(x)/x^2 = Sum(((-1)**(k - 1)* 2**(2* k - 1)*
> >> x**(2*k-2))/factorial(2*k), (k, 1, oo))
> >> = Sum(((-1)**k * 2**(2*k+1) * x**(2*k))/factorial(2*k+2), (k, 0, oo))
> >> = Sum((2**(2*k+1) * (-x**2)**k))/factorial(2*k+2), (k, 0, oo))
> >>
> >> So the series is of the form sum_k t_k*(-x^2)^k where
> >>
> >> t_k = 2**(2*k+1)/factorial(2*k+2)
> >>
> >> 3) Calculate t_{k+1} / t_k:
> >>
> >> In [78]: t_k = 2**(2*k+1)/factorial(2*k+2)
> >>
> >> In [79]: t_k.subs(k, k+1) / t_k
> >> Out[79]: 2**(-2*k - 1)*2**(2*k + 3)*factorial(2*k + 2)/factorial(2*k +
> 4)
> >>
> >> In [80]: _.simplify()
> >> Out[80]: 2/((k + 2)*(2*k + 3))
> >>
> >> We write the last formula as:
> >>
> >> 2/((k + 2)*(2*k + 3)) =  (k+1) / ((k+3/2)*(k+2)*(k+1))
> >>
> >> And we read off the hypergeometric function as 1F2(1; 3/2, 2; -x^2).
> >
> > Btw, this procedure is explained at the page 36 of the freely
> > available A=B book, together with many examples:
> >
> > https://www.math.upenn.edu/~wilf/Downld.html
> >
> > As they show, one can definitely determine if a given series is
> > hypergeometric (and find the function) or not. So the only hard part
> > is to find the series expansion of the final expression in closed form
> > (i.e. as an infinite sum, but have a closed form expression for each
> > coefficient) and then apply this algorithm.
> >
> > Looking at the chapters 4 and 5, I think we can actually make use of
> > the general multiplication formula here:
> >
> >
> http://functions.wolfram.com/HypergeometricFunctions/HypergeometricPFQ/16/ShowAll.html
> >
> > Since it takes two general hypergeometric functions, multiplies them
> > and writes the result as an infinite series: Sum(c_k * z**k, (k, 0,
> > oo)), where the coefficients c_k are given using a hypergeometric
> > function. Then we apply the algorithm from page 36 to determine
> > whether or not this sum can be written as a hypergeometric function,
> > and if so, which one (i.e. by calculating and simplifying
> > c_{k+1}/c_k). So this is what we need to implement. And the chapters 4
> > and 5 also treat similar sums, where the c_k coefficients are given
> > using a hypergeometric function.
>
> Here is a script that implements it:
>
> https://gist.github.com/certik/a47e2040d9a44812e2f2
>
> I tested a few examples (see the commented out lines in the script)
> and it works as expected.
>
> One starts with two hypergeometric sequences, it calculates the
> coefficients in the infinite series of the product, then calculates
> the ratio. E.g. for the example above the ratio is:
>
> -gamma(k + 3/2)/((k + 2)*gamma(k + 5/2))
>
> It would be nice if sympy could simplify it to:
>
> -1/((k + 2)*(k+3/2)) = -(k+1)/((k + 2)*(k+3/2)*(k+1))
>
> But in the meantime I simply read the hypergeometric function manually
> in the script as hyper([1], [2, S(3)/2], -z) in this case. Then the
> script compares the series expansions to show that it works.
>
> So I think this is a viable approach.
>
> Ondrej
>
>
>
> P.S. One thing that I don't understand is the cos^2(x) case. The
> general formula is:
>
> 0F1^2(b; z) = 2F3(b, b-1/2; b, b, 2b-1; 4z) = 1F2(b-1/2; b, 2b-1; 4z)
>
> E.g. for sin(x)/x we have b=3/2 and get 0F1^2(3/2; -x^2/4) = 1F2(1;
> 3/2, 2; -x^2), consistent with above. But for cos(x) we get b=1/2 and:
>
> cos^2(x) = 0F1^2(1/2; -x^2/4) = 1F2(0; 1/2, 0; -x^2)
>
> Which is not well defined. However, I have experimentally found out, that:
>
> cos^2(x) = 0F1(1/2; -x^2) + x^2*1F2(1; 3/2, 2; -x^2)
>
> >>> hyperexpand(hyper([], [S(1)/2], -x**2) + x**2*hyper([1], [S(3)/2, 2],
> -x**2)).trigsimp()
> cos(x)**2
>
> The script for this case returns a ratio of:
>
> -gamma(k + 1/2)/((k + 1)*gamma(k + 3/2)) = -1/((k+1)*(k+1/2))
>
> Which would suggest 0F1(1/2; -x^2) as the solution, but that is incorrect:
>
> >>> hyperexpand(hyper([], [S(1)/2], -x**2))
> cos(2*x)
>
> since cos(2*x) = cos^2(x) - sin^2(x) and one needs to add
> sin^2(x)=x^2*1F2(1; 3/2, 2; -x^2) to it, as shown above. Since this
> case is essentially a linear combination of hypergeometric functions,
> maybe something in the algorithm fails. I would expect the ratio to
> return something that is not a rational function, since the result is
> not just one hypergeometric function. One would have to look into this
> more.
>
> --
> 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+unsubscr...@googlegroups.com.
> To post to this group, send email to sympy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sympy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sympy/CADDwiVBm6KhcTOkf8Smo86Ucro5CAx6LOLeCRpzYZ5wNu8paqg%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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+unsubscr...@googlegroups.com.
To post to this group, send email to sympy@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/CAKgW%3D6%2Ba6T2E5W1OSTeudkSfCEOAfhJCkvYG_hGFK-6A6eNR4w%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to