package math;

import math.number.Rational;

public class Sequence {
	
	/**
	 * Triangular numbers.
	 * 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105, 120 &hellip;
	 * T<sub>n</sub> = &sum;k = 1 + 2 + 3 + 4 + &hellip; + n = 0.5*n*(n+1).
	 * @param n
	 * @return
	 */
	public static int triangularNumber(int n){
		return polygonalNumber(3,n);
	}
	
	/**
	 * Triangular roots.
	 * @param x
	 * @return
	 */
	public static double triangularRoot(int x){
		return (Math.sqrt(8*x+1)-1)/2;
	}
	
	/**
	 * (s-2)*n*(n-1)/2+n
	 * @param s
	 * @param n
	 * @return
	 */
	public static int polygonalNumber(int s, int n){
		switch(s){
			case 3:  return n*(n+1)/2;
			case 4:  return n*n;
			default: return n*((s-2)*n-s)/2;
		}
	}
	
	/**
	 *  Prints out binomial coefficients such that such that a[N][k] contains 
	 *  the probability that you get exactly k heads when you toss a
	 *  coin N times.
	 *  Pascal triangle.
	 *
	 *  BinomialCoefficients 7:
	 *  1/1 
	 *  1/2 1/2 
	 *  1/4 2/4 1/4 
	 *  1/8 3/8 3/8 1/8 
	 *  1/16 4/16 6/16 4/16 1/16 
	 *  1/32 5/32 10/32 10/32 5/32 1/32 
	 *  1/64 6/64 15/64 20/64 15/64 6/64 1/64
	 */
    public static void binomialCoefficients(int N) {
        int[][] pascal = new int[N+1][];

        // initialize first row
        pascal[1] = new int[1 + 2];
        pascal[1][1] = 1;

        // fill in Pascal's triangle
        for (int n = 2; n <= N; n++) {
            pascal[n] = new int[n + 2];
            for (int k = 1; k < pascal[n].length - 1; k++)
                pascal[n][k] = pascal[n-1][k-1] + pascal[n-1][k];
        }

        // print binomial coefficients
        int denominator = 1;
        for (int n = 1; n <= N; n++) {
            for (int k = 1; k < pascal[n].length - 1; k++) {
                System.out.print(pascal[n][k] + "/" + denominator + " ");
            }
            System.out.println();
            denominator += denominator;
        }
    }
	
	/**
	 * Print the collatz sequence of N.
	 * Collatz 6: 6 3 10 5 16 8 4 2 1 
	 * Collatz 27:
	 * 27 82 41 124 62 31 94 47 142 71 214 107 322 161 484 242 121 364 182
	 * 91 274 137 412 206 103 310 155 466 233 700 350 175 526 263 790 395
	 * 1186 593 1780 890 445 1336 668 334 167 502 251 754 377 1132 566 283
	 * 850 425 1276 638 319 958 479 1438 719 2158 1079 3238 1619 4858 2429
	 * 7288 3644 1822 911 2734 1367 4102 2051 6154 3077 9232 4616 2308
	 * 1154 577 1732 866 433 1300 650 325 976 488 244 122 61 184 92 46 23
	 * 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1 
	 * Collatz 35: 35 106 53 160 80 40 20 10 5 16 8 4 2 1 
	 * Collatz 256: 256 128 64 32 16 8 4 2 1 
	 * @param n 
	 */
    public static void collatz(int n) {
        System.out.print(n + " ");
        if (n == 1) return;
        else if (n % 2 == 0) collatz(n / 2);
        else collatz(3*n + 1);
    }
	
	/**
	 * Farey sequence.
	 * Farey 2: 0/1  1/2  1/1  
	 * Farey 3: 0/1  1/3  1/2  2/3  1/1  
	 * Farey 4: 0/1  1/4  1/3  1/2  2/3  3/4  1/1  
	 * Farey 5: 0/1  1/5  1/4  1/3  2/5  1/2  3/5  2/3  3/4  4/5  1/1</pre>
	 */
	public static Rational farey(int N){
		Rational one = new Rational(1, 1);
		Rational r0  = new Rational(0, 1);
		Rational r1  = new Rational(1, N);

		// repeat until r0 equals 1/1
		while (r0.compareTo(one) < 0) {
			System.out.print(r0 + "  ");
			int num = ((r0.getDenominator() + N) / r1.getDenominator()) * r1.getNumerator()
					- r0.getNumerator();
			int den = ((r0.getDenominator() + N) / r1.getDenominator()) * r1.getDenominator()
					- r0.getDenominator();
			Rational rnew = new Rational(num, den);
			r0 = r1;
			r1 = rnew;
		}
		return r0;
	}

	public static void main(String[] args) {
		int N = 3;
		binomialCoefficients(N);
        collatz(N);
        System.out.println();
		System.out.println(farey(N));
	}
}