| dmitriy@92 | 1 | #include <topology/rips.h> |
| dmitriy@113 | 2 | #include <topology/filtration.h> |
| dmitriy@113 | 3 | #include <topology/static-persistence.h> |
| dmitriy@115 | 4 | #include <topology/dynamic-persistence.h> |
| dmitriy@113 | 5 | #include <topology/persistence-diagram.h> |
| dmitriy@122 | 6 | |
| dmitriy@122 | 7 | #include <geometry/l2distance.h> |
| dmitriy@136 | 8 | #include <geometry/distances.h> |
| dmitriy@116 | 9 | |
| dmitriy@113 | 10 | #include <utilities/containers.h> // for BackInsertFunctor |
| dmitriy@116 | 11 | #include <utilities/timer.h> |
| dmitriy@113 | 12 | |
| dmitriy@116 | 13 | #include <vector> |
| dmitriy@92 | 14 | |
| dmitriy@116 | 15 | #include <boost/program_options.hpp> |
| dmitriy@92 | 16 | |
| dmitriy@92 | 17 | |
| dmitriy@116 | 18 | typedef PairwiseDistances<PointContainer, L2Distance> PairDistances; |
| dmitriy@116 | 19 | typedef PairDistances::DistanceType DistanceType; |
| dmitriy@116 | 20 | typedef PairDistances::IndexType Vertex; |
| dmitriy@92 | 21 | |
| dmitriy@116 | 22 | typedef Rips<PairDistances> Generator; |
| dmitriy@113 | 23 | typedef Generator::Simplex Smplx; |
| dmitriy@179 | 24 | typedef Filtration<Smplx> Fltr; |
| dmitriy@179 | 25 | // typedef StaticPersistence<> Persistence; |
| dmitriy@115 | 26 | typedef DynamicPersistenceChains<> Persistence; |
| dmitriy@115 | 27 | typedef PersistenceDiagram<> PDgm; |
| dmitriy@113 | 28 | |
| dmitriy@174 | 29 | void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, std::string& diagram_name); |
| dmitriy@113 | 30 | |
| dmitriy@92 | 31 | int main(int argc, char* argv[]) |
| dmitriy@92 | 32 | { |
| dmitriy@135 | 33 | Dimension skeleton; |
| dmitriy@116 | 34 | DistanceType max_distance; |
| dmitriy@174 | 35 | std::string infilename, diagram_name; |
| dmitriy@92 | 36 | |
| dmitriy@174 | 37 | program_options(argc, argv, infilename, skeleton, max_distance, diagram_name); |
| dmitriy@174 | 38 | std::ofstream diagram_out(diagram_name.c_str()); |
| dmitriy@174 | 39 | std::cout << "Diagram: " << diagram_name << std::endl; |
| dmitriy@92 | 40 | |
| dmitriy@116 | 41 | PointContainer points; |
| dmitriy@135 | 42 | read_points(infilename, points); |
| dmitriy@92 | 43 | |
| dmitriy@116 | 44 | PairDistances distances(points); |
| dmitriy@113 | 45 | Generator rips(distances); |
| dmitriy@113 | 46 | Generator::Evaluator size(distances); |
| dmitriy@179 | 47 | Fltr f; |
| dmitriy@92 | 48 | |
| dmitriy@113 | 49 | // Generate 2-skeleton of the Rips complex for epsilon = 50 |
| dmitriy@179 | 50 | rips.generate(skeleton, max_distance, make_push_back_functor(f)); |
| dmitriy@179 | 51 | std::cout << "# Generated complex of size: " << f.size() << std::endl; |
| dmitriy@113 | 52 | |
| dmitriy@113 | 53 | // Generate filtration with respect to distance and compute its persistence |
| dmitriy@179 | 54 | f.sort(Generator::Comparison(distances)); |
| dmitriy@116 | 55 | |
| dmitriy@116 | 56 | Timer persistence_timer; persistence_timer.start(); |
| dmitriy@113 | 57 | Persistence p(f); |
| dmitriy@113 | 58 | p.pair_simplices(); |
| dmitriy@116 | 59 | persistence_timer.stop(); |
| dmitriy@113 | 60 | |
| dmitriy@179 | 61 | #if 1 |
| dmitriy@116 | 62 | // Output cycles |
| dmitriy@179 | 63 | Persistence::SimplexMap<Fltr> m = p.make_simplex_map(f); |
| dmitriy@179 | 64 | for (Persistence::iterator cur = p.begin(); cur != p.end(); ++cur) |
| dmitriy@115 | 65 | { |
| dmitriy@179 | 66 | const Persistence::Cycle& cycle = cur->cycle; |
| dmitriy@115 | 67 | |
| dmitriy@116 | 68 | if (!cur->sign()) // only negative simplices have non-empty cycles |
| dmitriy@116 | 69 | { |
| dmitriy@116 | 70 | Persistence::OrderIndex birth = cur->pair; // the cycle that cur killed was born when we added birth (another simplex) |
| dmitriy@113 | 71 | |
| dmitriy@179 | 72 | const Smplx& b = m[birth]; |
| dmitriy@179 | 73 | const Smplx& d = m[cur]; |
| dmitriy@115 | 74 | |
| dmitriy@142 | 75 | // if (b.dimension() != 1) continue; |
| dmitriy@142 | 76 | // std::cout << "Pair: (" << size(b) << ", " << size(d) << ")" << std::endl; |
| dmitriy@142 | 77 | if (b.dimension() >= skeleton) continue; |
| dmitriy@174 | 78 | diagram_out << b.dimension() << " " << size(b) << " " << size(d) << std::endl; |
| dmitriy@179 | 79 | } else if (cur->unpaired()) // positive could be unpaired |
| dmitriy@115 | 80 | { |
| dmitriy@179 | 81 | const Smplx& b = m[cur]; |
| dmitriy@142 | 82 | // if (b.dimension() != 1) continue; |
| dmitriy@115 | 83 | |
| dmitriy@142 | 84 | // std::cout << "Unpaired birth: " << size(b) << std::endl; |
| dmitriy@179 | 85 | // cycle = cur->chain; // TODO |
| dmitriy@142 | 86 | if (b.dimension() >= skeleton) continue; |
| dmitriy@174 | 87 | diagram_out << b.dimension() << " " << size(b) << " inf" << std::endl; |
| dmitriy@116 | 88 | } |
| dmitriy@115 | 89 | |
| dmitriy@115 | 90 | // Iterate over the cycle |
| dmitriy@142 | 91 | // for (Persistence::Cycle::const_iterator si = cycle.begin(); |
| dmitriy@142 | 92 | // si != cycle.end(); ++si) |
| dmitriy@142 | 93 | // { |
| dmitriy@179 | 94 | // const Smplx& s = m[*si]; |
| dmitriy@142 | 95 | // //std::cout << s.dimension() << std::endl; |
| dmitriy@142 | 96 | // const Smplx::VertexContainer& vertices = s.vertices(); // std::vector<Vertex> where Vertex = Distances::IndexType |
| dmitriy@142 | 97 | // AssertMsg(vertices.size() == s.dimension() + 1, "dimension of a simplex is one less than the number of its vertices"); |
| dmitriy@142 | 98 | // std::cout << vertices[0] << " " << vertices[1] << std::endl; |
| dmitriy@142 | 99 | // } |
| dmitriy@115 | 100 | } |
| dmitriy@179 | 101 | #endif |
| dmitriy@116 | 102 | |
| dmitriy@142 | 103 | persistence_timer.check("# Persistence timer"); |
| dmitriy@92 | 104 | } |
| dmitriy@116 | 105 | |
| dmitriy@174 | 106 | void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, std::string& diagram_name) |
| dmitriy@116 | 107 | { |
| dmitriy@116 | 108 | namespace po = boost::program_options; |
| dmitriy@116 | 109 | |
| dmitriy@116 | 110 | po::options_description hidden("Hidden options"); |
| dmitriy@116 | 111 | hidden.add_options() |
| dmitriy@116 | 112 | ("input-file", po::value<std::string>(&infilename), "Point set whose Rips zigzag we want to compute"); |
| dmitriy@116 | 113 | |
| dmitriy@116 | 114 | po::options_description visible("Allowed options", 100); |
| dmitriy@116 | 115 | visible.add_options() |
| dmitriy@116 | 116 | ("help,h", "produce help message") |
| dmitriy@116 | 117 | ("skeleton-dimsnion,s", po::value<Dimension>(&skeleton)->default_value(2), "Dimension of the Rips complex we want to compute") |
| dmitriy@174 | 118 | ("max-distance,m", po::value<DistanceType>(&max_distance)->default_value(Infinity), "Maximum value for the Rips complex construction") |
| dmitriy@174 | 119 | ("diagram,d", po::value<std::string>(&diagram_name), "Filename where to output the persistence diagram"); |
| dmitriy@174 | 120 | #if LOGGING |
| dmitriy@174 | 121 | std::vector<std::string> log_channels; |
| dmitriy@174 | 122 | visible.add_options() |
| dmitriy@174 | 123 | ("log,l", po::value< std::vector<std::string> >(&log_channels), "log channels to turn on (info, debug, etc)"); |
| dmitriy@174 | 124 | #endif |
| dmitriy@116 | 125 | |
| dmitriy@116 | 126 | po::positional_options_description pos; |
| dmitriy@116 | 127 | pos.add("input-file", 1); |
| dmitriy@116 | 128 | |
| dmitriy@116 | 129 | po::options_description all; all.add(visible).add(hidden); |
| dmitriy@116 | 130 | |
| dmitriy@116 | 131 | po::variables_map vm; |
| dmitriy@116 | 132 | po::store(po::command_line_parser(argc, argv). |
| dmitriy@116 | 133 | options(all).positional(pos).run(), vm); |
| dmitriy@116 | 134 | po::notify(vm); |
| dmitriy@116 | 135 | |
| dmitriy@174 | 136 | #if LOGGING |
| dmitriy@174 | 137 | for (std::vector<std::string>::const_iterator cur = log_channels.begin(); cur != log_channels.end(); ++cur) |
| dmitriy@174 | 138 | stderrLog.subscribeTo( RLOG_CHANNEL(cur->c_str()) ); |
| dmitriy@174 | 139 | #endif |
| dmitriy@174 | 140 | |
| dmitriy@116 | 141 | if (vm.count("help") || !vm.count("input-file")) |
| dmitriy@116 | 142 | { |
| dmitriy@116 | 143 | std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl; |
| dmitriy@116 | 144 | std::cout << visible << std::endl; |
| dmitriy@116 | 145 | std::abort(); |
| dmitriy@116 | 146 | } |
| dmitriy@116 | 147 | } |