/*
 * consts.cpp: spigot implementations of mathematical constants.
 */

#include "spigot.h"
#include "funcs.h"
#include "cr.h"

class E : public Source {
    int k;

  public:

    E() : Source(), k(1) {}

    virtual E *clone() { return new E(); }

    /*
     * The spigot definition for e is derived from the obvious
     * series for e obtained by expanding the Taylor series for
     * exp(1):
     *
     *  e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + ...
     *    = 1 + 1/1 * (1 + 1/2 * (1 + 1/3 * (1 + 1/4 * *...)))
     *
     * which gives us the infinite function composition
     *
     *   (x |-> 1+x) o (x |-> 1+x/2) o (x |-> 1+x/3) o ...
     *
     * and hence the sequence of matrices
     *
     *   ( 1 1 ) ( 1 2 ) ( 1 3 ) ... ( 1 k ) ...
     *   ( 0 1 ) ( 0 2 ) ( 0 3 )     ( 0 k )
     *
     * We must also adjust the limits 3 and 4. We picked the
     * interval [3,4] for the pi expansion because we know that each
     * of the functions in the infinite composition for pi maps
     * [3,4] to a subinterval of itself, meaning that the images of
     * the ends of that interval always bracket pi. However, this is
     * not true for the above series of functions for e. In fact,
     * there is _no_ interval which all of the above functions map
     * to a subinterval of itself, because the first function (x |->
     * 1+x) translates every interval upwards!
     *
     * Fortunately, all the functions _other_ than the first one
     * have the property that they map [0,2] to a subinterval of
     * itself. So once the image of [0,2] under a `partial sum' of
     * at least two terms of this function series contains e, its
     * image under subsequent partial sums will be a subinterval of
     * that and hence will always contain e as well. So we need only
     * check that no spurious `digits' are output before that
     * happens, and then we're safe. And this is OK, because the
     * identity matrix maps [0,2] to [0,2] which doesn't have a
     * constant integer part, the first function maps it to [1,3]
     * which doesn't either, and the first two functions map it to
     * [2,3] which contains e and is late enough in the series to be
     * safe.
     */

    bool gen_interval(bigint *low, bigint *high)
    {
        *low = 0;
        *high = 2;
        return true;
    }

    bool gen_matrix(bigint *matrix)
    {
        matrix[0] = 1;
        matrix[1] = k;
        matrix[2] = 0;
        matrix[3] = k;

        k++;

        return false;
    }
};

class Apery : public Source {
    int crState;
    bigint k;

    /*
     * Apery's constant: zeta(3), or the sum of the reciprocals of the
     * cubes of the natural numbers.
     */

  public:

    Apery() { crState = -1; }

    virtual Apery *clone() { return new Apery(); }

    bool gen_interval(bigint *low, bigint *high)
    {
        *low = -1;
        *high = +1;
        return true;
    }

    bool gen_matrix(bigint *matrix)
    {
        crBegin;

        /*
         * We spigotise the really simple series of Hjortnaes (source:
         * Wikipedia)
         *
         *           5          k-1    k!^2
         * zeta(3) = -  sum (-1)    ---------
         *           2 k>=1         k^3 (2k)!
         *
         * into a sequence of spigot matrices in which each one adds
         * 1/k^3, and multiplies in a factor n/d converting k!^2/(2k)!
         * into the same thing for k+1. (The factor also includes the
         * sign flip.)
         */

        /*
         * x |-> 5/2 x
         */
        matrix[0] = 5;
        matrix[1] = matrix[2] = 0;
        matrix[3] = 2;
        crReturn(true);

        for (k = 1 ;; ++k) {
            {
                bigint k3 = k*k*k;
                bigint n = k*k, d = (2*k-1) * (2*k);

                /*
                 * x |-> n/d (1/k3 - x) = (-n k3 x + n) / (0x + d k3)
                 */
                matrix[0] = -n*k3;
                matrix[1] = n;
                matrix[2] = 0;
                matrix[3] = d*k3;
            }

            crReturn(false);
        }

        crEnd;
    }
};

class Phi : public CfracSource {
    virtual Phi *clone() { return new Phi(); }

    /*
     * We could set up a spigot definition for phi, but it's more
     * easily defined in terms of its continued fraction, which
     * consists of nothing but 1s.
     */
  public:
    virtual bool gen_term(bigint *term)
    {
        *term = 1;
        return true;
    }
};

Spigot *spigot_pi()
{
    /*
     * Machin's formula: pi/4 = 4 atan(1/5) - atan(1/239).
     *
     * I used to compute pi using Jeremy Gibbons's original spigot
     * representation based on constructing a series of matrices
     * representing the formula
     *
     *             1     1.2     1.2.3
     *  pi = 2 + 2 - + 2 --- + 2 ----- + ...
     *             3     3.5     3.5.7
     *
     * but it turned out that telling spigot to compute the expression
     * '16*atan(1/5) - 4*atan(1/239)' was then much faster than 'pi'
     * and gave the same result.
     *
     * By using a Gosper instance with custom coefficients, we improve
     * the speed by one more notch by doing the scaling and summing of
     * the two atans in one go.
     */
    return spigot_combine(spigot_atan(spigot_rational(1, 5)),
                          spigot_atan(spigot_rational(1, 239)),
                          0, 16, -4, 0, 0, 0, 0, 1);
}

Spigot *spigot_tau()
{
    /*
     * Same implementation as pi above, but with coefficients doubled.
     */
    return spigot_combine(spigot_atan(spigot_rational(1, 5)),
                          spigot_atan(spigot_rational(1, 239)),
                          0, 32, -8, 0, 0, 0, 0, 1);
}

Spigot *spigot_e()
{
    return new E();
}

Spigot *spigot_phi()
{
    return new Phi();
}

Spigot *spigot_apery()
{
    return new Apery();
}
