Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

analytic combinatorics: new code for computing asymptotics for multivariate generating functions #10519

Closed
sagetrac-araichev mannequin opened this issue Dec 22, 2010 · 167 comments

Comments

@sagetrac-araichev
Copy link
Mannequin

sagetrac-araichev mannequin commented Dec 22, 2010

This code is a collection of functions designed
to compute asymptotics of Maclaurin coefficients of certain classes of
multivariate generating functions.

The main function asymptotics() returns the first N terms of
the asymptotic expansion of the Maclaurin coefficients F_{n\alpha}
of the multivariate meromorphic function F=G/H as n\to\infty.
It assumes that F is holomorphic in a neighborhood of the origin,
that H is a polynomial, and that asymptotics in the direction of
\alpha (a tuple of positive integers) are controlled by smooth
or multiple points.

CC: @sagetrac-cyril-banderier @zafeirakopoulos @sagetrac-tmonteil @dkrenn @behackl

Component: combinatorics

Keywords: analytic combinatorics, multivariate generating functions

Author: Daniel Krenn, Alex Raichev

Branch/Commit: a951f08

Reviewer: Daniel Krenn, David Loeffler, Travis Scrimshaw

Issue created by migration from https://trac.sagemath.org/ticket/10519

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Dec 22, 2010

Attachment: mgf.sage.gz

@sagetrac-araichev sagetrac-araichev mannequin modified the milestones: sage-4.6.2, sage-4.6.1 Dec 22, 2010
@rbeezer
Copy link
Mannequin

rbeezer mannequin commented Dec 27, 2010

comment:2

Hi Alex,

I can't address the mathematics on this one, but can give some hints about getting this reviewed.

  1. You'll want to submit this as a patch - then folks can run the doctests, check the documentation formatting. There is a lot of checking that can't happen easily with a *.sage file. (See below.) Read the "Walk Through" section of the developer guide for help.

  2. Your examples need slightly different formatting, like

    EXAMPLES::

        sage: input 1
        output-1

    Something nice to say. ::

        sage: input-2
        output-2

Double-colons start verbatim blocks and sometimes print as colons.

Sage code samples needs indentation.

  1. Sage is mostly object-oriented. "Internal" method names should begin with an underscore, then they won't show in tab-completion etc (Python convention).

All your functions won't be available in teh global namespace (where they could conflict with other). You should find an object (like maybe some kind of polynomial, especially if it is already int eh combinatorial library?) and make your functions be methods on that object.

Thanks for your contribution - I hope the above is helpful for you.

Rob

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jan 5, 2011

comment:3

Question for you experienced Sage developers: how can i better package my code?

I think it makes sense to move the major functions such as 'asymptotics' to methods in the class /Applications/sage/devel/sage/sage/rings/polynomial/multi_polynomial.pyx, but what about the subsidiary functions that don't concern polynomials in particular such as 'diff_prod' which calculates derivatives of products and solves equations?

@seblabbe
Copy link
Contributor

comment:4

Question for you experienced Sage developers: how can i better package my code?

Hi, I am currently at Sage Days 28. Right now, there is a discussion about
Analytic combinatorics in Sage and your code was mentionned in the discussion.
I am not an expert of the domain, but I am coding oriented object Python since
some time now. So below are just some of my thoughts to, I hope, help you turn
your set of functions into an oriented object structure.

How to structure a bunch of functions into classes? How to find which objects
(python classes) you need? Here is the trick I personaly use. Consider each of
your functions as a question you ask. Then, ask yourself to who are you asking
each of your questions? Answers often gives you a good hint about the objects
you need to implement. EXAMPLE. Suppose I code the function determinant.
Question : To who do I ask the determinant?. Answer: To a matrix.
Hence, matrix might be a good object (a python class) to implement.

You are the best person to answer to these questions. You might have 30
functions in you file, but only two or three different answers to the above
question. Regroup the similar functions together: they will become the methods
of a same class.

The sage file you uploaded starts with :

> This code relates to analytic combinatorics.
> More specifically, it is a collection of functions designed
> to compute asymptotics of Maclaurin coefficients of certain classes of
> multivariate generating functions.

> The main function asymptotics() returns the first `N` terms of
> the asymptotic expansion of the Maclaurin coefficients `F_{n\alpha}`
> of the multivariate meromorphic function `F=G/H` as `n\to\infty`.
> It assumes that `F` is holomorphic in a neighborhood of the origin,
> that `H` is a polynomial, and that asymptotics in the direction of
> `\alpha` (a tuple of positive integers) are controlled by smooth
> or multiple points.

Reading only these lines, I imagine the following structure:

class HolomorphicMultivariateMeromorphicFunction(object):

    # Constructor of the object
    def __init__(self, F, G):
        #stores important information on the object as attributes of self
        self._F = F
        self._G = G

    def maclaurin_coefficients(self, n, alpha):
        r"""
        Return the maclaurin coefficients of self.

        INPUT:

        - ``alpha`` - tuple of positive integers

        OUTPUT:

        a python list of the first terms 
        
        OR 
        
        maybe an object of a class you implement if there exists pertinent
        questions to ask to it.
        """
        #Do some computations based (I guess) on self._F and self._G
        intermediate_result1 = self.some_intermediate_computations_1()
        #Do more computations
        return something

    def asymptotics(self, N, alpha):
        r"""
        Returns the asymptotics of Maclaurin coefficients.
        """
        #Do some computations based (I guess) on self._F and self._G
        intermediate_result2 = self.some_intermediate_computations_2()
        intermediate_result3 = self.some_intermediate_computations_3()
        return something

    #put here all the others functions needed to compute the asymptotics
    def some_intermediate_computations_1(self):
        pass
    def some_intermediate_computations_2(self):
        pass
    def some_intermediate_computations_3(self):
        pass

    ...

It also looks like you need some robustness somehow. But I need to know more
information about what means

that asymptotics in the direction of \alpha (a tuple of positive integers)
are controlled by smooth or multiple points.

to decide whether this is checked at the creation of the object or before
returning the asymptotics. But these hypothesis should be checked somewhere.

Hope this helps.

Cheers,

Sébastien Labbé, Montréal, (but currently at Sage Days 28, Orsay, France)

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jan 20, 2011

comment:6

Hi Sebastien:

Thanks very much for your helpful comments. I've been working on rewriting my code in an object-oriented way and will incorporate your suggestions. Some functions in mgf.sage, such as deciding whether a list of polynomials is algebraically dependent, are general purpose, and so i'm trying to put them into existing Sage classes. The others are more specific to asymptotics and deserve their own class similar to the one you outlined above. Robustness is also something i need to improve upon.

I'll post my modifications here after i write and test them more.

Thanks again.

Alex

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented May 1, 2011

Attachment: amgf_alpha_0_5.sage.gz

New object oriented version

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented May 6, 2011

Attachment: amgf.sage.gz

Fixed a bug in cohomologous_integrand()

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented May 6, 2011

comment:7

Hi Sebastien et al:

I rewrote my code in object-oriented style. Please have a look if you have the time. Do i need to make the file into a patch, or is it useable as is?

Thanks for your help.
Alex

@seblabbe
Copy link
Contributor

seblabbe commented Jun 1, 2011

comment:9

Cool. I now see that a lot of the functions are now inside a class, which looks better. So, as I said earlier, this is not really my field of study, so I don't know how far I can go on that review. But, I can suggest at least two things:

  1. It would be better if you post a Mercurial patch instead of a Sage file so that people can apply it and test it. Are you able to do this? Take a look at the Sage Developper's Guide, where it should be explain how to create a patch.

To add your file to the documentation, you might want to look here.

This winter, I gave a presentation on How to Contribute to Sage. This may helps you to start with Mercurial for instance.

Also, right now, I am working on #11379 where I am adding a new file to Sage. You might find it helpfull to see how I proceed.

  1. Some the Python convention are not always followed. See also pep-0008. Especially for spaces :
      Yes:

          i = i + 1

      No:

          i= i+1

@seblabbe
Copy link
Contributor

seblabbe commented Jun 1, 2011

comment:10

To add a file to a patch, you must do:

sage -hg add your_file.py

I was not able to find this information anywhere which is strange...

Tell me if you have questions.

Sébastien

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jun 11, 2011

comment:11

Thanks for your help, Se'bastien. I'm trying to put my Sage file into a patch by following your presentation slides, but am running into difficulties. I cloned Sage and copied my Sage file as 'amgf.sage' into

/Applications/sage/devel/sage-araichev/sage/combinat/

I rebuilt Sage etc. and made it to step 10 "Test the changes" of your slides. But when i run Sage and test a few commands, Sage doesn't seem to see the QuasiRationalExpression class i created in /Applications/sage/devel/sage-araichev/sage/combinat/amgf.sage.

I thought this might be because amgf.sage is a Sage file and not a Python file. So i renamed it amgf.py instead and got syntax errors. What's up with that? Do i have to rewrite all my code in Python instead of Sage?

Thanks for your attention.
Alex

@hivert
Copy link

hivert commented Jun 11, 2011

comment:12

Hi Alex,

I thought this might be because amgf.sage is a Sage file and not a Python
file. So i renamed it amgf.py instead and got syntax errors. What's up with
that? Do i have to rewrite all my code in Python instead of Sage?

The basic answer is yes, but Rewriting is a big word for what is really
needed. There is little work to do since Sage mostly follows Python syntax.
The two main difference are handling of integer (see
http://www.sagemath.org/doc/tutorial/afterword.html), and the necessity to
import what you need.

Handling of integer

  • Notation for exponentiation: In Python ** means exponentiation and
    ^ means “xor”.

  • If you need to return an integer for the user, write it return
    Integer(1) instead of return 1. In Python 1 is a machine integer
    int (32 or 64 bits depending on your machine) and Integer(1) is
    a Sage/Gmp arbitrary precision integer. Also Integer are much more
    powerful than int, for example they know about prime and
    factorization.

Importing stuff

The second big change is the necessity to import all what you need. More
precisely, each time you use some Sage function, you need to import it at the
beginning of the file. for example if you want to you PolynomialRing,
you need to write

from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

You can ask Sage where to find PolynomialRing using:

sage: PolynomialRing.__module__
'sage.rings.polynomial.polynomial_ring_constructor'

This also correspond to the path starting after site-packages
given when you are asking Sage for
PolynomialRing help:

sage: PolynomialRing?
Type:           function
[...]
File:           /home/florent/src/Sage/sage/local/lib/python2.6/site-packages/sage/rings/polynomial/polynomial_ring_constructor.py
[...]

I hope this helps,

Florent

@seblabbe
Copy link
Contributor

comment:13

Just answering as a complement to Florent's answer.

But when i run Sage and test a few commands, Sage doesn't seem to see the QuasiRationalExpression class i created in /Applications/sage/devel/sage-araichev/sage/combinat/amgf.sage.

To test your code in a Sage session, you will first need to import the good class (or function). For instance :

sage: from sage.combinat.amgf import QuasiRationalExpression

If you would like QuasiRationalExpression to be already imported once Sage is started, you must add the line from sage.combinat.amgf import QuasiRationalExpression to the file sage/combinat/all.py. Note that it is not "à la mode" to add new stuff to all.py files because Sage is very slow to start because of all the things that are imported. If you think a lot of people will use the code, then it might be defendable.

Sébastien

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jun 12, 2011

comment:14

Thanks for the tips, Florent and Se'bastien. I'll get to work on converting amgf.sage to amgf.py.

Alex

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jun 12, 2011

comment:15

Hang on, can i somehow use the Sage pre-parser to automatically convert amgf.sage to amgf.py?

Alex

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jun 13, 2011

comment:16

Aha! The command 'sage amgf.sage' pre-parses amgf.sage and saves it as amgf.py. Thank you ask.sagemath.org!

Alex

@sagetrac-araichev
Copy link
Mannequin Author

sagetrac-araichev mannequin commented Jun 13, 2011

Pythonified amgf.sage

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Changed commit from a30a18a to f58efc9

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Branch pushed to git repo; I updated commit sha1. New commits:

c37497fTrac #10519: more fixes to make platform-independent
85c1f37Trac #10519: another fix; not really nice... :(

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Changed commit from f58efc9 to 85c1f37

@vbraun
Copy link
Member

vbraun commented Feb 16, 2016

comment:131

The displayhook sorts but x, y have no particular order


New commits:

c37497fTrac #10519: more fixes to make platform-independent
85c1f37Trac #10519: another fix; not really nice... :(

@dkrenn
Copy link
Contributor

dkrenn commented Feb 16, 2016

comment:132

I've now fixed all (at least I hope I got all) platform-dependent. Can someone please check with other platform than Linux, x86_64 on Intel i5-4690?

@dkrenn
Copy link
Contributor

dkrenn commented Feb 16, 2016

comment:133

Replying to @vbraun:

The displayhook sorts but x, y have no particular order

Oh, I see (I thought, that display hooks sort by str in such a case). Thanks.

@tscrim
Copy link
Collaborator

tscrim commented Feb 16, 2016

comment:134

Replying to @dkrenn:

I've now fixed all (at least I hope I got all) platform-dependent. Can someone please check with other platform than Linux, x86_64 on Intel i5-4690?

I didn't see a difference from the original doctests on my laptop, so I can't give an explicit check. However, from looking over the doctestvs and Volker's failures, this seems to do the trick. Although I don't like the changes on ​85c1f37. Instead, I think you should just explicitly check that the dictionary of solutions is the correct one:

sage: s == [{SR(x): 1, SR(y): 1}]
True

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Changed commit from 85c1f37 to 3182c5b

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Branch pushed to git repo; I updated commit sha1. New commits:

59792e2Revert "Trac #10519: another fix; not really nice... :("
3182c5bTrac #10519: better fix for previous issue

@dkrenn
Copy link
Contributor

dkrenn commented Feb 16, 2016

comment:136

Replying to @tscrim:
Although I don't like the changes on ​85c1f37. Instead, I think you should just explicitly check that the dictionary of solutions is the correct one:

sage: s == [{SR(x): 1, SR(y): 1}]
True

Reverted and changed; indeed much nicer.

@tscrim
Copy link
Collaborator

tscrim commented Feb 16, 2016

comment:138

Thanks!

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Changed commit from 3182c5b to a951f08

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 16, 2016

Branch pushed to git repo; I updated commit sha1 and set ticket back to needs_review. New commits:

a951f08Trac #10519: trivial ReST error

@vbraun
Copy link
Member

vbraun commented Feb 17, 2016

Changed branch from public/combinat/10519 to a951f08

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests