/*
 * Problem1b.java
 * Created on Apr 11, 2005
 */
package kernel;

import javax.vecmath.GMatrix;
import javax.vecmath.GVector;

/**
 * Do problem 1b.
 */
public final class Problem1b {
    
    private final static int DIMENSION  = 2;
    private final static int NUM_TRAIN = 100;
    private final static int NUM_TEST  = 10;
    
    private final static double LAMBDA = 0.5;
    private final static double OFFSET_VARIANCE = 0.1;
    private final static double KERNEL_VARIANCE = 1.0;
    
    private final static Function G = new GFunction();
    
    private Problem1b() {}

    public static void main(String[] args) {
        // training data
        GMatrix data = Matrices.randomNormalMatrix(DIMENSION, NUM_TRAIN);
        GVector values = Matrices.map(G, data);
        GVector offsets = Matrices.randomGaussianVector(NUM_TRAIN, OFFSET_VARIANCE);
        values.add(offsets);
        
        // test data
        GMatrix testData = Matrices.randomNormalMatrix(DIMENSION, NUM_TEST);
        GVector testValues = Matrices.map(G, testData);
        GVector testOffsets = Matrices.randomGaussianVector(NUM_TEST, OFFSET_VARIANCE);
        testValues.add(testOffsets);
        
        // trying linear kernel
        tryKernel("linear", LinearKernel.KERNEL, data, values, testData, testValues);
        
        // trying linear quadratic kernel
        Kernel quadKernel = new PolynomialKernel(2);
        tryKernel("quadratic", quadKernel, data, values, testData, testValues);
        
        // trying gaussian kernel
        Kernel gaussianKernel = new GaussianKernel(KERNEL_VARIANCE);
        tryKernel("gaussian", gaussianKernel, data, values, testData, testValues);
    }
    
    private static void tryKernel(String name, Kernel kernel,
            GMatrix data, GVector values, GMatrix testData, GVector testValues) {
        Representer rep = Regression.solve(data, values, kernel, LAMBDA);
        GVector repTestValues = Matrices.map(rep, testData);
        System.out.println(name + ": " + repTestValues);
        repTestValues.sub(testValues);
        double cost = repTestValues.normSquared();
        System.out.println("cost: " + cost);
        System.out.println();
    }
    
    private static class GFunction implements Function {
        public double eval(GVector x) {
            final double TWO_PI   = 2 * Math.PI;
        	final double THREE_PI = 3 * Math.PI;
        	double u = x.getElement(0), v = x.getElement(1);
        	return u * Math.sin(TWO_PI * (u + v)) + v * Math.sin(THREE_PI * (u - v));
        }
    }
    
}
