Skip to content

Commit

Permalink
Merge pull request #3289 from lambday/develop
Browse files Browse the repository at this point in the history
added translational invariant kernel class, refactored distance kernel
  • Loading branch information
karlnapf committed Jun 17, 2016
2 parents 8422681 + 5181c9b commit 784ae71
Show file tree
Hide file tree
Showing 3 changed files with 389 additions and 0 deletions.
124 changes: 124 additions & 0 deletions src/shogun/kernel/ShiftInvariantKernel.cpp
@@ -0,0 +1,124 @@
/*
* Copyright (c) The Shogun Machine Learning Toolbox
* Written (w) 2016 Soumyajit De
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of the Shogun Development Team.
*/

#include <shogun/lib/common.h>
#include <shogun/kernel/ShiftInvariantKernel.h>
#include <shogun/distance/CustomDistance.h>

using namespace shogun;

CShiftInvariantKernel::CShiftInvariantKernel() : CKernel(0)
{
register_params();
}

CShiftInvariantKernel::CShiftInvariantKernel(CFeatures *l, CFeatures *r) : CKernel(l, r, 0)
{
register_params();
init(l, r);
}

CShiftInvariantKernel::~CShiftInvariantKernel()
{
cleanup();
SG_UNREF(m_distance);
}

bool CShiftInvariantKernel::init(CFeatures* l, CFeatures* r)
{
REQUIRE(m_distance, "The distance instance cannot be NULL!\n");
CKernel::init(l,r);
m_distance->init(l, r);
return init_normalizer();
}

void CShiftInvariantKernel::precompute_distance()
{
REQUIRE(m_distance, "The distance instance cannot be NULL!\n");
REQUIRE(m_distance->init(lhs, rhs), "Could not initialize the distance instance!\n");

SGMatrix<float32_t> dist_mat=m_distance->get_distance_matrix<float32_t>();
if (m_precomputed_distance==NULL)
{
m_precomputed_distance=new CCustomDistance();
SG_REF(m_precomputed_distance);
}

if (lhs==rhs)
m_precomputed_distance->set_triangle_distance_matrix_from_full(dist_mat.data(), dist_mat.num_rows, dist_mat.num_cols);
else
m_precomputed_distance->set_full_distance_matrix_from_full(dist_mat.data(), dist_mat.num_rows, dist_mat.num_cols);
}

void CShiftInvariantKernel::cleanup()
{
SG_UNREF(m_precomputed_distance);
m_precomputed_distance=NULL;
CKernel::cleanup();
}

EDistanceType CShiftInvariantKernel::get_distance_type() const
{
REQUIRE(m_distance, "The distance instance cannot be NULL!\n");
return m_distance->get_distance_type();
}

float64_t CShiftInvariantKernel::distance(int32_t a, int32_t b) const
{
REQUIRE(m_distance, "The distance instance cannot be NULL!\n");
if (m_precomputed_distance!=NULL)
return m_precomputed_distance->distance(a, b);
else
return m_distance->distance(a, b);
}

void CShiftInvariantKernel::register_params()
{
SG_ADD((CSGObject**) &m_distance, "m_distance", "Distance to be used.", MS_NOT_AVAILABLE);
SG_ADD((CSGObject**) &m_precomputed_distance, "m_precomputed_distance", "Precomputed istance to be used.", MS_NOT_AVAILABLE);

m_distance=NULL;
m_precomputed_distance=NULL;
}

void CShiftInvariantKernel::set_precomputed_distance(CCustomDistance* precomputed_distance)
{
REQUIRE(precomputed_distance, "The precomputed distance instance cannot be NULL!\n");
SG_REF(precomputed_distance);
SG_UNREF(m_precomputed_distance);
m_precomputed_distance=precomputed_distance;
}

CCustomDistance* CShiftInvariantKernel::get_precomputed_distance() const
{
REQUIRE(m_precomputed_distance, "The precomputed distance instance cannot be NULL!\n");
SG_REF(m_precomputed_distance);
return m_precomputed_distance;
}
138 changes: 138 additions & 0 deletions src/shogun/kernel/ShiftInvariantKernel.h
@@ -0,0 +1,138 @@
/*
* Copyright (c) The Shogun Machine Learning Toolbox
* Written (w) 2016 Soumyajit De
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of the Shogun Development Team.
*/

#include <shogun/lib/config.h>

#ifndef SHIFT_INVARIANT_KERNEL_H_
#define SHIFT_INVARIANT_KERNEL_H_

#include <shogun/kernel/Kernel.h>
#include <shogun/distance/CustomDistance.h>

namespace shogun
{

/** @brief Base class for the family of kernel functions that only depend on
* the difference of the inputs, i.e. whose values does not change if the
* inputs are shifted by the same amount. More precisely,
* \f[
* k(\mathbf{x}, \mathbf{x'}) = k(\mathbf{x-x'})
* \f]
* For example, Gaussian (RBF) kernel is a shfit invariant kernel.
*/
class CShiftInvariantKernel: public CKernel
{
public:
/** Default constructor. */
CShiftInvariantKernel();

/**
* Constructor that initializes the kernel with two feature instances.
*
* @param l features of left-hand side
* @param r features of right-hand side
*/
CShiftInvariantKernel(CFeatures *l, CFeatures *r);

/** Destructor. */
virtual ~CShiftInvariantKernel();

/**
* Initialize kernel.
*
* @param l features of left-hand side
* @param r features of right-hand side
* @return if initializing was successful
*/
virtual bool init(CFeatures* l, CFeatures* r);

/** Method that precomputes the distance */
virtual void precompute_distance();

/**
* Method that releases any precomputed distance instance in addition to
* clean up the base class methods.
*/
virtual void cleanup();

/** @return kernel type */
virtual EKernelType get_kernel_type()=0;

/** @return feature type of distance used */
virtual EFeatureType get_feature_type()=0;

/** @return feature class of distance used */
virtual EFeatureClass get_feature_class()=0;

/** @return the distance type */
virtual EDistanceType get_distance_type() const;

/** @return name Distance */
virtual const char* get_name() const
{
return "ShiftInvariantKernel";
}

protected:
/**
* Computes distance between features a and b, where idx_{a,b} denote the indices
* of the feature vectors in the corresponding feature object.
*
* @param idx_a index a
* @param idx_b index b
* @return distance between features a and b
*/
virtual float64_t distance(int32_t idx_a, int32_t idx_b) const;

/** Distance instance for the kernel. MUST be initialized by the subclasses */
CDistance* m_distance;

private:
/** Registers the parameters (serialization support). */
virtual void register_params();

/** Precomputed distance instance */
CCustomDistance* m_precomputed_distance;

/**
* Method that sets a precomputed distance.
*
* @param precomputed_distance The precomputed distance object.
*/
void set_precomputed_distance(CCustomDistance* precomputed_distance);

/** @return the precomputed distance. */
CCustomDistance* get_precomputed_distance() const;

};

}

#endif // SHIFT_INVARIANT_KERNEL_H__
127 changes: 127 additions & 0 deletions tests/unit/kernel/ShiftInvariantKernel_unittest.cc
@@ -0,0 +1,127 @@
/*
* Copyright (c) The Shogun Machine Learning Toolbox
* Written (w) 2016 Soumyajit De
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of the Shogun Development Team.
*/

#include <shogun/lib/config.h>

#ifdef HAVE_CXX11

#include <shogun/base/some.h>
#include <shogun/kernel/Kernel.h>
#include <shogun/kernel/ShiftInvariantKernel.h>
#include <shogun/distance/Distance.h>
#include <shogun/distance/EuclideanDistance.h>
#include <shogun/features/FeatureTypes.h>
#include <shogun/features/DenseFeatures.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <algorithm>

using namespace shogun;
using std::iota;
using std::for_each;

class CShiftInvariantKernelMock : public CShiftInvariantKernel
{
public:
CShiftInvariantKernelMock() : CShiftInvariantKernel()
{
m_distance=new CEuclideanDistance();
SG_REF(m_distance);
}

float64_t get_distance(int32_t a, int32_t b) const
{
return CShiftInvariantKernel::distance(a, b);
}

MOCK_METHOD2(compute, float64_t(int32_t, int32_t));
MOCK_METHOD0(get_kernel_type, EKernelType());
MOCK_METHOD0(get_feature_type, EFeatureType());
MOCK_METHOD0(get_feature_class, EFeatureClass());
};

TEST(ShiftInvariantKernel, precompute_distance_asymmetric)
{
const index_t dim=1;
const index_t N=10;
const index_t M=15;

SGMatrix<float64_t> data_1(dim, N);
SGMatrix<float64_t> data_2(dim, M);

iota(data_1.data(), data_1.data()+data_1.size(), 1);
iota(data_2.data(), data_2.data()+data_2.size(), data_1.size()+1);

for_each(data_1.data(), data_1.data()+data_1.size(), [&data_1](float64_t& val) { val=val/data_1.size(); });
for_each(data_2.data(), data_2.data()+data_2.size(), [&data_2](float64_t& val) { val=val/data_2.size(); });

auto feats_1=some<CDenseFeatures<float64_t> >(data_1);
auto feats_2=some<CDenseFeatures<float64_t> >(data_2);

auto kernel_1=some<CShiftInvariantKernelMock>();
auto kernel_2=some<CShiftInvariantKernelMock>();

kernel_1->init(feats_1, feats_2);
kernel_2->init(feats_1, feats_2);

kernel_1->precompute_distance();

for (auto i=0; i<N; ++i)
{
for (auto j=0; j<M; ++j)
EXPECT_NEAR(kernel_1->get_distance(i, j), kernel_1->get_distance(i, j), 1E-6);
}
}

TEST(ShiftInvariantKernel, precompute_distance_symmetric)
{
const index_t dim=1;
const index_t N=10;

SGMatrix<float64_t> data(dim, N);
iota(data.data(), data.data()+data.size(), 1);
for_each(data.data(), data.data()+data.size(), [&data](float64_t& val) { val=val/data.size(); });
auto feats=some<CDenseFeatures<float64_t> >(data);

auto kernel_1=some<CShiftInvariantKernelMock>();
auto kernel_2=some<CShiftInvariantKernelMock>();

kernel_1->init(feats, feats);
kernel_2->init(feats, feats);

kernel_1->precompute_distance();

for (auto i=0; i<N; ++i)
{
for (auto j=0; j<N; ++j)
EXPECT_NEAR(kernel_1->get_distance(i, j), kernel_1->get_distance(i, j), 1E-6);
}
}
#endif // HAVE_CXX11

0 comments on commit 784ae71

Please sign in to comment.