/* This file is part of the Gudhi Library. The Gudhi library
* (Geometric Understanding in Higher Dimensions) is a generic C++
* library for computational topology.
*
* Author(s): Siargey Kachanovich
*
* Copyright (C) 2015 INRIA Sophia Antipolis-Méditerranée (France)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef GUDHI_WITNESS_COMPLEX_H_
#define GUDHI_WITNESS_COMPLEX_H_
#include
#include
#include
#include
#include "gudhi/reader_utils.h"
#include "gudhi/distance_functions.h"
#include "gudhi/Simplex_tree.h"
#include
#include
#include
#include
#include
#include
#include
#include
// Needed for nearest neighbours
//#include
//#include
//#include
//#include
// Needed for the adjacency graph in bad link search
#include
#include
#include
namespace Gudhi {
/** \addtogroup simplex_tree
* Witness complex is a simplicial complex defined on two sets of points in \f$\mathbf{R}^D\f$:
* \f$W\f$ set of witnesses and \f$L \subseteq W\f$ set of landmarks. The simplices are based on points in \f$L\f$
* and a simplex belongs to the witness complex if and only if it is witnessed (there exists a point \f$w \in W\f$ such that
* w is closer to the vertices of this simplex than others) and all of its faces are witnessed as well.
*/
template
class Witness_complex: public Simplex_tree<> {
private:
struct Active_witness {
int witness_id;
int landmark_id;
Simplex_handle simplex_handle;
Active_witness(int witness_id_, int landmark_id_, Simplex_handle simplex_handle_)
: witness_id(witness_id_),
landmark_id(landmark_id_),
simplex_handle(simplex_handle_)
{}
};
public:
/** \brief Type for the vertex handle.
*
* Must be a signed integer type. It admits a total order <. */
typedef VertexHandle Vertex_handle;
/* Type of node in the simplex tree. */
typedef Simplex_tree_node_explicit_storage Node;
/* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
typedef typename boost::container::flat_map Dictionary;
typedef typename Dictionary::iterator Simplex_handle;
typedef std::vector< double > Point_t;
typedef std::vector< Point_t > Point_Vector;
typedef std::vector< Vertex_handle > typeVectorVertex;
typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex;
typedef std::pair< Simplex_tree<>::Simplex_handle, bool > typePairSimplexBool;
typedef int Witness_id;
typedef int Landmark_id;
typedef std::list< Vertex_handle > ActiveWitnessList;
private:
/** Number of landmarks
*/
int nbL;
/** Desired density
*/
double density;
public:
/** \brief Set number of landmarks to nbL_
*/
void setNbL(int nbL_)
{
nbL = nbL_;
}
/** \brief Set density to density_
*/
void setDensity(double density_)
{
density = density_;
}
/**
* /brief Iterative construction of the witness complex basing on a matrix of k nearest neighbours of the form {witnesses}x{landmarks}.
* Landmarks are supposed to be in [0,nbL-1]
*/
template< typename KNearestNeighbours >
void witness_complex(KNearestNeighbours & knn)
//void witness_complex(std::vector< std::vector< Vertex_handle > > & knn)
{
std::cout << "**Start the procedure witness_complex" << std::endl;
int k=2; /* current dimension in iterative construction */
//Construction of the active witness list
int nbW = knn.size();
//int nbL = knn.at(0).size();
typeVectorVertex vv;
typeSimplex simplex;
typePairSimplexBool returnValue;
int counter = 0;
/* The list of still useful witnesses
* it will diminuish in the course of iterations
*/
ActiveWitnessList active_w;// = new ActiveWitnessList();
for (int i=0; i != nbL; ++i) {
// initial fill of 0-dimensional simplices
// by doing it we don't assume that landmarks are necessarily witnesses themselves anymore
counter++;
vv = {i};
/* TODO Filtration */
returnValue = insert_simplex(vv, Filtration_value(0.0));
/* TODO Error if not inserted : normally no need here though*/
}
//std::cout << "Successfully added landmarks" << std::endl;
// PRINT2
//print_sc(root()); std::cout << std::endl;
int u,v; // two extremities of an edge
if (nbL > 1) // if the supposed dimension of the complex is >0
{
for (int i=0; i != nbW; ++i)
{
// initial fill of active witnesses list
u = knn[i][0];
v = knn[i][1];
vv = {u,v};
returnValue = this->insert_simplex(vv,Filtration_value(0.0));
//print_sc(root()); std::cout << std::endl;
//std::cout << "Added edges" << std::endl;
}
//print_sc(root());
for (int i=0; i != nbW; ++i)
{
// initial fill of active witnesses list
u = knn[i][0];
v = knn[i][1];
if ( u > v)
{
u = v;
v = knn[i][0];
knn[i][0] = knn[i][1];
knn[i][1] = v;
}
Simplex_handle sh;
vv = {u,v};
//if (u==v) std::cout << "Bazzinga!\n";
sh = (root()->find(u))->second.children()->find(v);
active_w.push_back(i);
}
}
std::cout << "k=1, active witnesses: " << active_w.size() << std::endl;
//std::cout << "Successfully added edges" << std::endl;
count_good = {0,0};
count_bad = {0,0};
int D = knn[0].size();
while (!active_w.empty() && k < D )
{
count_good.push_back(0);
count_bad.push_back(0);
//std::cout << "Started the step k=" << k << std::endl;
typename ActiveWitnessList::iterator it = active_w.begin();
while (it != active_w.end())
{
typeVectorVertex simplex_vector;
/* THE INSERTION: Checking if all the subfaces are in the simplex tree*/
// First sort the first k landmarks
VertexHandle inserted_vertex = knn[*it][k];
bool ok = all_faces_in(knn, *it, k, inserted_vertex);
if (ok)
{
for (int i = 0; i != k+1; ++i)
simplex_vector.push_back(knn[*it][i]);
returnValue = insert_simplex(simplex_vector,0.0);
it++;
}
else
active_w.erase(it++); //First increase the iterator and then erase the previous element
}
std::cout << "k=" << k << ", active witnesses: " << active_w.size() << std::endl;
k++;
}
//print_sc(root()); std::cout << std::endl;
}
/** \brief Construction of witness complex from points given explicitly
* nbL must be set to the right value of landmarks for strategies
* FURTHEST_POINT_STRATEGY and RANDOM_POINT_STRATEGY and
* density must be set to the right value for DENSITY_STRATEGY
*/
// void witness_complex_from_points(Point_Vector point_vector)
// {
// std::vector > WL;
// landmark_choice_by_random_points(point_vector, point_vector.size(), WL);
// witness_complex(WL);
// }
private:
/** \brief Print functions
*/
void print_sc(Siblings * sibl)
{
if (sibl == NULL)
std::cout << "&";
else
print_children(sibl->members_);
}
void print_children(Dictionary map)
{
std::cout << "(";
if (!map.empty())
{
std::cout << map.begin()->first;
if (has_children(map.begin()))
print_sc(map.begin()->second.children());
typename Dictionary::iterator it;
for (it = map.begin()+1; it != map.end(); ++it)
{
std::cout << "," << it->first;
if (has_children(it))
print_sc(it->second.children());
}
}
std::cout << ")";
}
public:
/** \brief Print functions
*/
void st_to_file(std::ofstream& out_file)
{
sc_to_file(out_file, root());
}
private:
void sc_to_file(std::ofstream& out_file, Siblings * sibl)
{
assert(sibl);
children_to_file(out_file, sibl->members_);
}
void children_to_file(std::ofstream& out_file, Dictionary& map)
{
out_file << "(" << std::flush;
if (!map.empty())
{
out_file << map.begin()->first << std::flush;
if (has_children(map.begin()))
sc_to_file(out_file, map.begin()->second.children());
typename Dictionary::iterator it;
for (it = map.begin()+1; it != map.end(); ++it)
{
out_file << "," << it->first << std::flush;
if (has_children(it))
sc_to_file(out_file, it->second.children());
}
}
out_file << ")" << std::flush;
}
/** \brief Check if the facets of the k-dimensional simplex witnessed
* by witness witness_id are already in the complex.
* inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
*/
template
bool all_faces_in(KNearestNeighbours &knn, int witness_id, int k, VertexHandle inserted_vertex)
{
//std::cout << "All face in with the landmark " << inserted_vertex << std::endl;
std::vector< VertexHandle > facet;
//VertexHandle curr_vh = curr_sh->first;
// CHECK ALL THE FACETS
for (int i = 0; i != k+1; ++i)
{
if (knn[witness_id][i] != inserted_vertex)
{
facet = {};
for (int j = 0; j != k+1; ++j)
{
if (j != i)
{
facet.push_back(knn[witness_id][j]);
}
}//endfor
if (find(facet) == null_simplex())
return false;
//std::cout << "++++ finished loop safely\n";
}//endif
} //endfor
return true;
}
template
void print_vector(std::vector v)
{
std::cout << "[";
if (!v.empty())
{
std::cout << *(v.begin());
for (auto it = v.begin()+1; it != v.end(); ++it)
{
std::cout << ",";
std::cout << *it;
}
}
std::cout << "]";
}
template
void print_vvector(std::vector< std::vector > vv)
{
std::cout << "[";
if (!vv.empty())
{
print_vector(*(vv.begin()));
for (auto it = vv.begin()+1; it != vv.end(); ++it)
{
std::cout << ",";
print_vector(*it);
}
}
std::cout << "]\n";
}
public:
/**
* \brief Landmark choice strategy by iteratively adding the landmark the furthest from the
* current landmark set
* \arg W is the vector of points which will be the witnesses
* \arg nbP is the number of witnesses
* \arg nbL is the number of landmarks
* \arg WL is the matrix of the nearest landmarks with respect to witnesses (output)
*/
template
void landmark_choice_by_furthest_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
{
//std::cout << "Enter landmark_choice_by_furthest_points "<< std::endl;
//std::cout << "W="; print_vvector(W);
//double density = 5.;
Point_Vector wit_land_dist(nbP,std::vector()); // distance matrix witness x landmarks
typeVectorVertex chosen_landmarks; // landmark list
WL = KNearestNeighbours(nbP,std::vector());
int current_number_of_landmarks=0; // counter for landmarks
double curr_max_dist = 0; // used for defining the furhest point from L
double curr_dist; // used to stock the distance from the current point to L
double infty = std::numeric_limits::infinity(); // infinity (see next entry)
std::vector< double > dist_to_L(nbP,infty); // vector of current distances to L from points
// double mindist = infty;
int curr_max_w=0; // the point currently furthest from L
int j;
int temp_swap_int;
double temp_swap_double;
//CHOICE OF THE FIRST LANDMARK
std::cout << "Enter the first landmark stage\n";
srand(354698);
int rand_int = rand()% nbP;
curr_max_w = rand_int; //For testing purposes a pseudo-random number is used here
for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
{
//curr_max_w at this point is the next landmark
chosen_landmarks.push_back(curr_max_w);
//std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
//std::cout << "WL="; print_vvector(WL);
//std::cout << "WLD="; print_vvector(wit_land_dist);
//std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
for (auto v: WL)
v.push_back(current_number_of_landmarks);
for (int i = 0; i < nbP; ++i)
{
// iteration on points in W. update of distance vectors
//std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
//std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
curr_dist = euclidean_distance(W[i],W[chosen_landmarks[current_number_of_landmarks]]);
//std::cout << "The problem is not in distance function\n";
wit_land_dist[i].push_back(curr_dist);
WL[i].push_back(current_number_of_landmarks);
//std::cout << "Push't back\n";
if (curr_dist < dist_to_L[i])
dist_to_L[i] = curr_dist;
j = current_number_of_landmarks;
//std::cout << "First half complete\n";
while (j > 0 && wit_land_dist[i][j-1] > wit_land_dist[i][j])
{
// sort the closest landmark vector for every witness
temp_swap_int = WL[i][j];
WL[i][j] = WL[i][j-1];
WL[i][j-1] = temp_swap_int;
temp_swap_double = wit_land_dist[i][j];
wit_land_dist[i][j] = wit_land_dist[i][j-1];
wit_land_dist[i][j-1] = temp_swap_double;
--j;
}
//std::cout << "result WL="; print_vvector(WL);
//std::cout << "result WLD="; print_vvector(wit_land_dist);
//std::cout << "result distL="; print_vector(dist_to_L); std::cout << std::endl;
//std::cout << "End loop\n";
}
//std::cout << "Distance to landmarks="; print_vector(dist_to_L); std::cout << std::endl;
curr_max_dist = 0;
for (int i = 0; i < nbP; ++i) {
if (dist_to_L[i] > curr_max_dist)
{
curr_max_dist = dist_to_L[i];
curr_max_w = i;
}
}
//std::cout << "Chose " << curr_max_w << " as new landmark\n";
}
//std::cout << endl;
}
/** \brief Landmark choice strategy by taking random vertices for landmarks.
*
*/
// template
// void landmark_choice_by_random_points(Point_Vector &W, int nbP, KNearestNeighbours &WL)
// {
// std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
// //std::cout << "W="; print_vvector(W);
// std::unordered_set< int > chosen_landmarks; // landmark set
// Point_Vector wit_land_dist(nbP,std::vector()); // distance matrix witness x landmarks
// WL = KNearestNeighbours(nbP,std::vector());
// int current_number_of_landmarks=0; // counter for landmarks
// srand(24660);
// int chosen_landmark = rand()%nbP;
// double curr_dist;
// //int j;
// //int temp_swap_int;
// //double temp_swap_double;
// for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
// {
// while (chosen_landmarks.find(chosen_landmark) != chosen_landmarks.end())
// {
// srand((int)clock());
// chosen_landmark = rand()% nbP;
// //std::cout << chosen_landmark << "\n";
// }
// chosen_landmarks.insert(chosen_landmark);
// //std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
// //std::cout << "WL="; print_vvector(WL);
// //std::cout << "WLD="; print_vvector(wit_land_dist);
// //std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
// for (auto v: WL)
// v.push_back(current_number_of_landmarks);
// for (int i = 0; i < nbP; ++i)
// {
// // iteration on points in W. update of distance vectors
// //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
// //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
// curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
// //std::cout << "The problem is not in distance function\n";
// wit_land_dist[i].push_back(curr_dist);
// WL[i].push_back(current_number_of_landmarks);
// //std::cout << "Push't back\n";
// //j = current_number_of_landmarks;
// //std::cout << "First half complete\n";
// //std::cout << "result WL="; print_vvector(WL);
// //std::cout << "result WLD="; print_vvector(wit_land_dist);
// //std::cout << "End loop\n";
// }
// }
// for (int i = 0; i < nbP; i++)
// {
// sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
// }
// //std::cout << endl;
// }
/** \brief Landmark choice strategy by taking random vertices for landmarks.
*
*/
// template
void landmark_choice_by_random_points(Point_Vector &W, int nbP, std::set &L)
{
std::cout << "Enter landmark_choice_by_random_points "<< std::endl;
//std::cout << "W="; print_vvector(W);
//std::unordered_set< int > chosen_landmarks; // landmark set
//Point_Vector wit_land_dist(nbP,std::vector()); // distance matrix witness x landmarks
//WL = KNearestNeighbours(nbP,std::vector());
int current_number_of_landmarks=0; // counter for landmarks
srand(24660);
int chosen_landmark = rand()%nbP;
//double curr_dist;
//int j;
//int temp_swap_int;
//double temp_swap_double;
for (current_number_of_landmarks = 0; current_number_of_landmarks != nbL; current_number_of_landmarks++)
{
while (L.find(chosen_landmark) != L.end())
{
srand((int)clock());
chosen_landmark = rand()% nbP;
//std::cout << chosen_landmark << "\n";
}
L.insert(chosen_landmark);
//std::cout << "**********Entered loop with current number of landmarks = " << current_number_of_landmarks << std::endl;
//std::cout << "WL="; print_vvector(WL);
//std::cout << "WLD="; print_vvector(wit_land_dist);
//std::cout << "landmarks="; print_vector(chosen_landmarks); std::cout << std::endl;
// for (auto v: WL)
// v.push_back(current_number_of_landmarks);
// for (int i = 0; i < nbP; ++i)
// {
// // iteration on points in W. update of distance vectors
// //std::cout << "In the loop with i=" << i << " and landmark=" << chosen_landmarks[current_number_of_landmarks] << std::endl;
// //std::cout << "W[i]="; print_vector(W[i]); std::cout << " W[landmark]="; print_vector(W[chosen_landmarks[current_number_of_landmarks]]); std::cout << std::endl;
// curr_dist = euclidean_distance(W[i],W[chosen_landmark]);
// //std::cout << "The problem is not in distance function\n";
// wit_land_dist[i].push_back(curr_dist);
// WL[i].push_back(current_number_of_landmarks);
// //std::cout << "Push't back\n";
// //j = current_number_of_landmarks;
// //std::cout << "First half complete\n";
// //std::cout << "result WL="; print_vvector(WL);
// //std::cout << "result WLD="; print_vvector(wit_land_dist);
// //std::cout << "End loop\n";
// }
}
// for (int i = 0; i < nbP; i++)
// {
// sort(WL[i].begin(), WL[i].end(), [&](int j1, int j2){return wit_land_dist[i][j1] < wit_land_dist[i][j2];});
// }
//std::cout << endl;
}
/** \brief Construct the matrix |W|x(D+1) of D+1 closest landmarks
* where W is the set of witnesses and D is the ambient dimension
*/
template
void nearest_landmarks(Point_Vector &W, std::set &L, KNearestNeighbours &WL)
{
int D = W[0].size();
int nbP = W.size();
WL = KNearestNeighbours(nbP,std::vector());
typedef std::pair dist_i;
typedef bool (*comp)(dist_i,dist_i);
for (int W_i = 0; W_i < nbP; W_i++)
{
//std::cout << "<<<<<<<<<<<<<<" << W_i <<"\n";
std::priority_queue, comp> l_heap([&](dist_i j1, dist_i j2){return j1.first > j2.first;});
std::set::iterator L_it;
int L_i;
for (L_it = L.begin(), L_i=0; L_it != L.end(); L_it++, L_i++)
{
dist_i dist = std::make_pair(euclidean_distance(W[W_i],W[*L_it]), L_i);
l_heap.push(dist);
}
for (int i = 0; i < D+1; i++)
{
dist_i dist = l_heap.top();
WL[W_i].push_back(dist.second);
//WL[W_i].insert(WL[W_i].begin(),dist.second);
//std::cout << dist.first << " " << dist.second << std::endl;
l_heap.pop();
}
}
}
/** \brief Returns true if the link is good
*/
bool has_good_link(Vertex_handle v)
{
std::vector< Vertex_handle > link_vertices;
// Fill link_vertices
for (auto u: complex_vertex_range())
{
typeVectorVertex edge = {u,v};
if (u != v && find(edge) != null_simplex())
link_vertices.push_back(u);
}
/*
print_vector(link_vertices);
std::cout << "\n";
*/
print_vector(link_vertices); std::cout << "\n";
// Find the dimension
typeVectorVertex empty_simplex = {};
int d = link_dim(link_vertices, link_vertices.begin(),-1, empty_simplex);
//std::cout << " dim " << d << "\n";
//Siblings* curr_sibl = root();
//std::cout << "Currently at vertex "
return (link_is_pseudomanifold(link_vertices,d));
}
/** \brief Search and output links around vertices that are not pseudomanifolds
*
*/
void write_bad_links(std::ofstream& out_file)
{
out_file << "Bad links list\n";
std::cout << "Entered write_bad_links\n";
//typeVectorVertex testv = {9,15,17};
//int count = 0;
for (auto v: complex_vertex_range())
{
std::cout << "Vertex " << v << ": ";
std::vector< Vertex_handle > link_vertices;
// Fill link_vertices
for (auto u: complex_vertex_range())
{
typeVectorVertex edge = {u,v};
if (u != v && find(edge) != null_simplex())
link_vertices.push_back(u);
}
print_vector(link_vertices);
std::cout << "\n";
// Find the dimension
typeVectorVertex empty_simplex = {};
int d = link_dim(link_vertices, link_vertices.begin(),-1, empty_simplex);
//std::cout << " dim " << d << "\n";
//Siblings* curr_sibl = root();
if (link_is_pseudomanifold(link_vertices,d))
count_good[d]++;
//out_file << "Bad link at " << v << "\n";
}
//out_file << "Number of bad links: " << count << "/" << root()->size();
//std::cout << "Number of bad links: " << count << "/" << root()->size() << std::endl;
nc = nbL;
for (unsigned int i = 0; i != count_good.size(); i++)
{
out_file << "count_good[" << i << "] = " << count_good[i] << std::endl;
nc -= count_good[i];
if (count_good[i] != 0)
std::cout << "count_good[" << i << "] = " << count_good[i] << std::endl;
}
for (unsigned int i = 0; i != count_bad.size(); i++)
{
out_file << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
nc -= count_bad[i];
if (count_bad[i] != 0)
std::cout << "count_bad[" << i << "] = " << count_bad[i] << std::endl;
}
std::cout << "not_connected = " << nc << std::endl;
}
private:
std::vector count_good;
std::vector count_bad;
int nc;
int link_dim(std::vector< Vertex_handle >& link_vertices,
typename std::vector< Vertex_handle >::iterator curr_v,
int curr_d,
typeVectorVertex& curr_simplex)
{
//std::cout << "Entered link_dim for " << *(curr_v-1) << "\n";
Simplex_handle sh;
int final_d = curr_d;
typename std::vector< Vertex_handle >::iterator it;
//std::cout << "Current vertex is " <<
for (it = curr_v; it != link_vertices.end(); ++it)
{
curr_simplex.push_back(*it);
/*
std::cout << "Searching for ";
print_vector(curr_simplex);
std::cout << " curr_dim " << curr_d << " final_dim " << final_d;
*/
sh = find(curr_simplex);
if (sh != null_simplex())
{
//std::cout << " -> " << *it << "\n";
int d = link_dim(link_vertices, it+1, curr_d+1, curr_simplex);
if (d >= final_d)
{
final_d = d;
std::cout << d << " ";
print_vector(curr_simplex);
std::cout << std::endl;
}
}
/*
else
std::cout << "\n";
*/
curr_simplex.pop_back();
}
return final_d;
}
// color is false is a (d-1)-dim face, true is a d-dim face
//typedef bool Color;
// graph is an adjacency list
typedef typename boost::adjacency_list Adj_graph;
// map that gives to a certain simplex its node in graph and its dimension
//typedef std::pair Reference;
typedef boost::graph_traits::vertex_descriptor Vertex_t;
typedef boost::graph_traits::edge_descriptor Edge_t;
typedef boost::container::flat_map Graph_map;
/* \brief Verifies if the simplices formed by vertices given by link_vertices
* form a pseudomanifold.
* The idea is to make a bipartite graph, where vertices are the d- and (d-1)-dimensional
* faces and edges represent adjacency between them.
*/
bool link_is_pseudomanifold(std::vector< Vertex_handle >& link_vertices,
int dimension)
{
Adj_graph adj_graph;
Graph_map d_map, f_map; // d_map = map for d-dimensional simplices
// f_map = map for its facets
typeVectorVertex empty_vector = {};
add_vertices(link_vertices,
link_vertices.begin(),
adj_graph,
d_map,
f_map,
empty_vector,
0, dimension);
//std::cout << "DMAP_SIZE: " << d_map.size() << "\n";
//std::cout << "FMAP_SIZE: " << f_map.size() << "\n";
add_edges(adj_graph, d_map, f_map);
for (auto f_map_it : f_map)
{
//std::cout << "Degree of " << f_map_it.first->first << " is " << boost::out_degree(f_map_it.second, adj_graph) << "\n";
if (boost::out_degree(f_map_it.second, adj_graph) != 2)
{
if (boost::out_degree(f_map_it.second, adj_graph) == 3)
{
std::cout << "This simplex has 3 cofaces: ";
for(auto v : simplex_vertex_range(f_map_it.first))
std::cout << v << " ";
std::cout << std::endl;
}
count_bad[dimension]++;
return false;
}
}
// At this point I know that all (d-1)-simplices are adjacent to exactly 2 d-simplices
// What is left is to check the connexity
//std::vector components(boost::num_vertices(adj_graph));
return true; //Forget the connexity
//return (boost::connected_components(adj_graph, &components[0]) == 1);
}
void add_vertices(typeVectorVertex& link_vertices,
typename typeVectorVertex::iterator curr_v,
Adj_graph& adj_graph,
Graph_map& d_map,
Graph_map& f_map,
typeVectorVertex& curr_simplex,
int curr_d,
int dimension)
{
Simplex_handle sh;
Vertex_t vert;
typename typeVectorVertex::iterator it;
std::pair resPair;
//typename Graph_map::iterator resPair;
//Add vertices
//std::cout << "Entered add vertices\n";
for (it = curr_v; it != link_vertices.end(); ++it)
{
curr_simplex.push_back(*it);
/*
std::cout << "Searching for ";
print_vector(curr_simplex);
std::cout << " curr_dim " << curr_d << " d " << dimension << "";
*/
sh = find(curr_simplex);
if (sh != null_simplex())
{
//std::cout << " added\n";
if (curr_d == dimension)
{
vert = boost::add_vertex(adj_graph);
resPair = d_map.emplace(sh,vert);
}
else
{
if (curr_d == dimension-1)
{
vert = boost::add_vertex(adj_graph);
resPair = f_map.emplace(sh,vert);
}
add_vertices(link_vertices,
it+1,
adj_graph,
d_map,
f_map,
curr_simplex,
curr_d+1, dimension);
}
}
/*
else
std::cout << "\n";
*/
curr_simplex.pop_back();
}
}
void add_edges(Adj_graph& adj_graph,
Graph_map& d_map,
Graph_map& f_map)
{
Simplex_handle sh;
// Add edges
//std::cout << "Entered add edges:\n";
typename Graph_map::iterator map_it;
for (auto d_map_pair : d_map)
{
//std::cout << "*";
sh = d_map_pair.first;
Vertex_t d_vert = d_map_pair.second;
for (auto facet_sh : boundary_simplex_range(sh))
//for (auto f_map_it : f_map)
{
//std::cout << "'";
map_it = f_map.find(facet_sh);
//We must have all the facets in the graph at this point
assert(map_it != f_map.end());
Vertex_t f_vert = map_it->second;
//std::cout << "Added edge " << sh->first << "-" << map_it->first->first << "\n";
boost::add_edge(d_vert,f_vert,adj_graph);
}
}
}
}; //class Witness_complex
} // namespace Guhdi
#endif