/*
 * spigot.cpp: Implementation of the Spigot base classes, i.e.
 * methods which convert between a spigot description and the
 * various other output types.
 *
 * This file is where the implementation of the core spigot
 * algorithm lives.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <map>
using std::map;

#include "spigot.h"
#include "error.h"
#include "cr.h"

/* ----------------------------------------------------------------------
 * Class definitions private to this source file.
 */

class Core1 : public Core {
    unique_ptr<Source> source;
    bool started;
    Matrix matrix;
    bigint bot;
    bigint_or_inf top;
  public:
    Core1(unique_ptr<Source> asource);
  private:
    virtual void premultiply(const Matrix &matrix) override;
    virtual Spigot clone() override;
    virtual void refine() override;
    virtual void endpoints(vector<endpoint> &) override;

    /*
     * Because Core1 has a unique child Source, it passes through the
     * special-case is_rational function to that Source.
     */
    virtual bool is_rational(bigint *n, bigint *d) override;
};

class GeneratorSource : public BinaryIntervalSource {
    BracketingGenerator bg;
    unique_ptr<Core> core_orig;
  public:
    GeneratorSource(unique_ptr<Core> acore);
  private:
    virtual Spigot clone() override;
    virtual void gen_bin_interval(bigint *ret_lo, bigint *ret_hi,
                                  unsigned *ret_bits) override;
};

class RationalSource : public Source {
    bigint n, d;
  public:
    RationalSource(const bigint &an, const bigint &ad);
  private:
    virtual Spigot clone() override;
    virtual bool gen_interval(bigint *low, bigint_or_inf *high) override;
    virtual bool gen_matrix(Matrix &matrix) override;
    virtual bool is_rational(bigint *n, bigint *d) override;
};

/* ----------------------------------------------------------------------
 * Utility function.
 */

Matrix matmul(const Matrix &a, const Matrix &b)
{
    return { a[0]*b[0] + a[1]*b[2], a[0]*b[1] + a[1]*b[3],
             a[2]*b[0] + a[3]*b[2], a[2]*b[1] + a[3]*b[3] };
}

/* ----------------------------------------------------------------------
 * Diagnostics.
 */

set<Debuggable::Id> Debuggable::debug_ids;
set<string> Debuggable::debug_names;
bool Debuggable::debug_all_greetings = false;
bool Debuggable::debug_all_objects = false;

Debuggable::Debuggable()
    : debugging(false)
{
    static unsigned long next_id = 0;
    debuggable_object_id = static_cast<Id>(next_id++);
    if (debug_all_objects ||
        debug_ids.find(debuggable_object_id) != debug_ids.end())
        debugging = true;
}

void Debuggable::set_debuggable_object_name(const ClassName &name)
{
    debuggable_object_name = name.name;
    if (debug_names.find(debuggable_object_name) != debug_names.end())
        debugging = true;
}

auto Debuggable::dbg_id() -> Id
{
    return debuggable_object_id;
}

void Debuggable::add_debug_id(Id id)
{
    debug_ids.insert(id);
}

void Debuggable::add_debug_name(const string &name)
{
    debug_names.insert(name);
}

void Debuggable::debug_greetings()
{
    debug_all_greetings = true;
}

void Debuggable::debug_all()
{
    debug_all_objects = true;
}

struct DebuggableClassNameList {
    map<string, const Debuggable::ClassName *> name_map;
    static DebuggableClassNameList &instance();
    static void register_name(const Debuggable::ClassName *cn);
};

DebuggableClassNameList &DebuggableClassNameList::instance()
{
    static DebuggableClassNameList the_instance;
    return the_instance;
}

void DebuggableClassNameList::register_name(const Debuggable::ClassName *cn)
{
    auto &name_map = instance().name_map;
    assert(name_map.find(cn->name) == name_map.end());
    name_map[cn->name] = cn;
}

Debuggable::ClassName::ClassName(const char *name) : name(name)
{
    DebuggableClassNameList::register_name(this);
}

bool Debuggable::is_known_class_name(const string &name)
{
    auto &name_map = DebuggableClassNameList::instance().name_map;
    return name_map.find(name) != name_map.end();
}

vector<string> Debuggable::known_class_names()
{
    vector<string> toret;
    for (auto kv: DebuggableClassNameList::instance().name_map)
        toret.push_back(kv.first);
    return toret;
}

/* ----------------------------------------------------------------------
 * Administrivia: tiny functions in abstract base classes and small
 * struct-oids like endpoint.
 */

bool Coreable::is_rational(bigint * /*n*/, bigint * /*d*/)
{
    return false;
}

unique_ptr<Core> Source::toCore()
{
    return make_unique<Core1>(unique_ptr<Source>(this));
}

unique_ptr<Core> Core::toCore()
{
    return unique_ptr<Core>(this);
}

unique_ptr<Source> Source::toSource()
{
    return unique_ptr<Source>(this);
}

unique_ptr<Source> Core::toSource()
{
    return make_unique<GeneratorSource>(unique_ptr<Core>(this));
}

endpoint::endpoint(const bigint &an, const bigint &ad)
    : n(an), d(ad)
{
}

OutputGenerator::OutputGenerator(Spigot acore)
    : Generator(move(acore))
{
}

/* ----------------------------------------------------------------------
 * The helper class bigint_or_inf for Source interval upper bounds.
 */

bigint_or_inf::bigint_or_inf(Infinity)
    : is_infinite{true}, n{0}
{
}

bigint_or_inf::bigint_or_inf(const bigint &an)
    : is_infinite{false}, n{an}
{
}

bigint_or_inf &bigint_or_inf::operator=(const bigint &an)
{
    is_infinite = false;
    n = an;
    return *this;
}

bool bigint_or_inf::finite(bigint *value) const
{
    if (is_infinite)
        return false;
    if (value)
        *value = n;
    return true;
}

const bigint_or_inf bigint_or_inf::infinity{Infinity()};

/* ----------------------------------------------------------------------
 * Non-virtual methods in Source.
 */

bool Source::get_interval(bigint *low, bigint_or_inf *high)
{
    if (got_interval)
        internal_fault("get_interval called twice");
    got_interval = true;

    bool force = gen_interval(&int_lo, &int_hi);

    if (!force)
        started = true;

    dprint("refining check: got interval [", int_lo, ",",
           int_hi, "], force=", force);

    *low = int_lo;
    *high = int_hi;
    return force;
}

bool Source::get_matrix(Matrix &matrix)
{
    if (!got_interval)
        internal_fault("get_matrix called before get_interval");

    bool force = gen_matrix(matrix);

    dprint("refining check: got matrix ", matrix, ", force=", force);

    if (!started) {
        if (!force)
            started = true;
        return force;
    }

    pending_matrix = matmul(pending_matrix, matrix);

    if (force)
        return force;

    // Compute the image of the low end of the input interval.
    // The high end will need more variable treatment below.
    bigint n_lo = pending_matrix[0] * int_lo + pending_matrix[1];
    bigint d_lo = pending_matrix[2] * int_lo + pending_matrix[3];
    bigint n_hi, d_hi;

    dprint("refining check: matrix ", pending_matrix,
           " vs interval [", int_lo, ",", int_hi, "]");

    bigint i_hi;
    if (!int_hi.finite(&i_hi)) {
        // Special-case handling for the top end of the input
        // interval being +inf.

        n_hi = pending_matrix[0];
        d_hi = pending_matrix[2];

        dprint("  image endpoints { ", n_lo, "/", d_lo, ", ",
               n_hi, "/", d_hi, " }");

        if (d_lo == 0 && d_hi == 0) {
            // One allowed special case with an infinite interval is
            // to return the 'constant function' that maps the _whole_
            // interval to infinity, and signals the termination of a
            // finitely long continued fraction.
            dprint("  constant-infinity function");
            goto checked;
        } else if (d_lo == 0 || d_hi == 0) {
            // A pole is permitted in the interval if it's at the very
            // bottom or at the (infinite) top.
            //
            // If so, then we require that the pole must be
            // the right way round (i.e. the large positive
            // values occur _inside_ the interval, and the
            // large negative ones outside). This occurs if
            // the numerator and denominator have the same
            // sign at int_lo+epsilon, i.e. n_lo has to have
            // the same sign as d_hi.
            //
            // To make this _and_ the next step easier,
            // normalise the nonzero denominator (whichever it
            // is) to be non-negative.
            if (d_hi < 0 || d_lo < 0) {
                n_lo = -n_lo;
                d_lo = -d_lo;
                n_hi = -n_hi;
                d_hi = -d_hi;
            }

            if (d_lo == 0) {
                // Case where the pole is at the bottom end.

                dprint("  pole at ", int_lo, " -> { ", n_lo, "/", d_lo, ", ",
                       n_hi, "/", d_hi, " }");

                // Complete the sign check from above.
                if (!(n_lo > 0 && d_hi > 0)) {
                    dprint("pole of wrong sign at bottom of "
                           "infinite interval");
                    internal_fault("refinement check failed");
                }

                // Now we know that the image of int_lo is +inf,
                // so we just need to check that the image of
                // int_hi (i.e. of +inf) is greater than or equal
                // to int_lo.
                if (!(n_hi >= int_lo * d_hi)) {
                    dprint("top of infinite interval has "
                           "image ", n_hi, "/", d_hi, " which "
                           "is less than interval lower bound ",
                           int_lo);
                    internal_fault("refinement check failed");
                }
            } else {
                // Case where the pole is at the top end.

                dprint("  pole at +inf -> { ", n_lo, "/", d_lo, ", ",
                       n_hi, "/", d_hi, " }");

                // Complete the sign check from above.
                if (!(n_hi > 0 && d_lo > 0)) {
                    dprint("pole of wrong sign at top of infinite interval");
                    internal_fault("refinement check failed");
                }

                // Now we know that the image of int_hi is
                // +inf, so we just need to check that the
                // image of int_lo is greater than or equal to
                // int_lo.
                if (!(n_lo >= int_lo * d_lo)) {
                    dprint("bottom of infinite interval has image ",
                           n_lo, "/", d_lo, " which is less than interval "
                           "lower bound ", int_lo);
                    internal_fault("refinement check failed");
                }
            }

            // And now we're done, so skip the remaining code.
            goto checked;
        }
    } else {
        n_hi = pending_matrix[0] * i_hi + pending_matrix[1];
        d_hi = pending_matrix[2] * i_hi + pending_matrix[3];

        dprint("  image endpoints { ", n_lo, "/", d_lo, ", ",
               n_hi, "/", d_hi, " }");
    }

    // Normalise one of the denominators to be non-negative.
    if (d_lo < 0) {
        n_lo = -n_lo;
        d_lo = -d_lo;
        n_hi = -n_hi;
        d_hi = -d_hi;
    }

    dprint("  normalised -> { ", n_lo, "/", d_lo, ", ",
           n_hi, "/", d_hi, " }");

    // Now both denominators must be strictly positive,
    // otherwise there's a pole in the interval and the
    // matrix can't be refining.
    if (!(d_lo > 0 && d_hi > 0)) {
        dprint("pole in finite interval");
        internal_fault("refinement check failed");
    }

    // Check that both image endpoints are within the
    // original interval.
    if (!(int_lo * d_lo <= n_lo)) {
        dprint("bottom of finite interval has image ",
               n_lo, "/", d_lo, " which is less than "
               "interval lower bound ", int_lo);
        internal_fault("refinement check failed");
    }
    if (!(int_lo * d_hi <= n_hi)) {
        dprint("top of finite interval has image ",
               n_hi, "/", d_hi, " which is less than "
               "interval lower bound ", int_lo);
        internal_fault("refinement check failed");
    }
    if (int_hi.finite(&i_hi)) {
        // Only need this check if the top end is not +infinity
        if (!(n_lo <= i_hi * d_lo)) {
            dprint("bottom of finite interval has image ",
                   n_lo, "/", d_lo, " which is greater than "
                   "interval upper bound ", int_hi);
            internal_fault("refinement check failed");
        }
        if (!(n_hi <= i_hi * d_hi)) {
            dprint("top of finite interval has image ",
                   n_hi, "/", d_hi, " which is less than "
                   "interval upper bound ", int_hi);
            internal_fault("refinement check failed");
        }
    }

  checked:
    pending_matrix = { 1, 0, 0, 1 };

    return force;
}

/* ----------------------------------------------------------------------
 * Core1, the primary default implementation of Core.
 */

MAKE_CLASS_GREETER(Core1);

Core1::Core1(unique_ptr<Source> asource)
    : source(move(asource))
    , started(false)
    , matrix{ 1, 0, 0, 1 }
{
    dgreet(source->dbg_id());
}

void Core1::premultiply(const Matrix &inmatrix)
{
    dprint("premultiply: ", inmatrix, " ", matrix);
    matrix = matmul(inmatrix, matrix);
    dprint("matrix after premult ", matrix);
}

Spigot Core1::clone()
{
    return spigot_clone(this, source->clone().release()->toSource());
}

void Core1::refine()
{
    bool force_absorb = false;

    dprint("refine started");

    if (!started) {
        /*
         * Fetch the interval bounds.
         */
        source->get_interval(&bot, &top);
        started = true;
        dprint("Core1 init: interval [", bot, ",", top, "]");
    }

    do {
        Matrix inmatrix;
        force_absorb = source->get_matrix(inmatrix);
        dprint("postmultiply: ", matrix, " ", inmatrix);
        matrix = matmul(matrix, inmatrix);
        dprint("matrix after postmult ", matrix);
    } while (force_absorb);
}

void Core1::endpoints(vector<endpoint> &endpoints)
{
    dprint("endpoints for ", matrix);
    endpoints.clear();
    endpoints.emplace_back(matrix[0] * bot + matrix[1],
                           matrix[2] * bot + matrix[3]);
    auto &ep = endpoints[endpoints.size() - 1];
    dprint("  1st endpoint ", ep.n, " / ", ep.d);
    bigint tv;
    if (top.finite(&tv)) {
        endpoints.emplace_back(matrix[0] * tv + matrix[1],
                               matrix[2] * tv + matrix[3]);
        auto &ep = endpoints[endpoints.size() - 1];
        dprint("  finite 2nd endpoint ", ep.n, " / ", ep.d);
    } else {
        /*
         * To evaluate a Mobius function at infinity, we take the
         * limit as x -> inf of its value at x.
         *
         * If at least one of a,c is nonzero, then the constant terms
         * b,d become insignificant, and the limit of (ax+b)/(cx+d) is
         * the same as the limit of ax/cx. But if a,c are both zero,
         * so that we have a constant function, then (ax+b)/(cx+d) =
         * b/d for any finite x, and hence the limit at infinity is
         * b/d as well.
         */
        if (matrix[0] == 0 && matrix[2] == 0) {
            endpoints.emplace_back(matrix[1], matrix[3]);
        } else {
            endpoints.emplace_back(matrix[0], matrix[2]);
        }
        auto &ep = endpoints[endpoints.size() - 1];
        dprint("  infinite 2nd endpoint ", ep.n, " / ", ep.d);
    }
}

bool Core1::is_rational(bigint *n, bigint *d)
{
    return source->is_rational(n, d);
}

/* ----------------------------------------------------------------------
 * The Generator class.
 */

MAKE_CLASS_GREETER(Generator);

Generator::Generator(unique_ptr<Coreable> acore)
    : started(false), we_are_now_constant(false)
{
    core = acore.release()->toCore();
    dgreet(core->dbg_id());
}

void Generator::ensure_started()
{
    if (!started) {
        started = true;
        iterate_spigot_algorithm(true);
    }
}

void Generator::iterate_spigot_algorithm(bool force)
{
    /*
     * This is the main loop of the spigot algorithm. It bounces on
     * core->refine() until the core's current state describes a
     * sensible interval rather than something with a pole in it, then
     * returns the current set of endpoints so that one of its wrapper
     * functions can check in turn whether there's enough detail to
     * satisfy the client.
     *
     * If 'force' is true, core->refine() will be called at least
     * once; otherwise we'll check first to see if we have enough data
     * already.
     */

    ensure_started();

    dprint("iterate_spigot_algorithm beginning");

    while (1) {
        if (!we_are_now_constant && force)
            core->refine();
        force = true;

        spigot_check_exception();

        core->endpoints(endpoints);
        if (endpoints.size() == 0)
            internal_fault("core returned no endpoints");

        dprint("iterate_spigot_algorithm got endpoints:");
        for (size_t i = 0; i < endpoints.size(); ++i)
            dprint("  ", i, ": ", endpoints[i].n, " / ", endpoints[i].d);

        int d_sign = bigint_sign(endpoints[0].d);
        bool d_signs_ok = (d_sign != 0);
        bool all_constant = true;
        for (size_t i = 1; i < endpoints.size(); ++i) {
            if (endpoints[i].n != endpoints[0].n ||
                endpoints[i].d != endpoints[0].d)
                all_constant = false;
            if (bigint_sign(endpoints[i].d) != bigint_sign(endpoints[0].d))
                d_signs_ok = false;
        }

        /*
         * We return if the interval is bounded, or if we have a
         * constant function. (The constant function returning
         * infinity counts as bounded, and is the _only_ thing
         * touching the point at infinity which does so!)
         */
        if (d_signs_ok || all_constant) {
            /*
             * If our interval is a single point, set the
             * we_are_now_constant flag, which will inhibit any
             * further calls to core->refine(). (This is necessary
             * because spigot sources which return a matrix intended
             * to terminate the stream in this way cannot deal
             * gracefully with being called again afterwards.)
             */
            if (all_constant)
                we_are_now_constant = true;

            dprint("iterate_spigot_algorithm returning");
            return;
        }
    }
}

static void divide_with_exactness(bigint *q, bool *remainder,
                                  const bigint &n, const bigint &d)
{
    *q = fdiv(n, d);
    *remainder = (*q) * d != n;
}

void Generator::iterate_to_bounds(bigint *rlo, bigint *rhi,
                                  bool *rlo_open, bool *rhi_open,
                                  int minwidth,
                                  const bigint *scale,
                                  bool force_refine)
{
    /*
     * Returns a bounding interval for the number, bounded by the two
     * integers 'lo' and 'hi'.
     *
     * Also optionally (if lo_open and hi_open are non-null) returns
     * information about whether those endpoints are open or closed,
     * i.e. distinguishes between (a,b), (a,b], [a,b) and [a,b].
     *
     * If minwidth is nonzero, this function iterates until hi-lo is
     * at most that. (Passing minwidth==1 risks never returning due to
     * an exactness hazard, but minwidth>=2 should reliably return.)
     * If minwidth is zero, we just return whatever bounding interval
     * we first get (though we do at least one refinement step first).
     *
     * If scale is provided, the bounding interval is not for the
     * number itself but for the number times 'scale'. (scale must be
     * positive.)
     */

    while (1) {
        iterate_spigot_algorithm(force_refine);
        force_refine = true;           // for next time

        bigint &lo = *rlo, &hi = *rhi;
        bool lo_extra, hi_extra;

        // In this mode, we never expect the constant-inf output function.
        if (endpoints.size() < 2)
            internal_fault("iterate_to_bounds only got ", endpoints.size(),
                           " endpoints");
        if (endpoints[0].d == 0)
            internal_fault("iterate_to_bounds got infinite lower bound");

        if (scale) {
            for (size_t i = 0; i < endpoints.size(); ++i)
                endpoints[i].n *= *scale;
        }

        divide_with_exactness(&lo, &lo_extra, endpoints[0].n, endpoints[0].d);
        hi = lo;
        hi_extra = lo_extra;
        for (size_t i = 1; i < endpoints.size(); ++i) {
            bigint tmp;
            bool tmp_extra;
            divide_with_exactness(&tmp, &tmp_extra,
                                  endpoints[i].n, endpoints[i].d);
            if (tmp < lo || (tmp == lo && !tmp_extra && lo_extra)) {
                lo = tmp;
                lo_extra = tmp_extra;
            }
            if (tmp > hi || (tmp == hi && tmp_extra && !hi_extra)) {
                hi = tmp;
                hi_extra = tmp_extra;
            }
        }

        /*
         * Our numbers are currently in the form (integer, boolean
         * saying whether there's a nonzero fraction part to go
         * with it). For the lower interval bound, that's
         * equivalent to (integer bound, boolean saying if it's an
         * open bound). For the higher bound, we must round the
         * integer part up if the fraction is nonzero.
         */
        if (hi_extra)
            ++hi;

        if (!minwidth || hi - lo <= minwidth) {
            /*
             * OK, return.
             */
            if (rlo_open) *rlo_open = lo_extra;
            if (rhi_open) *rhi_open = hi_extra;
            return;
        }
    }
}

bool Generator::iterate_to_floor_or_inf(bigint *rfloor, bool *rconstant)
{
    /*
     * Iterates until the number has a constant integer part (that is,
     * really a constant _floor_), and returns it.
     *
     * Also fills in 'constant', if non-null, indicating whether the
     * number is _exactly_ its constant integer part.
     *
     * A second possibility is that the spigot matrix might have
     * turned into the constant function always returning infinity
     * (which signals termination in continued fraction output mode).
     * Returning the boolean 'false' indicates this; 'true' indicates
     * that a sensible integer was returned.
     */
    bool force = false;
    while (1) {
        iterate_spigot_algorithm(force);
        force = true;                  // for next time

        // iterate_spigot_algorithm has ensured that all the
        // denominators of the endpoints have the same sign. Hence, we
        // need only test the first denominator for zero to tell
        // whether they're all zero and we have the constant-inf
        // function.
        if (endpoints[0].d == 0)
            return false;

        bigint &n = *rfloor;

        // See if everything has the same integer part.
        bool ok = true;
        n = fdiv(endpoints[0].n, endpoints[0].d);
        bool constant = endpoints[0].n == n * endpoints[0].d;
        for (size_t i = 1; i < endpoints.size(); ++i) {
            bigint tmp = fdiv(endpoints[i].n, endpoints[i].d);
            if (rconstant && endpoints[i].n != n * endpoints[i].d)
                constant = false;
            if (tmp != n) {
                ok = false;
                break;
            }
        }

        // If so, return it (it's already in *rfloor). Otherwise go
        // round again.
        if (ok) {
            if (rconstant)
                *rconstant = constant;
            return true;
        }
    }
}

bigint Generator::iterate_to_floor(bool *constant)
{
    /*
     * Wrapper around iterate_to_floor_or_inf, which checks that the
     * inf case never comes up.
     */
    bigint ret;

    if (!iterate_to_floor_or_inf(&ret, constant))
        internal_fault("iterate_to_floor got infinity");

    return ret;
}

/* ----------------------------------------------------------------------
 * CfracGenerator: convert a Core into a stream of continued fraction
 * terms.
 */

MAKE_CLASS_GREETER(CfracGenerator);

CfracGenerator::CfracGenerator(unique_ptr<Coreable> acore)
    : Generator(move(acore))
    , done(false)
{
    dgreet(core->dbg_id());
}

bool CfracGenerator::get_term(bigint *term)
{
    bool ret;

    if (done)
        return false;

    ret = iterate_to_floor_or_inf(term);

    if (!ret) {
        /*
         * An infinite return value means that the continued
         * fraction has terminated. At this point, and forever
         * hereafter, we return false.
         */
        dprint("terminated");
        done = true;
        return false;
    } else {
        /*
         * Otherwise, we return this term, and premultiply in a
         * matrix which represents subtracting it off and taking the
         * reciprocal: that is, x |-> 1/(x-a) = (0x+1)/(1x-a),
         * represented by the matrix (0  1)
         *                           (1 -a).
         */
        Matrix outmatrix = { 0, 1, 1, -*term };
        dprint("extract cfrac term ", term, ": ", outmatrix);
        core->premultiply(outmatrix);
        return true;
    }
}

/* ----------------------------------------------------------------------
 * ConvergentsGenerator: wrap CfracGenerator so that it returns
 * rational convergents reconstituted from the raw continued fraction
 * terms.
 */

ConvergentsGenerator::ConvergentsGenerator(unique_ptr<Coreable> acore)
    : cfg(move(acore))
    , cvn(1)
    , pcvn(0)
    , cvd(0)
    , pcvd(1)
{
}

bool ConvergentsGenerator::get_convergent(bigint *n, bigint *d)
{
    bigint term;
    bool ret;

    /*
     * Fetch a continued fraction term, if one is available, and
     * fold it in to the current stored convergent.
     */
    if ((ret = cfg.get_term(&term))) {
        bigint newcvn = cvn * term + pcvn;
        bigint newcvd = cvd * term + pcvd;
        pcvn = cvn;
        pcvd = cvd;
        cvn = newcvn;
        cvd = newcvd;
    }

    /*
     * Return the current convergent.
     */
    *n = cvn;
    *d = cvd;

    /*
     * Tell our caller whether this convergent is any different from
     * the last one, in case they want to stop outputting if so.
     */
    return ret;
}

/* ----------------------------------------------------------------------
 * BracketingGenerator: generate pairs of rationals converging to a
 * target, avoiding exactness hazards.
 */

MAKE_CLASS_GREETER(BracketingGenerator);

BracketingGenerator::BracketingGenerator(unique_ptr<Coreable> acore)
    : Generator(move(acore))
    , bits(0)
    , prevbits(0)
{
    dgreet(core->dbg_id());
}

void BracketingGenerator::set_denominator_lower_bound_shift(unsigned newbits)
{
    if (bits < newbits)
        bits = newbits;
}

void BracketingGenerator::set_denominator_lower_bound(bigint ad)
{
    set_denominator_lower_bound_shift(bigint_approxlog2(ad) + 1);
}

void BracketingGenerator::get_bracket_shift(bigint *ret_nlo, bigint *ret_nhi,
                                            unsigned *dbits)
{
    ensure_started();    // prerequisite for calling core->premultiply

    bits += 2;
    core->premultiply(Matrix { 1_bi << (bits - prevbits), 0, 0, 1 });

    prevbits = bits;

    *dbits = bits;
    iterate_to_bounds(ret_nlo, ret_nhi, nullptr, nullptr, 2, nullptr, false);
    dprint("returning: (", *ret_nlo, ",", *ret_nhi, ") / 2^", bits);
}

void BracketingGenerator::get_bracket(bigint *ret_nlo, bigint *ret_nhi,
                                      bigint *ret_d)
{
    unsigned dbits;
    get_bracket_shift(ret_nlo, ret_nhi, &dbits);
    *ret_d = 1_bi << dbits;
}

/* ----------------------------------------------------------------------
 * StaticGenerator: answer queries which don't require modifying the
 * underlying core.
 */

StaticGenerator::StaticGenerator(unique_ptr<Coreable> acore)
    : Generator(move(acore))
{
}

bigint StaticGenerator::get_floor(bool *constant)
{
    return iterate_to_floor(constant);
}

bigint StaticGenerator::get_approximate_approximant(const bigint &d)
{
    bigint n1, n2;

    /*
     * This function returns an integer somewhere near d*x
     * (specifically, within 2 of it), but avoids exactness hazards by
     * not necessarily returning the exact floor(d*x). Useful in range
     * reduction, when 'nearly' is generally good enough and 'exactly'
     * is hazardous.
     */
    iterate_to_bounds(&n1, &n2, nullptr, nullptr, 2, &d, false);

    return n1;
}

int StaticGenerator::get_sign()
{
    bigint a, b;
    bool a_open, b_open;
    int a_sign, b_sign;

    /*
     * Treat rationals specially, since they might be exactly zero.
     */
    if (core->is_rational(&a, &b)) {
        assert(b > 0);
        return bigint_sign(a);
    }

    /*
     * Otherwise, just iterate until we can agree on the sign of the
     * number.
     */
    while (1) {
        iterate_to_bounds(&a, &b, &a_open, &b_open, 0, nullptr, true);
        a_sign = bigint_sign(a);
        b_sign = bigint_sign(b);

        if (a_sign > 0 || (a_sign == 0 && a_open))
            return +1;
        if (b_sign < 0 || (b_sign == 0 && b_open))
            return -1;
        if (a_sign == 0 && b_sign == 0)
            return 0;
    }
}

int StaticGenerator::try_get_sign()
{
    bigint a, b;
    bool a_open, b_open;
    int a_sign, b_sign;

    /*
     * Like get_sign(), but only does a single iteration, and returns
     * 0 if a (nonzero) sign was not successfully obtained.
     */

    iterate_to_bounds(&a, &b, &a_open, &b_open, 0, nullptr, true);
    a_sign = bigint_sign(a);
    b_sign = bigint_sign(b);

    if (a_sign > 0 || (a_sign == 0 && a_open))
        return +1;
    if (b_sign < 0 || (b_sign == 0 && b_open))
        return -1;

    return 0;
}

void StaticGenerator::premultiply(const Matrix &matrix)
{
    core->premultiply(matrix);
}

/* ----------------------------------------------------------------------
 * BaseSource: abstract implementation of a spigot data source which
 * requires its subclass to provide a stream of digits in a specified
 * base.
 *
 * A number expressed in base b as
 * 
 *   intpart . d1 d2 d3 ...
 * 
 * is expressed as a spigot composition of the functions
 * 
 *   ( x |-> intpart + x/b ) o ( x |-> d1 + x/b) o ( x |-> d2 + x/b) o ...
 * 
 * applied to the initial interval [0,1].
 */

MAKE_CLASS_GREETER(BaseSource);

BaseSource::BaseSource(bigint abase, bool anegate)
    : first_digit(true)
    , base(abase)
    , negate(anegate)
{
    assert(base > 0);
    dgreet(base);
}

bool BaseSource::gen_interval(bigint *low, bigint_or_inf *high)
{
    *low = 0;
    *high = base;

    /*
     * Force absorption of the initial integer part, which probably
     * won't be within that interval.
     */
    return true;
}

bool BaseSource::gen_matrix(Matrix &matrix)
{
    bigint digit;
    if (!gen_digit(&digit)) {
        /*
         * The positional expansion has terminated. We therefore
         * return the matrix corresponding to the zero function,
         * which is (0 0) representing x |-> (0x+0)/(0x+1).
         *          (0 1)
         */
        matrix = { 0, 0, 0, 1 };
        dprint("termination matrix ", matrix);
    } else {
        if (!negate || digit >= 0 || !first_digit) {
            /*
             * We want a function which maps x to x/b + k. As a
             * Mobius transformation, this is equivalent to
             * (1x + kb)/(0x + b), so we output the matrix (1 kb)
             *                                             (0  b).
             */
            matrix = { 1, digit * base, 0, base };
            dprint("normal digit ", digit, " matrix ", matrix);
        } else {
            /*
             * Special case of a negative first digit and
             * display-mode input, just as in the output side. So
             * digit < 0; the 'real' digit we've received is
             * digit+1; and we therefore want to map x to
             * (digit+1) - x/b. Our matrix is therefore (-1 b(digit+1))
             *                                          ( 0     b     ).
             */
            matrix = { -1, (digit + 1) * base, 0, base };
            dprint("neg first digit ", digit, " matrix ", matrix);
        }
        first_digit = false;
    }

    return false;
}

/* ----------------------------------------------------------------------
 * CfracSource: abstract implementation of a spigot data source which
 * requires its subclass to provide a stream of continued fraction
 * terms.
 *
 * A number whose continued fraction expansion is
 * 
 *   t1 + 1/(t2 + 1/(t3 + 1/(...)))
 * 
 * is expressed as a spigot composition of the functions
 * 
 *   ( x |-> t1 + 1/x ) o ( x |-> t2 + 1/x ) o ( x |-> t3 + 1/x ) o ...
 * 
 * applied to the initial interval [0,infinity].
 */

bool CfracSource::gen_interval(bigint *low, bigint_or_inf *high)
{
    *low = 0;
    *high = bigint_or_inf::infinity;

    /*
     * Force absorption of the first matrix, in case the integer part
     * is negative.
     */
    return true;
}

bool CfracSource::gen_matrix(Matrix &matrix)
{
    bigint k;
    if (gen_term(&k)) {
        /*
         * We want a function which maps x to k + 1/x. As a Mobius
         * transformation, this is equivalent to (kx + 1)/(1x + 0),
         * so we output the matrix (k 1)
         *                         (1 0).
         */
        matrix = { k, 1, 1, 0 };
        dprint("normal term ", matrix[0], " matrix ", matrix);
    } else {
        /*
         * The positional expansion has terminated. We therefore
         * return the matrix corresponding to the function that
         * always returns infinity, which is (0 1) representing
         *                                   (0 0)
         * x |-> (0x+1)/(0x+0).
         *
         * This is the correct way to terminate a continued
         * fraction: the previous term (k+1/x) becomes
         * (k+1/infinity), which is exactly k.
         */
        matrix = { 0, 1, 0, 0 };
        dprint("termination matrix ", matrix);
    }

    return false;
}

/* ----------------------------------------------------------------------
 * BinaryIntervalSource: turn a stream of rational intervals with
 * power-of-2 denominators into a spigot source.
 */

MAKE_CLASS_GREETER(BinaryIntervalSource);

BinaryIntervalSource::BinaryIntervalSource()
    : started(false)
{
    dgreet();
}

bool BinaryIntervalSource::gen_interval(bigint *low, bigint_or_inf *high)
{
    *low = 0;
    *high = 1;
    /*
     * Those numbers are almost certainly lies, so enforce the
     * absorption of at least one matrix.
     */
    return true;
}

bool BinaryIntervalSource::gen_matrix(Matrix &matrix)
{
    bigint this_lo, this_hi;
    unsigned this_bits;

    gen_bin_interval(&this_lo, &this_hi, &this_bits);
    dprint("got interval (", this_lo, ",", this_hi, ") / 2^", this_bits);
    if (this_lo > this_hi)
        internal_fault("BinaryIntervalSource received interval with "
                       "wrong sense");

    if (!started) {
        /*
         * Initial matrix just maps the starting [0,1] directly to the
         * first interval we just received.
         */
        matrix =  { this_hi - this_lo, this_lo, 0, 1_bi << this_bits };
        dprint("initial matrix ", matrix);
        started = true;
        lo = this_lo;
        hi = this_hi;
        bits = this_bits;
        return false;
    }

    /*
     * Start by putting our old and new intervals over a common
     * denominator, i.e. equalising bits and this_bits.
     */
    bits = match_dyadic_rationals(lo, bits,
                                  hi, bits,
                                  this_lo, this_bits,
                                  this_hi, this_bits);
    dprint("old interval (", lo, ",", hi, ") / 2^", bits);

    /*
     * Now intersect the new interval with the old one, in case the
     * client isn't passing us a stream of strictly nested intervals.
     */
    intersect_intervals(this_lo, this_hi, lo, hi);
    dprint("new interval (", this_lo, ",", this_hi, ") / 2^", bits);
    if (this_lo > this_hi)
        internal_fault("BinaryIntervalSource overlap failure");

    /*
     * Construct a matrix which narrows from the old interval to the
     * new one.
     */
    matrix = { this_hi - this_lo, this_lo - lo, 0, hi - lo };
    if (matrix[3] == 0)
        matrix[3] = 1;
    dprint("refining matrix ", matrix);

    /*
     * And update our current interval.
     */
    lo = this_lo;
    hi = this_hi;

    return false;
}

/* ----------------------------------------------------------------------
 * RationalSource: turn an exact rational number provided as input
 * into a spigot source.
 *
 * This is a trivial spigot description: it consists of the single
 * function (x |-> n/d).
 */

RationalSource::RationalSource(const bigint &an, const bigint &ad)
    : n(an), d(ad)
{
    assert(d > 0);
}

Spigot RationalSource::clone()
{
    return spigot_clone(this, n, d);
}

bool RationalSource::gen_interval(bigint *low, bigint_or_inf *high)
{
    // It really doesn't matter what these are
    *low = 0;
    *high = 1;
    return true;
}

bool RationalSource::gen_matrix(Matrix &matrix)
{
    /*
     * We want a constant function which maps any x to n/d. As a
     * Mobius transformation, this is equivalent to (0x + n)/(0x +
     * d), so we output the matrix (0 n)
     *                             (0 d).
     */
    matrix = { 0, n, 0, d };
    return false;
}

bool RationalSource::is_rational(bigint *rn, bigint *rd)
{
    *rn = n;
    *rd = d;
    return true;
}

/*
 * Trivial constructors for integers and rationals, which might as
 * well go here rather than put them in a pointless extra source file.
 */
Spigot spigot_integer(bigint const &n)
{
    return make_unique<RationalSource>(n, 1);
}

Spigot spigot_rational(bigint const &an, bigint const &ad)
{
    assert(ad != 0);

    /*
     * Reduce the fraction to its lowest terms. This is partly a
     * space-saving measure, and partly functional: reliably doing
     * this means that other parts of the code can depend on it. For
     * instance, spigot_cbrt() will recognise a rational that's a
     * perfect cube divided by another perfect cube, but can't easily
     * recognise one that's (say) twice a perfect cube over twice
     * another perfect cube.
     */
    bigint a = gcd(an, ad);

    /*
     * Normalise the sign of d to 1.
     */
    if (ad < 0) {
        a = -a;
    }

    return make_unique<RationalSource>(an / a, ad / a);
}

/* ----------------------------------------------------------------------
 * GeneratorSource: turn a Core back into a Source, by reconstructing
 * a stream of matrices converging to the same value.
 *
 * This is done by the completely trivial method of feeding the output
 * of a BracketingGenerator straight to our base class of
 * BinaryIntervalSource.
 */

MAKE_CLASS_GREETER(GeneratorSource);

GeneratorSource::GeneratorSource(unique_ptr<Core> acore)
    : bg(acore->clone())
    , core_orig(move(acore))
{
    dgreet();
}

Spigot GeneratorSource::clone()
{
    return spigot_clone(this, core_orig->clone().release()->toCore());
}

void GeneratorSource::gen_bin_interval(bigint *ret_lo, bigint *ret_hi,
                                       unsigned *ret_bits)
{
    bg.get_bracket_shift(ret_lo, ret_hi, ret_bits);
}
