| dmitriy@116 | 1 | #include <topology/cohomology-persistence.h> |
| dmitriy@116 | 2 | #include <topology/rips.h> |
| dmitriy@122 | 3 | |
| dmitriy@122 | 4 | #include <geometry/l2distance.h> |
| dmitriy@136 | 5 | #include <geometry/distances.h> |
| dmitriy@116 | 6 | |
| dmitriy@116 | 7 | #include <utilities/containers.h> // for BackInsertFunctor |
| cmad@157 | 8 | #include <utilities/property-maps.h> |
| dmitriy@116 | 9 | #include <utilities/timer.h> |
| dmitriy@137 | 10 | #include <utilities/log.h> |
| dmitriy@174 | 11 | #include <utilities/counter.h> |
| dmitriy@174 | 12 | #include <utilities/memory.h> |
| dmitriy@116 | 13 | |
| dmitriy@116 | 14 | #include <string> |
| dmitriy@116 | 15 | |
| dmitriy@116 | 16 | #include <boost/tuple/tuple.hpp> |
| dmitriy@116 | 17 | #include <boost/program_options.hpp> |
| dmitriy@170 | 18 | #include <boost/progress.hpp> |
| dmitriy@116 | 19 | |
| cmad@157 | 20 | #include "wrappers.h" |
| cmad@157 | 21 | |
| dmitriy@116 | 22 | typedef PairwiseDistances<PointContainer, L2Distance> PairDistances; |
| dmitriy@116 | 23 | typedef PairDistances::DistanceType DistanceType; |
| dmitriy@116 | 24 | typedef PairDistances::IndexType Vertex; |
| dmitriy@137 | 25 | |
| cmad@157 | 26 | typedef boost::tuple<Dimension, DistanceType> BirthInfo; |
| cmad@157 | 27 | typedef CohomologyPersistence<BirthInfo, Wrapper<unsigned> > Persistence; |
| cmad@157 | 28 | typedef Persistence::SimplexIndex Index; |
| cmad@157 | 29 | typedef Persistence::Death Death; |
| dmitriy@187 | 30 | typedef Persistence::CocyclePtr CocyclePtr; |
| cmad@157 | 31 | |
| cmad@157 | 32 | typedef Rips<PairDistances, Simplex<Vertex, Index> > Generator; |
| dmitriy@137 | 33 | typedef Generator::Simplex Smplx; |
| dmitriy@137 | 34 | typedef std::vector<Smplx> SimplexVector; |
| dmitriy@137 | 35 | typedef SimplexVector::const_iterator SV_const_iterator; |
| dmitriy@137 | 36 | |
| dmitriy@137 | 37 | typedef std::map<Smplx, Index, Smplx::VertexComparison> Complex; |
| dmitriy@116 | 38 | |
| dmitriy@138 | 39 | #include "output.h" // for output_*() |
| dmitriy@138 | 40 | |
| dmitriy@138 | 41 | void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, ZpField::Element& prime, std::string& boundary_name, std::string& cocycle_prefix, std::string& vertices_name, std::string& diagram_name); |
| dmitriy@116 | 42 | |
| dmitriy@116 | 43 | int main(int argc, char* argv[]) |
| dmitriy@116 | 44 | { |
| dmitriy@137 | 45 | #ifdef LOGGING |
| dmitriy@137 | 46 | rlog::RLogInit(argc, argv); |
| dmitriy@137 | 47 | |
| dmitriy@137 | 48 | stderrLog.subscribeTo( RLOG_CHANNEL("error") ); |
| dmitriy@137 | 49 | #endif |
| dmitriy@137 | 50 | |
| dmitriy@135 | 51 | Dimension skeleton; |
| dmitriy@116 | 52 | DistanceType max_distance; |
| dmitriy@137 | 53 | ZpField::Element prime; |
| dmitriy@138 | 54 | std::string infilename, boundary_name, cocycle_prefix, vertices_name, diagram_name; |
| dmitriy@116 | 55 | |
| dmitriy@138 | 56 | program_options(argc, argv, infilename, skeleton, max_distance, prime, boundary_name, cocycle_prefix, vertices_name, diagram_name); |
| dmitriy@138 | 57 | std::ofstream bdry_out(boundary_name.c_str()); |
| dmitriy@138 | 58 | std::ofstream vertices_out(vertices_name.c_str()); |
| dmitriy@138 | 59 | std::ofstream diagram_out(diagram_name.c_str()); |
| dmitriy@138 | 60 | std::cout << "Boundary matrix: " << boundary_name << std::endl; |
| dmitriy@138 | 61 | std::cout << "Cocycles: " << cocycle_prefix << "*.ccl" << std::endl; |
| dmitriy@138 | 62 | std::cout << "Vertices: " << vertices_name << std::endl; |
| dmitriy@138 | 63 | std::cout << "Diagram: " << diagram_name << std::endl; |
| dmitriy@116 | 64 | |
| dmitriy@137 | 65 | Timer total_timer; total_timer.start(); |
| dmitriy@116 | 66 | PointContainer points; |
| dmitriy@135 | 67 | read_points(infilename, points); |
| dmitriy@116 | 68 | |
| dmitriy@116 | 69 | PairDistances distances(points); |
| dmitriy@116 | 70 | Generator rips(distances); |
| dmitriy@116 | 71 | Generator::Evaluator size(distances); |
| dmitriy@138 | 72 | Generator::Comparison cmp(distances); |
| dmitriy@116 | 73 | SimplexVector v; |
| dmitriy@116 | 74 | |
| dmitriy@137 | 75 | Timer rips_timer; rips_timer.start(); |
| dmitriy@116 | 76 | rips.generate(skeleton, max_distance, make_push_back_functor(v)); |
| cmad@157 | 77 | std::sort(v.begin(), v.end(), Smplx::VertexComparison()); |
| cmad@157 | 78 | |
| cmad@157 | 79 | std::vector<unsigned> index_in_v(v.size()); |
| cmad@157 | 80 | for (unsigned idx = 0; idx < v.size(); ++idx) |
| cmad@157 | 81 | index_in_v[idx] = idx; |
| cmad@157 | 82 | std::sort(index_in_v.begin(), index_in_v.end(), IndirectIndexComparison<SimplexVector, Generator::Comparison>(v, cmp)); |
| cmad@157 | 83 | |
| cmad@157 | 84 | BinarySearchMap<Smplx, SimplexVector::iterator, Smplx::VertexComparison> map_of_v(v.begin(), v.end()); |
| cmad@157 | 85 | |
| dmitriy@137 | 86 | rips_timer.stop(); |
| dmitriy@116 | 87 | std::cout << "Simplex vector generated, size: " << v.size() << std::endl; |
| dmitriy@138 | 88 | |
| cmad@157 | 89 | output_boundary_matrix(bdry_out, v, Smplx::VertexComparison()); |
| dmitriy@138 | 90 | output_vertex_indices(vertices_out, v); |
| dmitriy@116 | 91 | |
| dmitriy@116 | 92 | Timer persistence_timer; persistence_timer.start(); |
| dmitriy@137 | 93 | ZpField zp(prime); |
| dmitriy@137 | 94 | Persistence p(zp); |
| dmitriy@170 | 95 | boost::progress_display show_progress(v.size()); |
| dmitriy@174 | 96 | |
| dmitriy@174 | 97 | #ifdef COUNTERS |
| dmitriy@174 | 98 | Counter::CounterType max_element_count = 0; |
| dmitriy@174 | 99 | unsigned max_memory = 0; |
| dmitriy@174 | 100 | long max_rss = 0; |
| dmitriy@174 | 101 | long max_ixrss = 0; |
| dmitriy@174 | 102 | long max_idrss = 0; |
| dmitriy@174 | 103 | long max_isrss = 0; |
| dmitriy@174 | 104 | |
| dmitriy@174 | 105 | int max_uordblks = 0; |
| dmitriy@174 | 106 | int max_fordblks = 0; |
| dmitriy@174 | 107 | #endif |
| dmitriy@174 | 108 | |
| cmad@157 | 109 | for (unsigned j = 0; j < index_in_v.size(); ++j) |
| dmitriy@116 | 110 | { |
| cmad@157 | 111 | SimplexVector::const_iterator cur = v.begin() + index_in_v[j]; |
| dmitriy@116 | 112 | std::vector<Index> boundary; |
| dmitriy@137 | 113 | for (Smplx::BoundaryIterator bcur = cur->boundary_begin(); bcur != cur->boundary_end(); ++bcur) |
| cmad@157 | 114 | boundary.push_back(map_of_v[*bcur]->data()); |
| dmitriy@116 | 115 | |
| dmitriy@187 | 116 | Index idx; Death d; CocyclePtr ccl; |
| dmitriy@137 | 117 | bool store = cur->dimension() < skeleton; |
| dmitriy@187 | 118 | boost::tie(idx, d, ccl) = p.add(boundary.begin(), boundary.end(), boost::make_tuple(cur->dimension(), size(*cur)), store, index_in_v[j]); |
| dmitriy@137 | 119 | |
| dmitriy@137 | 120 | // c[*cur] = idx; |
| dmitriy@137 | 121 | if (store) |
| cmad@157 | 122 | map_of_v[*cur]->data() = idx; |
| dmitriy@137 | 123 | |
| dmitriy@137 | 124 | if (d && (size(*cur) - d->get<1>()) > 0) |
| dmitriy@137 | 125 | { |
| dmitriy@137 | 126 | AssertMsg(d->get<0>() == cur->dimension() - 1, "Dimensions must match"); |
| dmitriy@138 | 127 | diagram_out << (cur->dimension() - 1) << " " << d->get<1>() << " " << size(*cur) << std::endl; |
| dmitriy@137 | 128 | } |
| dmitriy@170 | 129 | ++show_progress; |
| dmitriy@174 | 130 | |
| dmitriy@174 | 131 | #ifdef COUNTERS |
| dmitriy@174 | 132 | max_element_count = std::max(max_element_count, cCohomologyElementCount->count); |
| dmitriy@174 | 133 | #endif |
| dmitriy@116 | 134 | } |
| dmitriy@138 | 135 | // output infinte persistence pairs |
| dmitriy@137 | 136 | for (Persistence::CocycleIndex cur = p.begin(); cur != p.end(); ++cur) |
| dmitriy@138 | 137 | diagram_out << cur->birth.get<0>() << " " << cur->birth.get<1>() << " inf" << std::endl; |
| dmitriy@116 | 138 | persistence_timer.stop(); |
| dmitriy@137 | 139 | |
| dmitriy@137 | 140 | |
| dmitriy@137 | 141 | // p.show_cocycles(); |
| dmitriy@138 | 142 | // Output alive cocycles of dimension 1 |
| dmitriy@174 | 143 | if (!cocycle_prefix.empty()) |
| dmitriy@137 | 144 | { |
| dmitriy@174 | 145 | unsigned i = 0; |
| dmitriy@174 | 146 | for (Persistence::Cocycles::const_iterator cur = p.begin(); cur != p.end(); ++cur) |
| dmitriy@174 | 147 | { |
| dmitriy@174 | 148 | if (cur->birth.get<0>() != 1) continue; |
| dmitriy@187 | 149 | output_cocycle(cocycle_prefix, i, v, cur->birth, cur->zcolumn, prime); |
| dmitriy@174 | 150 | // std::cout << "Cocycle of dimension: " << cur->birth.get<0>() << " born at " << cur->birth.get<1>() << std::endl; |
| dmitriy@174 | 151 | ++i; |
| dmitriy@174 | 152 | } |
| dmitriy@137 | 153 | } |
| dmitriy@137 | 154 | total_timer.stop(); |
| dmitriy@137 | 155 | rips_timer.check("Rips timer"); |
| dmitriy@116 | 156 | persistence_timer.check("Persistence timer"); |
| dmitriy@137 | 157 | total_timer.check("Total timer"); |
| dmitriy@174 | 158 | |
| dmitriy@174 | 159 | #ifdef COUNTERS |
| dmitriy@174 | 160 | std::cout << "Max element count: " << max_element_count << std::endl; |
| dmitriy@174 | 161 | #endif |
| dmitriy@116 | 162 | } |
| dmitriy@116 | 163 | |
| dmitriy@138 | 164 | void program_options(int argc, char* argv[], std::string& infilename, Dimension& skeleton, DistanceType& max_distance, ZpField::Element& prime, std::string& boundary_name, std::string& cocycle_prefix, std::string& vertices_name, std::string& diagram_name) |
| dmitriy@116 | 165 | { |
| dmitriy@116 | 166 | namespace po = boost::program_options; |
| dmitriy@116 | 167 | |
| dmitriy@116 | 168 | po::options_description hidden("Hidden options"); |
| dmitriy@116 | 169 | hidden.add_options() |
| dmitriy@116 | 170 | ("input-file", po::value<std::string>(&infilename), "Point set whose Rips zigzag we want to compute"); |
| dmitriy@116 | 171 | |
| dmitriy@116 | 172 | po::options_description visible("Allowed options", 100); |
| dmitriy@116 | 173 | visible.add_options() |
| dmitriy@116 | 174 | ("help,h", "produce help message") |
| dmitriy@116 | 175 | ("skeleton-dimsnion,s", po::value<Dimension>(&skeleton)->default_value(2), "Dimension of the Rips complex we want to compute") |
| dmitriy@138 | 176 | ("prime,p", po::value<ZpField::Element>(&prime)->default_value(11), "Prime p for the field F_p") |
| dmitriy@138 | 177 | ("max-distance,m", po::value<DistanceType>(&max_distance)->default_value(Infinity), "Maximum value for the Rips complex construction") |
| dmitriy@138 | 178 | ("boundary,b", po::value<std::string>(&boundary_name), "Filename where to output the boundary matrix") |
| dmitriy@138 | 179 | ("cocycle,c", po::value<std::string>(&cocycle_prefix), "Prefix of the filename where to output the 1-dimensional cocycles") |
| dmitriy@138 | 180 | ("vertices,v", po::value<std::string>(&vertices_name), "Filename where to output the simplex-vertex mapping") |
| dmitriy@138 | 181 | ("diagram,d", po::value<std::string>(&diagram_name), "Filename where to output the persistence diagram"); |
| dmitriy@137 | 182 | #if LOGGING |
| dmitriy@137 | 183 | std::vector<std::string> log_channels; |
| dmitriy@137 | 184 | visible.add_options() |
| dmitriy@137 | 185 | ("log,l", po::value< std::vector<std::string> >(&log_channels), "log channels to turn on (info, debug, etc)"); |
| dmitriy@137 | 186 | #endif |
| dmitriy@116 | 187 | |
| dmitriy@116 | 188 | po::positional_options_description pos; |
| dmitriy@116 | 189 | pos.add("input-file", 1); |
| dmitriy@116 | 190 | |
| dmitriy@116 | 191 | po::options_description all; all.add(visible).add(hidden); |
| dmitriy@116 | 192 | |
| dmitriy@116 | 193 | po::variables_map vm; |
| dmitriy@116 | 194 | po::store(po::command_line_parser(argc, argv). |
| dmitriy@116 | 195 | options(all).positional(pos).run(), vm); |
| dmitriy@116 | 196 | po::notify(vm); |
| dmitriy@116 | 197 | |
| dmitriy@137 | 198 | #if LOGGING |
| dmitriy@137 | 199 | for (std::vector<std::string>::const_iterator cur = log_channels.begin(); cur != log_channels.end(); ++cur) |
| dmitriy@137 | 200 | stderrLog.subscribeTo( RLOG_CHANNEL(cur->c_str()) ); |
| dmitriy@137 | 201 | #endif |
| dmitriy@137 | 202 | |
| dmitriy@116 | 203 | if (vm.count("help") || !vm.count("input-file")) |
| dmitriy@116 | 204 | { |
| dmitriy@116 | 205 | std::cout << "Usage: " << argv[0] << " [options] input-file" << std::endl; |
| dmitriy@116 | 206 | std::cout << visible << std::endl; |
| dmitriy@116 | 207 | std::abort(); |
| dmitriy@116 | 208 | } |
| dmitriy@116 | 209 | } |