// Path: src/main/java/net/finmath/experiments/montecarlo/randomnumbers/HaltonSequence.java
// public class HaltonSequence {
// 
// 	private final int[] baseVector;
// 
// 	/**
// 	 * Construct a Halton sequence with d = base.length dimensions where the i-th component
// 	 * uses base[i] as base of the corresponding van der Corput sequence.
// 	 *
// 	 * @param baseVector Vector of base integers for each component.
// 	 */
// 	public HaltonSequence(int[] baseVector) {
// 		// Check base
// 		for(final int base : baseVector) {
// 			if(base < 2) {
// 				throw new RuntimeException("Cannot create Halton sequence with base less than two.");
// 			}
// 		}
// 
// 		this.baseVector = baseVector;
// 	}
// 
// 	/**
// 	 * Construct a one dimensional Halton sequence (Van der Corput sequence) with given base.
// 	 *
// 	 * @param base Base of the sequence.
// 	 */
// 	public HaltonSequence(int base) {
// 		// Check base
// 		if(base < 2) {
// 			throw new RuntimeException("Cannot create Halton sequence with base less than two.");
// 		}
// 
// 		this.baseVector = new int[] { base };
// 	}
// 
// 	/**
// 	 * Print the first 1000 Halton numbers for base b = (2,3).
// 	 *
// 	 * @param args
// 	 */
// 	public static void main(String[] args) {
// 		System.out.println("Halton sequence (base b = (2,3)):");
// 		for(int i=0; i<1000; i++) {
// 			System.out.println("" + getHaltonNumber(i, 2) + "\t" + getHaltonNumber(i, 3));
// 		}
// 	}
// 
// 	/**
// 	 * Get Halton number for given index.
// 	 *
// 	 * @param index Index of the Halton number.
// 	 * @return Halton number (vector).
// 	 */
// 	public double[] getHaltonNumber(long index) {
// 		final double[] x = new double[baseVector.length];
// 		for(int baseIndex=0; baseIndex < baseVector.length; baseIndex++) {
// 			x[baseIndex] = getHaltonNumber(index, baseVector[baseIndex]);
// 		}
// 		return x;
// 	}
// 
// 	/**
// 	 * Get Halton number for given index and base.
// 	 *
// 	 * @param index Index of the Halton number (starting at 0).
// 	 * @param base Base of the Halton number.
// 	 * @return Halton number.
// 	 */
// 	public static double getHaltonNumber(long index, int base) {
// 		// Check base
// 		if(base < 2) {
// 			throw new RuntimeException("Cannot create Halton number with base less than two.");
// 		}
// 		if(index < 0) {
// 			throw new RuntimeException("Cannot create Halton number with index less than zero.");
// 		}
// 
// 		// Index shift: counting of the function starts at 0, algorithm below starts at 1.
// 		index++;
// 
// 		// Calculate Halton number x
// 		double x = 0;
// 		double factor = 1.0/base;
// 		while(index > 0) {
// 			x += (index % base) * factor;
// 			factor /= base;
// 			index /= base;
// 		}
// 		return x;
// 	}
// }


import net.finmath.experiments.montecarlo.randomnumbers.HaltonSequence;
/*
 * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com.
 *
 * Created on 12.10.2013
 */

package net.finmath.experiments.montecarlo;


/**
 * A simple class illustrating a Monte-Carlo integration using a Halton sequence (low discrepancy sequence)
 *
 * @author Christian Fries
 */
public class MonteCarloIntegrationWithQuasiRandomNumbersExperiment {


	/**
	 * Main program to run the experiment.
	 *
	 * @param args Arguments, not used
	 */
	public static void main(String[] args) {
		final long numberOfSimulations = 20000000;

		// Measure calculation time - start
		final long millisStart = System.currentTimeMillis();

		final double pi = getMonteCarloApproximationOfPi(numberOfSimulations);

		// Measure calculation time - end
		final long millisEnd = System.currentTimeMillis();

		System.out.println("Simulation with n = " + numberOfSimulations + " resulted in approximation of pi = " + pi +"\n");

		System.out.println("Approximation error is                                = " + Math.abs(pi-Math.PI));
		System.out.println("Theoretical order of the (quasi) Monte-Carlo error is = " + Math.pow(Math.log(numberOfSimulations),2)/numberOfSimulations + "\n");

		System.out.println("Calculation took " + (millisEnd-millisStart)/1000.0 + " sec.");
	}

	/**
	 * Calculates an approximation of pi via Monte-Carlo integration.
	 *
	 * @param numberOfSimulations The number of elements to use from the random number sequence.
	 * @return An approximation of pi.
	 */
	public static double getMonteCarloApproximationOfPi(long numberOfSimulations) {
		long numberOfPointsInsideUnitCircle = 0;
		for(long i=0; i<numberOfSimulations; i++) {
// Path: src/main/java/net/finmath/experiments/montecarlo/randomnumbers/HaltonSequence.java
// public class HaltonSequence {
// 
// 	private final int[] baseVector;
// 
// 	/**
// 	 * Construct a Halton sequence with d = base.length dimensions where the i-th component
// 	 * uses base[i] as base of the corresponding van der Corput sequence.
// 	 *
// 	 * @param baseVector Vector of base integers for each component.
// 	 */
// 	public HaltonSequence(int[] baseVector) {
// 		// Check base
// 		for(final int base : baseVector) {
// 			if(base < 2) {
// 				throw new RuntimeException("Cannot create Halton sequence with base less than two.");
// 			}
// 		}
// 
// 		this.baseVector = baseVector;
// 	}
// 
// 	/**
// 	 * Construct a one dimensional Halton sequence (Van der Corput sequence) with given base.
// 	 *
// 	 * @param base Base of the sequence.
// 	 */
// 	public HaltonSequence(int base) {
// 		// Check base
// 		if(base < 2) {
// 			throw new RuntimeException("Cannot create Halton sequence with base less than two.");
// 		}
// 
// 		this.baseVector = new int[] { base };
// 	}
// 
// 	/**
// 	 * Print the first 1000 Halton numbers for base b = (2,3).
// 	 *
// 	 * @param args
// 	 */
// 	public static void main(String[] args) {
// 		System.out.println("Halton sequence (base b = (2,3)):");
// 		for(int i=0; i<1000; i++) {
// 			System.out.println("" + getHaltonNumber(i, 2) + "\t" + getHaltonNumber(i, 3));
// 		}
// 	}
// 
// 	/**
// 	 * Get Halton number for given index.
// 	 *
// 	 * @param index Index of the Halton number.
// 	 * @return Halton number (vector).
// 	 */
// 	public double[] getHaltonNumber(long index) {
// 		final double[] x = new double[baseVector.length];
// 		for(int baseIndex=0; baseIndex < baseVector.length; baseIndex++) {
// 			x[baseIndex] = getHaltonNumber(index, baseVector[baseIndex]);
// 		}
// 		return x;
// 	}
// 
// 	/**
// 	 * Get Halton number for given index and base.
// 	 *
// 	 * @param index Index of the Halton number (starting at 0).
// 	 * @param base Base of the Halton number.
// 	 * @return Halton number.
// 	 */
// 	public static double getHaltonNumber(long index, int base) {
// 		// Check base
// 		if(base < 2) {
// 			throw new RuntimeException("Cannot create Halton number with base less than two.");
// 		}
// 		if(index < 0) {
// 			throw new RuntimeException("Cannot create Halton number with index less than zero.");
// 		}
// 
// 		// Index shift: counting of the function starts at 0, algorithm below starts at 1.
// 		index++;
// 
// 		// Calculate Halton number x
// 		double x = 0;
// 		double factor = 1.0/base;
// 		while(index > 0) {
// 			x += (index % base) * factor;
// 			factor /= base;
// 			index /= base;
// 		}
// 		return x;
// 	}
// }


// Path: src/main/java/net/finmath/experiments/montecarlo/MonteCarloIntegrationWithQuasiRandomNumbersExperiment.java
import net.finmath.experiments.montecarlo.randomnumbers.HaltonSequence;

/*
 * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christianfries.com.
 *
 * Created on 12.10.2013
 */

package net.finmath.experiments.montecarlo;


/**
 * A simple class illustrating a Monte-Carlo integration using a Halton sequence (low discrepancy sequence)
 *
 * @author Christian Fries
 */
public class MonteCarloIntegrationWithQuasiRandomNumbersExperiment {


	/**
	 * Main program to run the experiment.
	 *
	 * @param args Arguments, not used
	 */
	public static void main(String[] args) {
		final long numberOfSimulations = 20000000;

		// Measure calculation time - start
		final long millisStart = System.currentTimeMillis();

		final double pi = getMonteCarloApproximationOfPi(numberOfSimulations);

		// Measure calculation time - end
		final long millisEnd = System.currentTimeMillis();

		System.out.println("Simulation with n = " + numberOfSimulations + " resulted in approximation of pi = " + pi +"\n");

		System.out.println("Approximation error is                                = " + Math.abs(pi-Math.PI));
		System.out.println("Theoretical order of the (quasi) Monte-Carlo error is = " + Math.pow(Math.log(numberOfSimulations),2)/numberOfSimulations + "\n");

		System.out.println("Calculation took " + (millisEnd-millisStart)/1000.0 + " sec.");
	}

	/**
	 * Calculates an approximation of pi via Monte-Carlo integration.
	 *
	 * @param numberOfSimulations The number of elements to use from the random number sequence.
	 * @return An approximation of pi.
	 */
	public static double getMonteCarloApproximationOfPi(long numberOfSimulations) {
		long numberOfPointsInsideUnitCircle = 0;
		for(long i=0; i<numberOfSimulations; i++) {
			final double x = 2.0 * (HaltonSequence.getHaltonNumber(i, 2) - 0.5);	// quasi random number between -1 and 1