Skip to content

Commit

Permalink
Avoid using explicit this-> referencing of template base class (#98)
Browse files Browse the repository at this point in the history
* Avoid using explicit this-> referencing of template base class
* Simplify eigendecomposition
  • Loading branch information
lisitsyn authored May 18, 2024
1 parent 8bcf6be commit ab4176e
Show file tree
Hide file tree
Showing 20 changed files with 127 additions and 122 deletions.
33 changes: 31 additions & 2 deletions include/tapkee/methods/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ImplementationBase

}

public:
protected:
ParametersSet parameters;
Context context;
KernelCallback kernel;
Expand All @@ -78,20 +78,49 @@ class ImplementationBase
IndexType current_dimension;

protected:
template <class Distance> Neighbors findNeighborsWith(Distance d)
template <class Distance>
Neighbors find_neighbors_with(Distance d)
{
parameters[num_neighbors].checked().satisfies(InRange<IndexType>(3, n_vectors)).orThrow();
return find_neighbors(parameters[neighbors_method], begin, end, d, parameters[num_neighbors],
parameters[check_connectivity]);
}

template <class MatrixType>
EigendecompositionResult eigendecomposition_via(const EigendecompositionStrategy& eigen_strategy, const MatrixType& m, IndexType target_dimension)
{
return eigendecomposition(
parameters[eigen_method],
parameters[computation_strategy],
eigen_strategy,
m,
target_dimension
);
}


};

// TODO can we avoid these using things?
#define __TAPKEE_IMPLEMENTATION(Method) \
template <class RandomAccessIterator, class KernelCallback, class DistanceCallback, class FeaturesCallback> \
class Method ## Implementation : public ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback> \
{ \
public: \
typedef ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback> Base; \
using Base::parameters; \
using Base::context; \
using Base::kernel; \
using Base::distance; \
using Base::features; \
using Base::plain_distance; \
using Base::kernel_distance; \
using Base::begin; \
using Base::end; \
using Base::n_vectors; \
using Base::current_dimension; \
using Base::find_neighbors_with; \
using Base::eigendecomposition_via; \
Method ## Implementation(const ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>& other) : \
ImplementationBase<RandomAccessIterator, KernelCallback, DistanceCallback, FeaturesCallback>(other) \
{ \
Expand Down
14 changes: 6 additions & 8 deletions include/tapkee/methods/diffusion_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/diffusion_maps.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
/* End of Tapkee includes */

namespace tapkee
Expand All @@ -18,21 +17,20 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(DiffusionMap)
TapkeeOutput embed()
{
this->parameters[diffusion_map_timesteps].checked().satisfies(Positivity<IndexType>()).orThrow();
this->parameters[gaussian_kernel_width].checked().satisfies(Positivity<ScalarType>()).orThrow();
parameters[diffusion_map_timesteps].checked().satisfies(Positivity<IndexType>()).orThrow();
parameters[gaussian_kernel_width].checked().satisfies(Positivity<ScalarType>()).orThrow();

IndexType target_dimension_value = static_cast<IndexType>(this->parameters[target_dimension]);
IndexType target_dimension_value = static_cast<IndexType>(parameters[target_dimension]);
Parameter target_dimension_add = Parameter::create("target_dimension", target_dimension_value + 1);
DenseSymmetricMatrix diffusion_matrix =
compute_diffusion_matrix(this->begin, this->end, this->distance, this->parameters[gaussian_kernel_width]);
compute_diffusion_matrix(begin, end, distance, parameters[gaussian_kernel_width]);
EigendecompositionResult decomposition_result =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy], LargestEigenvalues,
diffusion_matrix, target_dimension_add);
eigendecomposition_via(LargestEigenvalues, diffusion_matrix, target_dimension_add);
DenseMatrix embedding = (decomposition_result.first).leftCols(target_dimension_value);
// scaling with lambda_i^t
for (IndexType i = 0; i < target_dimension_value; i++)
embedding.col(i).array() *=
pow(decomposition_result.second(i), static_cast<IndexType>(this->parameters[diffusion_map_timesteps]));
pow(decomposition_result.second(i), static_cast<IndexType>(parameters[diffusion_map_timesteps]));
// scaling by eigenvector to largest eigenvalue 1
for (IndexType i = 0; i < target_dimension_value; i++)
embedding.col(i).array() /= decomposition_result.first.col(target_dimension_value).array();
Expand Down
8 changes: 4 additions & 4 deletions include/tapkee/methods/factor_analysis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(FactorAnalysis)
TapkeeOutput embed()
{
this->parameters[fa_epsilon].checked().satisfies(NonNegativity<ScalarType>()).orThrow();
parameters[fa_epsilon].checked().satisfies(NonNegativity<ScalarType>()).orThrow();

DenseVector mean_vector = compute_mean(this->begin, this->end, this->features, this->current_dimension);
return TapkeeOutput(project(this->begin, this->end, this->features, this->current_dimension, this->parameters[max_iteration],
this->parameters[fa_epsilon], this->parameters[target_dimension], mean_vector),
DenseVector mean_vector = compute_mean(begin, end, features, current_dimension);
return TapkeeOutput(project(begin, end, features, current_dimension, parameters[max_iteration],
parameters[fa_epsilon], parameters[target_dimension], mean_vector),
unimplementedProjectingFunction());
}
__TAPKEE_END_IMPLEMENTATION()
Expand Down
8 changes: 3 additions & 5 deletions include/tapkee/methods/hessian_locally_linear_embedding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/locally_linear.hpp>
/* End of Tapkee includes */

Expand All @@ -18,11 +17,10 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(HessianLocallyLinearEmbedding)
TapkeeOutput embed()
{
Neighbors neighbors = this->findNeighborsWith(this->kernel_distance);
Neighbors neighbors = find_neighbors_with(kernel_distance);
SparseWeightMatrix weight_matrix =
hessian_weight_matrix(this->begin, this->end, neighbors, this->kernel, this->parameters[target_dimension]);
return TapkeeOutput(eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy],
SmallestEigenvalues, weight_matrix, this->parameters[target_dimension]).first,
hessian_weight_matrix(begin, end, neighbors, kernel, parameters[target_dimension]);
return TapkeeOutput(eigendecomposition_via(SmallestEigenvalues, weight_matrix, parameters[target_dimension]).first,
unimplementedProjectingFunction());
}
__TAPKEE_END_IMPLEMENTATION()
Expand Down
10 changes: 4 additions & 6 deletions include/tapkee/methods/isomap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/isomap.hpp>
#include <tapkee/routines/multidimensional_scaling.hpp>
/* End of Tapkee includes */
Expand All @@ -19,18 +18,17 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(Isomap)
TapkeeOutput embed()
{
Neighbors neighbors = this->findNeighborsWith(this->plain_distance);
Neighbors neighbors = find_neighbors_with(plain_distance);
DenseSymmetricMatrix shortest_distances_matrix =
compute_shortest_distances_matrix(this->begin, this->end, neighbors, this->distance);
compute_shortest_distances_matrix(begin, end, neighbors, distance);
shortest_distances_matrix = shortest_distances_matrix.array().square();
centerMatrix(shortest_distances_matrix);
shortest_distances_matrix.array() *= -0.5;

EigendecompositionResult embedding =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy], LargestEigenvalues,
shortest_distances_matrix, this->parameters[target_dimension]);
eigendecomposition_via(LargestEigenvalues, shortest_distances_matrix, parameters[target_dimension]);

for (IndexType i = 0; i < static_cast<IndexType>(this->parameters[target_dimension]); i++)
for (IndexType i = 0; i < static_cast<IndexType>(parameters[target_dimension]); i++)
embedding.first.col(i).array() *= sqrt(embedding.second(i));

return TapkeeOutput(embedding.first, unimplementedProjectingFunction());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/locally_linear.hpp>
/* End of Tapkee includes */

Expand All @@ -18,11 +17,10 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(KernelLocalTangentSpaceAlignment)
TapkeeOutput embed()
{
Neighbors neighbors = this->findNeighborsWith(this->kernel_distance);
Neighbors neighbors = find_neighbors_with(kernel_distance);
SparseWeightMatrix weight_matrix = tangent_weight_matrix(
this->begin, this->end, neighbors, this->kernel, this->parameters[target_dimension], this->parameters[nullspace_shift]);
DenseMatrix embedding = eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy],
SmallestEigenvalues, weight_matrix, this->parameters[target_dimension]).first;
begin, end, neighbors, kernel, parameters[target_dimension], parameters[nullspace_shift]);
DenseMatrix embedding = eigendecomposition_via(SmallestEigenvalues, weight_matrix, parameters[target_dimension]).first;

return TapkeeOutput(embedding, unimplementedProjectingFunction());
}
Expand Down
8 changes: 3 additions & 5 deletions include/tapkee/methods/kernel_locally_linear_embedding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/locally_linear.hpp>
/* End of Tapkee includes */

Expand All @@ -18,11 +17,10 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(KernelLocallyLinearEmbedding)
TapkeeOutput embed()
{
Neighbors neighbors = this->findNeighborsWith(this->kernel_distance);
Neighbors neighbors = find_neighbors_with(kernel_distance);
SparseWeightMatrix weight_matrix =
linear_weight_matrix(this->begin, this->end, neighbors, this->kernel, this->parameters[nullspace_shift], this->parameters[klle_shift]);
DenseMatrix embedding = eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy],
SmallestEigenvalues, weight_matrix, this->parameters[target_dimension]).first;
linear_weight_matrix(begin, end, neighbors, kernel, parameters[nullspace_shift], parameters[klle_shift]);
DenseMatrix embedding = eigendecomposition_via(SmallestEigenvalues, weight_matrix, parameters[target_dimension]).first;

return TapkeeOutput(embedding, unimplementedProjectingFunction());
}
Expand Down
8 changes: 3 additions & 5 deletions include/tapkee/methods/kernel_pca.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/pca.hpp>
/* End of Tapkee includes */

Expand All @@ -18,11 +17,10 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(KernelPrincipalComponentAnalysis)
TapkeeOutput embed()
{
DenseSymmetricMatrix centered_kernel_matrix = compute_centered_kernel_matrix(this->begin, this->end, this->kernel);
DenseSymmetricMatrix centered_kernel_matrix = compute_centered_kernel_matrix(begin, end, kernel);
EigendecompositionResult embedding =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy], LargestEigenvalues,
centered_kernel_matrix, this->parameters[target_dimension]);
for (IndexType i = 0; i < static_cast<IndexType>(this->parameters[target_dimension]); i++)
eigendecomposition_via(LargestEigenvalues, centered_kernel_matrix, parameters[target_dimension]);
for (IndexType i = 0; i < static_cast<IndexType>(parameters[target_dimension]); i++)
embedding.first.col(i).array() *= sqrt(embedding.second(i));
return TapkeeOutput(embedding.first, unimplementedProjectingFunction());
}
Expand Down
19 changes: 8 additions & 11 deletions include/tapkee/methods/landmark_isomap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/isomap.hpp>
#include <tapkee/routines/multidimensional_scaling.hpp>
/* End of Tapkee includes */
Expand All @@ -19,11 +18,11 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(LandmarkIsomap)
TapkeeOutput embed()
{
this->parameters[landmark_ratio].checked().satisfies(InClosedRange<ScalarType>(3.0 / this->n_vectors, 1.0)).orThrow();
parameters[landmark_ratio].checked().satisfies(InClosedRange<ScalarType>(3.0 / n_vectors, 1.0)).orThrow();

Neighbors neighbors = this->findNeighborsWith(this->plain_distance);
Landmarks landmarks = select_landmarks_random(this->begin, this->end, this->parameters[landmark_ratio]);
DenseMatrix distance_matrix = compute_shortest_distances_matrix(this->begin, this->end, landmarks, neighbors, this->distance);
Neighbors neighbors = find_neighbors_with(plain_distance);
Landmarks landmarks = select_landmarks_random(begin, end, parameters[landmark_ratio]);
DenseMatrix distance_matrix = compute_shortest_distances_matrix(begin, end, landmarks, neighbors, distance);
distance_matrix = distance_matrix.array().square();

DenseVector col_means = distance_matrix.colwise().mean();
Expand All @@ -36,23 +35,21 @@ __TAPKEE_IMPLEMENTATION(LandmarkIsomap)

EigendecompositionResult landmarks_embedding;

if (this->parameters[eigen_method].is(Dense))
if (parameters[eigen_method].is(Dense))
{
DenseMatrix distance_matrix_sym = distance_matrix * distance_matrix.transpose();
landmarks_embedding =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy], LargestEigenvalues,
distance_matrix_sym, this->parameters[target_dimension]);
eigendecomposition_via(LargestEigenvalues, distance_matrix_sym, parameters[target_dimension]);
}
else
{
landmarks_embedding =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy],
SquaredLargestEigenvalues, distance_matrix, this->parameters[target_dimension]);
eigendecomposition_via(SquaredLargestEigenvalues, distance_matrix, parameters[target_dimension]);
}

DenseMatrix embedding = distance_matrix.transpose() * landmarks_embedding.first;

for (IndexType i = 0; i < static_cast<IndexType>(this->parameters[target_dimension]); i++)
for (IndexType i = 0; i < static_cast<IndexType>(parameters[target_dimension]); i++)
embedding.col(i).array() /= sqrt(sqrt(landmarks_embedding.second(i)));
return TapkeeOutput(embedding, unimplementedProjectingFunction());
}
Expand Down
16 changes: 7 additions & 9 deletions include/tapkee/methods/landmark_multidimensional_scaling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

/* Tapkee includes */
#include <tapkee/methods/base.hpp>
#include <tapkee/routines/eigendecomposition.hpp>
#include <tapkee/routines/multidimensional_scaling.hpp>
/* End of Tapkee includes */

Expand All @@ -18,20 +17,19 @@ namespace tapkee_internal
__TAPKEE_IMPLEMENTATION(LandmarkMultidimensionalScaling)
TapkeeOutput embed()
{
this->parameters[landmark_ratio].checked().satisfies(InClosedRange<ScalarType>(3.0 / this->n_vectors, 1.0)).orThrow();
parameters[landmark_ratio].checked().satisfies(InClosedRange<ScalarType>(3.0 / n_vectors, 1.0)).orThrow();

Landmarks landmarks = select_landmarks_random(this->begin, this->end, this->parameters[landmark_ratio]);
DenseSymmetricMatrix distance_matrix = compute_distance_matrix(this->begin, this->end, landmarks, this->distance);
Landmarks landmarks = select_landmarks_random(begin, end, parameters[landmark_ratio]);
DenseSymmetricMatrix distance_matrix = compute_distance_matrix(begin, end, landmarks, distance);
DenseVector landmark_distances_squared = distance_matrix.colwise().mean();
centerMatrix(distance_matrix);
distance_matrix.array() *= -0.5;
EigendecompositionResult landmarks_embedding =
eigendecomposition(this->parameters[eigen_method], this->parameters[computation_strategy], LargestEigenvalues,
distance_matrix, this->parameters[target_dimension]);
for (IndexType i = 0; i < static_cast<IndexType>(this->parameters[target_dimension]); i++)
eigendecomposition_via(LargestEigenvalues, distance_matrix, parameters[target_dimension]);
for (IndexType i = 0; i < static_cast<IndexType>(parameters[target_dimension]); i++)
landmarks_embedding.first.col(i).array() *= sqrt(landmarks_embedding.second(i));
return TapkeeOutput(triangulate(this->begin, this->end, this->distance, landmarks, landmark_distances_squared,
landmarks_embedding, this->parameters[target_dimension]),
return TapkeeOutput(triangulate(begin, end, distance, landmarks, landmark_distances_squared,
landmarks_embedding, parameters[target_dimension]),
unimplementedProjectingFunction());
}
__TAPKEE_END_IMPLEMENTATION()
Expand Down
Loading

0 comments on commit ab4176e

Please sign in to comment.