1 #include <topology/rips.h>
2 #include <topology/filtration.h>
3 #include <topology/static-persistence.h>
4 #include <topology/dynamic-persistence.h>
5 #include <topology/persistence-diagram.h>
7 #include <geometry/l2distance.h>
8 #include <geometry/distances.h>
10 #include <utilities/containers.h> // for BackInsertFunctor
11 #include <utilities/timer.h>
15 #include <boost/program_options.hpp>
18 typedef PairwiseDistances<PointContainer, L2Distance> PairDistances;
19 typedef PairDistances::DistanceType DistanceType;
20 typedef PairDistances::IndexType Vertex;
22 typedef Rips<PairDistances> Generator;
23 typedef Generator::Simplex Smplx;
24 typedef std::vector<Smplx> SimplexVector;
25 typedef Filtration<SimplexVector, unsigned> Fltr;
26 typedef StaticPersistence<> Persistence;
27 // typedef DynamicPersistenceChains<> Persistence;
28 typedef PersistenceDiagram<> PDgm;
30 void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, std::string& diagram_name);
32 int main(int argc, char* argv[])
35 DistanceType max_distance;
36 std::string infilename, diagram_name;
38 program_options(argc, argv, infilename, skeleton, max_distance, diagram_name);
39 std::ofstream diagram_out(diagram_name.c_str());
40 std::cout << "Diagram: " << diagram_name << std::endl;
42 PointContainer points;
43 read_points(infilename, points);
45 PairDistances distances(points);
46 Generator rips(distances);
47 Generator::Evaluator size(distances);
48 SimplexVector complex;
50 // Generate 2-skeleton of the Rips complex for epsilon = 50
51 rips.generate(skeleton, max_distance, make_push_back_functor(complex));
52 std::sort(complex.begin(), complex.end(), Smplx::VertexComparison()); // unnecessary
53 std::cout << "Generated complex of size: " << complex.size() << std::endl;
55 // Generate filtration with respect to distance and compute its persistence
56 Fltr f(complex.begin(), complex.end(), Generator::Comparison(distances));
58 Timer persistence_timer; persistence_timer.start();
61 persistence_timer.stop();
64 for (Persistence::OrderIndex cur = p.begin(); cur != p.end(); ++cur)
66 Persistence::Cycle& cycle = cur->cycle;
68 if (!cur->sign()) // only negative simplices have non-empty cycles
70 Persistence::OrderIndex birth = cur->pair; // the cycle that cur killed was born when we added birth (another simplex)
72 const Smplx& b = f.simplex(f.begin() + (birth - p.begin())); // eventually this will be encapsulated behind an interface
73 const Smplx& d = f.simplex(f.begin() + (cur - p.begin()));
75 // if (b.dimension() != 1) continue;
76 // std::cout << "Pair: (" << size(b) << ", " << size(d) << ")" << std::endl; 77 if (b.dimension() >= skeleton) continue;
78 diagram_out << b.dimension() << " " << size(b) << " " << size(d) << std::endl;
79 } else if (cur->pair == cur) // positive could be unpaired
81 const Smplx& b = f.simplex(f.begin() + (cur - p.begin()));
82 // if (b.dimension() != 1) continue;
84 // std::cout << "Unpaired birth: " << size(b) << std::endl;
85 // cycle = cur->chain;
86 if (b.dimension() >= skeleton) continue;
87 diagram_out << b.dimension() << " " << size(b) << " inf" << std::endl;
90 // Iterate over the cycle
91 // for (Persistence::Cycle::const_iterator si = cycle.begin();
92 // si != cycle.end(); ++si)
94 // const Smplx& s = f.simplex(f.begin() + (*si - p.begin()));
95 // //std::cout << s.dimension() << std::endl;
96 // const Smplx::VertexContainer& vertices = s.vertices(); // std::vector<Vertex> where Vertex = Distances::IndexType
97 // AssertMsg(vertices.size() == s.dimension() + 1, "dimension of a simplex is one less than the number of its vertices");
98 // std::cout << vertices[0] << " " << vertices[1] << std::endl;
102 persistence_timer.check("# Persistence timer"); 105 void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, std::string& diagram_name)
107 namespace po = boost::program_options;
109 po::options_description hidden("Hidden options"); 111 ("input-file", po::value<std::string>(&infilename), "Point set whose Rips zigzag we want to compute"); 113 po::options_description visible("Allowed options", 100); 114 visible.add_options()
115 ("help,h", "produce help message") 116 ("skeleton-dimsnion,s", po::value<Dimension>(&skeleton)->default_value(2), "Dimension of the Rips complex we want to compute") 117 ("max-distance,m", po::value<DistanceType>(&max_distance)->default_value(Infinity), "Maximum value for the Rips complex construction") 118 ("diagram,d", po::value<std::string>(&diagram_name), "Filename where to output the persistence diagram"); 120 std::vector<std::string> log_channels;
121 visible.add_options()
122 ("log,l", po::value< std::vector<std::string> >(&log_channels), "log channels to turn on (info, debug, etc)"); 125 po::positional_options_description pos;
126 pos.add("input-file", 1); 128 po::options_description all; all.add(visible).add(hidden);
130 po::variables_map vm;
131 po::store(po::command_line_parser(argc, argv).
132 options(all).positional(pos).run(), vm);
136 for (std::vector<std::string>::const_iterator cur = log_channels.begin(); cur != log_channels.end(); ++cur)
137 stderrLog.subscribeTo( RLOG_CHANNEL(cur->c_str()) );
140 if (vm.count("help") || !vm.count("input-file")) 142 std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl;
143 std::cout << visible << std::endl;