Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

""" 

Local copy of Sloane On-Line Encyclopedia of Integer Sequences 

 

The SloaneEncyclopedia object provides access to a local copy of the database 

containing only the sequences and their names. To use this you must download 

and install the database using ``SloaneEncyclopedia.install()``, or 

``SloaneEncyclopedia.install_from_gz()`` if you have already downloaded the 

database manually. 

 

To look up a sequence, type 

 

:: 

 

sage: SloaneEncyclopedia[60843] # optional - sloane_database 

[1, 6, 21, 107] 

 

To get the name of a sequence, type 

 

:: 

 

sage: SloaneEncyclopedia.sequence_name(1) # optional - sloane_database 

'Number of groups of order n.' 

 

To search locally for a particular subsequence, type 

 

:: 

 

sage: SloaneEncyclopedia.find([1,2,3,4,5], 1) # optional - sloane_database 

[(15, [1, 2, 3, 4, 5, 7, 7, 8, 9, 11, 11, 13, 13, 16, 16, 16, 17, 19, 19, 23, 23, 23, 23, 25, 25, 27, 27, 29, 29, 31, 31, 32, 37, 37, 37, 37, 37, 41, 41, 41, 41, 43, 43, 47, 47, 47, 47, 49, 49, 53, 53, 53, 53, 59, 59, 59, 59, 59, 59, 61, 61, 64, 64, 64, 67, 67, 67, 71, 71, 71, 71, 73])] 

 

The default maximum number of results is 30, but to return up to 

100, type 

 

:: 

 

sage: SloaneEncyclopedia.find([1,2,3,4,5], 100) # optional - sloane_database 

[(15, [1, 2, 3, 4, 5, 7, 7, 8, 9, 11, 11, ... 

 

Results in either case are of the form [ (number, list) ]. 

 

 

.. SEEALSO:: 

 

- If you want to get more informations relative to a sequence (references, 

links, examples, programs, ...), you can use the On-Line Encyclopedia of 

Integer Sequences provided by the :mod:`OEIS <sage.databases.oeis>` 

module. 

- Some infinite OEIS sequences are implemented in Sage, via the 

:mod:`sloane_functions <sage.combinat.sloane_functions>` module. 

 

 

AUTHORS: 

 

- Steven Sivek (2005-12-22): first version 

 

- Steven Sivek (2006-02-07): updated to correctly handle the new 

search form on the Sloane website, and it's now also smarter about 

loading the local database in that it doesn't convert a sequence 

from string form to a list of integers until absolutely necessary. 

This seems to cut the loading time roughly in half. 

 

- Steven Sivek (2009-12-22): added the SloaneEncyclopedia functions 

install() and install_from_gz() so users can get the latest versions 

of the OEIS without having to get an updated spkg; added 

sequence_name() to return the description of a sequence; and changed 

the data type for elements of each sequence from int to Integer. 

 

- Thierry Monteil (2012-02-10): deprecate dead code and update related doc and 

tests. 

 

Classes and methods 

------------------- 

""" 

 

#***************************************************************************** 

# 

# Sage: Copyright (C) 2005-2006 William Stein <wstein@gmail.com> 

# and Steven Sivek <ssivek@mit.edu> 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

 

import bz2 

import os 

import re 

 

# import compatible with py2 and py3 

from six.moves.urllib.request import urlretrieve 

 

from sage.misc.all import verbose 

from sage.env import SAGE_SHARE 

import sage.rings.integer_ring 

ZZ = sage.rings.integer_ring.IntegerRing() 

from sage.misc.superseded import deprecation 

 

class SloaneEncyclopediaClass: 

""" 

A local copy of the Sloane Online Encyclopedia of Integer Sequences 

that contains only the sequence numbers and the sequences 

themselves. 

""" 

def __init__(self): 

""" 

Initialize the database but do not load any of the data. 

""" 

self.__path__ = os.path.join(SAGE_SHARE, 'sloane') 

self.__file__ = os.path.join(self.__path__, 'sloane-oeis.bz2') 

self.__file_names__ = os.path.join(self.__path__, 'sloane-names.bz2') 

self.__loaded__ = False 

self.__loaded_names__ = False 

 

def __repr__(self): 

""" 

String representation of this database. OUTPUT: str 

""" 

return "Local copy of Sloane Online Encyclopedia of Integer Sequences" 

 

def __iter__(self): 

""" 

Returns an iterator through the encyclopedia. Elements are of the 

form [number, sequence]. 

""" 

for i in self.__data__: 

yield [i, self[i]] 

 

def __getitem__(self, N): 

""" 

Return sequence N in the encyclopedia. If sequence N does not 

exist, return []. 

 

INPUT: 

 

 

- ``N`` - int 

 

 

OUTPUT: list 

""" 

self.load() 

if not N in self.__data__: # sequence N does not exist 

return [] 

if self.__data__[N][1] is None: # list N has not been created yet 

list = self.__data__[N][2].strip(',').split(',') 

self.__data__[N][1] = [ZZ(n) for n in list] 

return self.__data__[N][1] 

 

def __len__(self): 

""" 

Return the number of sequences in the encyclopedia. 

""" 

self.load() 

return len(self.__data__) 

 

 

def find(self, seq, maxresults=30): 

""" 

Return a list of all sequences which have seq as a subsequence, up 

to maxresults results. Sequences are returned in the form (number, 

list). 

 

INPUT: 

 

 

- ``seq`` - list 

 

- ``maxresults`` - int 

 

 

OUTPUT: list of 2-tuples (i, v), where v is a sequence with seq as 

a subsequence. 

""" 

self.load() 

 

answer, nanswer = [], 0 

pattern = re.sub(r'[\[\]]', ',', str(seq).replace(' ','')) 

for i in self.__data__: 

if self.__data__[i][2].find(pattern) != -1: 

answer.append((i, self[i])) 

nanswer = nanswer + 1 

if nanswer == maxresults: 

return answer 

 

return answer 

 

def install(self, oeis_url="http://oeis.org/stripped.gz", names_url="http://oeis.org/names.gz", overwrite=False): 

""" 

Download and install the online encyclopedia, raising an IOError if 

either step fails. 

 

INPUT: 

 

- ``oeis_url`` - string (default: "http://oeis.org...") 

The URL of the stripped.gz encyclopedia file. 

 

- ``names_url`` - string (default: "http://oeis.org...") 

The URL of the names.gz encyclopedia file. If you do not want to 

download this file, set names_url=None. 

 

- ``overwrite`` - boolean (default: False) If the encyclopedia is 

already installed and overwrite=True, download and install the latest 

version over the installed one. 

""" 

### See if the encyclopedia already exists 

if not overwrite and os.path.exists(self.__file__): 

raise IOError("Sloane encyclopedia is already installed") 

 

tm = verbose("Downloading stripped version of Sloane encyclopedia") 

try: 

fname, _ = urlretrieve(oeis_url); 

except IOError as msg: 

raise IOError("%s\nError fetching the following website:\n %s\nTry checking your internet connection."%(msg, oeis_url)) 

 

if not names_url is None: 

try: 

nname, _ = urlretrieve(names_url); 

except IOError as msg: 

raise IOError("%s\nError fetching the following website:\n %s\nTry checking your internet connection."%(msg, names_url)) 

else: 

nname = None 

verbose("Finished downloading", tm) 

 

self.install_from_gz(fname, nname, overwrite) 

# Delete the temporary downloaded files 

os.remove(fname) 

if not nname is None: 

os.remove(nname) 

 

def install_from_gz(self, stripped_file, names_file, overwrite=False): 

""" 

Install the online encyclopedia from a local stripped.gz file. 

 

INPUT: 

 

- ``stripped_file`` - string. The name of the stripped.gz OEIS file. 

 

- ``names_file`` - string. The name of the names.gz OEIS file, or 

None if the user does not want it installed. 

 

- ``overwrite`` - boolean (default: False) If the encyclopedia is 

already installed and overwrite=True, install 'filename' over the 

old encyclopedia. 

""" 

if not overwrite and os.path.exists(self.__file__): 

raise IOError("Sloane encyclopedia is already installed") 

 

copy_gz_file(stripped_file, self.__file__) 

 

if not names_file is None: 

copy_gz_file(names_file, self.__file_names__) 

else: 

# Delete old copies of names.gz since their sequence numbers 

# probably won't match the newly installed stripped.gz 

if os.path.exists(self.__file_names__): 

os.remove(self.__file_names__) 

 

# Remove the old database from memory so the new one will be 

# automatically loaded next time the user tries to access it 

self.unload() 

 

 

def load(self): 

""" 

Load the entire encyclopedia into memory from a file. This is done 

automatically if the user tries to perform a lookup or a search. 

""" 

if self.__loaded__: 

return 

try: 

file_seq = bz2.BZ2File(self.__file__, 'r') 

except IOError: 

raise IOError("The Sloane Encyclopedia database must be installed. Use e.g. 'SloaneEncyclopedia.install()' to download and install it.") 

 

self.__data__ = {} 

 

tm = verbose("Loading Sloane encyclopedia from disk") 

entry = re.compile(r'A(?P<num>\d{6}) ,(?P<body>.*),$'); 

for L in file_seq: 

if len(L) == 0: 

continue 

m = entry.search(L) 

if m: 

seqnum = int(m.group('num')) 

msg = m.group('body').strip() 

self.__data__[seqnum] = [seqnum, None, ','+msg+',', None] 

file_seq.close() 

 

try: 

file_names = bz2.BZ2File(self.__file_names__, 'r') 

entry = re.compile(r'A(?P<num>\d{6}) (?P<body>.*)$'); 

for L in file_names: 

if len(L) == 0: continue 

m = entry.search(L) 

if m: 

seqnum = int(m.group('num')) 

self.__data__[seqnum][3] = m.group('body').strip() 

file_names.close() 

self.__loaded_names__ = True 

except KeyError: 

### Some sequence in the names file isn't in the database 

raise KeyError("Sloane OEIS sequence and name files do not match. Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") 

except IOError as msg: 

### The names database is not installed 

self.__loaded_names__ = False 

 

verbose("Finished loading", tm) 

self.__loaded__ = True 

 

def sequence_name(self, N): 

""" 

Return the name of sequence N in the encyclopedia. If sequence N 

does not exist, return ''. If the names database is not installed, 

raise an IOError. 

 

INPUT: 

 

- ``N`` - int 

 

OUTPUT: string 

 

EXAMPLES: 

 

sage: SloaneEncyclopedia.sequence_name(1) # optional - sloane_database 

'Number of groups of order n.' 

""" 

self.load() 

if not self.__loaded_names__: 

raise IOError("The Sloane OEIS names file is not installed. Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") 

 

if not N in self.__data__: # sequence N does not exist 

return '' 

return self.__data__[N][3] 

 

def unload(self): 

""" 

Remove the database from memory. 

""" 

if not self.__loaded__: 

return 

del self.__data__ 

self.__loaded__ = False 

self.__loaded_names__ = False 

 

SloaneEncyclopedia = SloaneEncyclopediaClass() 

 

def copy_gz_file(gz_source, bz_destination): 

""" 

Decompress a gzipped file and install the bzipped verson. This is 

used by SloaneEncyclopedia.install_from_gz to install several 

gzipped OEIS database files. 

 

INPUT: 

 

- ``gz_source`` - string. The name of the gzipped file. 

 

- ``bz_destination`` - string. The name of the newly compressed file. 

""" 

import gzip 

from sage.misc.misc import sage_makedirs 

 

# Read the gzipped input 

try: 

gz_input = gzip.open(gz_source, 'r') 

db_text = gz_input.read() 

gz_input.close() 

except IOError as msg: 

raise IOError("Error reading gzipped input file:\n%s"%msg) 

 

# Write the bzipped output 

try: 

sage_makedirs(os.path.dirname(bz_destination)) 

bz2_output = bz2.BZ2File(bz_destination, 'w') 

bz2_output.write(db_text) 

bz2_output.close() 

except IOError as msg: 

raise IOError("Error writing bzipped output file:\n%s"%msg) 

 

def parse_sequence(text=''): 

r""" 

This internal function was only used by the sloane_find function, 

which is now deprecated. 

 

TESTS:: 

 

sage: from sage.databases.sloane import parse_sequence 

sage: parse_sequence() 

doctest:...: DeprecationWarning: The function parse_sequence is not used anymore (2012-01-01). 

See http://trac.sagemath.org/10358 for details. 

""" 

deprecation(10358, "The function parse_sequence is not used anymore (2012-01-01).") 

 

def sloane_sequence(number=1, verbose=True): 

r""" 

This function is broken. It is replaced by the 

:mod:`OEIS <sage.databases.oeis>` module. 

 

Type ``oeis?`` for more information. 

 

TESTS:: 

 

sage: sloane_sequence(123) 

doctest:...: DeprecationWarning: The function sloane_sequence is deprecated. Use oeis() instead (2012-01-01). 

See http://trac.sagemath.org/10358 for details. 

""" 

deprecation(10358, 

"The function sloane_sequence is deprecated. " 

"Use oeis() instead (2012-01-01).") 

 

def sloane_find(list=[], nresults=30, verbose=True): 

r""" 

This function is broken. It is replaced by the 

:mod:`OEIS <sage.databases.oeis>` module. 

 

Type ``oeis?`` for more information. 

 

TESTS:: 

 

sage: sloane_find([1,2,3]) 

doctest:...: DeprecationWarning: The function sloane_find is deprecated. Use oeis() instead (2012-01-01). 

See http://trac.sagemath.org/10358 for details. 

""" 

deprecation(10358, 

"The function sloane_find is deprecated. " 

"Use oeis() instead (2012-01-01).")