sagemath / sage

Main repository of SageMath. Now open for Issues and Pull Requests.
https://www.sagemath.org
Other
1.18k stars 409 forks source link

Implement symbolic q-analogues #25713

Open mathzeta opened 6 years ago

mathzeta commented 6 years ago

Currently the module sage.combinat.q_analogues does not support symbolic q-analogs.

We would like things like this to work:

sage: from sage.combinat.q_analogues import q_int, q_factorial
sage: var("n")
n
sage: q_int(n)
q_int(n)
sage: latex(q_int(n))
[n]_{q}!
sage: q_int(3, q=x, hold=True)
q_int(3, x)
sage: _(x=4)
21

This ticket might serve as a meta-ticket also for more advanced options, of which simplification is the most important:

sage: var("k")
sage: product(q_int(k), k, 1, n)
q_factorial(n)
sage: R.<q> = ZZ[]
sage: simplify(q^k*q_binomial(n-1, k, q) + q_binomial(n-1, k-1, q))
q_binomial(n, k, q)

CC: @pelegm @rwst @tscrim

Component: symbolics

Keywords: days94, q-analogs, symbolics

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

pelegm commented 6 years ago

Description changed:

--- 
+++ 
@@ -2,7 +2,7 @@

 Things like the following should work:

-```
+```sage
 sage: from sage.combinat.q_analogues import q_int, q_factorial
 sage: var("n")
 n
@@ -18,7 +18,7 @@

 This ticket might serve as a meta-ticket also for more advanced options, of which simplification is the most important:

-```
+```sage
 sage: var("k")
 sage: product(q_int(k), k, 1, n)
 q_factorial(n)
pelegm commented 6 years ago
comment:3

We have to figure out how to "register" a new ginac function, otherwise this happens:

Traceback (most recent call last):
...
  File "sage/symbolic/function.pyx", line 114, in sage.symbolic.function.Function.__init__ (build/cythonized/sage/symbolic/function.cpp:4278)
    if not self._is_registered():
...
ValueError: cannot find GiNaC function with name q_int and 1 arguments
pelegm commented 6 years ago
comment:4

First attempt:

from sage.symbolic.function import BuiltinFunction
from sage.rings.all import ZZ

class Function_q_int(BuiltinFunction):
    def __init__(self):
        BuiltinFunction.__init__(self, "q_int", nargs=2, conversions=dict())

    def _eval_(self, n, q):
        if n not in ZZ:
            return
        # if q is None:
            # q = ZZ['q'].gen()
        if n == 0:  # Special case
            return q.parent().zero()
        if n >= 0:
            return sum(q**i for i in range(n))
        return -q**n*sum(q**i for i in range(-n))

    def _print_latex_(self, x):
        pass

q_int2 = Function_q_int()

def q_int(n, q=None):
    if q is None:
        q = ZZ['q'].gen()
    return q_int2(n, q)

The problem is that BuiltinFunction coerces q into an expression, and the result is an Expression (and not Polynomial_integer_dense_flint). This is apparently much slower. Passing coerce=False results an exception from here:

        else: # coerce == False
            for a in args:
                if not isinstance(a, Expression):
                    raise TypeError("arguments must be symbolic expressions")

Other than that, this implementation seems to be correct.

rwst commented 6 years ago
comment:5

It's not clear to me: will you need held q_int... expressions together with expanded series in a single expression? If so, then output to Flint polys is not useful because polys and expressions cannot be mixed. If you decide to go fully with expressions:

If you need a fast way to get an expression of sum type with identical (or other) coefficients, Pynac can do that. But better first implement it in Python to have a proof of concept. I think you need to decide if the expanded polynomial should be an expression or a poly before you can design everything else.

Try this, here Pynac uses Flint internally, and it has an order term:

sage: var('q')
q
sage: (1/(1-q)).series(q,10)
1 + 1*q + 1*q^2 + 1*q^3 + 1*q^4 + 1*q^5 + 1*q^6 + 1*q^7 + 1*q^8 + 1*q^9 + Order(q^10)

Series manipulation of symbolic series like above is also done using Flint.

tscrim commented 6 years ago
comment:6

I softened the ticket description to make not seem like a bug (which is not).

tscrim commented 6 years ago

Description changed:

--- 
+++ 
@@ -1,6 +1,6 @@
 Currently the module sage.combinat.q_analogues does not support symbolic q-analogs.

-Things like the following should work:
+We would like things like this to work:

 ```sage
 sage: from sage.combinat.q_analogues import q_int, q_factorial