/** * Obtains no more than maxNumSamples distinct samples. Each sample belongs to * [loInclusive, hiExclusive). * * @param loInclusive The lower bound (inclusive). * @param hiExclusive The high bound (exclusive). * @param maxNumSamples The maximum number of samples to obtain. * @param distinctSamples The samples that will be obtained. */ inline void ObtainDistinctSamples(const size_t loInclusive, const size_t hiExclusive, const size_t maxNumSamples, arma::uvec& distinctSamples) { const size_t samplesRangeSize = hiExclusive - loInclusive; if (samplesRangeSize > maxNumSamples) { arma::Col<size_t> samples; samples.zeros(samplesRangeSize); for (size_t i = 0; i < maxNumSamples; i++) samples [ (size_t) math::RandInt(samplesRangeSize) ]++; distinctSamples = arma::find(samples > 0); if (loInclusive > 0) distinctSamples += loInclusive; } else { distinctSamples.set_size(samplesRangeSize); for (size_t i = 0; i < samplesRangeSize; i++) distinctSamples[i] = loInclusive + i; } }
/// /// \brief Vespucci::Math::DimensionReduction::VCA /// Vertex Component Analysis /// \param R The dataset /// \param endmembers Number of endmembers to compute /// \param indices Row indices of pure components. /// \param endmember_spectra Spectra of pure components (note that these are in /// columns, not rows as in spectra_) /// \param projected_data Projected data /// \param fractional_abundances Purity of a given spectrum relative to endmember /// \return Convergeance (no actual test implemented...) /// bool Vespucci::Math::DimensionReduction::VCA(const arma::mat &R, arma::uword p, arma::uvec &indices, arma::mat &endmember_spectra, arma::mat &projected_data, arma::mat &fractional_abundances) { //Initializations arma::uword L = R.n_rows; arma::uword N = R.n_cols; if (L == 0 || N == 0){ std::cerr << "No data!" << std::endl; return false; } if (p > L){ std::cerr << "wrong number of endmembers (" << p << ")!"<< std::endl; std::cerr << "set to 5 or one less than number of spectra" << std::endl; p = (L < 5? 5: L-1); } //mat of SNR arma::mat r_m = mean(R, 1); arma::mat R_m = arma::repmat(r_m, 1, N); //the mean of each spectral band arma::mat R_o = R - R_m; //mean-center the data arma::mat Ud; arma::vec Sd; arma::mat Vd; //arma::svds(Ud, Sd, Vd, arma::sp_mat(R_o * R_o.t()/N), p); Vespucci::Math::DimensionReduction::svds(R_o*R_o.t()/N, p, Ud, Sd, Vd); arma::mat x_p; try{ x_p = Ud.t() * R_o; }catch(std::exception e){ std::cout << "Ud.t() * R_o" << std::endl; } double SNR = Vespucci::Math::DimensionReduction::estimate_snr(R, r_m, x_p); double SNR_th = 15 + 10*log10(p); //Choose projective projection or projection to p-1 subspace arma::mat y; if (SNR < SNR_th){ arma::uword d = p - 1; Ud = Ud.cols(0, d-1); projected_data = Ud * x_p.rows(0, d-1) + R_m; //in dimension L arma::mat x = x_p.rows(0, d-1);//x_p = trans(Ud)*R_o, p-dimensional subspace //following three lines are one in arma::matlab... arma::mat sum_squares = sum(pow(x, 2)); double c = sum_squares.max(); c = std::sqrt(c); y = arma::join_vert(x, c*arma::ones(1, N)); } else{ arma::uword d = p; Vespucci::Math::DimensionReduction::svds(R*R.t()/N, p, Ud, Sd, Vd); arma::svds(Ud, Sd, Vd, arma::sp_mat(R*R.t()/N), d);//R_o is a mean centered version... x_p = Ud.t() * R; projected_data = Ud * x_p.rows(0, d-1); arma::mat x = Ud.t() * R; arma::mat u = arma::mean(x, 1); y = x / arma::repmat(sum(x % arma::repmat(u, 1, N)), d, 1); } // The VCA algorithm arma::vec w; w.set_size(p); arma::vec f; arma::rowvec v; indices.set_size(p); //there are no fill functions for arma::uvecs for (arma::uword i = 0; i < p; ++i) indices(i) = 0; arma::mat A = arma::zeros(p, p); double v_max; double sum_squares; arma::uvec q1; A(p-1, 0) = 1; for (arma::uword i = 0; i < p; ++i){ w.randu(); f = w - A*arma::pinv(A)*w; sum_squares = sqrt(sum(square(f))); f /= sum_squares; v = f.t() * y; v_max = arma::max(abs(v)); q1 = arma::find(abs(v) == v_max, 1); indices(i) = q1(0); A.col(i) = y.col(indices(i)); //same as x.col(indices(i)); } endmember_spectra = projected_data.cols(indices); fractional_abundances = arma::trans(pinv(endmember_spectra) * projected_data); return true; }