Skip to content

Commit

Permalink
more cleaning. Implemented string representation for fitness
Browse files Browse the repository at this point in the history
  • Loading branch information
gAldeia committed Jun 5, 2024
1 parent f036a2d commit 9375c88
Show file tree
Hide file tree
Showing 16 changed files with 193 additions and 210 deletions.
32 changes: 16 additions & 16 deletions src/bindings/bind_fitness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ void bind_fitness(py::module& m)
.def("__gt__", &br::Fitness::operator>, py::is_operator())
.def("__le__", &br::Fitness::operator<=, py::is_operator())
.def("__ge__", &br::Fitness::operator>=, py::is_operator())
// .def("__str__", &br::Fitness::toString, "String representation of the Fitness object")
// .def("__repr__", &br::Fitness::repr, "Representation for debugging the Fitness object")
.def(py::pickle(
[](const br::Fitness &f) { // __getstate__
/* Return a tuple that fully encodes the state of the object */
// return py::make_tuple(p.value(), p.extra());
nl::json j = f;
return j;
},
[](nl::json j) { // __setstate__
br::Fitness f = j;
return f;
}
)
)
;
.def("__str__", &br::Fitness::toString, "String representation of the Fitness object")
.def("__repr__", &br::Fitness::repr, "Representation for debugging the Fitness object")
.def(py::pickle(
[](const br::Fitness &f) { // __getstate__
/* Return a tuple that fully encodes the state of the object */
// return py::make_tuple(p.value(), p.extra());
nl::json j = f;
return j;
},
[](nl::json j) { // __setstate__
br::Fitness f = j;
return f;
}
)
)
;

}
5 changes: 5 additions & 0 deletions src/bindings/bind_individuals.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ void bind_individual(py::module& m, string name)
.def_property("objectives", &Class::get_objectives, &Class::set_objectives)
.def_property_readonly("program", &Class::get_program)
.def_property_readonly("fitness", &Class::get_fitness)
.def("get_model", &Class::get_model,
py::arg("fmt") = "compact",
py::arg("pretty") = false)
.def("get_dot_model", &Class::get_dot_model,
py::arg("extras") = "")
.def("fit",
static_cast<Class &(Class::*)(const Dataset &d)>(&Class::fit),
"fit from Dataset object")
Expand Down
6 changes: 0 additions & 6 deletions src/bindings/bind_selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,8 @@ namespace py = pybind11;
namespace br = Brush;
namespace nl = nlohmann;

// using Reg = br::Program<ArrayXf>;
// using Cls = br::Program<ArrayXb>;
// using Rep = br::Program<ArrayXXf>;
// using MCls = br::Program<ArrayXi>;

void bind_selections(py::module& m)
{
// TODO: make them a single class
bind_selection<br::ProgramType::Regressor>(m, "RegressorSelector");
bind_selection<br::ProgramType::BinaryClassifier>(m, "ClassifierSelector");

Expand Down
16 changes: 7 additions & 9 deletions src/bindings/bind_selection.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "module.h"

// TODO: figure out why im having symbol errors (if i dont include the cpp here as well)
#include "../selection/selection.h"
#include "../selection/selection.cpp"
Expand All @@ -12,9 +13,6 @@
#include "../pop/population.cpp"
#include "../pop/population.h"

// #include "../individual.h"
//#include "../selection/selection.cpp"

namespace py = pybind11;
namespace nl = nlohmann;
namespace br = Brush;
Expand All @@ -31,7 +29,8 @@ void bind_selection(py::module& m, string name)
.def(py::init(
[](string type, bool survival){ Class s(type, survival); return s; })
)
.def("select", [](Class &self, std::vector<br::Pop::Individual<PT>>& individuals,
.def("select", [](Class &self,
std::vector<br::Pop::Individual<PT>>& individuals,
const Parameters& params) {

// auto sel = Class("nsga2", false);
Expand All @@ -53,10 +52,10 @@ void bind_selection(py::module& m, string name)
}
}

// returns references
return pool;
})
.def("survive", [](Class &self, std::vector<br::Pop::Individual<PT>>& individuals,
.def("survive", [](Class &self,
std::vector<br::Pop::Individual<PT>>& individuals,
const Parameters& params) {

// auto sel = Class("nsga2", false);
Expand All @@ -76,10 +75,10 @@ void bind_selection(py::module& m, string name)
}
}

// returns references
return pool;
})
.def("migrate", [](Class &self, std::vector<br::Pop::Individual<PT>>& individuals,
.def("migrate", [](Class &self,
std::vector<br::Pop::Individual<PT>>& individuals,
const Parameters& params) {

auto pop = br::Pop::Population<PT>();
Expand All @@ -98,7 +97,6 @@ void bind_selection(py::module& m, string name)
pool.push_back(pop[idx]);
}
}
// returns references
return pool;
})
;
Expand Down
7 changes: 1 addition & 6 deletions src/bindings/bind_variation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ namespace py = pybind11;
namespace br = Brush;
namespace nl = nlohmann;

// using Reg = br::Program<ArrayXf>;
// using Cls = br::Program<ArrayXb>;
// using Rep = br::Program<ArrayXXf>;
// using MCls = br::Program<ArrayXi>;

void bind_variations(py::module& m)
{
bind_variation<br::ProgramType::Regressor>(m, "RegressorVariator");
bind_variation<br::ProgramType::Regressor>(m,"RegressorVariator");
bind_variation<br::ProgramType::BinaryClassifier>(m, "ClassifierVariator");
bind_variation<br::ProgramType::MulticlassClassifier>(m, "MultiClassifierVariator");
bind_variation<br::ProgramType::Representer>(m, "RepresenterVariator");
Expand Down
31 changes: 19 additions & 12 deletions src/bindings/bind_variation.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "module.h"
#include "../vary/variation.h"
#include "../vary/variation.cpp" // TODO: figure out why im having symbol errors (if i dont include the cpp here as well)

#include "../pop/population.cpp"
#include "../vary/variation.h"
#include "../vary/variation.cpp"
#include "../pop/population.h"
#include "../pop/population.cpp"

namespace py = pybind11;
namespace nl = nlohmann;
Expand All @@ -22,10 +22,17 @@ void bind_variation(py::module& m, string name)
return variation; }))
.def("mutate", &Class::mutate, py::return_value_policy::automatic)
.def("cross", &Class::cross, py::return_value_policy::automatic)
.def("vary_pop", [](Class &self, std::vector<br::Pop::Individual<PT>>& individuals, const Parameters& params) {

.def("vary_pop", [](Class &self,
std::vector<br::Pop::Individual<PT>>& individuals,
const Parameters& params) {
if (individuals.size() != params.pop_size) {
throw std::runtime_error("Individual vector has different number of individuals than pop_size. When calling variation, they should be the same. popsize is "+to_string(params.pop_size)+", number of individuals is " + to_string(individuals.size()));
string msg = "Individual vector has different number of "
"individuals than pop_size. When calling "
"variation, they should be the same. popsize is "+
to_string(params.pop_size)+", number of "
"individuals is "+to_string(individuals.size());

throw std::runtime_error(msg);
}

auto pop = br::Pop::Population<PT>();
Expand All @@ -37,10 +44,12 @@ void bind_variation(py::module& m, string name)

for (int island = 0; island < params.num_islands; ++island)
{
// I am assuming the individual vector passed as argument will contain the selected parents already
// I am assuming the individual vector passed as argument
// will contain the selected parents already
vector<size_t> parents = pop.get_island_indexes(island);

// including offspring indexes (the vary method will store the offspring in the second half of the index vector)
// including offspring indexes (the vary method will store the
// offspring in the second half of the index vector)
pop.add_offspring_indexes(island);

self.vary(pop, island, parents, params);
Expand All @@ -53,10 +62,8 @@ void bind_variation(py::module& m, string name)
// this is where the offspring is saved
pool.push_back(pop[indices.at(i)]);
}
}

// returns references
}
return pool;
})
;
}
}
2 changes: 2 additions & 0 deletions src/data/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class Dataset
const vector<string>& vn = {}
);

// TODO: let the user specify the datatypes

/// turns input into a feature map, with feature types copied from a reference
map<string,State> copy_and_make_features(const ArrayXXf& X,
const Dataset& ref_dataset,
Expand Down
2 changes: 0 additions & 2 deletions src/eval/metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace Eval {
float mse(const VectorXf& y, const VectorXf& yhat, VectorXf& loss,
const vector<float>& class_weights=vector<float>() );

// TODO: test cases for the metrics

/// log loss (2 methods below)
VectorXf log_loss(const VectorXf& y, const VectorXf& predict_proba,
const vector<float>& class_weights=vector<float>());
Expand Down
74 changes: 73 additions & 1 deletion src/ind/fitness.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,73 @@
#include "fitness.h"
#include "fitness.h"

namespace Brush
{

void to_json(json &j, const Fitness &f)
{
j = json{
{"values", f.values},
{"weights", f.weights},
{"wvalues", f.wvalues},
{"loss", f.loss},
{"loss_v", f.loss_v},
{"complexity", f.complexity},
{"size", f.size},
{"depth", f.depth},
{"dcounter", f.dcounter},
{"dominated", f.dominated},
{"rank", f.rank},
{"crowding_dist", f.crowding_dist}
};
}

void from_json(const json &j, Fitness& f)
{
j.at("values").get_to( f.values );
j.at("weights").get_to( f.weights );
j.at("wvalues").get_to( f.wvalues );
j.at("loss").get_to( f.loss );
j.at("loss_v").get_to( f.loss_v );
j.at("complexity").get_to( f.complexity );
j.at("size").get_to( f.size );
j.at("depth").get_to( f.depth );
j.at("dcounter").get_to( f.dcounter );
j.at("dominated").get_to( f.dominated );
j.at("rank").get_to( f.rank );
j.at("crowding_dist").get_to( f.crowding_dist );
}


int Fitness::dominates(const Fitness& b) const
{
int flag1 = 0, // to check if this has a better objective
flag2 = 0; // to check if b has a better objective

// TODO: replace comparison of individual values by using the overloaded operators (here and in nsga2)
for (int i=0; i<get_wvalues().size(); ++i) {
if (get_wvalues().at(i) > b.get_wvalues().at(i)
|| std::isnan(b.get_wvalues().at(i))
)
flag1 = 1;
if (get_wvalues().at(i) < b.get_wvalues().at(i)
|| std::isnan(get_wvalues().at(i))
)
flag2 = 1;
}

// the proper way of comparing weighted values is considering everything as a maximization problem
// (this is like deap does, and our fitness is inspired by them)
if (flag1==1 && flag2==0)
// there is at least one smaller objective for this and none
// for b
return 1;
else if (flag1==0 && flag2==1)
// there is at least one smaller objective for b and none
// for this
return -1;
else
// no smaller objective or both have one smaller
return 0;
}

} // Brush
33 changes: 16 additions & 17 deletions src/ind/fitness.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,15 @@

#include <functional>
#include "../init.h"

#include "../util/utils.h"

using namespace nlohmann;


template <> // this is intended to be used with DEAP (so our brush individuals can be hashed and compared to each other in python side)
struct std::hash<std::vector<float>> {
std::size_t operator()(const std::vector<float>& v) const {
std::size_t seed = v.size();
for (const auto& elem : v) {
seed ^= std::hash<float>{}(elem) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};

namespace Brush{

struct Fitness {
// the loss is used in evolutionary functions

float loss; ///< aggregate loss score
float loss_v; ///< aggregate validation loss score

Expand Down Expand Up @@ -163,18 +153,27 @@ struct Fitness {
// String representation
std::string toString() const {
if (valid()) {
return "TODO: implement string representation"; //std::to_string(wvalues);
string s = "Fitness(";
for (auto& v : values)
s += to_string(v) + " ";
return s+")";
} else {
return "Tuple()";
return "Fitness()";
}
}

// Representation for debugging
std::string repr() const {
return "TODO: implement string representation";
if (valid()) {
string s = "Fitness(";
for (auto& v : values)
s += to_string(v) + " ";
return s+")";
} else {
return "Fitness()";
}
}


/// set obj vector given a string of objective names
int dominates(const Fitness& b) const;
};
Expand Down
Loading

0 comments on commit 9375c88

Please sign in to comment.