Closed mantepse closed 4 years ago
patch for principal and exponential specialization
Attachment: sf_principal_specialization-mr.patch.gz
Description changed:
---
+++
@@ -1,8 +1,16 @@
-This patch implements the principal and exponential specialisations for symmetric functions as given in Stanley, Enumerative Combinatorics, Section 7.8.
+This patch -- in the combinat queue:
+
+http://combinat.sagemath.org/hgwebdir.cgi/patches/file/tip/sf_principal_specialization-mr.patch
+
+implements the principal and exponential specialisations for symmetric functions as given in Stanley, Enumerative Combinatorics, Section 7.8.
Unfortunately, the patch currently has several problems:
+
1) it seems that always the default code in sf/sfa.py is called, I don't know why
+
2) I do not know how to give the desired default argument 1 the correct type in exponential_specialization
+
3) I guess one should rather implement this for quasi-symmetric functions, but I do not know enough about these currently
+
4) the documentation and sensible tests are still missing
Hi Martin,
Thanks submitting this! A quick response to your points above. I'm not sure what you mean by point (1)... can you elaborate?
For point (2), you can use None as the default value, and then do
if q is None:
q = self.parent().base_ring().one()
as the first line of your code.
For point (3), quasisymmetric functions are still somewhat immature--in particular they are not in Sage proper. So this is not too big of a concern.
For point (4), yes, there should be more doc and tests. In particular, I find tests like
all( e[mu].principal_specialization(4) == e[mu].expand(4)(1,q,q^2,q^3) for mu in Partitions(4) )
particularly convincing.
Hi Jason!
Many thanks for your quick comments.
1) Using trace I find
sage: S = SymmetricFunctions(QQ); s=S.s(); f = s[2,1]
sage: trace("f.principal_specialization()")
> <string>(1)<module>()
ipdb> s
--Call--
> /home/martin/SAGE/local/lib/python2.6/site-packages/sage/combinat/sf/sfa.py(1653)principal_specialization()
1652
-> 1653 def principal_specialization(self, n=infinity, q=var('q')):
1654 r"""
ipdb> s
> /home/martin/SAGE/local/lib/python2.6/site-packages/sage/combinat/sf/sfa.py(1681)principal_specialization()
1680 """
-> 1681 from sage.combinat.sf.sf import SymmetricFunctions
1682 p = SymmetricFunctions(self.parent().base_ring()).p()
ipdb>
but I was hoping that the principal specialisation from schur.py would be called.
2) Well, currently the actual value of 1 is not used at all (I test q==1 and call principal_specialization without passing q). So my question really is: some day somebody might implement something where the q is actually used. Is it better then if the default is None and the doc says, None should always mean one?
Thanks again!
I fixed indenting, bugs and added documentation and tests. Feedback welcome!
Hi Martin, a few more points:
1) If I'm not mistaken, the function f in the exponential_specialization code for Schur functions is returning the product of the hooks of partition. This can also be done with Partition(partition).hook_product(1)
2) You do not give the result of the test in line 275 of the Schur function code.
3) See this and make sure that your patch satisfies these criteria. Please ask the sage-combinat list if you have any questions about these.
4) Once you have completed all of this, mark the patch as 'Needs Review' (by clicking the button at the bottom of the page). Then the 'Patchbot' will automatically apply and test your code.
Again, many thanks for your good work!
Replying to @jbandlow:
Jason, might it be that you were looking on a different version of the patch? There is no exponential_specialization for Schur functions (I use the generic version) and there is no test in line 275...
On the other hand, I just noticed several other problems with the code. Eg., s[1].exponential_specialization()
doesn't work right now. I also should include tests for calling without any arguments...
Replying to @mantepse:
Hi Martin,
Sorry for the delay. Yes I was looking at the wrong version of the patch last time. Everything on the combinat queue now looks good to me. I think that all that is left is for you to prepare the patch for sage as mentioned in my point (3) above.
Description changed:
---
+++
@@ -1,3 +1,24 @@
+Eight years having passed, it might be time to finish this. I added tests that discovered a dozen glitches, and fixed them all.
+
+With this patch, you can now do:
+
+```
+sage: s = SymmetricFunctions(QQ).s()
+sage: x = s[2,2,1]
+sage: x.principal_specialization()
+-q^4/(q^11 - 2*q^10 + q^8 + 2*q^6 - 2*q^5 - q^3 + 2*q - 1)
+sage: x.principal_specialization(q=var("q"))
+-q^4/((q^4 - 1)*(q^3 - 1)*(q^2 - 1)*(q - 1)^2)
+sage: x.principal_specialization(n=4, q=var("q"))
+(q^5 - 1)*(q^4 - 1)*q^4/(q - 1)^2
+sage: x.exponential_specialization()
+1/24*t^5
+sage: x.exponential_specialization(q=QQ["q"].gen())
+(q^4/(q^6 + 3*q^5 + 5*q^4 + 6*q^3 + 5*q^2 + 3*q + 1))*t^5
+```
+
+old description:
+
This patch -- in the combinat queue:
http://combinat.sagemath.org/hgwebdir.cgi/patches/file/tip/sf_principal_specialization-mr.patch
Branch pushed to git repo; I updated commit sha1. New commits:
1784ac6 | fix doctests |
Your description of the definition of principle_specialization
is clear, but all of your exponential_specialization
functions need a description.
The one place that you have a description, it doesn't make sense to me because you seem to explain q-exponential_specialization, but not exponential_specialization and they don't clearly seem to be compatible by setting q=1. It wouldn't hurt to add a reference to the definition in the documentation either.
Branch pushed to git repo; I updated commit sha1. New commits:
309e5da | add documentation |
Thank you, that was an oversight. I hope it is better now!
Moving tickets from the Sage 8.8 milestone that have been actively worked on in the last six months to the next release milestone (optimistically).
ping?
I think that this needs to be more compatible with Hall-Littlewood and Macdonald symmetric functions because this seems to be one place that they might be used. If the base ring already has a q in it, this creates an expression with two q's.
sage: Ht = SymmetricFunctions(QQ['q,t'].fraction_field()).macdonald().Ht()
sage: Ht[2].principal_specialization()
(q*q + 1)/(q^3 - q^2 - q + 1)
sage: _.parent()
Fraction Field of Univariate Polynomial Ring in q over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field
and I think that is wrong. What about:
try:
q = self.base_ring()('q')
except:
q = self.base_ring()["q"].fraction_field().gen()
Currently in 'powersum.py' you have just the last line.
Also maybe should have doc tests comparing the principal specialization to plethysm.
sage: one=f.parent().one()
sage: f.principal_specialization(q=q)==f(one/(1-q)).coefficient([])
True
sage: f.principal_specialization(n=4,q=q)==f(one*(1-q^4)/(1-q)).coefficient([])
True
I am not sure I agree with you Mike that the q
for the principle specialization should be the same q
as for the Macdonald. For example, at t=0
, the Macdonald q
counts the affine grading whereas the principle specialization q
counts the principle grading after restricting to a finite-type representation. Because of this, I feel they should be different variables (and I would try to have a different name, perhaps q1
, if 'q' in self.base_ring().variable_names_recursive()
). Could you explain more why do you think they should be the same q
?
I was thinking of applications like The Delta Conjecture (e.g. see Theorem 5.1). My comment is not specific to Macdonald polynomials though, it was just an example. Whatever variable you use, if it is in your base ring it seems that you should be using that letter and not adding another copy of it by default. If you want to use another variable in your specialization you can always add one.
I see. I think that violates the principle of least surprise: someone trying this method changes the variable in their base ring and suddenly the polynomial behaves differently. If you really wanted that base ring variable, then I think you should pass it as a parameter. So if you want a different variable name, then we should change the default name if q is already on the base ring.
From my understanding what you are saying you are recommending behavior like:
sage: SymmetricFunctions(QQ).s()[1].principal_specialization()
1/(1-q)
sage: SymmetricFunctions(SR).s()[1].principal_specialization()
1/(1-z)
I think it is in the long run more user friendly, if the rule that determines which name is used for a variable, or whether a symbol is actually reused, is as simple and predictable as possible. Therefore I would be rather against a "renaming" rule.
So you would rather it be a part of the base ring then Martin? Or same name (with possibly repeated variable name)?
I don't mind either way. I guess that having two q's which are different in one expression is more likely to be overlooked, so I guess that checking whether q is there is less bad. I would think that even the casual user might be aware that the base ring contains a q.
Is this OK for you?
A question: it turns out that the explicit fraction_field()
in
try:
q = self.base_ring()('q')
except:
q = self.base_ring()["q"].fraction_field().gen()
is unnecessary. Should I keep it anyway?
If you are visually looking at output, then I agree, but if you are programming something, then it will break if you are doing something assuming that the output is a univariate polynomial ring. It is also much easier for the user to pass in the q
of the base ring than to create a new polynomial ring with the variable.
Perhaps as a compromise, we raise an error if there is no q
given but q
is a variable name in the base ring? This is clearly the safest option, and it requires the user to know exactly what they are doing.
Also, I agree with removing the fraction_field
since it is unnecessary.
Replying to @tscrim:
If you are visually looking at output, then I agree, but if you are programming something, then it will break if you are doing something assuming that the output is a univariate polynomial ring. It is also much easier for the user to pass in the
q
of the base ring than to create a new polynomial ring with the variable.
I agree!
Perhaps as a compromise, we raise an error if there is no
q
given butq
is a variable name in the base ring? This is clearly the safest option, and it requires the user to know exactly what they are doing.
I think that is an excellent idea!
Also, I agree with removing the
fraction_field
since it is unnecessary.
will do.
Branch pushed to git repo; I updated commit sha1. New commits:
3934475 | Merge branch 'develop' of git://trac.sagemath.org/sage into t/10930/specializations_for_symmetric_functions |
Perhaps as a compromise, we raise an error if there is no
q
given butq
is a variable name in the base ring? This is clearly the safest option, and it requires the user to know exactly what they
are doing.
I think that is an excellent idea!
Unfortunately, it doesn't work. The base ring could be the symbolic ring.
Replying to @mantepse:
Unfortunately, it doesn't work. The base ring could be the symbolic ring.
We can treat the symbolic ring as special. What I was think was doing
try:
if 'q' in self.base_ring().variable_names_recursive():
raise ValueError("q is already a variable name, so you must give the parameter q")
else:
q = self.base_ring()['q'].gen()
except AttributeError:
q = self.base_ring()['q'].gen()
For this, they symbolic ring would be treated the same as QQ
, and we would get a univariate polynomial ring over SR
. The other option is just explicitly test for self.base_ring() is SR
and just let q = SR.var('q')
.
Branch pushed to git repo; I updated commit sha1. New commits:
c5f5b61 | raise error if q is in the base ring, add comment about plethysm |
emails crossed :-)
I think it's OK to require q to be passed explicitely for the symbolic ring. I would rather not test explicitely for SR
, because it is quite possible to have, for example and some time in future, a polynomial ring which contains all variables.
Since not all rings have variable_names_recursive
, I simply try to convert "q" to a ring element, as Mike proposed.
Are you OK with this version?
This is acceptable to me. Mike?
I'll need a little time to try it out. "explicitely" is spelled wrong and I want to check that all coercions are correct.
As long as there is an option to use one of the variables in the ring in case that is what is desired that should be ok.
Branch pushed to git repo; I updated commit sha1. New commits:
cff572b | explicitely -> explicitly |
Thanks for spotting the misspelling! I created ticket #28843 for the other occurrences of "explicitely" :-)
The startup modules plugin says:
========== startup_modules ==========
git checkout patchbot/ticket_merged
/local/sage-patchbot/sage/sage -c ''
Total count: 1687
New:
sage.combinat.q_analogues
====================
I am guessing that this happens because I import q_binomial
and q_factorial
in elementary.py
and homogeneous.py
. Should I rather import them locally?
I think it is better to do them locally as I don't see the extra import making a timing difference.
Branch pushed to git repo; I updated commit sha1. New commits:
a19c6f5 | fix default values for eponential specialisation, import q_analogues locally |
I just noticed that I overlooked the default values for the exponential specialisation.
I factored out the following little helper function, but I do not know where to put it:
def get_variable(ring, name):
try:
ring(name)
except TypeError:
return ring[name].gen()
else:
raise ValueError("the variable %s is in the base ring, pass it explicitly" % name)
This could also be used in theta_qt
:
def theta_qt(self, q=None, t=None):
r"""
Return the image of ``self`` under the `q,t`-deformed theta
endomorphism which sends `p_k` to `\frac{1-q^k}{1-t^k} \cdot p_k`
for all positive integers `k`.
In general, this is well-defined outside of the powersum basis only
if the base ring is a `\QQ`-algebra.
INPUT:
- ``q``, ``t`` -- parameters (default: ``None``, in which case 'q'
and 't' are used)
...
"""
parent = self.parent()
BR = parent.base_ring()
p = parent.realization_of().power()
p_self = p(self)
if t is None:
if hasattr(parent,"t"):
t = parent.t
else:
t = BR(QQ['t'].gen())
if q is None:
if hasattr(parent,"q"):
q = parent.q
else:
q = BR(QQ['q'].gen())
same in omega_qt
, nabla
, scalar_qt
, scalar_jack
No it can't be. For theta_qt
the q
and the t
must be in the base_ring
.
With this patch, you can now do:
Implement the principal and exponential specializations for symmetric functions as given in Stanley, Enumerative Combinatorics, Section 7.8.
CC: @jbandlow @zabrocki @tscrim @darijgr
Component: combinatorics
Keywords: principal specialization, exponential specialization, symmetric functions
Author: Martin Rubey
Branch/Commit:
cf9e0f2
Reviewer: Darij Grinberg, Mike Zabrocki
Issue created by migration from https://trac.sagemath.org/ticket/10930