Skip to content

Commit a554edb

Browse files
Release Managervbraun
Release Manager
authored andcommitted
Trac #16719: replace gap.eval with libgap calls in combinat/combinat.py
As first reported in #15625 (comment:7) with `lucas_number1`, the same problem is encountered with gap evaluation of Stirling numbers: {{{ sage: stirling_number1(1000,2) ------------------------------------------------------------------------ --- TypeError Traceback (most recent call last) <ipython-input-22-b29f3b3e2003> in <module>() ----> 1 stirling_number1(Integer(1000),Integer(2)) /home/ralf/sage/local/lib/python2.7/site- packages/sage/combinat/combinat.pyc in stirling_number1(n, k) 650 """ 651 return Integer(gap.eval("Stirling1({0},{1})".format(Integer(n), --> 652 Integer(k)))) 653 654 /home/ralf/sage/local/lib/python2.7/site-packages/sage/rings/integer.so in sage.rings.integer.Integer.__init__ (build/cythonized/sage/rings/integer.c:7902)() TypeError: unable to convert x (=<integer 301...000 (2566 digits)>) to an integer }}} The way to go would be to replace `gap.eval` with `libgap.eval` and it's faster, too: {{{ sage: timeit('Integer(gap.eval("Stirling1(100,2)"))') 625 loops, best of 3: 419 µs per loop sage: timeit('libgap.eval("Stirling1(100,2)").sage()') 625 loops, best of 3: 125 µs per loop sage: timeit('libgap.eval("Stirling1(1000,2)").sage()') 125 loops, best of 3: 6.45 ms per loop }}} Addendum: even faster would be to use `(n-1)!*H(n-1)` for `stirling(n,2)`, dependent on #16671: {{{ sage: harmonic_number(99)*factorial(99)==stirling_number1(100,2) True sage: timeit('harmonic_number(99)*factorial(99)') 625 loops, best of 3: 56.9 µs per loop sage: timeit('harmonic_number(999)*factorial(999)') 625 loops, best of 3: 119 µs per loop }}} URL: http://trac.sagemath.org/16719 Reported by: rws Ticket author(s): Ralf Stephan Reviewer(s): Jeroen Demeyer, Volker Braun
2 parents d6feebb + d6698e2 commit a554edb

File tree

3 files changed

+38
-33
lines changed

3 files changed

+38
-33
lines changed

src/sage/combinat/combinat.py

+34-32
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,10 @@
147147
#
148148
# http://www.gnu.org/licenses/
149149
#*****************************************************************************
150-
from sage.interfaces.all import gap, maxima
151-
from sage.rings.all import QQ, ZZ, Integer
150+
from sage.interfaces.all import maxima
151+
from sage.rings.all import ZZ, QQ, Integer, infinity
152152
from sage.rings.arith import bernoulli, binomial
153153
from sage.rings.polynomial.polynomial_element import Polynomial
154-
from sage.misc.sage_eval import sage_eval
155154
from sage.libs.all import pari
156155
from sage.misc.prandom import randint
157156
from sage.misc.misc import prod
@@ -379,7 +378,7 @@ def bell_number(n, algorithm='flint', **options):
379378

380379
elif algorithm == 'gap':
381380
from sage.libs.gap.libgap import libgap
382-
return libgap.eval("Bell(%s)" % n).sage()
381+
return libgap.Bell(n).sage()
383382

384383
elif algorithm == 'dobinski':
385384
# Hardcode small cases. We only proved the algorithm below
@@ -544,7 +543,8 @@ def fibonacci(n, algorithm="pari"):
544543
if algorithm == 'pari':
545544
return ZZ(pari(n).fibonacci())
546545
elif algorithm == 'gap':
547-
return ZZ(gap.eval("Fibonacci({})".format(n)))
546+
from sage.libs.gap.libgap import libgap
547+
return libgap.Fibonacci(n).sage()
548548
else:
549549
raise ValueError("no algorithm {}".format(algorithm))
550550

@@ -578,22 +578,15 @@ def lucas_number1(n,P,Q):
578578
13
579579
sage: lucas_number1(7,1,-2)
580580
43
581-
582-
::
583-
584581
sage: lucas_number1(5,2,3/5)
585582
229/25
586583
sage: lucas_number1(5,2,1.5)
587-
Traceback (most recent call last):
588-
...
589-
TypeError: no canonical coercion from Real Field with 53 bits of precision to Rational Field
584+
1/4
590585
591586
There was a conjecture that the sequence `L_n` defined by
592587
`L_{n+2} = L_{n+1} + L_n`, `L_1=1`,
593588
`L_2=3`, has the property that `n` prime implies
594-
that `L_n` is prime.
595-
596-
::
589+
that `L_n` is prime. ::
597590
598591
sage: lucas = lambda n : Integer((5/2)*lucas_number1(n,1,-1)+(1/2)*lucas_number2(n,1,-1))
599592
sage: [[lucas(n),is_prime(lucas(n)),n+1,is_prime(n+1)] for n in range(15)]
@@ -615,8 +608,9 @@ def lucas_number1(n,P,Q):
615608
616609
Can you use Sage to find a counterexample to the conjecture?
617610
"""
618-
ans=gap.eval("Lucas(%s,%s,%s)[1]"%(QQ._coerce_(P),QQ._coerce_(Q),ZZ(n)))
619-
return sage_eval(ans)
611+
n = ZZ(n); P = QQ(P); Q = QQ(Q)
612+
from sage.libs.gap.libgap import libgap
613+
return libgap.Lucas(P, Q, n)[0].sage()
620614

621615
def lucas_number2(n,P,Q):
622616
r"""
@@ -662,8 +656,9 @@ def lucas_number2(n,P,Q):
662656
sage: [lucas_number2(n,1,-1) for n in range(10)]
663657
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
664658
"""
665-
ans=gap.eval("Lucas(%s,%s,%s)[2]"%(QQ._coerce_(P),QQ._coerce_(Q),ZZ(n)))
666-
return sage_eval(ans)
659+
n = ZZ(n); P = QQ(P); Q = QQ(Q)
660+
from sage.libs.gap.libgap import libgap
661+
return libgap.Lucas(P, Q, n)[1].sage()
667662

668663

669664
def stirling_number1(n, k):
@@ -687,8 +682,9 @@ def stirling_number1(n, k):
687682
688683
Indeed, `S_1(n,k) = S_1(n-1,k-1) + (n-1)S_1(n-1,k)`.
689684
"""
690-
return Integer(gap.eval("Stirling1({0},{1})".format(Integer(n),
691-
Integer(k))))
685+
n = ZZ(n); k = ZZ(k)
686+
from sage.libs.gap.libgap import libgap
687+
return libgap.Stirling1(n, k).sage()
692688

693689

694690
def stirling_number2(n, k, algorithm=None):
@@ -809,13 +805,15 @@ def stirling_number2(n, k, algorithm=None):
809805
Traceback (most recent call last):
810806
...
811807
ValueError: unknown algorithm: CloudReading
812-
"""
808+
"""
809+
n = ZZ(n); k = ZZ(k)
813810
if algorithm is None:
814811
return _stirling_number2(n, k)
815812
elif algorithm == 'gap':
816-
return ZZ(gap.eval("Stirling2(%s,%s)"%(ZZ(n),ZZ(k))))
813+
from sage.libs.gap.libgap import libgap
814+
return libgap.Stirling2(n, k).sage()
817815
elif algorithm == 'maxima':
818-
return ZZ(maxima.eval("stirling2(%s,%s)"%(ZZ(n),ZZ(k))))
816+
return ZZ(maxima.eval("stirling2(%s,%s)"%(n, k)))
819817
else:
820818
raise ValueError("unknown algorithm: %s" % algorithm)
821819

@@ -2129,7 +2127,6 @@ def an_element(self):
21292127
return self.f(self.cc.an_element())
21302128

21312129
##############################################################################
2132-
from sage.rings.all import infinity
21332130
class InfiniteAbstractCombinatorialClass(CombinatorialClass):
21342131
r"""
21352132
This is an internal class that should not be used directly. A class which
@@ -2249,7 +2246,7 @@ def tuples(S,k):
22492246
ans.append(y)
22502247
return ans
22512248

2252-
def number_of_tuples(S,k):
2249+
def number_of_tuples(S, k):
22532250
"""
22542251
Return the size of ``tuples(S,k)``. Wraps GAP's ``NrTuples``.
22552252
@@ -2262,10 +2259,12 @@ def number_of_tuples(S,k):
22622259
sage: number_of_tuples(S,2)
22632260
25
22642261
"""
2265-
ans=gap.eval("NrTuples(%s,%s)"%(S,ZZ(k)))
2266-
return ZZ(ans)
2262+
k = ZZ(k)
2263+
from sage.libs.gap.libgap import libgap
2264+
S = libgap.eval(str(S))
2265+
return libgap.NrTuples(S, k).sage()
22672266

2268-
def unordered_tuples(S,k):
2267+
def unordered_tuples(S, k):
22692268
"""
22702269
Return the set of all unordered tuples of length ``k`` of the
22712270
set ``S``. Wraps GAP's ``UnorderedTuples``.
@@ -2296,8 +2295,10 @@ def unordered_tuples(S,k):
22962295
sage: unordered_tuples(["a","b","c"],2)
22972296
['aa', 'ab', 'ac', 'bb', 'bc', 'cc']
22982297
"""
2299-
ans=gap.eval("UnorderedTuples(%s,%s)"%(S,ZZ(k)))
2300-
return eval(ans)
2298+
k = ZZ(k)
2299+
from sage.libs.gap.libgap import libgap
2300+
S = libgap.eval(str(S))
2301+
return libgap.UnorderedTuples(S, k).sage()
23012302

23022303
def number_of_unordered_tuples(S,k):
23032304
"""
@@ -2310,8 +2311,9 @@ def number_of_unordered_tuples(S,k):
23102311
sage: number_of_unordered_tuples(S,2)
23112312
15
23122313
"""
2313-
ans=gap.eval("NrUnorderedTuples(%s,%s)"%(S,ZZ(k)))
2314-
return ZZ(ans)
2314+
from sage.libs.gap.libgap import libgap
2315+
S = libgap.eval(str(S))
2316+
return libgap.NrUnorderedTuples(S, k).sage()
23152317

23162318
def unshuffle_iterator(a, one=1):
23172319
r"""

src/sage/libs/gap/element.pyx

+3-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ cdef GapElement make_any_gap_element(parent, libGAP_Obj obj):
167167
sage: type(T_CHAR)
168168
<type 'sage.libs.gap.element.GapElement_String'>
169169
170-
sage: t = libgap.eval("UnorderedTuples(['a', 'b', 'c'], 2)"); t
170+
sage: libgap.eval("['a', 'b', 'c']") # gap strings are also lists of chars
171+
"abc"
172+
sage: t = libgap.UnorderedTuples('abc', 2); t
171173
[ "aa", "ab", "ac", "bb", "bc", "cc" ]
172174
sage: t[1]
173175
"ab"

src/sage/libs/gap/gap_functions.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'BaseOfGroup',
4141
'Basis',
4242
'BasisVectors',
43+
'Bell',
4344
'Binomial',
4445
'BlockMatrix',
4546
'Blocks',

0 commit comments

Comments
 (0)