EmbeddingResult embed(const LMatrixType& lhs, const RMatrixType& rhs, IndexType target_dimension, unsigned int skip) { timed_context context("ARPACK DSXUPD generalized eigendecomposition"); #ifndef TAPKEE_NO_ARPACK ArpackGeneralizedSelfAdjointEigenSolver<LMatrixType, RMatrixType, MatrixTypeOperation> arpack(lhs,rhs,target_dimension+skip,"SM"); if (arpack.info() == Eigen::Success) { stringstream ss; ss << "Took " << arpack.getNbrIterations() << " iterations."; LoggingSingleton::instance().message_info(ss.str()); DenseMatrix embedding_feature_matrix = (arpack.eigenvectors()).block(0,skip,lhs.cols(),target_dimension); return EmbeddingResult(embedding_feature_matrix,arpack.eigenvalues().tail(target_dimension)); } else { throw eigendecomposition_error("eigendecomposition failed"); } return EmbeddingResult(); #else return EmbeddingResult(); #endif }
EmbeddingResult embed(const LMatrixType& lhs, const RMatrixType& rhs, IndexType target_dimension, unsigned int skip) { timed_context context("Eigen dense generalized eigendecomposition"); DenseMatrix dense_lhs = lhs; DenseMatrix dense_rhs = rhs; Eigen::GeneralizedSelfAdjointEigenSolver<DenseMatrix> solver(dense_lhs, dense_rhs); if (solver.info() == Eigen::Success) { if (MatrixOperationType::largest) { assert(skip==0); DenseMatrix embedding_feature_matrix = solver.eigenvectors().rightCols(target_dimension); return EmbeddingResult(embedding_feature_matrix,solver.eigenvalues().tail(target_dimension)); } else { DenseMatrix embedding_feature_matrix = solver.eigenvectors().leftCols(target_dimension+skip).rightCols(target_dimension); return EmbeddingResult(embedding_feature_matrix,solver.eigenvalues().segment(skip,skip+target_dimension)); } } else { throw eigendecomposition_error("eigendecomposition failed"); } return EmbeddingResult(); }
EmbeddingResult embed(const MatrixType& wm, IndexType target_dimension, unsigned int skip) { timed_context context("Randomized eigendecomposition"); DenseMatrix O(wm.rows(), target_dimension+skip); for (IndexType i=0; i<O.rows(); ++i) { IndexType j=0; for ( ; j+1 < O.cols(); j+= 2) { ScalarType v1 = (ScalarType)(rand()+1.f)/((float)RAND_MAX+2.f); ScalarType v2 = (ScalarType)(rand()+1.f)/((float)RAND_MAX+2.f); ScalarType len = sqrt(-2.f*log(v1)); O(i,j) = len*cos(2.f*M_PI*v2); O(i,j+1) = len*sin(2.f*M_PI*v2); } for ( ; j < O.cols(); j++) { ScalarType v1 = (ScalarType)(rand()+1.f)/((float)RAND_MAX+2.f); ScalarType v2 = (ScalarType)(rand()+1.f)/((float)RAND_MAX+2.f); ScalarType len = sqrt(-2.f*log(v1)); O(i,j) = len*cos(2.f*M_PI*v2); } } MatrixTypeOperation operation(wm); DenseMatrix Y = operation(O); for (IndexType i=0; i<Y.cols(); i++) { for (IndexType j=0; j<i; j++) { ScalarType r = Y.col(i).dot(Y.col(j)); Y.col(i) -= r*Y.col(j); } ScalarType norm = Y.col(i).norm(); if (norm < 1e-4) { for (int k = i; k<Y.cols(); k++) Y.col(k).setZero(); } Y.col(i) *= (1.f / norm); } DenseMatrix B1 = operation(Y); DenseMatrix B = Y.householderQr().solve(B1); DenseSelfAdjointEigenSolver eigenOfB(B); if (eigenOfB.info() == Eigen::Success) { DenseMatrix embedding = (Y*eigenOfB.eigenvectors()).block(0, skip, wm.cols(), target_dimension); return EmbeddingResult(embedding,eigenOfB.eigenvalues()); } else { throw eigendecomposition_error("eigendecomposition failed"); } return EmbeddingResult(); }
EmbeddingResult embed(const LMatrixType& lhs, const RMatrixType& rhs, unsigned int target_dimension, unsigned int skip) { timed_context context("ARPACK DSXUPD generalized eigendecomposition"); #ifndef TAPKEE_NO_ARPACK ArpackGeneralizedSelfAdjointEigenSolver<LMatrixType, RMatrixType, MatrixTypeOperation> arpack(lhs,rhs,target_dimension+skip,"SM"); DenseMatrix embedding_feature_matrix = (arpack.eigenvectors()).block(0,skip,lhs.cols(),target_dimension); return EmbeddingResult(embedding_feature_matrix,arpack.eigenvalues().tail(target_dimension)); #else return EmbeddingResult(); #endif }
EmbeddingResult embed(const MatrixType& wm, IndexType target_dimension, unsigned int skip) { timed_context context("Eigen library dense eigendecomposition"); DenseMatrix dense_wm = wm; DenseSelfAdjointEigenSolver solver(dense_wm); if (solver.info() == Eigen::Success) { DenseMatrix embedding_feature_matrix = (solver.eigenvectors()).block(0,skip,wm.cols(),target_dimension); return EmbeddingResult(embedding_feature_matrix,solver.eigenvalues().tail(target_dimension)); } else { throw eigendecomposition_error("eigendecomposition failed"); } return EmbeddingResult(); }
EmbeddingResult embed(const LMatrixType& lhs, const RMatrixType& rhs, IndexType target_dimension, unsigned int skip) { timed_context context("Eigen dense generalized eigendecomposition"); DenseMatrix dense_lhs = lhs; DenseMatrix dense_rhs = rhs; Eigen::GeneralizedSelfAdjointEigenSolver<DenseMatrix> solver(dense_lhs, dense_rhs); if (solver.info() == Eigen::Success) { DenseMatrix embedding_feature_matrix = (solver.eigenvectors()).block(0,skip,lhs.cols(),target_dimension); return EmbeddingResult(embedding_feature_matrix,solver.eigenvalues().tail(target_dimension)); } else { throw eigendecomposition_error("eigendecomposition failed"); } return EmbeddingResult(); }
EmbeddingResult generalized_eigen_embedding(TAPKEE_EIGEN_EMBEDDING_METHOD method, const LMatrixType& lhs, const RMatrixType& rhs, unsigned int target_dimension, unsigned int skip) { switch (method) { case ARPACK: return generalized_eigen_embedding_impl<LMatrixType, RMatrixType, MatrixTypeOperation, ARPACK>().embed(lhs, rhs, target_dimension, skip); case EIGEN_DENSE_SELFADJOINT_SOLVER: return generalized_eigen_embedding_impl<LMatrixType, RMatrixType, MatrixTypeOperation, EIGEN_DENSE_SELFADJOINT_SOLVER>().embed(lhs, rhs, target_dimension, skip); case RANDOMIZED: // TODO fail here return EmbeddingResult(); default: break; } return EmbeddingResult(); };
EmbeddingResult generalized_eigen_embedding(TAPKEE_EIGEN_EMBEDDING_METHOD method, const LMatrixType& lhs, const RMatrixType& rhs, IndexType target_dimension, unsigned int skip) { switch (method) { #ifdef TAPKEE_WITH_ARPACK case ARPACK: return generalized_eigen_embedding_impl<LMatrixType, RMatrixType, MatrixOperationType, ARPACK>().embed(lhs, rhs, target_dimension, skip); #endif case EIGEN_DENSE_SELFADJOINT_SOLVER: return generalized_eigen_embedding_impl<LMatrixType, RMatrixType, MatrixOperationType, EIGEN_DENSE_SELFADJOINT_SOLVER>().embed(lhs, rhs, target_dimension, skip); case RANDOMIZED: throw unsupported_method_error("Randomized method is not supported for generalized eigenproblems"); return EmbeddingResult(); default: break; } return EmbeddingResult(); }
EmbeddingResult embed(const LMatrixType& lhs, const RMatrixType& rhs, unsigned int target_dimension, unsigned int skip) { timed_context context("Eigen dense generalized eigendecomposition"); DenseMatrix dense_lhs = lhs; DenseMatrix dense_rhs = rhs; Eigen::GeneralizedSelfAdjointEigenSolver<DenseMatrix> solver(dense_lhs, dense_rhs); DenseMatrix embedding_feature_matrix = (solver.eigenvectors()).block(0,skip,lhs.cols(),target_dimension); return EmbeddingResult(embedding_feature_matrix,solver.eigenvalues().tail(target_dimension)); }
EmbeddingResult project(const ProjectionResult& projection_result, RandomAccessIterator begin, RandomAccessIterator end, FeatureVectorCallback callback, unsigned int dimension) { timed_context context("Data projection"); DenseVector current_vector(dimension); const DenseSymmetricMatrix& projection_matrix = projection_result.first; DenseMatrix embedding = DenseMatrix::Zero((end-begin),projection_matrix.cols()); for (RandomAccessIterator iter=begin; iter!=end; ++iter) { callback(*iter,current_vector); embedding.row(iter-begin) = projection_matrix.transpose()*current_vector; } return EmbeddingResult(embedding,DenseVector()); }
EmbeddingResult eigen_embedding(TAPKEE_EIGEN_EMBEDDING_METHOD method, const MatrixType& m, IndexType target_dimension, unsigned int skip) { LoggingSingleton::instance().message_info("Using " + get_eigen_embedding_name(method) + " eigendecomposition."); switch (method) { case ARPACK: return eigen_embedding_impl<MatrixType, MatrixTypeOperation, ARPACK>().embed(m, target_dimension, skip); case RANDOMIZED: return eigen_embedding_impl<MatrixType, MatrixTypeOperation, RANDOMIZED>().embed(m, target_dimension, skip); case EIGEN_DENSE_SELFADJOINT_SOLVER: return eigen_embedding_impl<MatrixType, MatrixTypeOperation, EIGEN_DENSE_SELFADJOINT_SOLVER>().embed(m, target_dimension, skip); default: break; } return EmbeddingResult(); };
EmbeddingResult spe_embedding(RandomAccessIterator begin, RandomAccessIterator end, PairwiseCallback callback, const Neighbors& neighbors, unsigned int target_dimension, bool global_strategy, DefaultScalarType tolerance, int nupdates) { timed_context context("SPE embedding computation"); unsigned int k = 0; if (!global_strategy) k = neighbors[0].size(); // The number of data points int N = end-begin; while (nupdates > N/2) nupdates = N/2; // Look for the maximum distance DefaultScalarType max = 0.0; for (RandomAccessIterator i_iter=begin; i_iter!=end; ++i_iter) { for (RandomAccessIterator j_iter=i_iter+1; j_iter!=end; ++j_iter) { max = std::max(max, callback(*i_iter,*j_iter)); } } // Distances normalizer used in global strategy DefaultScalarType alpha = 0.0; if (global_strategy) alpha = 1.0 / max * std::sqrt(2.0); // Random embedding initialization, Y is the short for embedding_feature_matrix std::srand(std::time(0)); DenseMatrix Y = (DenseMatrix::Random(target_dimension,N) + DenseMatrix::Ones(target_dimension,N)) / 2; // Auxiliary diffference embedding feature matrix DenseMatrix Yd(target_dimension,nupdates); // SPE's main loop typedef std::vector<int> Indices; typedef std::vector<int>::iterator IndexIterator; // Maximum number of iterations int max_iter = 2000 + round(0.04 * N*N); if (!global_strategy) max_iter *= 3; // Learning parameter DefaultScalarType lambda = 1.0; // Vector of indices used for shuffling Indices indices(N); for (int i=0; i<N; ++i) indices[i] = i; // Vector with distances in the original space of the points to update DenseVector Rt(nupdates); DenseVector scale(nupdates); DenseVector D(nupdates); // Pointers to the indices of the elements to update IndexIterator ind1; IndexIterator ind2; // Helper used in local strategy Indices ind1Neighbors; if (!global_strategy) ind1Neighbors.resize(k*nupdates); for (int i=0; i<max_iter; ++i) { // Shuffle to select the vectors to update in this iteration std::random_shuffle(indices.begin(),indices.end()); ind1 = indices.begin(); ind2 = indices.begin()+nupdates; // With local strategy, the seecond set of indices is selected among // neighbors of the first set if (!global_strategy) { // Neighbors of interest for(int j=0; j<nupdates; ++j) { const LocalNeighbors& current_neighbors = neighbors[*ind1++]; for(unsigned int kk=0; kk<k; ++kk) ind1Neighbors[kk + j*k] = current_neighbors[kk]; } // Restore ind1 ind1 = indices.begin(); // Generate pseudo-random indices and select final indices for(int j=0; j<nupdates; ++j) { unsigned int r = round( std::rand()*1.0/RAND_MAX*(k-1) ) + k*j; indices[nupdates+j] = ind1Neighbors[r]; } } // Compute distances between the selected points in the embedded space for(int j=0; j<nupdates; ++j) { //FIXME it seems that here Euclidean distance is forced D[j] = (Y.col(*ind1) - Y.col(*ind2)).norm(); ++ind1, ++ind2; } // Get the corresponding distances in the original space if (global_strategy) Rt.fill(alpha); else // local_strategy Rt.fill(1); ind1 = indices.begin(); ind2 = indices.begin()+nupdates; for (int j=0; j<nupdates; ++j) Rt[j] *= callback(*(begin + *ind1++), *(begin + *ind2++)); // Compute some terms for update // Scale factor D.array() += tolerance; scale = (Rt-D).cwiseQuotient(D); ind1 = indices.begin(); ind2 = indices.begin()+nupdates; // Difference matrix for (int j=0; j<nupdates; ++j) { Yd.col(j).noalias() = Y.col(*ind1) - Y.col(*ind2); ++ind1, ++ind2; } ind1 = indices.begin(); ind2 = indices.begin()+nupdates; // Update the location of the vectors in the embedded space for (int j=0; j<nupdates; ++j) { Y.col(*ind1) += lambda / 2 * scale[j] * Yd.col(j); Y.col(*ind2) -= lambda / 2 * scale[j] * Yd.col(j); ++ind1, ++ind2; } // Update the learning parameter lambda = lambda - ( lambda / max_iter ); } return EmbeddingResult(Y.transpose(),DenseVector()); };