package de.lmu.ifi.dbs.elki.distance.similarityfunction.kernel;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.database.query.DistanceSimilarityQuery;
import de.lmu.ifi.dbs.elki.database.query.distance.PrimitiveDistanceSimilarityQuery;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.distance.distancefunction.AbstractNumberVectorDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.distancefunction.PrimitiveDistanceFunction;
import de.lmu.ifi.dbs.elki.distance.similarityfunction.AbstractVectorSimilarityFunction;
import de.lmu.ifi.dbs.elki.math.MathUtil;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
/**
* Polynomial Kernel function that computes a similarity between the two feature
* vectors V1 and V2 defined by (V1^T*V2)^degree.
*
* @author Simon Paradies
*/
public class PolynomialKernelFunction extends AbstractVectorSimilarityFunction implements PrimitiveDistanceFunction {
/**
* The default degree.
*/
public static final int DEFAULT_DEGREE = 2;
/**
* Degree of the polynomial kernel function.
*/
private final int degree;
/**
* Bias of the similarity function.
*/
private final double bias;
/**
* Constructor.
*
* @param degree Kernel degree
* @param bias Bias offset
*/
public PolynomialKernelFunction(int degree, double bias) {
super();
this.degree = degree;
this.bias = bias;
}
/**
* Constructor.
*
* @param degree Kernel degree
*/
public PolynomialKernelFunction(int degree) {
this(degree, 0.);
}
@Override
public double similarity(NumberVector o1, NumberVector o2) {
final int dim = AbstractNumberVectorDistanceFunction.dimensionality(o1, o2);
double sim = 0.;
for(int i = 0; i < dim; i++) {
sim += o1.doubleValue(i) * o2.doubleValue(i);
}
return MathUtil.powi(sim + bias, degree);
}
@Override
public boolean isMetric() {
return true;
}
@Override
public double distance(NumberVector fv1, NumberVector fv2) {
return Math.sqrt(similarity(fv1, fv1) + similarity(fv2, fv2) - 2 * similarity(fv1, fv2));
}
@Override
public DistanceSimilarityQuery instantiate(Relation database) {
return new PrimitiveDistanceSimilarityQuery<>(database, this, this);
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Degree parameter.
*/
public static final OptionID DEGREE_ID = new OptionID("kernel.polynomial.degree", "The degree of the polynomial kernel function. Default: " + DEFAULT_DEGREE);
/**
* Bias parameter.
*/
public static final OptionID BIAS_ID = new OptionID("kernel.polynomial.bias", "The bias of the polynomial kernel, a constant that is added to the scalar product.");
/**
* Degree of the polynomial kernel function.
*/
protected int degree = 0;
/**
* Bias parameter.
*/
protected double bias = 0.;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
final IntParameter degreeP = new IntParameter(DEGREE_ID, DEFAULT_DEGREE);
degreeP.addConstraint(CommonConstraints.GREATER_EQUAL_ONE_INT);
if(config.grab(degreeP)) {
degree = degreeP.intValue();
}
final DoubleParameter biasP = new DoubleParameter(BIAS_ID);
biasP.setOptional(true);
if(config.grab(biasP)) {
bias = biasP.doubleValue();
}
}
@Override
protected PolynomialKernelFunction makeInstance() {
if(degree == 1 && (bias == 0.)) {
return LinearKernelFunction.STATIC;
}
return new PolynomialKernelFunction(degree, bias);
}
}
}