Skip to content

Commit

Permalink
Update to work with island indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
gAldeia committed Nov 17, 2023
1 parent 186895b commit 6f2b13c
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 129 deletions.
46 changes: 12 additions & 34 deletions src/eval/evaluation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,21 @@ namespace Eval{

template<ProgramType T>
void Evaluation<T>::validation(Population<T>& pop,
tuple<size_t, size_t> island_range,
int island,
const Dataset& data,
const Parameters& params,
bool offspring
)
{
// if offspring false --> if has offspring, do it on first half. else, do on entire island
// offspring true --> assert that has offspring, do it on the second half of the island
auto idxs = pop.get_island_indexes(island);

auto [idx_start, idx_end] = island_range;
size_t delta = idx_end - idx_start;
int start = 0;
if (offspring)
{
assert(pop.offspring_ready
&& ("Population does not have offspring to calculate validation fitness"));

idx_start = idx_start + (delta/2);
}
else if (pop.offspring_ready) // offspring is false. We need to see where we sould stop
{
idx_end = idx_end - (delta/2);
}
start = idxs.size()/2;

for (unsigned i = idx_start; i<idx_end; ++i)
for (unsigned i = start; i<idxs.size(); ++i)
{
Individual<T>& ind = pop[i];
Individual<T>& ind = *pop.individuals.at(idxs.at(i)).get(); // we are modifying it, so operator[] wont work

// if there is no validation data,
// set fitness_v to fitness and return ( this assumes that fitness on train was calculated previously.)
Expand Down Expand Up @@ -60,33 +49,22 @@ void Evaluation<T>::validation(Population<T>& pop,
// fitness of population
template<ProgramType T>
void Evaluation<T>::fitness(Population<T>& pop,
tuple<size_t, size_t> island_range,
int island,
const Dataset& data,
const Parameters& params,
bool fit,
bool offspring
)
{
// if offspring false --> if has offspring, do it on first half. else, do on entire island
// offspring true --> assert that has offspring, do it on the second half of the island
auto idxs = pop.get_island_indexes(island);

auto [idx_start, idx_end] = island_range;
size_t delta = idx_end - idx_start;
int start = 0;
if (offspring)
{
assert(pop.offspring_ready
&& ("Population does not have offspring to calculate validation fitness"));

idx_start = idx_start + (delta/2);
}
else if (pop.offspring_ready) // offspring is false. We need to see where we sould stop
{
idx_end = idx_end - (delta/2);
}
start = idxs.size()/2;

for (unsigned i = idx_start; i<idx_end; ++i)
for (unsigned i = start; i<idxs.size(); ++i)
{
Individual<T>& ind = pop.individuals.at(i);
Individual<T>& ind = *pop.individuals.at(idxs.at(i)).get(); // we are modifying it, so operator[] wont work

bool pass = true;

Expand Down
4 changes: 2 additions & 2 deletions src/eval/evaluation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Evaluation {
// TODO: IMPLEMENT THIS
/// validation of population.
void validation(Population<T>& pop,
tuple<size_t, size_t> island_range,
int island,
const Dataset& data,
const Parameters& params,
bool offspring = false
Expand All @@ -40,7 +40,7 @@ class Evaluation {
// TODO: MAKE it work for classification (do I need to have a way to set accuracy as a minimization problem?)
/// fitness of population.
void fitness(Population<T>& pop,
tuple<size_t, size_t> island_range,
int island,
const Dataset& data,
const Parameters& params,
bool fit=true,
Expand Down
31 changes: 16 additions & 15 deletions src/population.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ void Population<T>::init(SearchSpace& ss, const Parameters& params)
// this calls the default constructor for the container template class
individuals.resize(2*p); // we will never increase or decrease the size during execution (because is not thread safe). this way, theres no need to sync between selecting and varying the population

#pragma omp parallel for
for (int i = 0; i< p; ++i)
{
individuals.at(i) = std::make_shared<Individual<T>>();
Expand All @@ -50,7 +49,7 @@ void Population<T>::init(SearchSpace& ss, const Parameters& params)
}

/// update individual vector size and island indexes
template<ProgramType T>
template<ProgramType T> // TODO: rename to include_offspring_indexes or something like this
void Population<T>::prep_offspring_slots(int island)
{
// reading and writing is thread-safe, as long as there's no overlap on island ranges.
Expand All @@ -64,12 +63,12 @@ void Population<T>::prep_offspring_slots(int island)
size_t idx_start = std::floor(island*p/n_islands);
size_t idx_end = std::floor((island+1)*p/n_islands);

auto delta = idx_end - idx_start;
auto delta = idx_end - idx_start; // island size

// inserting indexes of the offspring
island_indexes.at(island).resize(delta*2);
iota(
island_indexes.at(island).begin() + p, island_indexes.at(island).end(),
island_indexes.at(island).begin() + delta, island_indexes.at(island).end(),
p+idx_start);

// Im keeping the offspring and parents in the same population object, because we
Expand All @@ -92,12 +91,12 @@ void Population<T>::update(vector<vector<size_t>> survivors)
// update will set the complexities (for migration step. we do it here because update handles non-thread safe operations)
new_pop.at(i)->set_complexity();

++i;
++i; // this will fill just half of the pop
}

// need to make island point to original range
size_t idx_start = std::floor(j*size/n_islands);
size_t idx_end = std::floor((j+1)*size/n_islands);
size_t idx_start = std::floor(j*pop_size/n_islands);
size_t idx_end = std::floor((j+1)*pop_size/n_islands);

auto delta = idx_end - idx_start;

Expand All @@ -119,12 +118,14 @@ string Population<T>::print_models(bool just_offspring, string sep)
output += "island " + to_string(j) + ":\n";

int start = 0;

if (just_offspring)
start = island_indexes.at(j).size()/2;

for (int k=start; k<island_indexes.at(j).size(); ++k)
output += individuals.at(island_indexes.at(j).at(k))->get_model() + sep;
for (int k=start; k<island_indexes.at(j).size(); ++k) {
fmt::print("ind {}", (island_indexes.at(j).at(k)));
Individual<T>& ind = *individuals.at(island_indexes.at(j).at(k)).get();
output += ind.get_model() + sep;
}
}
return output;
}
Expand All @@ -138,12 +139,12 @@ vector<vector<size_t>> Population<T>::sorted_front(unsigned rank)
vector<vector<size_t>> pf_islands;
pf_islands.resize(n_islands);

for (int i=0; i<n_islands; ++i)
for (int j=0;j<n_islands; ++j)
{
auto idxs = island_indexes.at(i);
auto idxs = island_indexes.at(j);
vector<size_t> pf;

for (unsigned int& i : idxs)
for (unsigned int i : idxs)
{
// this assumes that rank was previously calculated. It is set in selection (ie nsga2) if the information is useful to select/survive
if (individuals.at(i)->rank == rank)
Expand All @@ -153,7 +154,7 @@ vector<vector<size_t>> Population<T>::sorted_front(unsigned rank)
auto it = std::unique(pf.begin(),pf.end(),SameFitComplexity(*this));

pf.resize(std::distance(pf.begin(),it));
pf_islands.at(i) = pf;
pf_islands.at(j) = pf;
}

return pf_islands;
Expand Down Expand Up @@ -226,7 +227,7 @@ void Population<T>::migrate()
island_fronts.at(other_island).end());
}

island_indexes.at(i) = migrating_idx;
island_indexes.at(island).at(i) = migrating_idx;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/population.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class Population{
SortComplexity(Population& p): pop(p){}
bool operator()(size_t i, size_t j)
{
return pop.individuals[i].get_complexity() < pop.individuals[j].get_complexity();
return pop[i].get_complexity() < pop[j].get_complexity();
}
};

Expand All @@ -82,8 +82,8 @@ class Population{
SameFitComplexity(Population<T>& p): pop(p){}
bool operator()(size_t i, size_t j)
{
return (pop.individuals[i].fitness == pop.individuals[j].fitness
&& pop.individuals[i].get_complexity() == pop.individuals[j].get_complexity());
return (pop[i].fitness == pop[j].fitness
&& pop[i].get_complexity() == pop[j].get_complexity());
}
};
};
Expand Down
10 changes: 8 additions & 2 deletions src/selection/nsga2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ template<ProgramType T>
vector<size_t> NSGA2<T>::survive(Population<T>& pop, int island,
const Parameters& params, const Dataset& d)
{

size_t idx_start = std::floor(island*pop.size()/pop.n_islands);
size_t idx_end = std::floor((island+1)*pop.size()/pop.n_islands);

auto original_size = idx_end - idx_start; // island size

auto island_pool = pop.get_island_indexes(island);

// set objectives (this is when the obj vector is updated.)
Expand All @@ -83,7 +89,7 @@ vector<size_t> NSGA2<T>::survive(Population<T>& pop, int island,
// Push back selected individuals until full
vector<size_t> selected(0);
int i = 0;
while ( selected.size() + front.at(i).size() < island_pool.size()/2 ) // (size/2) because we want to get to the original size (prepare_offspring_slots doubled it before survival operation)
while ( selected.size() + front.at(i).size() < original_size ) // (size/2) because we want to get to the original size (prepare_offspring_slots doubled it before survival operation)
{
fmt::print("-- crawd dist\n");
std::vector<int>& Fi = front.at(i); // indices in front i
Expand All @@ -100,7 +106,7 @@ vector<size_t> NSGA2<T>::survive(Population<T>& pop, int island,
std::sort(front.at(i).begin(),front.at(i).end(),sort_n(pop));

fmt::print("adding last front)\n");
const int extra = island_pool.size()/2 - selected.size();
const int extra = original_size - selected.size();
for (int j = 0; j < extra; ++j) // Pt+1 = Pt+1 U Fi[1:N-|Pt+1|]
selected.push_back(front.at(i).at(j));

Expand Down
33 changes: 8 additions & 25 deletions src/variation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,34 +568,17 @@ std::optional<Program<T>> Variation<T>::mutate(const Program<T>& parent)
}

template <Brush::ProgramType T>
void Variation<T>::vary(Population<T>& pop, tuple<size_t, size_t> island_range,
void Variation<T>::vary(Population<T>& pop, int island,
const vector<size_t>& parents)
{
/*!
* performs variation on the current population.
*
* @param pop: current population
* @param parents: indices of population to use for variation
* @param params: feat parameters
*
* @return appends params.pop_size offspring derived from parent variation
*/

assert(pop.offspring_ready
&& ("Population does not have slots for generating the offspring. "
+"You should `prep_offspring_slots`. `vary` will add new xmen individuals "
+"starting from the middle of the island"));

// parents should be within island range. TODO: assert that they are

auto [idx_start, idx_end] = island_range;
size_t delta = idx_end - idx_start;

idx_start = idx_start + (delta/2);
{
auto idxs = pop.get_island_indexes(island);

// assumes it should save new individuals in second half of the island
int start = idxs.size()/2;

// TODO: fix pragma omp usage
//#pragma omp parallel for
for (unsigned i = idx_start; i<idx_end; ++i)
for (unsigned i = start; i<idxs.size(); ++i)
{
// pass check for children undergoing variation
std::optional<Program<T>> opt=std::nullopt; // new individual
Expand Down Expand Up @@ -625,7 +608,7 @@ void Variation<T>::vary(Population<T>& pop, tuple<size_t, size_t> island_range,
Program<T> child = opt.value();

assert(child.size()>0);
pop.individuals.at(i) = Individual<T>(child);
pop.individuals.at(idxs.at(i)) = std::make_shared<Individual<T>>(child);
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/variation.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ class Variation
std::optional<Program<T>> mutate(const Program<T>& parent);

/// method to handle variation of population
void vary(Population<T>& pop, tuple<size_t, size_t> island_range,
const vector<size_t>& parents);
void vary(Population<T>& pop, int island, const vector<size_t>& parents);
};

} //namespace Var
Expand Down
Loading

0 comments on commit 6f2b13c

Please sign in to comment.