Skip to main content

Look a number up in NumberDB and find out whether it is already known

Project description

numberdb

Look a number up in NumberDB and find out whether it is already known, and where else it appears.

$ pip install numberdb
>>> import numberdb
>>> for result in numberdb.search_real_ball(3.14159265, 1e-8):
...     print(result.exact_text[:24], '--', result.table.title)
3.1415926535897932384626 -- Pi
3.1415926535897932384626 -- Complete elliptic integral of the third kind $\Pi(n,m)$
3.1415926535897932384626 -- Best Sobolev constant for $W^{1,p}(\mathbb{R}^n)$

One number, three places it is known to appear; that is the question this package exists to answer.

In Python

Every call below is a complete example. Each returns a list of results, and the counts shown are what numberdb.org answers today.

A number you have, of whatever type. search accepts a single value and works out what it is:

>>> len(numberdb.search(10))                                  # int
2
>>> len(numberdb.search(Fraction(1, 3)))                      # fractions.Fraction
2
>>> len(numberdb.search('3.14159265358979'))                  # decimal string
3
>>> len(numberdb.search(numberdb.RealInterval('3.1415', '3.1416')))  # lower, upper
3
>>> len(numberdb.search(numberdb.PAdic(2, 0, 1, 167)))  # prime, valuation, unit, precision
6

RealInterval takes any scalar for its endpoints (int, Fraction, a decimal string, a float, or a Sage number), and keeps it exactly, as a Fraction. PAdic takes four integers, and its precision is absolute: PAdic(2, 0, 1, 167) is 1 + O(2^167).

A number whose type you want to state. These take the number's components directly, so nothing has to be spelled as a string first:

>>> len(numberdb.search_integer(10))
2
>>> len(numberdb.search_rational(1, 3))                       # numerator, denominator
2
>>> len(numberdb.search_real_interval('3.1415', '3.1416'))    # lower, upper
3
>>> len(numberdb.search_real_ball(3.14159265, 1e-8))          # centre, radius
3
>>> len(numberdb.search_complex_interval(0, 1, 0, 1))         # re_lower, re_upper, im_lower, im_upper
100
>>> len(numberdb.search_complex_ball(0, 1, '1/1000'))         # re_centre, im_centre, radius
2
>>> len(numberdb.search_p_adic(2, 0, 1, absolute_precision=167))   # prime, valuation, unit
6

search_p_adic takes absolute_precision or relative_precision; give exactly one.

Polynomials, matched up to renaming of the variables. The database stores this one in x, and asking in y finds it:

>>> numberdb.search_polynomial('x^20 + x^15 + x^10 + x^5 + 1')[0].table.title
'Cyclotomic polynomials'
>>> numberdb.search_polynomial('y^20 + y^15 + y^10 + y^5 + 1')[0].exact_text
'x^20 + x^15 + x^10 + x^5 + 1'

Text, in the search bar's grammar. This reads the string as a number in any of the written forms the website accepts: '3.14159' for a real, '1415' for a fractional part, 'Q5:1010' or '1 + O(5^20)' for a p-adic, '1/2 + i*0.866' for a complex number, 'x^2-2' for a polynomial. A string states its own precision, which is why text is a sound way to search and a bare float is not:

>>> len(numberdb.search_text('3.14159265358979'))
3

The same term is also read as words, against table titles and tag names. Those matches arrive as .tables and .tags rather than in the list itself, since they are signposts and not numbers:

>>> found = numberdb.search_text('matrix multiplication')
>>> len(found)
0
>>> [table.title for table in found.tables]
['Exponent of matrix multiplication complexity']
>>> [tag.name for tag in found.tags]
['matrix multiplication']
>>> numberdb.tag(found.tags[0].url)['table_count']
1

Note the 0: the list holds numbers, and this term matched none, so len() and if not found: speak only for the numbers. total counts everything the term matched, and is the question usually meant:

>>> found.total
2
>>> if not found.total:
...     print('nothing at all')

Both are asked, because a term is often both questions: '0.5' is a number, 'matrix multiplication' is words, and 'Pi' is honestly each. A term containing : or ^ is machinery written for a parser, and is not offered to the word search. Every other search fills .tables and .tags with empty lists.

An expression, evaluated by SageMath on the server:

>>> len(numberdb.search_by_expression('pi'))
3

Several numbers in one request. Cheaper than one call each (one round trip and a reduced rate-limit cost), and the result is keyed by position in the list:

>>> results = numberdb.search_many([10, Fraction(1, 3), numberdb.PAdic(2, 0, 1, 167)])
>>> {index: len(found) for index, found in sorted(results.items())}
{0: 2, 1: 2, 2: 6}

At most 100 numbers per call. Every position asked about is present in the result, so results[i] always answers for values[i]; a number that matched nothing maps to an empty list.

Tables and tags, fetched whole:

>>> sorted(numberdb.table('T12'))[:6]
['Comments', 'Data properties', 'Definition', 'Display properties', 'Formulas', 'ID']
>>> sorted(numberdb.tag('matrix+multiplication'))
['name', 'number_count', 'table_count', 'tables']

In SageMath

The same package, installed into Sage's own Python, with one import line:

$ sage -pip install numberdb
sage: import numberdb.sage as numberdb

Every function above is present under the same name and signature. Two things change: Sage's own types are accepted as arguments, and .value comes back as a Sage object in the natural parent.

sage: numberdb.search(10)[0].value.parent()
Integer Ring
sage: numberdb.search(1/3)[0].value.parent()
Rational Field
sage: numberdb.search(RIF(3.1415, 3.1416))[0].value
3.141592653589794?
sage: numberdb.search(RIF(3.1415, 3.1416))[0].value.parent()
Real Interval Field with 53 bits of precision
sage: numberdb.search(Qp(2)(1, 167))[0].value
1 + O(2^167)
sage: R.<x> = QQ[]
sage: numberdb.search(x^20 + x^15 + x^10 + x^5 + 1)[0].value
x^20 + x^15 + x^10 + x^5 + 1

The component-wise calls behave identically and also accept Sage scalars:

sage: len(numberdb.search_rational(1, 3))
2
sage: len(numberdb.search_real_ball(3.14159265, 1e-8))
3
sage: len(numberdb.search_real_interval(3.1415, 3.1416))
3
sage: len(numberdb.search_p_adic(2, 0, 1, absolute_precision=167))
6
sage: len(numberdb.search_by_expression('pi'))
3
sage: numberdb.search_polynomial('y^20 + y^15 + y^10 + y^5 + 1')[0].value
x^20 + x^15 + x^10 + x^5 + 1

numberdb.sage uses the SageMath you already have and installs nothing. Plain import numberdb never imports Sage, so it starts instantly; a single result can be converted on demand with .sage() either way.

What you get back

A search returns a SearchResults, which is a list of Result objects with two additional attributes.

Attribute Type Meaning
.messages list[str] remarks from the server about the search itself, if it had any
.unreadable list[Result] results whose value this version of the package cannot decode
.tables list[Table] tables whose title matched, filled in by search_text alone
.tags list[Tag] tags whose name matched, likewise
.total int everything matched: numbers, tables and tags together. len() counts the numbers alone

A Table carries .tid, .title, .url and .number_count; a Tag carries .name, .url, .table_count and .number_count. Both are signposts; numberdb.table(tid) and numberdb.tag(url) fetch the contents.

Each Result carries:

Attribute Type Meaning
.value see below the number itself, decoded on first access
.exact_text str the database's own spelling; the form to quote, or to paste back into a search
.str_short str an abbreviated form, comparable across results
.kind str one of ZZ, QQ, RIF, RBF, CIF, Qp, polynomial
.param str which entry of its table this is
.table Table where it lives, with .tid, .title and .url
.is_readable bool whether .value can be decoded by this version
.url() str the page describing it
.sage() Sage object the value converted to Sage, on request

The type of .value depends on which module you imported:

.kind plain numberdb numberdb.sage
ZZ int (unbounded) Integer
QQ fractions.Fraction Rational
RIF, RBF RealInterval, endpoints exact Fractions element of RealIntervalField
CIF ComplexInterval of two RealIntervals element of ComplexIntervalField
Qp PAdic(prime, valuation, unit, precision_absolute) element of Qp(prime)
polynomial Polynomial(variable_count, text) element of a polynomial ring over QQ

Exact values stay exact. Integers are Python int, which is unbounded (the database holds integers of over a thousand digits); rationals are Fraction, and interval endpoints are exact Fractions rather than rounded floats. Conversion to float is therefore explicit, never an accident of transport:

>>> result = numberdb.search_real_ball(3.14159265, 1e-8)[0]
>>> result.value
RealInterval(884279719003555/281474976710656, 7074237752028441/2251799813685248)
>>> float(result.value)          # the midpoint, explicitly lossy
3.141592653589793

A PAdic carries its unit as an integer together with a valuation, because Q_p is not Z_p: a value of negative valuation such as 1/5 in Q_5 has no integer form. Its precision is absolute: the ball is everything congruent to the value modulo prime ** precision_absolute, matching the O(p^k) in the printed form.

When the server is newer than the package

NumberDB will learn new kinds of number. An older package still returns every result: values are decoded only when asked for, so an unfamiliar one costs you that value and nothing else, and its .exact_text is there regardless.

>>> for result in numberdb.search_text('3.14159'):
...     if result.is_readable:
...         use(result.value)
...     else:
...         print(result.exact_text)   # still perfectly readable

results.unreadable lists them. Every exception the package raises derives from numberdb.NumberDBError, so a single except covers it; TransportError, RateLimited, Unauthorized and UnsupportedNumber are the specific cases.

Rate limits and API keys

Anonymous use is rate limited; a key raises the limit. Keep it out of your worksheet; a shared notebook should not carry its author's key:

$ export NUMBERDB_API_KEY=...

or, if you must set it in code:

>>> numberdb.configure(api_key='...')

For more than one server or key in a process, use a client directly:

>>> client = numberdb.Client(api_key='...')
>>> numberdb.search_text('3.14159', client=client)

Exceeding the limit raises numberdb.RateLimited, which carries .retry_after in seconds when the server supplies it.

Pointing it somewhere else

The default is https://numberdb.org. Override it for a development server, or a private instance:

$ export NUMBERDB_URL=http://localhost:8000
>>> client = numberdb.Client(base_url='https://example.org/numberdb')
>>> numberdb.search_text('3.14159', client=client)

A trailing slash is optional, and a base URL with a path prefix keeps it either way.

Licence

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

numberdb-0.0.2.tar.gz (50.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

numberdb-0.0.2-py3-none-any.whl (38.1 kB view details)

Uploaded Python 3

File details

Details for the file numberdb-0.0.2.tar.gz.

File metadata

  • Download URL: numberdb-0.0.2.tar.gz
  • Upload date:
  • Size: 50.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for numberdb-0.0.2.tar.gz
Algorithm Hash digest
SHA256 ceed398ea2ad5555c71747ac302e60469899a3dbb9237acffb0977f0653db3c4
MD5 e16b7348adea00cd8a47141885a0c274
BLAKE2b-256 a5d898628c7c61c13ad18ee40c9885467a9d3f10e1f61872f675059dc962326c

See more details on using hashes here.

Provenance

The following attestation bundles were made for numberdb-0.0.2.tar.gz:

Publisher: publish-numberdb.yml on numberdb/numberdb-website

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file numberdb-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: numberdb-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 38.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for numberdb-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9ef0e58329532092a92889a34ad592d5fb9280614949cdea3d84b4b82374bea7
MD5 f0c61f30db0d61183d6103bcd8b866ae
BLAKE2b-256 5c85082a57d5a4e4ce1c0856467dc6e8c13f723189340e9f3a07b006e815e85e

See more details on using hashes here.

Provenance

The following attestation bundles were made for numberdb-0.0.2-py3-none-any.whl:

Publisher: publish-numberdb.yml on numberdb/numberdb-website

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page