double fitnessDistanceCorrelation( const std::unordered_map<arma::vec, double, Hash, IsEqual>& samples) { if (samples.size() < 2) { throw std::invalid_argument("fitnessDistanceCorrelation: The number of samples must be greater than 2."); } else if (!isDimensionallyConsistent(samples)) { throw std::invalid_argument("fitnessDistanceCorrelation: The samples must be dimensionally consistent"); } // Converts the set of samples into a matrix of parameters (each row is a dimension and each column a parameter) and a row vector of objective values, such that we can use Armadillo C++ to manipulate them. arma::mat parameters(samples.cbegin()->first.n_elem, samples.size()); arma::rowvec objectiveValues(parameters.n_cols); arma::uword n = 0; for (const auto& sample : samples) { parameters.col(n) = sample.first; objectiveValues(n) = sample.second; ++n; } // Determines one parameter having a minimal objective value within the set of samples. // The best parameter is then subtracted from all other parameters, so that we can later calculated the distance towards the best one. arma::uword bestParameterIndex; objectiveValues.min(bestParameterIndex); parameters.each_col() -= parameters.col(bestParameterIndex); // Excludes the best/reference parameter from the correlation, as it will always perfectly correlate with itself and therefore bias the correlation coefficient. parameters.shed_col(bestParameterIndex); objectiveValues.shed_col(bestParameterIndex); // Uses `arma::sum(arma::square(...))` to emulate a column-wise vector norm operator that Armadillo C++ does not have (and this is not likely to change, as it interferes with matrix norms). return arma::as_scalar(arma::cor(arma::sqrt(arma::sum(arma::square(parameters))), objectiveValues)); }
void FitnessDistanceCorrelationAnalysis::analyseImplementation() { assert(samples_.size() > 1); arma::Mat<double> parameters(numberOfDimensions_, samples_.size()); arma::Row<double> objectiveValues(parameters.n_cols); arma::uword n = 0; for (const auto& parameterToObjectiveValueMapping : samples_) { parameters.col(n) = parameterToObjectiveValueMapping.first; objectiveValues(n) = parameterToObjectiveValueMapping.second; ++n; } arma::uword bestParameterIndex; objectiveValues.min(bestParameterIndex); parameters.each_col() -= parameters.col(bestParameterIndex); parameters.shed_col(bestParameterIndex); objectiveValues.shed_col(bestParameterIndex); correlationCoefficient_ = arma::as_scalar(arma::cor(arma::sqrt(arma::sum(arma::square(parameters))), objectiveValues)); }