Changed implementation of WeightedRips to store simplex values (max distance between simplices' vertices) as an invisible layer on top of each simplex object, so that the data() field of WeightedRips has been freed for use by the users again.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include "avida-population-detail.h"
#include <boost/program_options.hpp>
#include <topology/lowerstarfiltration.h>
// Lower-star filtration
typedef AvidaPopulationDetail::OrganismIndex OrganismIndex;
struct OrganismVertexType;
typedef std::vector<OrganismVertexType> VertexVector;
typedef VertexVector::iterator VertexIndex;
typedef LowerStarFiltration<VertexIndex> LSFiltration;
typedef LSFiltration::Simplex Simplex;
struct OrganismVertexType: public LSFiltration::VertexType<OrganismIndex>
{
typedef LSFiltration::VertexType<OrganismIndex> Parent;
OrganismVertexType(OrganismIndex i): Parent(i) {}
};
struct OrganismVertexComparison
{
public:
bool operator()(VertexIndex i, VertexIndex j) const
{ return i->index()->fitness() > j->index()->fitness(); }
// > because of -fitness, so that maxima turn into minima
};
typedef LSFiltration::Vineyard LSVineyard;
class StaticEvaluator: public LSVineyard::Evaluator
{
public:
StaticEvaluator(float max_fitness):
max_fitness_(max_fitness) {}
virtual RealType
value(const Simplex& s) const
{ return s.get_attachment()->index()->fitness()/max_fitness_; }
private:
float max_fitness_;
};
std::ostream& operator<<(std::ostream& out, VertexIndex i)
{ return (out << (i->index())); }
// Distance filtration
typedef SimplexWithValue<VertexIndex> DistanceSimplex;
typedef std::vector<DistanceSimplex> DistanceSimplexVector;
typedef Filtration<DistanceSimplex> DistanceSimplexFiltration;
namespace po = boost::program_options;
int main(int argc, char** argv)
{
#ifdef LOGGING
rlog::RLogInit(argc, argv);
stderrLog.subscribeTo(RLOG_CHANNEL("error"));
//stdoutLog.subscribeTo(RLOG_CHANNEL("info"));
#endif
typedef AvidaOrganismDetail::DistanceType DistanceType;
DistanceType connected_distance;
bool connect_mst = false;
std::string population_input_fn;
// Parse program options
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value<std::string>(&population_input_fn),
"Avida population file");
po::options_description visible("Allowed options");
visible.add_options()
("help,h", "produce help message")
("distance,d", po::value<DistanceType>(&connected_distance)->default_value(0),
"set connected distance")
("mst,m", "connect minimum spanning tree");
po::positional_options_description p;
p.add("input-file", 1);
po::options_description all; all.add(visible).add(hidden);
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(all).positional(p).run(), vm);
po::notify(vm);
if (vm.count("mst")) { connect_mst = true; }
if (vm.count("help") || !vm.count("input-file"))
{
std::cout << "Usage: " << argv[0] << " [options] POPULATION" << std::endl;
std::cout << visible << std::endl;
return 1;
}
// Read organisms
AvidaPopulationDetail population(population_input_fn);
const AvidaPopulationDetail::OrganismVector& organisms = population.get_organisms();
rInfo("Number of organisms: %d", organisms.size());
float max_fitness = organisms[0].fitness();
for (int i = 0; i < population.get_organisms().size(); ++i)
{
max_fitness = std::max(max_fitness, organisms[i].fitness());
rInfo("%d (%s) %f %d %d", organisms[i].id(),
organisms[i].genome().c_str(),
organisms[i].fitness(),
organisms[i].length(),
organisms[i].genome().size());
}
// Order vertices
StaticEvaluator evaluator(max_fitness);
LSVineyard vineyard(&evaluator);
VertexVector vertices;
for (OrganismIndex cur = organisms.begin(); cur != organisms.end(); ++cur) vertices.push_back(cur);
LSFiltration fitness_filtration(vertices.begin(), vertices.end(), OrganismVertexComparison(), &vineyard);
// Compute MST and insert its edges if asked
if (connect_mst)
{
DistanceSimplexFiltration filtration;
{ // Scope so that simplices is deleted once it's not needed
// Distance function filtration
DistanceSimplexVector simplices;
// Insert edges
for (VertexIndex i = vertices.begin(); i != vertices.end(); ++i)
{
simplices.push_back(DistanceSimplex());
simplices.back().add(i);
for (VertexIndex j = boost::next(i); j != vertices.end(); ++j)
{
simplices.push_back(DistanceSimplex(i->index()->genome_distance(*(j->index()))));
simplices.back().add(i);
simplices.back().add(j);
}
}
std::sort(simplices.begin(), simplices.end(), DimensionValueComparison<DistanceSimplex>());
for (DistanceSimplexVector::const_iterator cur = simplices.begin();
cur != simplices.end(); ++cur)
filtration.append(*cur);
}
filtration.fill_simplex_index_map();
filtration.pair_simplices(false); // pair simplices without storing trails
for (DistanceSimplexFiltration::Index i = filtration.begin(); i != filtration.end(); ++i)
{
if (i->is_paired() && !i->sign())
{
Simplex s(*i);
if (i->get_value() > connected_distance) // <= will be connected below
fitness_filtration.append(s);
}
}
}
// Add simplices
for (VertexIndex cur = vertices.begin(); cur != vertices.end(); ++cur)
for (VertexIndex link = boost::next(cur); link != vertices.end(); ++link)
if (cur->index()->genome_distance(*(link->index())) <= connected_distance)
{
Simplex s(2, cur); s.add(link);
fitness_filtration.append(s);
}
rInfo("Number of simplices: %d", fitness_filtration.size());
// Pair simplices
fitness_filtration.fill_simplex_index_map();
fitness_filtration.pair_simplices(false); // pair simplices without storing trails
//std::cout << "Outputting persistence pairs" << std::endl;
for (LSFiltration::Index i = fitness_filtration.begin(); i != fitness_filtration.end(); ++i)
{
if (i->is_paired())
{
if (i->sign())
{
AssertMsg(i->dimension() == 0, "Expecting only 0-dimensional diagram");
if (i->pair()->get_attachment() == i->vertices()[0]) continue; // skip non-critical pairs
std::cout << i->dimension() << " "
<< evaluator.value(*i) << " "
<< evaluator.value(*(i->pair())) << std::endl;
}
}
else
{
if (i->dimension() != 0) continue;
std::cout << i->dimension() << " "
<< evaluator.value(*i) << " "
<< 0 << std::endl;
// The infinite pair does not make sense since we are interested in
// max of fitness, rather than min of -fitness. However min value for
// fitness is 0, so it's a natural choice of the answer.
}
}
}