/* Lecture code 17.2
 *
 * Code to generate a function's derivative using functors.  This
 * example illustrates using templates to pass functors as parameters,
 * as well as type inference for functions.
 */

#include <iostream>
#include <cmath> // For sin, cos
using namespace std;

const int kNumSteps = 20;

/* Function that takes in a function as a parameter, then prints out some of the values
 * it takes on.  Notice that this function takes as a final parameter an arbitrary type
 * called "UnaryFunction."  As long as UnaryFunction can be invoked on a double argument
 * and produce a double value, this function will compile.
 */
template <typename UnaryFunction>
void TabulateValues(double start, double stop, UnaryFunction function) {
	const double step = (stop - start) / (kNumSteps - 1);
	for(int i = 0; i < kNumSteps; ++i) {
		const double value = start + step * i;
		cout << "f(" << value << ") = " << function(value) << endl;
	}
}

/* sinc ("sinus cardinalis") is defined as
 *
 * sin(x) / x    if x != 0
 * 1             otherwise
 *
 * It has a really cool graph!
 */
double sinc(double x) {
	return x == 0? 1.0 : sin(x) / x;
}

/* Haversine is an archaic trig function defined as
 *
 * hav(x) = (1 - cos(x)) / 2
 *
 * It used to be used in navigation tables before the advent of the computer.
 */
class Haversine {
public:
	double operator() (double x) const {
		return (1.0 - cos(x)) / 2.0;
	}
};

/* Functor class responsible for approximating a derivative.
*
 * Internally, the functor uses a secant-line approximation of the derivative,
 * as shown here:
 *
 *            f(x + e) - f(x - e)
 * f'(x) ~=   -------------------
 *                     2e
 *
 * This can be shown to produce the derivative with a very good approximation
 * for small e.
 */
template <typename UnaryFunction> class Derivative {
public:
	/* Constructor stores the function to use. */
	Derivative(UnaryFunction function) : mFunction(function) {
		// Handled in initializer list.
	}

	/* Functor operator produces a derivative approximation. */
	double operator() (double x) const {
		return (mFunction(x + kEpsilon) - mFunction(x - kEpsilon)) / (2.0 * kEpsilon);
	}

private:
	UnaryFunction mFunction; // The function to call
};

/**
 * Function: TakeDerivative(UnaryFunction function);
 * Usage: transform(v.begin(), v.end(), v.begin(), TakeDerivative(sinc));
 * --------------------------------------------------------------------------
 * Given a unary function, returns a function object containing an approximation
 * of the first derivative of that function.
 *
 * We have this function in addition to the functor class itself so that C++'s
 * template type inference can fill in all the types for us.
 */
template <typename UnaryFunction>
Derivative<UnaryFunction> TakeDerivative(UnaryFunction function) {
	return Derivative<UnaryFunction>(function);
}

/* Print out some values of the second derivative of sinc. */
int main() {
	TabulateValues(1.0, 2.0, TakeDerivative(TakeDerivative(sinc)));
	return 0;
}