" << std::endl
#ifdef USE_COEFFICIENTS
<< " --modulus compute homology with coefficients in the prime field Z/
Z"
#endif
<< std::endl;
exit(exit_code);
}
int main(int argc, char** argv) {
const char* ifilename = nullptr;
const char* ofilename = nullptr;
input_file_format iformat = DISTANCE_MATRIX;
output_file_format oformat = TEXT_PD;
index_t dim_max = 1;
value_t threshold = std::numeric_limits::max();
#ifdef USE_COEFFICIENTS
coefficient_t modulus = 2;
#else
const coefficient_t modulus = 2;
#endif
for (index_t i = 1; i < argc; ++i) {
const std::string arg(argv[i]);
if (arg == "--help") {
print_usage_and_exit(0);
} else if (arg == "--dim") {
std::string parameter = std::string(argv[++i]);
size_t next_pos;
dim_max = std::stol(parameter, &next_pos);
if (next_pos != parameter.size()) print_usage_and_exit(-1);
} else if (arg == "--threshold") {
std::string parameter = std::string(argv[++i]);
size_t next_pos;
threshold = std::stof(parameter, &next_pos);
if (next_pos != parameter.size()) print_usage_and_exit(-1);
} else if (arg == "--iformat") {
std::string parameter = std::string(argv[++i]);
if (parameter == "lower-distance")
iformat = LOWER_DISTANCE_MATRIX;
else if (parameter == "upper-distance")
iformat = UPPER_DISTANCE_MATRIX;
else if (parameter == "distance")
iformat = DISTANCE_MATRIX;
else if (parameter == "point-cloud")
iformat = POINT_CLOUD;
else if (parameter == "dipha")
iformat = DIPHA_DISTANCE_MATRIX;
else
print_usage_and_exit(-1);
} else if (arg == "--oformat") {
std::string parameter = std::string(argv[++i]);
if (parameter == "text")
oformat = TEXT_PD;
else if (parameter == "dipha")
oformat = DIPHA_PD;
else
print_usage_and_exit(-1);
#ifdef USE_COEFFICIENTS
} else if (arg == "--modulus") {
std::string parameter = std::string(argv[++i]);
size_t next_pos;
modulus = std::stol(parameter, &next_pos);
if (next_pos != parameter.size() || !is_prime(modulus)) print_usage_and_exit(-1);
#endif
} else if (i == argc - 2) {
ifilename = argv[i];
}
else if (i == argc - 1) {
ofilename = argv[i];
}
else {
print_usage_and_exit(-1);
}
}
if (!ifilename || !ofilename) {
std::cerr << "You need to specify input and output files." << std::endl;
print_usage_and_exit(-1);
}
if (std::string(ifilename) == std::string("-"))
ifilename = nullptr;
if (std::string(ofilename) == std::string("-"))
ofilename = nullptr;
std::ifstream input_file_stream(ifilename);
if (ifilename && input_file_stream.fail()) {
std::cerr << "couldn't open file " << ifilename << std::endl;
exit(-1);
}
if (!ofilename && oformat == DIPHA_PD) {
std::cerr << "Warning: Will not write a DIPHA persistence diagram to stdout. Changing output format to text." << std::endl;
oformat = TEXT_PD;
}
std::ofstream output_file_stream;
if (oformat == TEXT_PD) {
output_file_stream.open(ofilename, std::ios::out);
}
else if (oformat == DIPHA_PD) {
// The in/out opening mode is so that we can seek back to the third third entry in the file and write the pair count at the very end.
output_file_stream.open(ofilename, std::ios::out | std::ios::in | std::ios::trunc | std::ios::binary);
}
if (ofilename && output_file_stream.fail()) {
std::cerr << "couldn't open file " << ofilename << std::endl;
exit(-1);
}
std::ostream & output_stream = ofilename ? output_file_stream : std::cout;
if (oformat == DIPHA_PD) {
write(output_stream, DIPHA_MAGIC);
write(output_stream, DIPHA_TYPE_PERSISTENCE_DIAGRAM);
write(output_stream, DIPHA_MAGIC); // This is to later be replaced by the number of pairs in the persistence diagram. This is the reason we don't allow binary stdout output, since we'd have to buffer up the entire PD to know the count beforehand. In a file we can seek back and overwrite.
}
int64_t pair_count = 0;
compressed_lower_distance_matrix dist = read_file(ifilename ? input_file_stream : std::cin, iformat);
index_t n = dist.size();
std::cout << "distance matrix with " << n << " points" << std::endl;
auto value_range = std::minmax_element(dist.distances.begin(), dist.distances.end());
std::cout << "value range: [" << *value_range.first << "," << *value_range.second << "]" << std::endl;
dim_max = std::min(dim_max, n - 2);
binomial_coeff_table binomial_coeff(n, dim_max + 2);
std::vector multiplicative_inverse(multiplicative_inverse_vector(modulus));
std::vector columns_to_reduce;
{
union_find dset(n);
std::vector edges;
rips_filtration_comparator comp(dist, 1, binomial_coeff);
for (index_t index = binomial_coeff(n, 2); index-- > 0;) {
value_t diameter = comp.diameter(index);
if (diameter <= threshold) edges.push_back(diameter_index_t(diameter, index));
}
std::sort(edges.rbegin(), edges.rend(), greater_diameter_or_smaller_index());
if (oformat == TEXT_PD) {
output_stream << "persistence intervals in dim 0:" << std::endl;
}
std::vector vertices_of_edge(2);
for (auto e : edges) {
vertices_of_edge.clear();
get_simplex_vertices(get_index(e), 1, n, binomial_coeff, std::back_inserter(vertices_of_edge));
index_t u = dset.find(vertices_of_edge[0]), v = dset.find(vertices_of_edge[1]);
if (u != v) {
if (oformat == TEXT_PD) {
output_stream << " [0," << get_diameter(e) << ")" << std::endl;
} else if (oformat == DIPHA_PD) {
write(output_stream, 0);
write(output_stream, 0);
write(output_stream, get_diameter(e));
pair_count++;
}
dset.link(u, v);
} else
columns_to_reduce.push_back(e);
}
std::reverse(columns_to_reduce.begin(), columns_to_reduce.end());
for (index_t i = 0; i < n; ++i)
{
if (dset.find(i) == i) {
if (oformat == TEXT_PD) {
output_stream << " [0, )" << std::endl << std::flush;
} else if (oformat == DIPHA_PD) {
write(output_stream, -0 - 1); // Indicate essential class.
write(output_stream, 0);
write(output_stream, NAN); // Undefined/unused for essential classes.
pair_count++;
}
}
}
}
for (index_t dim = 1; dim <= dim_max; ++dim) {
rips_filtration_comparator comp(dist, dim + 1, binomial_coeff);
rips_filtration_comparator comp_prev(dist, dim, binomial_coeff);
hash_map pivot_column_index;
pivot_column_index.reserve(columns_to_reduce.size());
compute_pairs(columns_to_reduce, pivot_column_index, dist, comp, comp_prev, dim, n, threshold, modulus,
multiplicative_inverse, binomial_coeff, output_stream, oformat, pair_count);
if (dim < dim_max) {
assemble_columns_to_reduce(columns_to_reduce, pivot_column_index, comp, dim, n, threshold, binomial_coeff);
}
}
if (oformat == DIPHA_PD) {
output_file_stream.seekp(2*sizeof(int64_t), std::ios_base::beg); // Rewind to the spot in the DIPHA file where we write the number of intervals.
write(output_file_stream, pair_count);
}
input_file_stream.close();
output_file_stream.close();
}