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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ceed398ea2ad5555c71747ac302e60469899a3dbb9237acffb0977f0653db3c4
|
|
| MD5 |
e16b7348adea00cd8a47141885a0c274
|
|
| BLAKE2b-256 |
a5d898628c7c61c13ad18ee40c9885467a9d3f10e1f61872f675059dc962326c
|
Provenance
The following attestation bundles were made for numberdb-0.0.2.tar.gz:
Publisher:
publish-numberdb.yml on numberdb/numberdb-website
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
numberdb-0.0.2.tar.gz -
Subject digest:
ceed398ea2ad5555c71747ac302e60469899a3dbb9237acffb0977f0653db3c4 - Sigstore transparency entry: 2332695024
- Sigstore integration time:
-
Permalink:
numberdb/numberdb-website@65ad6c0e091b0b75570c9e9d4614afb3add2021b -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/numberdb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-numberdb.yml@65ad6c0e091b0b75570c9e9d4614afb3add2021b -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ef0e58329532092a92889a34ad592d5fb9280614949cdea3d84b4b82374bea7
|
|
| MD5 |
f0c61f30db0d61183d6103bcd8b866ae
|
|
| BLAKE2b-256 |
5c85082a57d5a4e4ce1c0856467dc6e8c13f723189340e9f3a07b006e815e85e
|
Provenance
The following attestation bundles were made for numberdb-0.0.2-py3-none-any.whl:
Publisher:
publish-numberdb.yml on numberdb/numberdb-website
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
numberdb-0.0.2-py3-none-any.whl -
Subject digest:
9ef0e58329532092a92889a34ad592d5fb9280614949cdea3d84b4b82374bea7 - Sigstore transparency entry: 2332695036
- Sigstore integration time:
-
Permalink:
numberdb/numberdb-website@65ad6c0e091b0b75570c9e9d4614afb3add2021b -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/numberdb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-numberdb.yml@65ad6c0e091b0b75570c9e9d4614afb3add2021b -
Trigger Event:
release
-
Statement type: