147147
148148from sage .version import version
149149from sage .cpython .string import bytes_to_str
150- from sage .misc .cachefunc import cached_method
151150from sage .misc .flatten import flatten
152151from sage .misc .html import HtmlFragment
153152from sage .misc .temporary_file import tmp_filename
154153from sage .misc .unknown import Unknown
155154from sage .misc .verbose import verbose
156155from sage .repl .preparse import preparse
157156from sage .rings .integer import Integer
157+ from sage .rings .integer_ring import ZZ
158+ from sage .rings .infinity import infinity
159+ from sage .structure .global_options import GlobalOptions
158160from sage .structure .sage_object import SageObject
159161from sage .structure .unique_representation import UniqueRepresentation
160162
@@ -246,7 +248,7 @@ class OEIS:
246248 - a list representing a sequence of integers.
247249 - a string, representing a text search.
248250
249- - ``max_results`` -- integer (default: 30 ); the maximum number of
251+ - ``max_results`` -- integer (default: 3 ); the maximum number of
250252 results to return, they are sorted according to their relevance. In
251253 any cases, the OEIS website will never provide more than 100 results.
252254
@@ -255,6 +257,8 @@ class OEIS:
255257 This is useful if you are looking for a sequence that may appear
256258 after the 100 first found sequences.
257259
260+ ``max_results`` can also be set using :meth:`options`.
261+
258262 OUTPUT:
259263
260264 - if ``query`` is an integer or an OEIS ID (e.g. 'A000045'), returns
@@ -361,8 +365,7 @@ class OEIS:
361365 sage: oeis('A000045') # optional -- internet
362366 A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
363367 """
364-
365- def __call__ (self , query , max_results = 3 , first_result = 0 ):
368+ def __call__ (self , query , max_results = None , first_result = 0 ):
366369 r"""
367370 See the documentation of :class:`OEIS`.
368371
@@ -383,6 +386,46 @@ def __call__(self, query, max_results=3, first_result=0):
383386 elif isinstance (query , (list , tuple )):
384387 return self .find_by_subsequence (query , max_results , first_result )
385388
389+ class options (GlobalOptions ):
390+ r"""
391+ Set and display the options for the OEIS.
392+
393+ If no parameters are set, then the function returns a copy of
394+ the options dictionary.
395+
396+ The ``options`` can be accessed as using
397+ :class:`oeis.options`.
398+
399+ @OPTIONS@
400+
401+ EXAMPLES::
402+
403+ sage: oeis.options
404+ Current options for OEIS
405+ - fetch_b_file: False
406+ - max_results: 3
407+
408+ sage: oeis.options.max_results = 5
409+ sage: oeis('beaver') # optional -- internet
410+ 0: A...: ...eaver...
411+ 1: A...: ...eaver...
412+ 2: A...: ...eaver...
413+ 3: A...: ...eaver...
414+ 4: A...: ...eaver...
415+
416+ sage: oeis.options._reset()
417+ sage: oeis.options.max_results
418+ 3
419+ """
420+ NAME = 'OEIS'
421+ module = 'sage.databases.oeis'
422+ max_results = dict (default = 3 ,
423+ description = 'the maximum number of results to return' ,
424+ checker = lambda x : x in ZZ and x > 0 )
425+ fetch_b_file = dict (default = False ,
426+ description = 'whether to fetch terms from the b-file by default' ,
427+ checker = lambda x : isinstance (x , bool ))
428+
386429 def __repr__ (self ) -> str :
387430 r"""
388431 Return the representation of ``self``.
@@ -440,7 +483,7 @@ def find_by_entry(self, entry):
440483 sequence ._raw = entry
441484 return sequence
442485
443- def find_by_description (self , description , max_results = 3 , first_result = 0 ):
486+ def find_by_description (self , description , max_results = None , first_result = 0 ):
444487 r"""
445488 Search for OEIS sequences corresponding to the description.
446489
@@ -483,7 +526,19 @@ def find_by_description(self, description, max_results=3, first_result=0):
483526 1: A...: ...eaver...
484527 2: A...: ...eaver...
485528 3: A...: ...eaver...
529+
530+ Alternatively, we can also set the global option `max_results`::
531+
532+ sage: oeis.options.max_results = 5
533+ sage: oeis('beaver') # optional -- internet
534+ 0: A...: ...eaver...
535+ 1: A...: ...eaver...
536+ 2: A...: ...eaver...
537+ 3: A...: ...eaver...
538+ 4: A...: ...eaver...
486539 """
540+ if max_results is None :
541+ max_results = self .options ['max_results' ]
487542 options = {'q' : description ,
488543 'n' : str (max_results ),
489544 'fmt' : 'text' ,
@@ -493,7 +548,7 @@ def find_by_description(self, description, max_results=3, first_result=0):
493548 T = [self .find_by_entry (entry = s ) for s in sequence_list ]
494549 return FancyTuple ([s for s in T if not s .is_dead ()])
495550
496- def find_by_subsequence (self , subsequence , max_results = 3 , first_result = 0 ):
551+ def find_by_subsequence (self , subsequence , max_results = None , first_result = 0 ):
497552 r"""
498553 Search for OEIS sequences containing the given subsequence.
499554
@@ -689,7 +744,7 @@ def __init__(self, ident):
689744
690745 def online_update (self ):
691746 r"""
692- Fetch the online OEIS to update the informations about this sequence .
747+ Fetch the sequence from the OEIS .
693748
694749 TESTS::
695750
@@ -1205,15 +1260,17 @@ def is_full(self):
12051260 else :
12061261 return Unknown
12071262
1208- @cached_method
12091263 def first_terms (self , number = None ):
12101264 r"""
1265+ Return the first few terms of the sequence.
12111266
12121267 INPUT:
12131268
1214- - ``number`` -- integer or ``None`` (default); the number of
1215- terms returned (if less than the number of available terms). When set
1216- to ``None``, returns all the known terms.
1269+ - ``number`` -- integer, ``infinity`` or ``None`` (default);
1270+ the number of terms returned. When set to ``None``,
1271+ returns all the known terms. When set to an integer larger
1272+ than the number of terms in the internal format, or to
1273+ ``infinity``, the b-file is fetched.
12171274
12181275 OUTPUT: tuple of integers
12191276
@@ -1237,9 +1294,54 @@ def first_terms(self, number=None):
12371294 (1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
12381295 sage: s.first_terms(5)
12391296 (1, 1, 1, 1, 2)
1297+
1298+ sage: len(oeis(45).first_terms()) # optional -- internet
1299+ 41
1300+ sage: len(oeis(45).first_terms(oo)) # optional -- internet
1301+ 2001
1302+
1303+ sage: len(oeis(1).first_terms()) # optional -- internet
1304+ 94
1305+
1306+ sage: oeis.options.fetch_b_file = True
1307+ sage: len(oeis(1).first_terms()) # optional -- internet
1308+ 2048
1309+ sage: oeis.options._reset()
12401310 """
1241- fields = ['S' , 'T' , 'U' ]
1242- return to_tuple (" " .join (flatten ([self ._field (a ) for a in fields ])))[:number ]
1311+ def fetch_b_file ():
1312+ url = oeis_url + f"b{ self .id (format = 'int' )} .txt"
1313+ terms = _fetch (url )
1314+ first_terms = tuple ()
1315+ check = None
1316+ for term in terms .split ('\n ' ):
1317+ if not term or term [0 ] == '#' :
1318+ continue
1319+ k , v = [Integer (e ) for e in term .strip ().split ()]
1320+ if check is not None and k != check + 1 :
1321+ raise ValueError (f"malformed b-file { url } : key { check } followed by { k } " )
1322+ check = k
1323+ first_terms += (v ,)
1324+ self ._first_terms = True , first_terms
1325+
1326+ if ((number is infinity or oeis .options ['fetch_b_file' ])
1327+ and self is not oeis ._imaginary_sequence ()): # all other sequences have a b-file
1328+ # self._first_terms is a pair (all?, first_terms)
1329+ if not hasattr (self , "_first_terms" ) or not self ._first_terms [0 ]:
1330+ fetch_b_file ()
1331+ return self ._first_terms [1 ]
1332+
1333+ if not hasattr (self , "_first_terms" ):
1334+ fields = ['S' , 'T' , 'U' ]
1335+ first_terms = to_tuple (" " .join (flatten ([self ._field (a ) for a in fields ])))
1336+ self ._first_terms = (False , first_terms )
1337+
1338+ if number is None :
1339+ return self ._first_terms [1 ]
1340+
1341+ if number > len (self ._first_terms [1 ]) and not self ._first_terms [0 ]:
1342+ fetch_b_file ()
1343+
1344+ return self ._first_terms [1 ][:number ]
12431345
12441346 def _repr_ (self ):
12451347 r"""
@@ -1755,8 +1857,7 @@ def show(self):
17551857 https://oeis.org/A012345
17561858 <BLANKLINE>
17571859 AUTHOR
1758- Patrick Demichel (patrick.demichel(AT)hp.com)
1759- <BLANKLINE>
1860+ ...
17601861
17611862 TESTS::
17621863
0 commit comments