Skip to content

Commit

Permalink
Convert DimensionReductionMethod to a class instead of enum (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
lisitsyn authored May 6, 2024
1 parent 1bd6790 commit 2ceea82
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 289 deletions.
1 change: 0 additions & 1 deletion include/tapkee/defines.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
/* Tapkee includes */
#include <tapkee/exceptions.hpp>
#include <tapkee/traits/callbacks_traits.hpp>
#include <tapkee/traits/methods_traits.hpp>
/* End of Tapkee includes */

#include <iterator>
Expand Down
197 changes: 109 additions & 88 deletions include/tapkee/defines/methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,12 @@
*/
#pragma once

/* Tapkee includes */
#include <tapkee/defines/types.hpp>
#include <tapkee/traits/methods_traits.hpp>
/* End of Tapkee includes */

namespace tapkee
{
//! Dimension reduction methods
enum DimensionReductionMethod
{
/** Kernel Locally Linear Embedding as described
* in @cite Decoste2001 */
KernelLocallyLinearEmbedding,
/** Neighborhood Preserving Embedding as described
* in @cite He2005 */
NeighborhoodPreservingEmbedding,
/** Local Tangent Space Alignment as described
* in @cite Zhang2002 */
KernelLocalTangentSpaceAlignment,
/** Linear Local Tangent Space Alignment as described
* in @cite Zhang2007 */
LinearLocalTangentSpaceAlignment,
/** Hessian Locally Linear Embedding as described in
* @cite Donoho2003 */
HessianLocallyLinearEmbedding,
/** Laplacian Eigenmaps as described in
* @cite Belkin2002 */
LaplacianEigenmaps,
/** Locality Preserving Projections as described in
* @cite He2003 */
LocalityPreservingProjections,
/** Diffusion map as described in
* @cite Coifman2006 */
DiffusionMap,
/** Isomap as described in
* @cite Tenenbaum2000 */
Isomap,
/** Landmark Isomap as described in
* @cite deSilva2002 */
LandmarkIsomap,
/** Multidimensional scaling as described in
* @cite Cox2000 */
MultidimensionalScaling,
/** Landmark multidimensional scaling as described in
* @cite deSilva2004 */
LandmarkMultidimensionalScaling,
/** Stochastic Proximity Embedding as described in
* @cite Agrafiotis2003 */
StochasticProximityEmbedding,
/** Kernel PCA as described in
* @cite Scholkopf1997 */
KernelPCA,
/** Principal Component Analysis */
PCA,
/** Random Projection as described in
* @cite Kaski1998*/
RandomProjection,
/** Factor Analysis */
FactorAnalysis,
/** t-SNE and Barnes-Hut-SNE as described in
* @cite vanDerMaaten2008 and @cite vanDerMaaten2013 */
tDistributedStochasticNeighborEmbedding,
/** Manifold Sculpting as described in
* @cite Gashler2007 */
ManifoldSculpting,
/** Passing through (doing nothing just passes the
* data through) */
PassThru
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS
// Methods identification
METHOD_THAT_NEEDS_ONLY_KERNEL_IS(KernelLocallyLinearEmbedding);
METHOD_THAT_NEEDS_KERNEL_AND_FEATURES_IS(NeighborhoodPreservingEmbedding);
METHOD_THAT_NEEDS_ONLY_KERNEL_IS(KernelLocalTangentSpaceAlignment);
METHOD_THAT_NEEDS_KERNEL_AND_FEATURES_IS(LinearLocalTangentSpaceAlignment);
METHOD_THAT_NEEDS_ONLY_KERNEL_IS(HessianLocallyLinearEmbedding);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(LaplacianEigenmaps);
METHOD_THAT_NEEDS_DISTANCE_AND_FEATURES_IS(LocalityPreservingProjections);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(DiffusionMap);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(Isomap);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(LandmarkIsomap);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(MultidimensionalScaling);
METHOD_THAT_NEEDS_ONLY_DISTANCE_IS(LandmarkMultidimensionalScaling);
METHOD_THAT_NEEDS_DISTANCE_AND_FEATURES_IS(StochasticProximityEmbedding);
METHOD_THAT_NEEDS_ONLY_KERNEL_IS(KernelPCA);
METHOD_THAT_NEEDS_ONLY_FEATURES_IS(PCA);
METHOD_THAT_NEEDS_ONLY_FEATURES_IS(RandomProjection);
METHOD_THAT_NEEDS_NOTHING_IS(PassThru);
METHOD_THAT_NEEDS_ONLY_FEATURES_IS(FactorAnalysis);
METHOD_THAT_NEEDS_ONLY_FEATURES_IS(tDistributedStochasticNeighborEmbedding);
METHOD_THAT_NEEDS_DISTANCE_AND_FEATURES_IS(ManifoldSculpting);
#endif // DOXYGEN_SHOULD_SKIP_THS

template <typename M> struct Method
{
Expand All @@ -119,6 +34,112 @@ template <typename M> struct Method
const char* name_;
};

struct DimensionReductionTraits
{
const bool needs_kernel;
const bool needs_distance;
const bool needs_features;
};

struct DimensionReductionMethod : public Method<DimensionReductionMethod>
{
DimensionReductionMethod(const char* n, const DimensionReductionTraits& traits)
: Method<DimensionReductionMethod>(n)
, needs_kernel(traits.needs_kernel)
, needs_distance(traits.needs_distance)
, needs_features(traits.needs_features)
{
}
using Method<DimensionReductionMethod>::operator==;
bool needs_kernel;
bool needs_distance;
bool needs_features;
};

static const DimensionReductionTraits RequiresKernel{true, false, false};
static const DimensionReductionTraits RequiresKernelAndFeatures{true, false, true};
static const DimensionReductionTraits RequiresDistance{false, true, false};
static const DimensionReductionTraits RequiresDistanceAndFeatures{false, true, true};
static const DimensionReductionTraits RequiresFeatures{false, false, true};

/** Kernel Locally Linear Embedding as described
* in @cite Decoste2001 */
static const DimensionReductionMethod KernelLocallyLinearEmbedding("Kernel Locally Linear Embedding (KLLE)", RequiresKernel);

/** Neighborhood Preserving Embedding as described
* in @cite He2005 */
static const DimensionReductionMethod NeighborhoodPreservingEmbedding("Neighborhood Preserving Embedding (NPE)", RequiresKernelAndFeatures);

/** Local Tangent Space Alignment as described
* in @cite Zhang2002 */
static const DimensionReductionMethod KernelLocalTangentSpaceAlignment("Kernel Local Tangent Space Alignment (KLTSA)", RequiresKernel);

/** Linear Local Tangent Space Alignment as described
* in @cite Zhang2007 */
static const DimensionReductionMethod LinearLocalTangentSpaceAlignment("Linear Local Tangent Space Alignment (LLTSA)", RequiresKernelAndFeatures);

/** Hessian Locally Linear Embedding as described in
* @cite Donoho2003 */
static const DimensionReductionMethod HessianLocallyLinearEmbedding("Hessian Locally Linear Embedding (HLLE)", RequiresKernel);

/** Laplacian Eigenmaps as described in
* @cite Belkin2002 */
static const DimensionReductionMethod LaplacianEigenmaps("Laplacian Eigenmaps", RequiresDistance);

/** Locality Preserving Projections as described in
* @cite He2003 */
static const DimensionReductionMethod LocalityPreservingProjections("Locality Preserving Projections (LPP)", RequiresDistanceAndFeatures);

/** Diffusion map as described in
* @cite Coifman2006 */
static const DimensionReductionMethod DiffusionMap("Diffusion Map", RequiresDistance);

/** Isomap as described in
* @cite Tenenbaum2000 */
static const DimensionReductionMethod Isomap("Isomap", RequiresDistance);

/** Landmark Isomap as described in
* @cite deSilva2002 */
static const DimensionReductionMethod LandmarkIsomap("Landmark Isomap", RequiresDistance);

/** Multidimensional scaling as described in
* @cite Cox2000 */
static const DimensionReductionMethod MultidimensionalScaling("Multidimensional Scaling (MDS)", RequiresDistance);

/** Landmark multidimensional scaling as described in
* @cite deSilva2004 */
static const DimensionReductionMethod LandmarkMultidimensionalScaling("Landmark Multidimensional Scaling (LMDS)", RequiresDistance);

/** Stochastic Proximity Embedding as described in
* @cite Agrafiotis2003 */
static const DimensionReductionMethod StochasticProximityEmbedding("Stochastic Proximity Embedding (SPE)", RequiresDistanceAndFeatures);

/** Kernel PCA as described in
* @cite Scholkopf1997 */
static const DimensionReductionMethod KernelPCA("Kernel Principal Component Analysis (KPCA)", RequiresKernel);

/** Principal Component Analysis */
static const DimensionReductionMethod PCA("Principal Component Analysis (PCA)", RequiresFeatures);

/** Random Projection as described in
* @cite Kaski1998*/
static const DimensionReductionMethod RandomProjection("Random Projection", RequiresFeatures);

/** Factor Analysis */
static const DimensionReductionMethod FactorAnalysis("Factor Analysis", RequiresFeatures);

/** t-SNE and Barnes-Hut-SNE as described in
* @cite vanDerMaaten2008 and @cite vanDerMaaten2013 */
static const DimensionReductionMethod tDistributedStochasticNeighborEmbedding("t-distributed Stochastic Neighbor Embedding (t-SNE)", RequiresFeatures);

/** Manifold Sculpting as described in
* @cite Gashler2007 */
static const DimensionReductionMethod ManifoldSculpting("Manifold Sculpting", RequiresFeatures);

/** Passing through (doing nothing just passes the
* data through) */
static const DimensionReductionMethod PassThru("Pass-through", RequiresFeatures);

struct NeighborsMethod : public Method<NeighborsMethod>
{
NeighborsMethod(const char* n) : Method<NeighborsMethod>(n)
Expand Down Expand Up @@ -199,7 +220,7 @@ struct EigendecompositionStrategy : public Method<EigendecompositionStrategy>
{
return skip_;
}
IndexType skip_;
const IndexType skip_;
};

static const EigendecompositionStrategy LargestEigenvalues("Largest eigenvalues", 0);
Expand Down
84 changes: 40 additions & 44 deletions include/tapkee/methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,58 +22,54 @@ class DynamicImplementation : public ImplementationBase<RandomAccessIterator, Ke
{
public:
using ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>::ImplementationBase;
TapkeeOutput embedUsing(DimensionReductionMethod method)
TapkeeOutput embedUsing(const DimensionReductionMethod& method)
{
timed_context tctx__(fmt::format("[+] embedding with {}", method.name()));

if (this->context.is_cancelled())
throw cancelled_exception();

if (method.needs_kernel && is_dummy<KernelCallback>::value)
{
throw unsupported_method_error("Kernel callback is missed");
}
if (method.needs_distance && is_dummy<DistanceCallback>::value)
{
throw unsupported_method_error("Distance callback is missed");
}
if (method.needs_features && is_dummy<FeaturesCallback>::value)
{
throw unsupported_method_error("Features callback is missed");
}

const auto& self = static_cast<ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>>(*this);

#define tapkee_method_handle(X) \
case X: { \
timed_context tctx__("[+] embedding with " #X); \
if (MethodTraits<X>::needs_kernel && is_dummy<KernelCallback>::value) \
{ \
throw unsupported_method_error("Kernel callback is missed"); \
} \
if (MethodTraits<X>::needs_distance && is_dummy<DistanceCallback>::value) \
{ \
throw unsupported_method_error("Distance callback is missed"); \
} \
if (MethodTraits<X>::needs_features && is_dummy<FeaturesCallback>::value) \
{ \
throw unsupported_method_error("Features callback is missed"); \
} \
auto self = static_cast<ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>>(*this); \
if (method == X) { \
auto implementation = \
X ## Implementation<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>(self); \
return implementation.embed(); \
} \
break;

switch (method)
{
tapkee_method_handle(KernelLocallyLinearEmbedding);
tapkee_method_handle(KernelLocalTangentSpaceAlignment);
tapkee_method_handle(DiffusionMap);
tapkee_method_handle(MultidimensionalScaling);
tapkee_method_handle(LandmarkMultidimensionalScaling);
tapkee_method_handle(Isomap);
tapkee_method_handle(LandmarkIsomap);
tapkee_method_handle(NeighborhoodPreservingEmbedding);
tapkee_method_handle(LinearLocalTangentSpaceAlignment);
tapkee_method_handle(HessianLocallyLinearEmbedding);
tapkee_method_handle(LaplacianEigenmaps);
tapkee_method_handle(LocalityPreservingProjections);
tapkee_method_handle(PCA);
tapkee_method_handle(KernelPCA);
tapkee_method_handle(RandomProjection);
tapkee_method_handle(StochasticProximityEmbedding);
tapkee_method_handle(PassThru);
tapkee_method_handle(FactorAnalysis);
tapkee_method_handle(tDistributedStochasticNeighborEmbedding);
tapkee_method_handle(ManifoldSculpting);
default:
break;
}
}
tapkee_method_handle(KernelLocallyLinearEmbedding);
tapkee_method_handle(KernelLocalTangentSpaceAlignment);
tapkee_method_handle(DiffusionMap);
tapkee_method_handle(MultidimensionalScaling);
tapkee_method_handle(LandmarkMultidimensionalScaling);
tapkee_method_handle(Isomap);
tapkee_method_handle(LandmarkIsomap);
tapkee_method_handle(NeighborhoodPreservingEmbedding);
tapkee_method_handle(LinearLocalTangentSpaceAlignment);
tapkee_method_handle(HessianLocallyLinearEmbedding);
tapkee_method_handle(LaplacianEigenmaps);
tapkee_method_handle(LocalityPreservingProjections);
tapkee_method_handle(PCA);
tapkee_method_handle(KernelPCA);
tapkee_method_handle(RandomProjection);
tapkee_method_handle(StochasticProximityEmbedding);
tapkee_method_handle(PassThru);
tapkee_method_handle(FactorAnalysis);
tapkee_method_handle(tDistributedStochasticNeighborEmbedding);
tapkee_method_handle(ManifoldSculpting);
#undef tapkee_method_handle
return TapkeeOutput();
}
Expand Down
16 changes: 8 additions & 8 deletions include/tapkee/methods/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ class ImplementationBase

};

#define __TAPKEE_IMPLEMENTATION(Method) \
template <class RandomAccessIterator, class KernelCallback, class DistanceCallback, class FeaturesCallback> \
class Method ## Implementation : public ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback> \
{ \
public: \
Method ## Implementation(const ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>& other) : \
ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>(other) \
{ \
#define __TAPKEE_IMPLEMENTATION(Method) \
template <class RandomAccessIterator, class KernelCallback, class DistanceCallback, class FeaturesCallback> \
class Method ## Implementation : public ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback> \
{ \
public: \
Method ## Implementation(const ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>& other) : \
ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>(other) \
{ \
}
#define __TAPKEE_END_IMPLEMENTATION() };

Expand Down
6 changes: 0 additions & 6 deletions include/tapkee/traits/callbacks_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@
namespace tapkee
{

template <class Callback> struct BatchCallbackTraits
{
static const bool supports_batch;
};
#define TAPKEE_CALLBACK_SUPPORTS_BATCH(X) template <> const bool BatchCallbackTraits<X>::supports_batch = true;

template <class T> class is_dummy
{
typedef char yes;
Expand Down
28 changes: 0 additions & 28 deletions include/tapkee/traits/methods_traits.hpp

This file was deleted.

Loading

0 comments on commit 2ceea82

Please sign in to comment.