// example_rational.cpp -- Rational API examples
// All code snippets are subroutines called from main()
//
// Build:
//   cl /std:c++latest /EHsc /O2 /MD /utf-8 /I<calx>/include examples\example_rational.cpp
//      /link calx_rational.lib calx_float.lib calx_int.lib /MACHINE:X64

#include <math/core/mp/Rational.hpp>
#include <math/core/mp/Rational/RationalConstants.hpp>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace calx;

// ============================================================
// Constructors
// ============================================================

void demo_default_constructor() {
    std::cout << "--- default constructor ---" << std::endl;
    Rational r;
    std::cout << "Rational() = " << r << std::endl;
}

void demo_int_constructor() {
    std::cout << "--- integer constructor ---" << std::endl;
    Rational a(3, 4);         // 3/4
    Rational b(6, 4);         // auto-reduced to 3/2
    Rational c(-5, 10);       // auto-reduced to -1/2
    Rational d(7);            // 7/1
    std::cout << "Rational(3, 4) = " << a << std::endl;
    std::cout << "Rational(6, 4) = " << b << "  (auto-reduced)" << std::endl;
    std::cout << "Rational(-5, 10) = " << c << "  (auto-reduced)" << std::endl;
    std::cout << "Rational(7) = " << d << std::endl;
}

void demo_bigint_constructor() {
    std::cout << "--- Int constructor (auto-reduce) ---" << std::endl;
    Int p("123456789012345678901234567890");
    Int q("987654321098765432109876543210");
    Rational r(p, q);
    Int g = gcd(p, q);
    std::cout << "p = " << p << std::endl;
    std::cout << "q = " << q << std::endl;
    std::cout << "gcd(p, q) = " << g << std::endl;
    std::cout << "Rational(p, q) = " << r << "  (auto-reduced)" << std::endl;
}

void demo_string_constructor() {
    std::cout << "--- string constructor ---" << std::endl;
    Rational a("3/4");
    Rational b("-22/7");
    std::cout << "Rational(\"3/4\") = " << a << std::endl;
    std::cout << "Rational(\"-22/7\") = " << b << std::endl;
}

void demo_double_constructor() {
    std::cout << "--- double constructor ---" << std::endl;
    Rational r(0.75);         // exact: 3/4
    Rational s(0.1);          // exact representation of the double 0.1
    std::cout << "Rational(0.75) = " << r << std::endl;
    std::cout << "Rational(0.1) = " << s << "  (exact IEEE 754)" << std::endl;
}

// ============================================================
// Arithmetic
// ============================================================

void demo_arithmetic() {
    std::cout << "--- arithmetic ---" << std::endl;
    Rational a(1, 3), b(1, 6);
    std::cout << "a = " << a << ",  b = " << b << std::endl;
    std::cout << "a + b = " << (a + b) << std::endl;
    std::cout << "a - b = " << (a - b) << std::endl;
    std::cout << "a * b = " << (a * b) << std::endl;
    std::cout << "a / b = " << (a / b) << std::endl;
}

void demo_mixed_arithmetic() {
    std::cout << "--- mixed arithmetic (Rational <-> int / Int) ---" << std::endl;
    Rational r(2, 3);
    std::cout << "r = " << r << std::endl;
    std::cout << "r + 1 = " << (r + 1) << std::endl;
    std::cout << "r * 6 = " << (r * 6) << std::endl;
    std::cout << "3 - r = " << (3 - r) << std::endl;
    std::cout << "r / Int(5) = " << (r / Int(5)) << std::endl;
}

void demo_compound_assignment() {
    std::cout << "--- compound assignment ---" << std::endl;
    Rational r(1, 2);
    std::cout << "r = " << r << std::endl;
    r += Rational(1, 3);  std::cout << "r += 1/3  ->  " << r << std::endl;
    r *= 2;               std::cout << "r *= 2    ->  " << r << std::endl;
    r -= Rational(1, 6);  std::cout << "r -= 1/6  ->  " << r << std::endl;
}

// ============================================================
// Comparison
// ============================================================

void demo_comparison() {
    std::cout << "--- comparison ---" << std::endl;
    Rational a(2, 3), b(3, 4);
    std::cout << "a = " << a << ",  b = " << b << std::endl;
    std::cout << "a == b ? " << (a == b ? "true" : "false") << std::endl;
    std::cout << "a < b  ? " << (a < b  ? "true" : "false") << std::endl;
    std::cout << "a > b  ? " << (a > b  ? "true" : "false") << std::endl;
    std::cout << "a == 0 ? " << (a == 0 ? "true" : "false") << std::endl;
}

// ============================================================
// Power, shift, reciprocal
// ============================================================

void demo_power() {
    std::cout << "--- pow ---" << std::endl;
    Rational r(2, 3);
    std::cout << "r = " << r << std::endl;
    std::cout << "r.pow(0)  = " << r.pow(0) << std::endl;
    std::cout << "r.pow(5)  = " << r.pow(5) << std::endl;
    std::cout << "r.pow(-3) = " << r.pow(-3) << std::endl;
}

void demo_reciprocal() {
    std::cout << "--- reciprocal ---" << std::endl;
    Rational r(3, 7);
    std::cout << "r = " << r << std::endl;
    std::cout << "r.reciprocal() = " << r.reciprocal() << std::endl;
    std::cout << "r * r.reciprocal() = " << (r * r.reciprocal()) << std::endl;
}

void demo_shift() {
    std::cout << "--- shift (multiply/divide by power of 2) ---" << std::endl;
    Rational r(3, 1);
    std::cout << "r = " << r << std::endl;
    std::cout << "r << 3 = " << (r << 3) << "  (= 3 * 8)" << std::endl;
    std::cout << "r >> 2 = " << (r >> 2) << "  (= 3 / 4)" << std::endl;
}

// ============================================================
// State queries
// ============================================================

void demo_state() {
    std::cout << "--- state queries ---" << std::endl;
    Rational pos(3, 4), zero(0, 1), neg(-1, 2);
    std::cout << "Rational(3,4).isPositive() = " << pos.isPositive() << std::endl;
    std::cout << "Rational(0,1).isZero()     = " << zero.isZero() << std::endl;
    std::cout << "Rational(-1,2).isNegative()= " << neg.isNegative() << std::endl;
    std::cout << "Rational(5,1).isInteger()  = " << Rational(5).isInteger() << std::endl;
}

// ============================================================
// Conversions
// ============================================================

void demo_conversion() {
    std::cout << "--- conversions ---" << std::endl;
    Rational r(355, 113);
    std::cout << "r = " << r << std::endl;
    std::cout << "r.toDouble()    = " << std::setprecision(15) << r.toDouble() << std::endl;
    std::cout << "r.toDecimal(20) = " << r.toDecimal(20) << std::endl;
    std::cout << "r.toString()    = \"" << r.toString() << "\"" << std::endl;
}

// ============================================================
// Free functions (abs, floor, ceil, round, frac, sgn)
// ============================================================

void demo_free_functions() {
    std::cout << "--- free functions ---" << std::endl;
    Rational r(-7, 3);  // -2.333...
    std::cout << "r = " << r << "  (" << r.toDecimal(6) << ")" << std::endl;
    std::cout << "abs(r)    = " << abs(r) << std::endl;
    std::cout << "floor(r)  = " << floor(r) << std::endl;
    std::cout << "ceil(r)   = " << ceil(r) << std::endl;
    std::cout << "round(r)  = " << round(r) << std::endl;
    std::cout << "trunc(r)  = " << trunc(r) << std::endl;
    std::cout << "frac(r)   = " << frac(r) << std::endl;
    std::cout << "sgn(r)    = " << sgn(r) << std::endl;
    std::cout << "square(r) = " << square(r) << std::endl;
    std::cout << "inv(r)    = " << inv(r) << std::endl;
}

void demo_mediant() {
    std::cout << "--- mediant ---" << std::endl;
    Rational a(1, 3), b(1, 2);
    std::cout << "mediant(" << a << ", " << b << ") = " << mediant(a, b) << std::endl;
}

void demo_gcd() {
    std::cout << "--- rational gcd ---" << std::endl;
    Rational a(4, 9), b(2, 3);
    std::cout << "gcd(" << a << ", " << b << ") = " << gcd(a, b) << std::endl;
}

// ============================================================
// Continued fractions
// ============================================================

void demo_continued_fraction() {
    std::cout << "--- continued fraction ---" << std::endl;
    Rational r(355, 113);
    auto cf = r.toContinuedFraction();
    std::cout << "Rational(355, 113).toContinuedFraction() = [";
    for (size_t i = 0; i < cf.size(); ++i) {
        if (i > 0) std::cout << "; ";
        std::cout << cf[i];
    }
    std::cout << "]" << std::endl;

    // Reconstruct
    Rational back = Rational::fromContinuedFraction(cf);
    std::cout << "fromContinuedFraction([3; 7, 16]) = " << back << std::endl;
}

// ============================================================
// Harmonic number, Bernoulli number
// ============================================================

void demo_harmonic() {
    std::cout << "--- harmonicNumber ---" << std::endl;
    for (int n : {1, 5, 10}) {
        Rational Hn = harmonicNumber(n);
        std::cout << "H_" << n << " = " << Hn << std::endl;
    }
}

void demo_bernoulli() {
    std::cout << "--- bernoulli ---" << std::endl;
    for (int n : {0, 1, 2, 4, 6, 8, 10}) {
        std::cout << "B_" << std::setw(2) << n << " = " << bernoulli(n) << std::endl;
    }
}

// ============================================================
// Dedekind sum, mod
// ============================================================

void demo_dedekind() {
    std::cout << "--- dedekindSum ---" << std::endl;
    std::cout << "s(5, 7) = " << dedekindSum(Int(5), Int(7)) << std::endl;
}

void demo_mod() {
    std::cout << "--- mod (Rational mod Int) ---" << std::endl;
    Rational r(7, 3);
    Int m(11);
    std::cout << "(7/3) mod 11 = " << mod(r, m) << std::endl;
}

// ============================================================
// Enumeration (nextMinimal, nextCalkinWilf, fareyNeighbors, simplestBetween)
// ============================================================

void demo_enumeration() {
    std::cout << "--- nextMinimal (Stern-Brocot order) ---" << std::endl;
    Rational x(1, 1);
    std::cout << x;
    for (int i = 0; i < 9; ++i) {
        x = nextMinimal(x);
        std::cout << ", " << x;
    }
    std::cout << ", ..." << std::endl;

    std::cout << "--- simplestBetween ---" << std::endl;
    Rational a(1, 3), b(1, 2);
    std::cout << "simplestBetween(" << a << ", " << b << ") = "
              << simplestBetween(a, b) << std::endl;
}

// ============================================================
// main
// ============================================================
int main() {
    std::cout << "=== calx Rational API Examples ===" << std::endl << std::endl;

    demo_default_constructor();
    demo_int_constructor();
    demo_bigint_constructor();
    demo_string_constructor();
    demo_double_constructor();
    std::cout << std::endl;

    demo_arithmetic();
    demo_mixed_arithmetic();
    demo_compound_assignment();
    std::cout << std::endl;

    demo_comparison();
    std::cout << std::endl;

    demo_power();
    demo_reciprocal();
    demo_shift();
    std::cout << std::endl;

    demo_state();
    std::cout << std::endl;

    demo_conversion();
    std::cout << std::endl;

    demo_free_functions();
    demo_mediant();
    demo_gcd();
    std::cout << std::endl;

    demo_continued_fraction();
    std::cout << std::endl;

    demo_harmonic();
    demo_bernoulli();
    std::cout << std::endl;

    demo_dedekind();
    demo_mod();
    std::cout << std::endl;

    demo_enumeration();

    std::cout << std::endl;
    std::cout << "=== All examples completed ===" << std::endl;
    return 0;
}
