/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.math.statistics.nonparametric.kernels; import xxl.core.math.functions.Differentiable; import xxl.core.math.functions.Integrable; import xxl.core.math.functions.RealFunction; /** This class provides a transformation of a one-dimensional kernel function with * restricted support to <tt>[-1,1]</tt> like the * {@link xxl.core.math.statistics.nonparametric.kernels.EpanechnikowKernel epanechnikow kernel function} or the * {@link xxl.core.math.statistics.nonparametric.kernels.BiweightKernel biweight kernel function} to an interval * given by <tt>[l,l+c]</tt>. * The transformed kernel function keeps its enclosed area of size <tt>1</tt> so one could use it * to provide a {@link xxl.core.math.statistics.nonparametric.kernels.DifferenceKernelEstimator difference kernel estimator}. * The used transformation is:<br> <table border="0"><tr> <td> K_t (x)_I(x)[l,l+c] </td> <td> = (2/c) * K ( (2/c) * ( x - ( l + (c/2)) )_I(x)[-1,1] </td></tr> <tr> <td> </td> <td> = (2/c) K ( (2/c) (x-l) - 1 )_I(x)[-1,1] </td></tr></table> * <br> This transformation preserves the area enclosed by the transformed kernel function, i.e. * the integral \int_{l}^{l+c} K^t (t) dt == 1 for all l \in R and c >0 , c \in R. * * @see xxl.core.math.statistics.nonparametric.kernels.DifferenceKernelEstimator * @see xxl.core.math.statistics.nonparametric.kernels.KernelFunction * @see xxl.core.math.statistics.nonparametric.kernels.EpanechnikowKernel * @see xxl.core.math.statistics.nonparametric.kernels.BiweightKernel * @see xxl.core.math.statistics.nonparametric.kernels.TriweightKernel * @see xxl.core.math.statistics.nonparametric.kernels.CosineArchKernel */ public class TransformedKernelFunction extends KernelFunction implements Integrable, Differentiable { /** one-dimensional kernel function to transform to the given interval respectively support */ protected KernelFunction kernelFunction; /** left border of the new support respectively the left interval border of the transformed kernel function */ protected double l; /** width of the new support respectively width of the interval of the transformed kernel function */ protected double c; /** Constructs a new transformed kernel function based upon a given kernel function. * * @param kernelFunction one-dimensional kernel function with appropriate support to transform * @param l left border of the target interval * @param c width of the target interval * @throws IllegalArgumentException if c <= 0 */ public TransformedKernelFunction(KernelFunction kernelFunction, double l, double c) throws IllegalArgumentException { if (c <= 0) throw new IllegalArgumentException("the width of the interval the kernel function is transformed to needs to be greater than 0"); this.kernelFunction = kernelFunction; this.l = l; this.c = c; } /** Evaluates the transformed kernel function at given point x. * The transformation is performed by <br> * K^t (t) = (2 /c) * K (x) with x = (2/c) * (t-l) - 1<br> * or<br> * K^t (t) = (2 /c) * K ( (2/c) * (t-l) - 1)<br> for l <= t <= l-c.<br> * For t < l and t > l+c is K^t (t) == 0.<br> * * @param x function argument where to evaluate the transformed kernel function * @return function value of the transformed kernel function using the wrapped kernel function */ public double eval(double x) { return (2.0 / c) * kernelFunction.eval((2.0 / c) * (x - l) - 1.0); // 2/c * k ( (2/c)(x-l) -1) } /** Returns the primitive of the transformed kernel function * if and only if the used {@link xxl.core.math.statistics.nonparametric.kernels.KernelFunction kernel function} * for transformation itself implements the interface {@link xxl.core.math.functions.Integrable Integrable}. * Otherwise an {@link java.lang.UnsupportedOperationException UnsupportedOperationException} occurs.<br> * The primitive of the transformed kernel rests upon the primitive of the kernel used for transformation:<br> * int_{l}^{a} K^t (t) dt = int{-1}^{(2/c)*( a - l) +1} K(x) dx * <br> with l <= a <= l+c, a \in R. * * @throws UnsupportedOperationException if the transformed kernel function is not * {@link xxl.core.math.functions.Integrable integrable} * @return primitive as {@link xxl.core.math.functions.RealFunction RealFunction} */ public RealFunction primitive() throws UnsupportedOperationException { final RealFunction f; try { f = ((Integrable) kernelFunction).primitive(); } catch (ClassCastException e) { throw new UnsupportedOperationException("The interface Integrable is not implemented by the used kernel function"); } return new RealFunction() { public double eval(double a) { if ((a < l) || (a > l + c)) return 0.0; double trans = (2.0 / c) * (a - l) - 1.0; double inner = f.eval(trans) - f.eval(-1.0); return inner; } }; } /** Returns the first derivative of the transformed kernel function * if and only if the used {@link xxl.core.math.statistics.nonparametric.kernels.KernelFunction kernel function} * for transformation itself implements the interface {@link xxl.core.math.functions.Differentiable Differentiable}. * Otherwise an {@link java.lang.UnsupportedOperationException UnsupportedOperationException} occurs.<br> * The derivative of the transformed kernel rests upon the derivative of the kernel used for transformation:<br> * K'^t (t) dt = (2 / c)^2 * K' ( (2/c)*(x-l) -1 ) for * <br> l <= t <= l+c, t \in R * <br> otherwise K'^t (t) = 0 * * @throws UnsupportedOperationException if the transformed kernel function is not * {@link xxl.core.math.functions.Differentiable differentiable} * @return first derivative as {@link xxl.core.math.functions.RealFunction RealFunction} */ public RealFunction derivative() throws UnsupportedOperationException { final RealFunction f; try { f = ((Differentiable) kernelFunction).derivative(); } catch (ClassCastException e) { throw new UnsupportedOperationException("The interface Differentiable is not implemented by the used kernel function"); } return new RealFunction() { public double eval(double t) { double trans = (2.0 / c) * (t - l) - 1.0; double inner = f.eval(trans); return (2.0 / c) * (2.0 / c) * inner; } }; } }