How to obtain explicit formula of coefficients for generating functions

233 views
Skip to first unread message

Melis Gezer

unread,
Jun 16, 2023, 10:42:41 PM6/16/23
to sympy
Is there any function to obtain an explicit formula of coefficients for generating functions?  

It should give, for example, (1/(n+1))C(2n,n) if I gave the generating function of Catalan numbers.


Oscar Benjamin

unread,
Jun 19, 2023, 4:29:52 PM6/19/23
to sy...@googlegroups.com
On Sat, 17 Jun 2023 at 03:42, Melis Gezer <melisg...@gmail.com> wrote:
>
> Is there any function to obtain an explicit formula of coefficients for generating functions?
>
> It should give, for example, (1/(n+1))C(2n,n) if I gave the generating function of Catalan numbers.

I don't understand exactly what you are asking for but if you have a
sequence a0, a1, a2, ... and the generating function is

f(x) = a0 + a1*x + a2*x**2 + ...

Then if you have a formula f_expr for f(x) you can find a formula for ai with

f_expr.diff(x, i).subs(x, 0)/factorial(i)

--
Oscar

David Bailey

unread,
Jun 19, 2023, 7:29:05 PM6/19/23
to sy...@googlegroups.com
I wonder if anyone here can explain why some mathematical functions -
e.g. sin and gamma evaluate completely if given a floating point
argument, while others such as besselj(0,0.2) only evaluate completely
if .evalf() is used.

Is this behaviour intentional?

Best Wishes,

David

Aaron Meurer

unread,
Jun 19, 2023, 7:47:42 PM6/19/23
to sy...@googlegroups.com
The automatic evalf logic in Function only calls evalf if every
argument is a float. It wasn't really designed for functions like
besselj where one argument is supposed to be an integer. It should
probably be updated to also automatically evalf if one argument is a
float and the rest are integers.

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/5da9b23e-4e62-9ff4-c643-8aa973b379c8%40dbailey.co.uk.

David Bailey

unread,
Jun 20, 2023, 6:34:17 AM6/20/23
to sy...@googlegroups.com
On 20/06/2023 00:47, Aaron Meurer wrote:
> The automatic evalf logic in Function only calls evalf if every
> argument is a float. It wasn't really designed for functions like
> besselj where one argument is supposed to be an integer. It should
> probably be updated to also automatically evalf if one argument is a
> float and the rest are integers.
>
Thanks Aaron for your fast reply!

I did wonder if I should replace the first argument by 0.0, but that
felt rather weird.

I hope nobody objects to that change.

David

David Bailey

unread,
Jul 2, 2023, 6:06:15 PM7/2/23
to sy...@googlegroups.com
Dear Group,

If I want to enter m+1/2, I define m as a symbol and write:

 m+S(1)/2.

However if I have a complicated expression with lots of fractions, such as:

1 + x*(m + 1/2)/(2*m + 1) + x**2*(m + 1/2)*(m + 3/2)/(2*(2*m + 1)*(2*m + 2))

it would be much neater if I could automatically wrap all the integers
in S so that no floating point numbers get introduced.

Is that feasible? I did try wrapping the whole expression in S, but that
does not work.

Best wishes,

David

Oscar Benjamin

unread,
Jul 2, 2023, 6:44:33 PM7/2/23
to sy...@googlegroups.com
You can wrap the whole expression in nsimplify:

>>> e = 1 + x*(m + 1/2)/(2*m + 1) + x**2*(m + 1/2)*(m + 3/2)/(2*(2*m
+ 1)*(2*m + 2))
>>> print(e)
x**2*(m + 0.5)*(m + 1.5)/((2*m + 2)*(4*m + 2)) + x*(m + 0.5)/(2*m + 1) + 1
>>> print(nsimplify(e))
x**2*(m + 1/2)*(m + 3/2)/((2*m + 2)*(4*m + 2)) + x*(m + 1/2)/(2*m + 1) + 1

The nsimplify function will attempt to guess what rational number a
float represents. In your example this is easy because all floats are
exactly represented in binary (having only twos in the denominator)
but otherwise the conversion can be inexact:

>>> f = 1/3
>>> f
0.3333333333333333
>>> print(Rational(f)) # exact value of the binary float
6004799503160661/18014398509481984
>>> nsimplify(f) # probably the value that the float was intended to have
1/3

https://docs.sympy.org/latest/modules/simplify/simplify.html#sympy.simplify.simplify.nsimplify

I normally use sympy through the command line isympy interface which
is a wrapper around ipython that provides an environment automatically
set up for using sympy. I don't use this myself but isympy has a -i
flag to interpret integer literals as sympy Integers (and therefore
integer division as rational division):

$ isympy -i
...
In [1]: 1/3
Out[1]: 1/3

In [2]: print(1 + x*(m + 1/2)/(2*m + 1) + x**2*(m + 1/2)*(m +
3/2)/(2*(2*m + 1)*(2*m + 2)))
x**2*(m + 1/2)*(m + 3/2)/((2*m + 2)*(4*m + 2)) + x*(m + 1/2)/(2*m + 1) + 1

I think that previous versions of SymPy Live would reinterpret 1/3 as
rational division in a similar way but that does not seem to be true
of the current version (maybe that was missed in the move to pyodide):

https://live.sympy.org/

--
Oscar

David Bailey

unread,
Jul 2, 2023, 7:16:18 PM7/2/23
to sy...@googlegroups.com
Thanks Oscar for that incredibly fast reply, but I'm not super keen on
algebra that is only probably correct!

David

Oscar Benjamin

unread,
Jul 3, 2023, 8:25:00 AM7/3/23
to sy...@googlegroups.com
Agreed but that means that you need to avoid creating floats in the
first place. Many users find it awkward to do this and prefer to use
nsimplify.

Another option is to call S with a string::

In [27]: s = '1 + x*(m + 1/2)/(2*m + 1) + x**2*(m + 1/2)*(m +
3/2)/(2*(2*m + 1)*(2*m + 2))'

In [28]: print(S(s))
x**2*(m + 1/2)*(m + 3/2)/((2*m + 2)*(4*m + 2)) + x*(m + 1/2)/(2*m + 1) + 1

--
Oscar

gu...@uwosh.edu

unread,
Jul 3, 2023, 9:44:07 AM7/3/23
to sympy
David,

I want to make sure I understand the behavior you would prefer, because I think I can implement it in algebra-with-sympy. The package already does some pre-parsing, so I think I could handle it there.

Here is what I think you are asking for:
1. Any number that is not in scientific notation and does not contain a decimal point would be considered an integer and be converted to S().
2. All other numerical values would be treated as they normally are.

Is that all you are asking for or do you need something more sophisticated?

As more of these usage questions come up, I am beginning to wonder if sympy needs an interactive mode that implements sensible/useful extensions and defaults that would get in the way of sympy's use as a symbolic manipulation back-end? The idea would be to have these features only turned on in the interactive mode.

Jonathan

gu...@uwosh.edu

unread,
Jul 3, 2023, 10:04:12 AM7/3/23
to sympy
The documentation for  isympy mode is not good. When I search the sympy docs I find this
https://docs.sympy.org/latest/modules/interactive.html. I am do not find anything about the -i option on this page.

A general web search turns up this old command line doc which also does not document the -i option. The only thing that is clear is some predefined symbols and automatic symbol creation.
None of the other links from the search are any better.

It looks like isympy is close to the sensible convenience mode I am suggesting. However, it needs to be identified and documented much more clearly. It probably should be in the introductory material.

>I normally use sympy through the command line isympy interface which
is a wrapper around ipython that provides an environment automatically
set up for using sympy. I don't use this myself but isympy has a -i
flag to interpret integer literals as sympy Integers (and therefore
integer division as rational division):

>$ isympy -i

David Bailey

unread,
Jul 3, 2023, 11:51:08 AM7/3/23
to sy...@googlegroups.com
On 03/07/2023 13:24, Oscar Benjamin wrote:
> Another option is to call S with a string::
> In [27]: s = '1 + x*(m + 1/2)/(2*m + 1) + x**2*(m + 1/2)*(m +
> 3/2)/(2*(2*m + 1)*(2*m + 2))'
>
> In [28]: print(S(s))
> x**2*(m + 1/2)*(m + 3/2)/((2*m + 2)*(4*m + 2)) + x*(m + 1/2)/(2*m + 1) + 1
>
> --
> Oscar
>
Thanks Oscar, that is a much more useful feature!


BTW, I couldn't see it mentioned in the documentation for S(), and I
think it should definitely also be mentioned in the section of of the
SymPy documentation that discusses the problem with Python evaluating
expressions like 1/2 in an unhelpful way.

David

David Bailey

unread,
Jul 3, 2023, 12:05:27 PM7/3/23
to sy...@googlegroups.com
On 03/07/2023 14:44, gu...@uwosh.edu wrote:
David,

I want to make sure I understand the behavior you would prefer, because I think I can implement it in algebra-with-sympy. The package already does some pre-parsing, so I think I could handle it there.

Here is what I think you are asking for:
1. Any number that is not in scientific notation and does not contain a decimal point would be considered an integer and be converted to S().
2. All other numerical values would be treated as they normally are.


Yes, that describes what I want completely!

I wonder if you should ban exponential notation completely from your tool except for a final step in which real numbers might be substituted into an expression?

I mean 3e4 looks very confusing in an algebraic expression, and if you permit implicit multiplication as in hand algebra it is ambiguous. Anyway performing algebra with expressions containing real numbers is decidedly dangerous.

Davis

gu...@uwosh.edu

unread,
Jul 3, 2023, 12:38:28 PM7/3/23
to sympy
3e4 in sympy pretty printing is output as a decimal number. At somewhere greater that 10^10 pretty printing switches to scientific notation with a • in sympy.

In the code cells I insist on using * for multiplication to avoid any questions about implicit multiplication and multi-character variable names. I think I will continue to do that.

Entering 3.2e4 as (3.2*10**4) also works. If you are running with integer recognition and the mantissa is entered as an integer the value will be treated as an integer in the case where you write it out.

Jonathan

Aaron Meurer

unread,
Jul 5, 2023, 4:40:49 PM7/5/23
to sy...@googlegroups.com
For interactive use, just passing a string to S() (or equivalently
sympify() or parse_expr()) is the simplest way to deal with this.
However, I would avoid this for non-interactive usage (i.e., any code
that gets saved to be executed later). Putting your expression in a
string breaks the ability for Python to parse it directly, meaning
things like simple syntax errors won't be caught until the code gets
run.

You should also be very careful when doing this if you use
assumptions. S("x + 1") will create a symbol x with the default
assumptions. If you already defined x with assumptions, like

x = symbols('x', real=True)

then this will be a *different* symbol. For example:

>>> x = symbols('x', real=True)
>>> expr = S("x + 1")
>>> x + expr
x + x + 1

This can lead to all sorts of confusion. So really only use string
input if you are very careful about these issues.

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/CAHVvXxT4LpkgZfdiKrvzxxENB24cRKUUx88ZLeBKp8ZZwsKJhA%40mail.gmail.com.

David Bailey

unread,
Jul 6, 2023, 6:15:16 PM7/6/23
to sy...@googlegroups.com
On 05/07/2023 21:40, Aaron Meurer wrote:
> For interactive use, just passing a string to S() (or equivalently
> sympify() or parse_expr()) is the simplest way to deal with this.
> However, I would avoid this for non-interactive usage (i.e., any code
> that gets saved to be executed later). Putting your expression in a
> string breaks the ability for Python to parse it directly, meaning
> things like simple syntax errors won't be caught until the code gets
> run.
>
> You should also be very careful when doing this if you use
> assumptions. S("x + 1") will create a symbol x with the default
> assumptions. If you already defined x with assumptions, like
>
> x = symbols('x', real=True)
>
> then this will be a *different* symbol. For example:

Thanks for that caution, Aaron,

This whole problem reminds me vaguely of a friend of mine that bought an
early Sinclair calculator. He discovered that ln(2) was seriously
inaccurate, so he wrote to them. They replied that there was nothing
wrong with his calculator, he had just chosen an unfortunate example!

What I'm trying to say is that there must be people out there who gave
given up on SymPy after discovering what it does to 1/2*x, or worse
still, got an error in their work (particularly if using Python 2).

Thinking about it, I can see how hard it is to do something really
effective about this problem, but couldn't you prevail on the Python
term to insert a hook in the Python parser to make it possible to change
an input string before Python parses it and applies its integer division
rule?

David

Aaron Meurer

unread,
Jul 7, 2023, 4:32:38 AM7/7/23
to sy...@googlegroups.com
On Thu, Jul 6, 2023 at 4:15 PM David Bailey <da...@dbailey.co.uk> wrote:
>
> On 05/07/2023 21:40, Aaron Meurer wrote:
> > For interactive use, just passing a string to S() (or equivalently
> > sympify() or parse_expr()) is the simplest way to deal with this.
> > However, I would avoid this for non-interactive usage (i.e., any code
> > that gets saved to be executed later). Putting your expression in a
> > string breaks the ability for Python to parse it directly, meaning
> > things like simple syntax errors won't be caught until the code gets
> > run.
> >
> > You should also be very careful when doing this if you use
> > assumptions. S("x + 1") will create a symbol x with the default
> > assumptions. If you already defined x with assumptions, like
> >
> > x = symbols('x', real=True)
> >
> > then this will be a *different* symbol. For example:
>
> Thanks for that caution, Aaron,
>
> This whole problem reminds me vaguely of a friend of mine that bought an
> early Sinclair calculator. He discovered that ln(2) was seriously
> inaccurate, so he wrote to them. They replied that there was nothing
> wrong with his calculator, he had just chosen an unfortunate example!
>
> What I'm trying to say is that there must be people out there who gave
> given up on SymPy after discovering what it does to 1/2*x, or worse
> still, got an error in their work (particularly if using Python 2).

No one should be using Python 2 at this point. So fortunately that
particular headache is behind us.

>
> Thinking about it, I can see how hard it is to do something really
> effective about this problem, but couldn't you prevail on the Python
> term to insert a hook in the Python parser to make it possible to change
> an input string before Python parses it and applies its integer division
> rule?

That particular way of solving the problem would very likely be
rejected. It's basically equivalent to adding macros to the language,
which has been rejected multiple times before.

I have wondered if it wouldn't be possible for Python to keep track of
how purely numeric constants are created at compile time and store
that information on the constant. Since it would only apply to pure
numbers and would only happen at compile time, it would have basically
no runtime penalties. That would also allow something like
1.0000000000000000001, which automatically truncates to 1.0, to create
sympy.Float('1.0000000000000000001'). But it's only a vague idea I've
ruminated on and I haven't written to the core Python team about it.

Aaron Meurer

>
> David
>
> --
> 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/d6b19b21-d61c-e4f8-3116-f5f64ac6ab48%40dbailey.co.uk.

Isuru Fernando

unread,
Jul 7, 2023, 5:09:50 AM7/7/23
to sy...@googlegroups.com
Hi David,

You could write a simple converter to convert all ints to sympy Integers
if you are writing the code inside a function. See code below.

Isuru


import sympy
from sympy.interactive.session import int_to_Integer
import inspect
import types

def use_sympy_ints(f):
    # https://stackoverflow.com/q/57480368/4768820
    source = inspect.getsource(f)
    source = '\n'.join(source.splitlines()[1:]) # remove the decorator first line.
    old_code_obj = f.__code__
    new_ast= int_to_Integer(source)
    new_code_obj = compile(new_ast, old_code_obj.co_filename, 'exec')
    g = dict(f.__globals__)
    g['Integer'] = sympy.Integer
    new_f = types.FunctionType(new_code_obj.co_consts[0], g)
    return new_f

@use_sympy_ints
def foo(x):
    return x + 1 / 2

David Bailey

unread,
Jul 7, 2023, 4:41:07 PM7/7/23
to sy...@googlegroups.com
On 07/07/2023 10:09, Isuru Fernando wrote:
> Hi David,
>
> You could write a simple converter to convert all ints to sympy Integers
> if you are writing the code inside a function. See code below.
>
> Isuru
>
Thanks, I can solve this problem to my satisfaction, but my main
concern, as a pointed out to Aaron, is that SymPy may get a bad
reputation among those who explore it cursorily. The point is, it can
give peculiar answers, which is analogous to my friend's problem with
his Sinclair calculator. The Sinclair folk could (presumably) explain in
detail why that result was bad, but my friend wasn't keen on using his
new flashy gadget any more. I think they were the first cheap
calculators to provide a full set of transcendental functions, so it was
very unfortunate.

David

gu...@uwosh.edu

unread,
Jul 7, 2023, 6:23:25 PM7/7/23
to sympy
David,

I will work to get this into Algebra_with_Sympy quickly. I will post when I complete the next release.

Since these ease of use issues are not cleanly addressable within SymPy proper, maybe you can think of Algebra_with_SymPy as your interactive front-end for sympy.

Jonathan

David Bailey

unread,
Jul 8, 2023, 5:39:46 AM7/8/23
to sy...@googlegroups.com
On 07/07/2023 23:23, gu...@uwosh.edu wrote:
> David,
>
> I will work to get this into Algebra_with_Sympy quickly. I will post
> when I complete the next release.
>
> Since these ease of use issues are not cleanly addressable within
> SymPy proper, maybe you can think of Algebra_with_SymPy as your
> interactive front-end for sympy.
>
I thought you wrote that you already wrapped integers in S() if the -i
option was specified. Do you just mean that you would make -i the default?

Can Algebra_with_SymPy operate as a frontend to SymPy in general?

David

Message has been deleted

gu...@uwosh.edu

unread,
Jul 9, 2023, 12:39:45 AM7/9/23
to sympy
David,

I hope this message is not a repeat. The one I wrote in reply seems to have been deleted.

So briefly:
1. Currently Algebra_with_Sympy does not interpret numbers without decimals as sympy integers, but I have got a working draft that does. I just need to finish updating the tests and documentation, before making a new release.
2. You can use Algebra_with_Sympy as a front-end for Sympy. You can ignore the `Equation` class and just do normal SymPy syntax. There are a some differences in what outputs look like. See the documentation about output formatting.

Jonathan

gu...@uwosh.edu

unread,
Jul 12, 2023, 4:49:11 PM7/12/23
to sympy
Algebra_with_Sympy release v0.12.0 is now available. It now interprets numbers without decimals as sympy integers. This feature can be turned on and off.

emanuel.c...@gmail.com

unread,
Jul 13, 2023, 6:23:25 AM7/13/23
to sympy

Le mercredi 12 juillet 2023 à 22:49:11 UTC+2, gu…@uwosh.edu a écrit :

Algebra_with_Sympy release v0.12.0 is now available. It now interprets numbers without decimals as sympy integers. This feature can be turned on and off.

Are you trying to reinvent Sage’s preparser ?

Jonathan Gutow

unread,
Jul 13, 2023, 8:44:48 AM7/13/23
to sy...@googlegroups.com


On Jul 13, 2023, at 5:23 AM, emanuel.c...@gmail.com <emanuel.c...@gmail.com> wrote:


CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.


Le mercredi 12 juillet 2023 à 22:49:11 UTC+2, gu…@uwosh.edu a écrit :



Algebra_with_Sympy release v0.12.0 is now available. It now interprets numbers without decimals as sympy integers. This feature can be turned on and off.


Are you trying to reinvent Sage’s preparser ?

Not really. I have used Sage math in the past, maintained a local server that I used with students and even contributed code for 3D visualization when Sage was primarily using Jmol/JSmol for that. However, I found that Sage was less appropriate for use with my chemistry students and much more heavy-weight than a simple SymPy installation. Additionally, in my field instructors are sharing many notebooks based on SymPy that are only partially Sage compatible. 

The features Algebra_with_SymPy layers on top of SymPy are those that the physical science community (physical chemistry in particular) have asked for. Most of the features do not involve the preparser and those that do and are similar to Sage’s features are only incidentally so. I have also been developing this with an eye towards it being useful for the Jupyter Physical Science Lab Project (https://jupyterphysscilab.github.io/Documentation/), which aims to be an electronic laboratory notebook which can support acquisition of analog data directly into the Jupyter notebooks along with symbolic math, numerical data analysis and textual notes, while being simple enough to use in introductory level college science courses. I also needed something that ran well on computers as low powered as the Raspberry Pi.

I have been trying to get approval to include the core feature of Algebra_with_Sympy (the Equation class) in SymPy, but the community has not reached a consensus on how some of the features should behave. See https://github.com/sympy/SymPEPs/pull/1/files.

Is there some feature overlap with Sage math? Yes. Do I wish to duplicate Sage math? No. For the use cases I primarily encounter I do not need the full power or complexity of Sage math, so I find the combination of Sympy + Algebra_with_Sympy is more appropriate. I like Sage and recommend it to people for more sophisticated uses than I have.

Jonathan

--
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.
Reply all
Reply to author
Forward
0 new messages