package base;

import java.util.concurrent.ConcurrentHashMap;

public abstract class CachedKernel<X extends Structure> extends ConcurrentHashMap<X, Integer> implements Kernel<X>
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public double[][] kernelCache;

	public void initKernelCache(int n)
	{
		this.clear();
		this.kernelCache = null;
		System.gc();
		this.kernelCache = new double[n][n];
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				kernelCache[i][j] = Double.NaN;
		System.out.println("Cache initialized");
	}
	
	public double k(X a,X b)
	{
		if (!containsKey(a))
		{
			if (size() % 10000 == 0)
				System.out.println("Cache Size: " + size());
			if (size() < kernelCache.length)
				synchronized (this)
				{
					putIfAbsent(a, size());
				}
			else
				return K(a, b);
		}
		if (!containsKey(b))
		{
			if (size() % 10000 == 0)
				System.out.println("Cache Size: " + size());

			if (size() < kernelCache.length)
				synchronized (this)
				{
					putIfAbsent(b, size());
				}
			else
				return K(a, b);
		}
		int i = get(a);
		int j = get(b);
		if (Double.isNaN(kernelCache[i][j]))
		{
			kernelCache[i][j] = K(a, b);
			kernelCache[j][i] = kernelCache[i][j];
		}
		return kernelCache[i][j];
	}
	
	abstract protected double K(X a, X b);
}
