-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DES #490
base: main
Are you sure you want to change the base?
Add DES #490
Changes from all commits
6383a4a
023a3ff
df4065c
b5237f8
e0decad
55247ca
ba0acc2
ec347c7
4468f05
716e82e
eb14603
8538902
c67c212
8411e6a
f94b2b7
09a45ce
7ace291
ebab96a
bb56794
f439248
0701118
ddd6853
f888035
a72e340
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,87 @@ | ||||
#include "des.h" | ||||
|
||||
#include "algorithms/nar/value_range.h" | ||||
#include "config/names_and_descriptions.h" | ||||
#include "config/option_using.h" | ||||
#include "config/tabular_data/input_table/option.h" | ||||
#include "model/types/types.h" | ||||
|
||||
namespace algos::des { | ||||
using model::ValueRange; | ||||
|
||||
DES::DES() : NARAlgorithm({}) { | ||||
using namespace config::names; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
RegisterOptions(); | ||||
} | ||||
|
||||
void DES::RegisterOptions() { | ||||
DESBORDANTE_OPTION_USING; | ||||
|
||||
DifferentialStrategy default_strategy = DifferentialStrategy::rand1Bin; | ||||
RegisterOption(Option{&population_size_, kPopulationSize, kDPopulationSize, 100u}); | ||||
RegisterOption( | ||||
Option{&num_evaluations_, kMaxFitnessEvaluations, kDMaxFitnessEvaluations, 1000u}); | ||||
RegisterOption(Option{&differential_options_.differential_scale, kDifferentialScale, | ||||
kDDifferentialScale, 0.5}); | ||||
RegisterOption(Option{&differential_options_.crossover_probability, kCrossoverProbability, | ||||
kDCrossoverProbability, 0.9}); | ||||
RegisterOption(Option{&differential_options_.differential_strategy, kDifferentialStrategy, | ||||
kDDifferentialStrategy, default_strategy}); | ||||
} | ||||
|
||||
void DES::MakeExecuteOptsAvailable() { | ||||
using namespace config::names; | ||||
MakeOptionsAvailable({kPopulationSize, kMaxFitnessEvaluations, kDifferentialScale, | ||||
kCrossoverProbability, kDifferentialStrategy}); | ||||
} | ||||
|
||||
FeatureDomains DES::FindFeatureDomains(TypedRelation const* typed_relation) { | ||||
std::vector<std::shared_ptr<ValueRange>> feature_domains; | ||||
feature_domains.reserve(typed_relation->GetNumColumns()); | ||||
for (size_t i = 0; i < typed_relation->GetNumColumns(); i++) { | ||||
std::shared_ptr<ValueRange> domain = CreateValueRange(typed_relation->GetColumnData(i)); | ||||
feature_domains.push_back(std::move(domain)); | ||||
} | ||||
return feature_domains; | ||||
} | ||||
|
||||
std::vector<EncodedNAR> DES::GetRandomPopulationInDomains(FeatureDomains const& domains) const { | ||||
std::vector<EncodedNAR> population(population_size_, | ||||
EncodedNAR(domains, typed_relation_.get())); | ||||
auto compare_by_fitness = [](EncodedNAR const& a, EncodedNAR const& b) { | ||||
return a.GetQualities().fitness > b.GetQualities().fitness; | ||||
}; | ||||
std::sort(population.begin(), population.end(), compare_by_fitness); | ||||
return population; | ||||
} | ||||
|
||||
EncodedNAR DES::MutatedIndividual(std::vector<EncodedNAR> const& population, size_t at) { | ||||
MutationFunction diff_func = | ||||
EnumToMutationStrategy(differential_options_.differential_strategy); | ||||
return (*diff_func)(population, at, differential_options_); | ||||
} | ||||
|
||||
unsigned long long DES::ExecuteInternal() { | ||||
FeatureDomains feature_domains = FindFeatureDomains(typed_relation_.get()); | ||||
std::vector<EncodedNAR> population = GetRandomPopulationInDomains(feature_domains); | ||||
|
||||
for (unsigned i = 0; i < num_evaluations_; i++) { | ||||
size_t candidate_i = i % population_size_; | ||||
EncodedNAR mutant = MutatedIndividual(population, candidate_i); | ||||
NAR mutant_decoded = mutant.SetQualities(feature_domains, typed_relation_.get()); | ||||
double candidate_fitness = population[candidate_i].GetQualities().fitness; | ||||
|
||||
if (mutant.GetQualities().fitness > candidate_fitness) { | ||||
population[candidate_i] = std::move(mutant); | ||||
nar_collection_.emplace_back(std::move(mutant_decoded)); | ||||
} | ||||
} | ||||
|
||||
auto compare_by_fitness = [](const NAR& a, const NAR& b) -> bool { | ||||
return a.GetQualities().fitness > b.GetQualities().fitness; | ||||
}; | ||||
Comment on lines
+80
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's code duplication, you used that in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or create a private method to sort There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They take in different types, first takes in two NARs, second takes two EncodedNARs. |
||||
std::sort(nar_collection_.begin(), nar_collection_.end(), compare_by_fitness); | ||||
return 0; | ||||
} | ||||
|
||||
} // namespace algos::des |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#pragma once | ||
|
||
#include "algorithms/nar/nar_algorithm.h" | ||
#include "config/names.h" | ||
#include "differential_functions.h" | ||
#include "encoded_nar.h" | ||
#include "enums.h" | ||
|
||
namespace algos::des { | ||
using FeatureDomains = std::vector<std::shared_ptr<model::ValueRange>> const; | ||
using TypedRelation = model::ColumnLayoutTypedRelationData; | ||
|
||
class DES : public NARAlgorithm { | ||
private: | ||
unsigned int population_size_; | ||
unsigned int num_evaluations_; | ||
DifferentialOptions differential_options_; | ||
|
||
void RegisterOptions(); | ||
|
||
static FeatureDomains FindFeatureDomains(TypedRelation const* typed_relation); | ||
std::vector<EncodedNAR> GetRandomPopulationInDomains(FeatureDomains const& domains) const; | ||
void EvolvePopulation(std::vector<EncodedNAR>& population) const; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't find definition of |
||
EncodedNAR MutatedIndividual(std::vector<EncodedNAR> const& population, size_t at); | ||
|
||
protected: | ||
void MakeExecuteOptsAvailable() override; | ||
unsigned long long ExecuteInternal() override; | ||
|
||
public: | ||
DES(); | ||
}; | ||
|
||
} // namespace algos::des |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,57 @@ | ||||||||||||||
#include "differential_functions.h" | ||||||||||||||
|
||||||||||||||
#include <algorithm> | ||||||||||||||
|
||||||||||||||
namespace algos::des { | ||||||||||||||
|
||||||||||||||
// gets slow if population ~= number_of_indices | ||||||||||||||
std::vector<size_t> GetRandIndices(size_t except_index, size_t population, | ||||||||||||||
size_t number_of_indices) { | ||||||||||||||
assert(number_of_indices <= population - 1); | ||||||||||||||
std::unordered_set<size_t> indices; | ||||||||||||||
indices.insert(except_index); | ||||||||||||||
while (indices.size() < number_of_indices + 1) { | ||||||||||||||
size_t random_index = RNG().Next() * population; | ||||||||||||||
indices.insert(random_index); | ||||||||||||||
} | ||||||||||||||
indices.erase(except_index); | ||||||||||||||
std::vector<size_t> ind_vec; | ||||||||||||||
ind_vec.reserve(number_of_indices); | ||||||||||||||
ind_vec.insert(ind_vec.end(), indices.begin(), indices.end()); | ||||||||||||||
return ind_vec; | ||||||||||||||
Comment on lines
+18
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
EncodedNAR Rand1Bin(std::vector<EncodedNAR> const& population, size_t candidate_index, | ||||||||||||||
DifferentialOptions options) { | ||||||||||||||
auto sample_indices = GetRandIndices(candidate_index, population.size(), 3); | ||||||||||||||
size_t sample_index1 = sample_indices[0]; | ||||||||||||||
size_t sample_index2 = sample_indices[1]; | ||||||||||||||
size_t sample_index3 = sample_indices[2]; | ||||||||||||||
|
||||||||||||||
auto new_individual = population[candidate_index]; | ||||||||||||||
auto sample1 = population[sample_index1]; | ||||||||||||||
auto sample2 = population[sample_index2]; | ||||||||||||||
auto sample3 = population[sample_index3]; | ||||||||||||||
|
||||||||||||||
for (size_t i = 0; i < new_individual.VectorSize(); i++) { | ||||||||||||||
if (RNG().Next() < options.crossover_probability) { | ||||||||||||||
double new_feature_val = | ||||||||||||||
sample1[i] + options.differential_scale * (sample2[i] - sample3[i]); | ||||||||||||||
new_feature_val = std::clamp(new_feature_val, 0.0, 1.0); | ||||||||||||||
new_individual[i] = new_feature_val; | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
return new_individual; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// TODO: name is probably inconsistent with how it's called in the field. | ||||||||||||||
MutationFunction EnumToMutationStrategy(DifferentialStrategy strategy) { | ||||||||||||||
switch (strategy) { | ||||||||||||||
case DifferentialStrategy::rand1Bin: | ||||||||||||||
return Rand1Bin; | ||||||||||||||
default: | ||||||||||||||
throw std::logic_error("No mutation function corresponding to DifferentialStategy."); | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
} // namespace algos::des |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#pragma once | ||
|
||
#include <enum.h> | ||
|
||
#include "encoded_nar.h" | ||
#include "enums.h" | ||
#include "rng.h" | ||
|
||
namespace algos::des { | ||
|
||
struct DifferentialOptions { | ||
double differential_scale; | ||
double crossover_probability; | ||
DifferentialStrategy differential_strategy = DifferentialStrategy::best1Exp; | ||
}; | ||
|
||
EncodedNAR Rand1Bin(std::vector<EncodedNAR> const& population, size_t candidate_index, | ||
DifferentialOptions options); | ||
|
||
using MutationFunction = EncodedNAR (*)(std::vector<EncodedNAR> const& population, size_t candidate_index, | ||
DifferentialOptions options); | ||
|
||
MutationFunction EnumToMutationStrategy(DifferentialStrategy strategy); | ||
|
||
} // namespace algos::des |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,101 @@ | ||||||||||||||||||||||
#include "encoded_nar.h" | ||||||||||||||||||||||
|
||||||||||||||||||||||
#include "algorithms/nar/value_range.h" | ||||||||||||||||||||||
#include "model/types/types.h" | ||||||||||||||||||||||
|
||||||||||||||||||||||
namespace algos::des { | ||||||||||||||||||||||
|
||||||||||||||||||||||
using model::NAR; | ||||||||||||||||||||||
|
||||||||||||||||||||||
size_t EncodedNAR::VectorSize() const { | ||||||||||||||||||||||
return encoded_value_ranges_.size() * EncodedValueRange::kFieldCount + 1; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
size_t EncodedNAR::FeatureCount() const { | ||||||||||||||||||||||
return encoded_value_ranges_.size(); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
// TODO: remove code duplication here | ||||||||||||||||||||||
double& EncodedNAR::operator[](size_t index) { | ||||||||||||||||||||||
qualities_consistent_ = false; | ||||||||||||||||||||||
if (index == 0) { | ||||||||||||||||||||||
return implication_sign_pos_; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
index--; | ||||||||||||||||||||||
size_t feature = index / EncodedValueRange::kFieldCount; | ||||||||||||||||||||||
size_t feature_field = index % EncodedValueRange::kFieldCount; | ||||||||||||||||||||||
return encoded_value_ranges_[feature][feature_field]; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
double const& EncodedNAR::operator[](size_t index) const { | ||||||||||||||||||||||
if (index == 0) { | ||||||||||||||||||||||
return implication_sign_pos_; | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
index--; | ||||||||||||||||||||||
size_t feature = index / EncodedValueRange().kFieldCount; | ||||||||||||||||||||||
size_t feature_field = index % EncodedValueRange().kFieldCount; | ||||||||||||||||||||||
return encoded_value_ranges_[feature][feature_field]; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+33
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
NAR EncodedNAR::SetQualities(FeatureDomains& domains, TypedRelation const* typed_relation) { | ||||||||||||||||||||||
NAR this_decoded = Decode(domains); | ||||||||||||||||||||||
this_decoded.SetQualities(typed_relation); | ||||||||||||||||||||||
qualities_ = this_decoded.GetQualities(); | ||||||||||||||||||||||
qualities_consistent_ = true; | ||||||||||||||||||||||
return this_decoded; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
model::NARQualities const& EncodedNAR::GetQualities() const { | ||||||||||||||||||||||
if (!qualities_consistent_) { | ||||||||||||||||||||||
throw std::logic_error("Getting uninitialized qualities from NAR."); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return qualities_; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
NAR EncodedNAR::Decode(FeatureDomains& domains) const { | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
If |
||||||||||||||||||||||
NAR resulting_nar; | ||||||||||||||||||||||
std::vector<size_t> feature_order(encoded_value_ranges_.size()); | ||||||||||||||||||||||
std::iota(std::begin(feature_order), std::end(feature_order), 0); | ||||||||||||||||||||||
VanyaVolgushev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
auto compare_by_permutation = [this](size_t a, size_t b) { | ||||||||||||||||||||||
return encoded_value_ranges_[a].permutation > encoded_value_ranges_[b].permutation; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
std::sort(feature_order.begin(), feature_order.end(), compare_by_permutation); | ||||||||||||||||||||||
|
||||||||||||||||||||||
size_t implication_sign_after = implication_sign_pos_ * (encoded_value_ranges_.size() - 1); | ||||||||||||||||||||||
size_t handling_feat_num = 0; | ||||||||||||||||||||||
for (size_t feature_index : feature_order) { | ||||||||||||||||||||||
EncodedValueRange const& encoded_feature = encoded_value_ranges_[feature_index]; | ||||||||||||||||||||||
if (encoded_feature.threshold < RNG().Next()) { | ||||||||||||||||||||||
handling_feat_num++; | ||||||||||||||||||||||
continue; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
auto domain = domains[feature_index]; | ||||||||||||||||||||||
auto decoded = encoded_value_ranges_[feature_index].Decode(domain); | ||||||||||||||||||||||
Comment on lines
+73
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, you copying the shared pointer when using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, no need to create an additional copy of |
||||||||||||||||||||||
if (handling_feat_num > implication_sign_after) { | ||||||||||||||||||||||
resulting_nar.InsertInCons(feature_index, decoded); | ||||||||||||||||||||||
} else { | ||||||||||||||||||||||
resulting_nar.InsertInAnte(feature_index, decoded); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
handling_feat_num++; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
return resulting_nar; | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
EncodedNAR::EncodedNAR(FeatureDomains& domains, TypedRelation const* typed_relation) { | ||||||||||||||||||||||
size_t feature_count = domains.size(); | ||||||||||||||||||||||
for (size_t feature_index = 0; feature_index < feature_count; feature_index++) { | ||||||||||||||||||||||
encoded_value_ranges_.emplace_back(EncodedValueRange()); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
implication_sign_pos_ = RNG().Next(); | ||||||||||||||||||||||
SetQualities(domains, typed_relation); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
EncodedNAR::EncodedNAR(size_t feature_count) { | ||||||||||||||||||||||
for (size_t feature_index = 0; feature_index < feature_count; feature_index++) { | ||||||||||||||||||||||
encoded_value_ranges_.emplace_back(EncodedValueRange()); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+94
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
implication_sign_pos_ = RNG().Next(); | ||||||||||||||||||||||
} | ||||||||||||||||||||||
Comment on lines
+90
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing with |
||||||||||||||||||||||
|
||||||||||||||||||||||
} // namespace algos::des |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#pragma once | ||
|
||
#include "algorithms/nar/nar.h" | ||
#include "encoded_value_range.h" | ||
#include "model/table/column_layout_typed_relation_data.h" | ||
|
||
namespace algos::des { | ||
using model::NAR; | ||
|
||
class EncodedNAR { | ||
private: | ||
using TypedRelation = model::ColumnLayoutTypedRelationData; | ||
using FeatureDomains = std::vector<std::shared_ptr<model::ValueRange>> const; | ||
|
||
double implication_sign_pos_ = -1; | ||
std::vector<EncodedValueRange> encoded_value_ranges_ = std::vector<EncodedValueRange>(); | ||
|
||
model::NARQualities qualities_; | ||
bool qualities_consistent_ = false; | ||
double& GetElementAtIndex(size_t index) const; | ||
|
||
public: | ||
size_t VectorSize() const; | ||
size_t FeatureCount() const; | ||
double& operator[](size_t index); | ||
double const& operator[](size_t index) const; | ||
|
||
model::NARQualities const& GetQualities() const; | ||
NAR SetQualities(FeatureDomains& domains, TypedRelation const* typed_relation); | ||
|
||
NAR Decode(FeatureDomains& domains) const; | ||
EncodedNAR(FeatureDomains& domains, TypedRelation const* typed_relation); | ||
EncodedNAR(size_t feature_count); | ||
}; | ||
|
||
} // namespace algos::des |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include-what-you-use is planned to be introduced in the CI, so it would be better to add these lines:
This also applies to other files