Navigation

Most function in mpmath are concerned with producing approximations from exact mathematical formulas. It is also useful to consider the inverse problem: given only a decimal approximation for a number, such as 0.7320508075688772935274463, is it possible to find an exact formula?

Subject to certain restrictions, such “reverse engineering” is indeed possible thanks to the existence of integer relation algorithms. Mpmath implements the PSLQ algorithm (developed by H. Ferguson), which is one such algorithm.

Automated number recognition based on PSLQ is not a silver bullet. Any occurring transcendental constants (, , etc) must be guessed by the user, and the relation between those constants in the formula must be linear (such as ). More complex formulas can be found by combining PSLQ with functional transformations; however, this is only feasible to a limited extent since the computation time grows exponentially with the number of operations that need to be combined.

The number identification facilities in mpmath are inspired by the Inverse Symbolic Calculator (ISC). The ISC is more powerful than mpmath, as it uses a lookup table of millions of precomputed constants (thereby mitigating the problem with exponential complexity).

Given a real number , identify(x) attempts to find an exact
formula for . This formula is returned as a string. If no match
is found, None is returned. With full=True, a list of
matching formulas is returned.

As a simple example, identify() will find an algebraic
formula for the golden ratio:

identify() can identify simple algebraic numbers and simple
combinations of given base constants, as well as certain basic
transformations thereof. More specifically, identify()
looks for the following:

Fractions

Quadratic algebraic numbers

Rational linear combinations of the base constants

Any of the above after first transforming into where
is , , , or , either
directly or with or multiplied or divided by one of
the base constants

Products of fractional powers of the base constants and
small integers

Base constants can be given as a list of strings representing mpmath
expressions (identify() will eval the strings to numerical
values and use the original strings for the output), or as a dict of
formula:value pairs.

In order not to produce spurious results, identify() should
be used with high precision; preferably 50 digits or more.

Examples

Simple identifications can be performed safely at standard
precision. Here the default recognition of rational, algebraic,
and exp/log of algebraic numbers is demonstrated:

By default, identify() does not recognize . At standard
precision it finds a not too useful approximation. At slightly
increased precision, this approximation is no longer accurate
enough and identify() more correctly returns None:

The output formula can be evaluated as a Python expression.
Note however that if fractions (like ‘2/3’) are present in
the formula, Python’s eval() may erroneously perform
integer division. Note also that the output is not necessarily
in the algebraically simplest form:

>>> identify(sqrt(2))'(sqrt(8)/2)'

As a solution to both problems, consider using SymPy’s
sympify() to convert the formula into a symbolic expression.
SymPy can be used to pretty-print or further simplify the formula
symbolically:

>>> fromsympyimportsympify>>> sympify(identify(sqrt(2)))2**(1/2)

Sometimes identify() can simplify an expression further than
a symbolic algorithm:

(In fact, this functionality is available directly in SymPy as the
function nsimplify(), which is essentially a wrapper for
identify().)

Miscellaneous issues and limitations

The input must be a real number. All base constants must be
positive real numbers and must not be rationals or rational linear
combinations of each other.

The worst-case computation time grows quickly with the number of
base constants. Already with 3 or 4 base constants,
identify() may require several seconds to finish. To search
for relations among a large number of constants, you should
consider using pslq() directly.

The extended transformations are applied to x, not the constants
separately. As a result, identify will for example be able to
recognize exp(2*pi+3) with pi given as a base constant, but
not 2*exp(pi)+3. It will be able to recognize the latter if
exp(pi) is given explicitly as a base constant.

findpoly(x,n) returns the coefficients of an integer
polynomial of degree at most such that .
If no polynomial having as a root can be found,
findpoly() returns None.

findpoly() works by successively calling pslq() with
the vectors , , , ...,
as input. Keyword arguments given to
findpoly() are forwarded verbatim to pslq(). In
particular, you can specify a tolerance for with tol
and a maximum permitted coefficient size with maxcoeff.

For large values of , it is recommended to run findpoly()
at high precision; preferably 50 digits or more.

Despite only containing square roots, the following number results
in a polynomial of degree 4:

>>> findpoly(sqrt(2)+sqrt(3),4)[1, 0, -10, 0, 1]

In fact, is the minimal polynomial of
, meaning that a rational polynomial of
lower degree having as a root does not exist. Given sufficient
precision, findpoly() will usually find the correct
minimal polynomial of a given algebraic number.

Non-algebraic numbers

If findpoly() fails to find a polynomial with given
coefficient size and tolerance constraints, that means no such
polynomial exists.

We can verify that is not an algebraic number of degree 3 with
coefficients less than 1000:

>>> mp.dps=15>>> findpoly(pi,3)>>>

It is always possible to find an algebraic approximation of a number
using one (or several) of the following methods:

It is unknown whether Euler’s constant is transcendental (or even
irrational). We can use findpoly() to check that if is
an algebraic number, its minimal polynomial must have degree
at least 7 and a coefficient of magnitude at least 1000000:

Note that the high precision and strict tolerance is necessary
for such high-degree runs, since otherwise unwanted low-accuracy
approximations will be detected. It may also be necessary to set
maxsteps high to prevent a premature exit (before the coefficient
bound has been reached). Running with verbose=True to get an
idea what is happening can be useful.

We could try to generate a custom Machin-like formula by running
the PSLQ algorithm with a few inverse cotangent values, for example
acot(2), acot(3) ... acot(10). Unfortunately, there is a linear
dependence among these values, resulting in only that dependence
being detected, with a zero coefficient for :