diff options
author | skachano <skachano@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2016-06-09 12:52:35 +0000 |
---|---|---|
committer | skachano <skachano@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2016-06-09 12:52:35 +0000 |
commit | 68752bc0ce16dbff783b5f84a2d02a10b7d05a4e (patch) | |
tree | 6021d91146819a5c1da9861f4b017ae4ef771136 /src/Witness_complex/include | |
parent | 8837fea64910e8f2e45bebe25c3733a8250ebca8 (diff) |
Added everything missing
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/relaxed-witness@1265 636b058d-ea47-450e-bf9e-a15bfbe3eedb
Former-commit-id: c148ce9136bb0786acc1c9ae49827cb3958326c6
Diffstat (limited to 'src/Witness_complex/include')
-rw-r--r-- | src/Witness_complex/include/gudhi/A0_complex.h | 337 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Dim_list_iterator.h | 155 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Dim_lists.h | 195 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Good_links.h | 72 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Relaxed_witness_complex.h | 131 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Strange_witness_complex.h | 232 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h | 337 | ||||
-rw-r--r-- | src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h | 379 |
8 files changed, 1827 insertions, 11 deletions
diff --git a/src/Witness_complex/include/gudhi/A0_complex.h b/src/Witness_complex/include/gudhi/A0_complex.h new file mode 100644 index 00000000..2018e1c8 --- /dev/null +++ b/src/Witness_complex/include/gudhi/A0_complex.h @@ -0,0 +1,337 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef A0_COMPLEX_H_ +#define A0_COMPLEX_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include "gudhi/Simplex_tree.h" +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +// Needed for nearest neighbours +#include <CGAL/Cartesian_d.h> +#include <CGAL/Search_traits.h> +#include <CGAL/Search_traits_adapter.h> +#include <CGAL/property_map.h> +#include <CGAL/Epick_d.h> +#include <CGAL/Orthogonal_k_neighbor_search.h> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplicial_complex > +class A0_complex { + +private: + struct Active_witness { + int witness_id; + int landmark_id; + + Active_witness(int witness_id_, int landmark_id_) + : witness_id(witness_id_), + landmark_id(landmark_id_) { } + }; + +private: + typedef typename Simplicial_complex::Simplex_handle Simplex_handle; + typedef typename Simplicial_complex::Vertex_handle Vertex_handle; + typedef typename Simplicial_complex::Filtration_value FT; + + typedef std::vector< double > Point_t; + typedef std::vector< Point_t > Point_Vector; + + // typedef typename Simplicial_complex::Filtration_value Filtration_value; + typedef std::vector< Vertex_handle > typeVectorVertex; + typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex; + typedef std::pair< Simplex_handle, bool > typePairSimplexBool; + + typedef int Witness_id; + typedef int Landmark_id; + typedef std::list< Vertex_handle > ActiveWitnessList; + + private: + int nbL; // Number of landmarks + Simplicial_complex& sc; // Simplicial complex + + public: + /** @name Constructor + */ + + //@{ + + /** + * \brief Iterative construction of the relaxed witness complex. + * \details The witness complex is written in sc_ basing on a matrix knn + * of k nearest neighbours of the form {witnesses}x{landmarks} and + * and a matrix distances of distances to these landmarks from witnesses. + * The parameter alpha defines relaxation and + * limD defines the + * + * The line lengths in one given matrix can differ, + * however both matrices have the same corresponding line lengths. + * + * The type KNearestNeighbors can be seen as + * Witness_range<Closest_landmark_range<Vertex_handle>>, where + * Witness_range and Closest_landmark_range are random access ranges. + * + * Constructor takes into account at most (dim+1) + * first landmarks from each landmark range to construct simplices. + * + * Landmarks are supposed to be in [0,nbL_-1] + */ + + template< typename KNearestNeighbours > + A0_complex(std::vector< std::vector<double> > const & distances, + KNearestNeighbours const & knn, + Simplicial_complex & sc_, + int nbL_, + double alpha2, + unsigned limD) : nbL(nbL_), sc(sc_) { + int nbW = knn.size(); + typeVectorVertex vv; + //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}; + sc.insert_simplex(vv, Filtration_value(0.0)); + /* TODO Error if not inserted : normally no need here though*/ + } + for (int i=0; i != nbW; ++i) { + // int i_end = limD+1; + // if (knn[i].size() < limD+1) + // i_end = knn[i].size(); + // double dist_wL = *(distances[i].begin()); + // while (distances[i][i_end] > dist_wL + alpha2) + // i_end--; + // add_all_witnessed_faces(distances[i].begin(), + // knn[i].begin(), + // knn[i].begin() + i_end + 1); + unsigned j_end = 0; + while (j_end < distances[i].size() && j_end <= limD && distances[i][j_end] <= distances[i][0] + alpha2) { + std::vector<int> simplex; + for (unsigned j = 0; j <= j_end; ++j) + simplex.push_back(knn[i][j]); + assert(distances[i][j_end] - distances[i][0] >= 0); + sc.insert_simplex_and_subfaces(simplex, distances[i][j_end] - distances[i][0]); + j_end++; + } + } + sc.set_dimension(limD); + } + + //@} + +private: + /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness + * Iterator is needed to know until how far we can take landmarks to form simplexes + * simplex is the prefix of the simplexes to insert + * The output value indicates if the witness rests active or not + */ + void add_all_witnessed_faces(std::vector<double>::const_iterator curr_d, + std::vector<int>::const_iterator curr_l, + std::vector<int>::const_iterator end) + { + std::vector<int> simplex; + std::vector<int>::const_iterator l_end = curr_l; + for (; l_end != end; ++l_end) { + std::vector<int>::const_iterator l_it = curr_l; + std::vector<double>::const_iterator d_it = curr_d; + simplex = {}; + for (; l_it != l_end; ++l_it, ++d_it) + simplex.push_back(*l_it); + sc.insert_simplex_and_subfaces(simplex, *(d_it--) - *curr_d); + } + } + + /** \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 + */ + bool all_faces_in(std::vector<int>& simplex, double* filtration_value) + { + std::vector< int > facet; + for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it) + { + facet.clear(); + for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it) + if (it != not_it) + facet.push_back(*it); + Simplex_handle facet_sh = sc.find(facet); + if (facet_sh == sc.null_simplex()) + return false; + else if (sc.filtration(facet_sh) > *filtration_value) + *filtration_value = sc.filtration(facet_sh); + } + return true; + } + + bool is_face(Simplex_handle face, Simplex_handle coface) + { + // vertex range is sorted in decreasing order + auto fvr = sc.simplex_vertex_range(face); + auto cfvr = sc.simplex_vertex_range(coface); + auto fv_it = fvr.begin(); + auto cfv_it = cfvr.begin(); + while (fv_it != fvr.end() && cfv_it != cfvr.end()) { + if (*fv_it < *cfv_it) + ++cfv_it; + else if (*fv_it == *cfv_it) { + ++cfv_it; + ++fv_it; + } + else + return false; + + } + return (fv_it == fvr.end()); + } + + // void erase_simplex(Simplex_handle sh) + // { + // auto siblings = sc.self_siblings(sh); + // auto oncles = siblings->oncles(); + // int prev_vertex = siblings->parent(); + // siblings->members().erase(sh->first); + // if (siblings->members().empty()) { + // typename typedef Simplicial_complex::Siblings Siblings; + // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex)); + // assert(!sc.has_children(oncles->members().find(prev_vertex))); + // //delete siblings; + // } + + // } + + void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh) + { + erase_simplex(coface_sh); + erase_simplex(face_sh); + } + +public: + // void collapse(std::vector<Simplex_handle>& simplices) + // { + // // Get a vector of simplex handles ordered by filtration value + // std::cout << sc << std::endl; + // //std::vector<Simplex_handle> simplices; + // for (Simplex_handle sh: sc.filtration_simplex_range()) + // simplices.push_back(sh); + // // std::sort(simplices.begin(), + // // simplices.end(), + // // [&](Simplex_handle sh1, Simplex_handle sh2) + // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2); + // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); }); + // // Double iteration + // auto face_it = simplices.rbegin(); + // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) { + // int coface_count = 0; + // auto reduced_coface = simplices.rbegin(); + // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it) + // if (face_it != coface_it && is_face(*face_it, *coface_it)) { + // coface_count++; + // if (coface_count == 1) + // reduced_coface = coface_it; + // else + // break; + // } + // if (coface_count == 1) { + // std::cout << "Erase ( "; + // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base()))) + // std::cout << v << " "; + + // simplices.erase(--(reduced_coface.base())); + // //elementary_collapse(*face_it, *reduced_coface); + // std::cout << ") and then ( "; + // for (auto v: sc.simplex_vertex_range(*(--face_it.base()))) + // std::cout << v << " "; + // std::cout << ")\n"; + // simplices.erase(--((face_it++).base())); + // //face_it = simplices.rbegin(); + // //std::cout << "Size of vector: " << simplices.size() << "\n"; + // } + // else + // face_it++; + // } + // sc.initialize_filtration(); + // //std::cout << sc << std::endl; + // } + + template <class Dim_lists> + void collapse(Dim_lists& dim_lists) + { + dim_lists.collapse(); + } + +private: + + /** Collapse recursively boundary faces of the given simplex + * if its filtration is bigger than alpha_lim. + */ + void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim) + { + for (Simplex_handle face_it : sc.boundary_simplex_range()) { + + } + + } + +}; //class Relaxed_witness_complex + +} // namespace witness_complex + +} // namespace Gudhi + +#endif diff --git a/src/Witness_complex/include/gudhi/Dim_list_iterator.h b/src/Witness_complex/include/gudhi/Dim_list_iterator.h new file mode 100644 index 00000000..3f23e8c9 --- /dev/null +++ b/src/Witness_complex/include/gudhi/Dim_list_iterator.h @@ -0,0 +1,155 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef DIM_LISTS_ITERATOR_H_ +#define DIM_LISTS_ITERATOR_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include "gudhi/Simplex_tree.h" +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplex_handle > +class Dim_lists_iterator { + +private: + + typedef typename std::list<Simplex_handle>::iterator List_iterator; + typedef typename std::vector<std::list<Simplex_handle>>::reverse_iterator Vector_iterator; + typedef typename Gudhi::witness_complex::Dim_lists_iterator<Simplex_handle> Iterator; + + + List_iterator sh_; + Vector_iterator curr_list_; + typename std::vector<std::list<Simplex_handle>>& table_; + +public: + + Dim_lists_iterator(List_iterator sh, + Vector_iterator curr_list, + typename std::vector<std::list<Simplex_handle>>& table) + : sh_(sh), curr_list_(curr_list), table_(table) + { + } + + Simplex_handle operator*() + { + return *sh_; + } + + Iterator operator++() + { + increment(); + return (*this); + } + + Iterator operator++(int) + { + Iterator prev_it(sh_, curr_list_, table_); + increment(); + return prev_it; + } + + Iterator dim_begin() + { + return Iterator(curr_list_->begin(), curr_list_, table_); + } + + Iterator dim_end() + { + return Iterator(curr_list_->end(), curr_list_, table_); + } + + Iterator dimp1_begin() + { + return Iterator((curr_list_-1)->begin(), curr_list_-1, table_); + } + + Iterator dimp1_end() + { + return Iterator((curr_list_-1)->end(), curr_list_-1, table_); + } + + bool operator==(const Iterator& it2) const + { + return (sh_ == it2.sh_); + } + + bool operator!=(const Iterator& it2) const + { + return (sh_ != it2.sh_); + } + + void remove_incr() + { + + } + +private: + + void increment() + { + if (++sh_ == curr_list_->end()) + if (++curr_list_ != table_.rend()) + sh_ = curr_list_->begin(); + // The iterator of the end of the table is the end of the last list + } + + +}; //class Dim_lists_iterator + +} // namespace witness_complex + +} // namespace Gudhi + +#endif diff --git a/src/Witness_complex/include/gudhi/Dim_lists.h b/src/Witness_complex/include/gudhi/Dim_lists.h new file mode 100644 index 00000000..1d1b03c3 --- /dev/null +++ b/src/Witness_complex/include/gudhi/Dim_lists.h @@ -0,0 +1,195 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef DIM_LISTS_H_ +#define DIM_LISTS_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include <gudhi/Dim_list_iterator.h> +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplicial_complex > +class Dim_lists { + +private: + + typedef typename Simplicial_complex::Simplex_handle Simplex_handle; + typedef typename Gudhi::witness_complex::Dim_lists_iterator<Simplex_handle> Iterator; + + std::vector<std::list<Simplex_handle>> table_; + Simplicial_complex& sc_; + +public: + + Dim_lists(Simplicial_complex & sc, int dim, double alpha_max = 100) + : sc_(sc) + { + table_ = std::vector<std::list<Simplex_handle>>(dim+1); + for (auto sh: sc.filtration_simplex_range()) { + if (sc_.filtration(sh) < alpha_max) + table_[sc.dimension(sh)].push_front(sh); + } + auto t_it = table_.rbegin(); + while (t_it->empty()) { + t_it++; + table_.pop_back(); + } + } + + Iterator begin() + { + return Iterator(table_.rbegin()->begin(), table_.rbegin(), table_); + } + + Iterator end() + { + return Iterator(table_[0].end(), table_.rend(), table_); + } + + unsigned size() + { + unsigned curr_size = 0; + for (auto l: table_) + curr_size += l.size(); + return curr_size; + } + + bool is_face(Simplex_handle face, Simplex_handle coface) + { + // vertex range is sorted in decreasing order + auto fvr = sc_.simplex_vertex_range(face); + auto cfvr = sc_.simplex_vertex_range(coface); + auto fv_it = fvr.begin(); + auto cfv_it = cfvr.begin(); + while (fv_it != fvr.end() && cfv_it != cfvr.end()) { + if (*fv_it < *cfv_it) + ++cfv_it; + else if (*fv_it == *cfv_it) { + ++cfv_it; + ++fv_it; + } + else + return false; + + } + return (fv_it == fvr.end()); + } + + void output_simplices() { + std::cout << "Size of vector: " << size() << std::endl; + for (auto line_it = table_.rbegin(); line_it != table_.rend(); ++line_it) + for (auto sh: *line_it) { + std::cout << sc_.dimension(sh) << " "; + for (auto v : sc_.simplex_vertex_range(sh)) + std::cout << v << " "; + std::cout << sc_.filtration(sh) << "\n"; + } + } + + void collapse() + { + auto coface_list_it = table_.rbegin(); + auto face_list_it = table_.rbegin()+1; + for ( ; + face_list_it != table_.rend(); + ++face_list_it) { + auto face_it = face_list_it->begin(); + while (face_it != face_list_it->end() && sc_.filtration(*face_it) != 0) { + int coface_count = 0; + auto reduced_coface = coface_list_it->begin(); + for (auto coface_it = coface_list_it->begin(); coface_it != coface_list_it->end() && sc_.filtration(*coface_it) != 0; ++coface_it) + if (is_face(*face_it, *coface_it)) { + coface_count++; + if (coface_count == 1) + reduced_coface = coface_it; + else + break; + } + if (coface_count == 1) { + /* + std::cout << "Erase ( "; + for (auto v: sc_.simplex_vertex_range(*reduced_coface)) + std::cout << v << " "; + */ + coface_list_it->erase(reduced_coface); + /* + std::cout << ") and then ( "; + for (auto v: sc_.simplex_vertex_range(*face_it)) + std::cout << v << " "; + std::cout << ")\n"; + */ + face_list_it->erase(face_it); + face_it = face_list_it->begin(); + } + else + face_it++; + } + if ((coface_list_it++)->empty()) + table_.pop_back(); + } + } + + bool is_pseudomanifold() + { + + return true; + } + +}; //class Dim_lists + +} // namespace witness_complex + +} // namespace Gudhi + +#endif diff --git a/src/Witness_complex/include/gudhi/Good_links.h b/src/Witness_complex/include/gudhi/Good_links.h new file mode 100644 index 00000000..a011c032 --- /dev/null +++ b/src/Witness_complex/include/gudhi/Good_links.h @@ -0,0 +1,72 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GOOD_LINKS_H_ +#define GOOD_LINKS_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include <gudhi/Dim_list_iterator.h> +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplicial_complex > +bool good_links(Simplicial_complex& sc_) +{ + +} + +} // namespace witness_complex + +} // namespace Gudhi + +#endif diff --git a/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h index 04dc37d4..2971149a 100644 --- a/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h +++ b/src/Witness_complex/include/gudhi/Relaxed_witness_complex.h @@ -83,6 +83,7 @@ private: private: typedef typename Simplicial_complex::Simplex_handle Simplex_handle; typedef typename Simplicial_complex::Vertex_handle Vertex_handle; + typedef typename Simplicial_complex::Filtration_value FT; typedef std::vector< double > Point_t; typedef std::vector< Point_t > Point_Vector; @@ -197,7 +198,7 @@ private: std::vector<int>::const_iterator l_it = curr_l; std::vector<double>::const_iterator d_it = curr_d; if (dim > 0) - for (; *d_it - alpha < norelax_dist && l_it != end; ++l_it, ++d_it) { + for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) { simplex.push_back(*l_it); if (sc.find(simplex) != sc.null_simplex()) will_be_active = add_all_faces_of_dimension(dim-1, @@ -209,7 +210,7 @@ private: end) || will_be_active; simplex.pop_back(); // If norelax_dist is infinity, change to first omitted distance - if (*d_it < norelax_dist) + if (*d_it <= norelax_dist) norelax_dist = *d_it; will_be_active = add_all_faces_of_dimension(dim-1, alpha, @@ -220,17 +221,16 @@ private: end) || will_be_active; } else if (dim == 0) - for (; *d_it - alpha < norelax_dist && l_it != end; ++l_it, ++d_it) { + for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) { simplex.push_back(*l_it); double filtration_value = 0; // if norelax_dist is infinite, relaxation is 0. if (*d_it > norelax_dist) filtration_value = *d_it - norelax_dist; - if (all_faces_in(simplex, &filtration_value)) - { - will_be_active = true; - sc.insert_simplex(simplex, filtration_value); - } + if (all_faces_in(simplex, &filtration_value)) { + will_be_active = true; + sc.insert_simplex(simplex, filtration_value); + } simplex.pop_back(); // If norelax_dist is infinity, change to first omitted distance if (*d_it < norelax_dist) @@ -260,11 +260,120 @@ private: } return true; } - -}; //class Witness_complex + + bool is_face(Simplex_handle face, Simplex_handle coface) + { + // vertex range is sorted in decreasing order + auto fvr = sc.simplex_vertex_range(face); + auto cfvr = sc.simplex_vertex_range(coface); + auto fv_it = fvr.begin(); + auto cfv_it = cfvr.begin(); + while (fv_it != fvr.end() && cfv_it != cfvr.end()) { + if (*fv_it < *cfv_it) + ++cfv_it; + else if (*fv_it == *cfv_it) { + ++cfv_it; + ++fv_it; + } + else + return false; + + } + return (fv_it == fvr.end()); + } + + // void erase_simplex(Simplex_handle sh) + // { + // auto siblings = sc.self_siblings(sh); + // auto oncles = siblings->oncles(); + // int prev_vertex = siblings->parent(); + // siblings->members().erase(sh->first); + // if (siblings->members().empty()) { + // typename typedef Simplicial_complex::Siblings Siblings; + // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex)); + // assert(!sc.has_children(oncles->members().find(prev_vertex))); + // //delete siblings; + // } + + // } + + void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh) + { + erase_simplex(coface_sh); + erase_simplex(face_sh); + } + +public: + // void collapse(std::vector<Simplex_handle>& simplices) + // { + // // Get a vector of simplex handles ordered by filtration value + // std::cout << sc << std::endl; + // //std::vector<Simplex_handle> simplices; + // for (Simplex_handle sh: sc.filtration_simplex_range()) + // simplices.push_back(sh); + // // std::sort(simplices.begin(), + // // simplices.end(), + // // [&](Simplex_handle sh1, Simplex_handle sh2) + // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2); + // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); }); + // // Double iteration + // auto face_it = simplices.rbegin(); + // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) { + // int coface_count = 0; + // auto reduced_coface = simplices.rbegin(); + // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it) + // if (face_it != coface_it && is_face(*face_it, *coface_it)) { + // coface_count++; + // if (coface_count == 1) + // reduced_coface = coface_it; + // else + // break; + // } + // if (coface_count == 1) { + // std::cout << "Erase ( "; + // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base()))) + // std::cout << v << " "; + + // simplices.erase(--(reduced_coface.base())); + // //elementary_collapse(*face_it, *reduced_coface); + // std::cout << ") and then ( "; + // for (auto v: sc.simplex_vertex_range(*(--face_it.base()))) + // std::cout << v << " "; + // std::cout << ")\n"; + // simplices.erase(--((face_it++).base())); + // //face_it = simplices.rbegin(); + // //std::cout << "Size of vector: " << simplices.size() << "\n"; + // } + // else + // face_it++; + // } + // sc.initialize_filtration(); + // //std::cout << sc << std::endl; + // } + + template <class Dim_lists> + void collapse(Dim_lists& dim_lists) + { + dim_lists.collapse(); + } + +private: + + /** Collapse recursively boundary faces of the given simplex + * if its filtration is bigger than alpha_lim. + */ + void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim) + { + for (Simplex_handle face_it : sc.boundary_simplex_range()) { + + } + + } + +}; //class Relaxed_witness_complex } // namespace witness_complex -} // namespace Guhdi +} // namespace Gudhi #endif diff --git a/src/Witness_complex/include/gudhi/Strange_witness_complex.h b/src/Witness_complex/include/gudhi/Strange_witness_complex.h new file mode 100644 index 00000000..c1c2912b --- /dev/null +++ b/src/Witness_complex/include/gudhi/Strange_witness_complex.h @@ -0,0 +1,232 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef WITNESS_COMPLEX_H_ +#define WITNESS_COMPLEX_H_ + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> + +#include <gudhi/distance_functions.h> + +#include <algorithm> +#include <utility> +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <ctime> +#include <iostream> + +namespace Gudhi { + +namespace witness_complex { + +/** + \class Witness_complex + \brief Constructs the witness complex for the given set of witnesses and landmarks. + \ingroup witness_complex + */ +template< class Simplicial_complex> +class Strange_witness_complex { + private: + struct Active_witness { + int witness_id; + int landmark_id; + + Active_witness(int witness_id_, int landmark_id_) + : witness_id(witness_id_), + landmark_id(landmark_id_) { } + }; + + private: + typedef typename Simplicial_complex::Simplex_handle Simplex_handle; + typedef typename Simplicial_complex::Vertex_handle Vertex_handle; + + typedef std::vector< double > Point_t; + typedef std::vector< Point_t > Point_Vector; + + // typedef typename Simplicial_complex::Filtration_value Filtration_value; + typedef std::vector< Vertex_handle > typeVectorVertex; + typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex; + typedef std::pair< Simplex_handle, bool > typePairSimplexBool; + + typedef int Witness_id; + typedef int Landmark_id; + typedef std::list< Vertex_handle > ActiveWitnessList; + + private: + int nbL; // Number of landmarks + Simplicial_complex& sc; // Simplicial complex + + public: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** @name Constructor + */ + + //@{ + + // Witness_range<Closest_landmark_range<Vertex_handle>> + + /** + * \brief Iterative construction of the witness complex. + * \details The witness complex is written in sc_ basing on a matrix knn of + * nearest neighbours of the form {witnesses}x{landmarks}. + * + * The type KNearestNeighbors can be seen as + * Witness_range<Closest_landmark_range<Vertex_handle>>, where + * Witness_range and Closest_landmark_range are random access ranges. + * + * Constructor takes into account at most (dim+1) + * first landmarks from each landmark range to construct simplices. + * + * Landmarks are supposed to be in [0,nbL_-1] + */ + template< typename KNearestNeighbors > + Strange_witness_complex(KNearestNeighbors const & knn, + Simplicial_complex & sc_, + int nbL_, + int dim) : nbL(nbL_), sc(sc_) { + // Construction of the active witness list + int nbW = knn.size(); + typeVectorVertex vv; + int counter = 0; + /* The list of still useful witnesses + * it will diminuish in the course of iterations + */ + 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}; + sc.insert_simplex(vv); + // TODO(SK) Error if not inserted : normally no need here though + } + for (int i = 0; i != nbW; ++i) { + std::vector<int> simplex; + simplex.reserve(dim+1); + for (int j = 0; j <= dim; j++) + simplex.push_back(knn[i][j]); + sc.insert_simplex_and_subfaces(simplex); + } + } + + //@} + + private: + /** \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 <typename KNearestNeighbors> + bool all_faces_in(KNearestNeighbors const &knn, int witness_id, int k) { + // std::cout << "All face in with the landmark " << inserted_vertex << std::endl; + std::vector< Vertex_handle > facet; + // Vertex_handle curr_vh = curr_sh->first; + // CHECK ALL THE FACETS + for (int i = 0; i != k + 1; ++i) { + facet = {}; + for (int j = 0; j != k + 1; ++j) { + if (j != i) { + facet.push_back(knn[witness_id][j]); + } + } // endfor + if (sc.find(facet) == sc.null_simplex()) + return false; + // std::cout << "++++ finished loop safely\n"; + } // endfor + return true; + } + + template <typename T> + static void print_vector(const std::vector<T>& 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 << "]"; + } + + public: + /** + * \brief Verification if every simplex in the complex is witnessed by witnesses in knn. + * \param print_output =true will print the witnesses for each simplex + * \remark Added for debugging purposes. + */ + template< class KNearestNeighbors > + bool is_witness_complex(KNearestNeighbors const & knn, bool print_output) { + // bool final_result = true; + for (Simplex_handle sh : sc.complex_simplex_range()) { + bool is_witnessed = false; + typeVectorVertex simplex; + int nbV = 0; // number of verticed in the simplex + for (int v : sc.simplex_vertex_range(sh)) + simplex.push_back(v); + nbV = simplex.size(); + for (typeVectorVertex w : knn) { + bool has_vertices = true; + for (int v : simplex) + if (std::find(w.begin(), w.begin() + nbV, v) == w.begin() + nbV) { + has_vertices = false; + // break; + } + if (has_vertices) { + is_witnessed = true; + if (print_output) { + std::cout << "The simplex "; + print_vector(simplex); + std::cout << " is witnessed by the witness "; + print_vector(w); + std::cout << std::endl; + } + break; + } + } + if (!is_witnessed) { + if (print_output) { + std::cout << "The following simplex is not witnessed "; + print_vector(simplex); + std::cout << std::endl; + } + assert(is_witnessed); + return false; + } + } + return true; + } +}; + +} // namespace witness_complex + +} // namespace Gudhi + +#endif // WITNESS_COMPLEX_H_ diff --git a/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h new file mode 100644 index 00000000..ee863a42 --- /dev/null +++ b/src/Witness_complex/include/gudhi/Strong_relaxed_witness_complex.h @@ -0,0 +1,337 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef STRONG_RELAXED_WITNESS_COMPLEX_H_ +#define STRONG_RELAXED_WITNESS_COMPLEX_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include "gudhi/Simplex_tree.h" +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +// Needed for nearest neighbours +#include <CGAL/Cartesian_d.h> +#include <CGAL/Search_traits.h> +#include <CGAL/Search_traits_adapter.h> +#include <CGAL/property_map.h> +#include <CGAL/Epick_d.h> +#include <CGAL/Orthogonal_k_neighbor_search.h> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplicial_complex > +class Strong_relaxed_witness_complex { + +private: + struct Active_witness { + int witness_id; + int landmark_id; + + Active_witness(int witness_id_, int landmark_id_) + : witness_id(witness_id_), + landmark_id(landmark_id_) { } + }; + +private: + typedef typename Simplicial_complex::Simplex_handle Simplex_handle; + typedef typename Simplicial_complex::Vertex_handle Vertex_handle; + typedef typename Simplicial_complex::Filtration_value FT; + + typedef std::vector< double > Point_t; + typedef std::vector< Point_t > Point_Vector; + + // typedef typename Simplicial_complex::Filtration_value Filtration_value; + typedef std::vector< Vertex_handle > typeVectorVertex; + typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex; + typedef std::pair< Simplex_handle, bool > typePairSimplexBool; + + typedef int Witness_id; + typedef int Landmark_id; + typedef std::list< Vertex_handle > ActiveWitnessList; + + private: + int nbL; // Number of landmarks + Simplicial_complex& sc; // Simplicial complex + + public: + /** @name Constructor + */ + + //@{ + + /** + * \brief Iterative construction of the relaxed witness complex. + * \details The witness complex is written in sc_ basing on a matrix knn + * of k nearest neighbours of the form {witnesses}x{landmarks} and + * and a matrix distances of distances to these landmarks from witnesses. + * The parameter alpha defines relaxation and + * limD defines the + * + * The line lengths in one given matrix can differ, + * however both matrices have the same corresponding line lengths. + * + * The type KNearestNeighbors can be seen as + * Witness_range<Closest_landmark_range<Vertex_handle>>, where + * Witness_range and Closest_landmark_range are random access ranges. + * + * Constructor takes into account at most (dim+1) + * first landmarks from each landmark range to construct simplices. + * + * Landmarks are supposed to be in [0,nbL_-1] + */ + + template< typename KNearestNeighbours > + Strong_relaxed_witness_complex(std::vector< std::vector<double> > const & distances, + KNearestNeighbours const & knn, + Simplicial_complex & sc_, + int nbL_, + double alpha2, + unsigned limD) : nbL(nbL_), sc(sc_) { + int nbW = knn.size(); + typeVectorVertex vv; + //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}; + sc.insert_simplex(vv, Filtration_value(0.0)); + /* TODO Error if not inserted : normally no need here though*/ + } + for (int i=0; i != nbW; ++i) { + // int i_end = limD+1; + // if (knn[i].size() < limD+1) + // i_end = knn[i].size(); + // double dist_wL = *(distances[i].begin()); + // while (distances[i][i_end] > dist_wL + alpha2) + // i_end--; + // add_all_witnessed_faces(distances[i].begin(), + // knn[i].begin(), + // knn[i].begin() + i_end + 1); + unsigned j_end = 0; + while (j_end < distances[i].size() && j_end <= limD && distances[i][j_end] <= distances[i][0] + alpha2) { + std::vector<int> simplex; + for (unsigned j = 0; j <= j_end; ++j) + simplex.push_back(knn[i][j]); + assert(distances[i][j_end] - distances[i][0] >= 0); + sc.insert_simplex_and_subfaces(simplex, distances[i][j_end] - distances[i][0]); + j_end++; + } + } + sc.set_dimension(limD); + } + + //@} + +private: + /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness + * Iterator is needed to know until how far we can take landmarks to form simplexes + * simplex is the prefix of the simplexes to insert + * The output value indicates if the witness rests active or not + */ + void add_all_witnessed_faces(std::vector<double>::const_iterator curr_d, + std::vector<int>::const_iterator curr_l, + std::vector<int>::const_iterator end) + { + std::vector<int> simplex; + std::vector<int>::const_iterator l_end = curr_l; + for (; l_end != end; ++l_end) { + std::vector<int>::const_iterator l_it = curr_l; + std::vector<double>::const_iterator d_it = curr_d; + simplex = {}; + for (; l_it != l_end; ++l_it, ++d_it) + simplex.push_back(*l_it); + sc.insert_simplex_and_subfaces(simplex, *(d_it--) - *curr_d); + } + } + + /** \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 + */ + bool all_faces_in(std::vector<int>& simplex, double* filtration_value) + { + std::vector< int > facet; + for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it) + { + facet.clear(); + for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it) + if (it != not_it) + facet.push_back(*it); + Simplex_handle facet_sh = sc.find(facet); + if (facet_sh == sc.null_simplex()) + return false; + else if (sc.filtration(facet_sh) > *filtration_value) + *filtration_value = sc.filtration(facet_sh); + } + return true; + } + + bool is_face(Simplex_handle face, Simplex_handle coface) + { + // vertex range is sorted in decreasing order + auto fvr = sc.simplex_vertex_range(face); + auto cfvr = sc.simplex_vertex_range(coface); + auto fv_it = fvr.begin(); + auto cfv_it = cfvr.begin(); + while (fv_it != fvr.end() && cfv_it != cfvr.end()) { + if (*fv_it < *cfv_it) + ++cfv_it; + else if (*fv_it == *cfv_it) { + ++cfv_it; + ++fv_it; + } + else + return false; + + } + return (fv_it == fvr.end()); + } + + // void erase_simplex(Simplex_handle sh) + // { + // auto siblings = sc.self_siblings(sh); + // auto oncles = siblings->oncles(); + // int prev_vertex = siblings->parent(); + // siblings->members().erase(sh->first); + // if (siblings->members().empty()) { + // typename typedef Simplicial_complex::Siblings Siblings; + // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex)); + // assert(!sc.has_children(oncles->members().find(prev_vertex))); + // //delete siblings; + // } + + // } + + void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh) + { + erase_simplex(coface_sh); + erase_simplex(face_sh); + } + +public: + // void collapse(std::vector<Simplex_handle>& simplices) + // { + // // Get a vector of simplex handles ordered by filtration value + // std::cout << sc << std::endl; + // //std::vector<Simplex_handle> simplices; + // for (Simplex_handle sh: sc.filtration_simplex_range()) + // simplices.push_back(sh); + // // std::sort(simplices.begin(), + // // simplices.end(), + // // [&](Simplex_handle sh1, Simplex_handle sh2) + // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2); + // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); }); + // // Double iteration + // auto face_it = simplices.rbegin(); + // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) { + // int coface_count = 0; + // auto reduced_coface = simplices.rbegin(); + // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it) + // if (face_it != coface_it && is_face(*face_it, *coface_it)) { + // coface_count++; + // if (coface_count == 1) + // reduced_coface = coface_it; + // else + // break; + // } + // if (coface_count == 1) { + // std::cout << "Erase ( "; + // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base()))) + // std::cout << v << " "; + + // simplices.erase(--(reduced_coface.base())); + // //elementary_collapse(*face_it, *reduced_coface); + // std::cout << ") and then ( "; + // for (auto v: sc.simplex_vertex_range(*(--face_it.base()))) + // std::cout << v << " "; + // std::cout << ")\n"; + // simplices.erase(--((face_it++).base())); + // //face_it = simplices.rbegin(); + // //std::cout << "Size of vector: " << simplices.size() << "\n"; + // } + // else + // face_it++; + // } + // sc.initialize_filtration(); + // //std::cout << sc << std::endl; + // } + + template <class Dim_lists> + void collapse(Dim_lists& dim_lists) + { + dim_lists.collapse(); + } + +private: + + /** Collapse recursively boundary faces of the given simplex + * if its filtration is bigger than alpha_lim. + */ + void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim) + { + for (Simplex_handle face_it : sc.boundary_simplex_range()) { + + } + + } + +}; //class Strong_relaxed_witness_complex + +} // namespace witness_complex + +} // namespace Gudhi + +#endif diff --git a/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h b/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h new file mode 100644 index 00000000..a1aedd8e --- /dev/null +++ b/src/Witness_complex/include/gudhi/Weak_relaxed_witness_complex.h @@ -0,0 +1,379 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef WEAK_RELAXED_WITNESS_COMPLEX_H_ +#define WEAK_RELAXED_WITNESS_COMPLEX_H_ + +#include <boost/container/flat_map.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <algorithm> +#include <utility> +#include "gudhi/reader_utils.h" +#include "gudhi/distance_functions.h" +#include "gudhi/Simplex_tree.h" +#include <vector> +#include <list> +#include <set> +#include <queue> +#include <limits> +#include <math.h> +#include <ctime> +#include <iostream> + +// Needed for nearest neighbours +#include <CGAL/Cartesian_d.h> +#include <CGAL/Search_traits.h> +#include <CGAL/Search_traits_adapter.h> +#include <CGAL/property_map.h> +#include <CGAL/Epick_d.h> +#include <CGAL/Orthogonal_k_neighbor_search.h> + +#include <boost/tuple/tuple.hpp> +#include <boost/iterator/zip_iterator.hpp> +#include <boost/iterator/counting_iterator.hpp> +#include <boost/range/iterator_range.hpp> + +// Needed for the adjacency graph in bad link search +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> + +namespace Gudhi { + +namespace witness_complex { + + /** \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 Simplicial_complex > +class Weak_relaxed_witness_complex { + +private: + struct Active_witness { + int witness_id; + int landmark_id; + + Active_witness(int witness_id_, int landmark_id_) + : witness_id(witness_id_), + landmark_id(landmark_id_) { } + }; + +private: + typedef typename Simplicial_complex::Simplex_handle Simplex_handle; + typedef typename Simplicial_complex::Vertex_handle Vertex_handle; + typedef typename Simplicial_complex::Filtration_value FT; + + typedef std::vector< double > Point_t; + typedef std::vector< Point_t > Point_Vector; + + // typedef typename Simplicial_complex::Filtration_value Filtration_value; + typedef std::vector< Vertex_handle > typeVectorVertex; + typedef std::pair< typeVectorVertex, Filtration_value> typeSimplex; + typedef std::pair< Simplex_handle, bool > typePairSimplexBool; + + typedef int Witness_id; + typedef int Landmark_id; + typedef std::list< Vertex_handle > ActiveWitnessList; + + private: + int nbL; // Number of landmarks + Simplicial_complex& sc; // Simplicial complex + + public: + /** @name Constructor + */ + + //@{ + + /** + * \brief Iterative construction of the relaxed witness complex. + * \details The witness complex is written in sc_ basing on a matrix knn + * of k nearest neighbours of the form {witnesses}x{landmarks} and + * and a matrix distances of distances to these landmarks from witnesses. + * The parameter alpha defines relaxation and + * limD defines the + * + * The line lengths in one given matrix can differ, + * however both matrices have the same corresponding line lengths. + * + * The type KNearestNeighbors can be seen as + * Witness_range<Closest_landmark_range<Vertex_handle>>, where + * Witness_range and Closest_landmark_range are random access ranges. + * + * Constructor takes into account at most (dim+1) + * first landmarks from each landmark range to construct simplices. + * + * Landmarks are supposed to be in [0,nbL_-1] + */ + + template< typename KNearestNeighbours > + Weak_relaxed_witness_complex(std::vector< std::vector<double> > const & distances, + KNearestNeighbours const & knn, + Simplicial_complex & sc_, + int nbL_, + double alpha, + int limD) : nbL(nbL_), sc(sc_) { + int nbW = knn.size(); + typeVectorVertex vv; + //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}; + sc.insert_simplex(vv, Filtration_value(0.0)); + /* TODO Error if not inserted : normally no need here though*/ + } + int k = 1; /* current dimension in iterative construction */ + for (int i=0; i != nbW; ++i) + active_w.push_back(i); + while (!active_w.empty() && k <= limD && k < nbL ) + { + typename ActiveWitnessList::iterator aw_it = active_w.begin(); + while (aw_it != active_w.end()) + { + std::vector<int> simplex; + bool ok = add_all_faces_of_dimension(k, + alpha, + std::numeric_limits<double>::infinity(), + distances[*aw_it].begin(), + knn[*aw_it].begin(), + simplex, + knn[*aw_it].end()); + if (!ok) + active_w.erase(aw_it++); //First increase the iterator and then erase the previous element + else + aw_it++; + } + k++; + } + sc.set_dimension(limD); + } + + //@} + +private: + /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness + * Iterator is needed to know until how far we can take landmarks to form simplexes + * simplex is the prefix of the simplexes to insert + * The output value indicates if the witness rests active or not + */ + bool add_all_faces_of_dimension(int dim, + double alpha, + double norelax_dist, + std::vector<double>::const_iterator curr_d, + std::vector<int>::const_iterator curr_l, + std::vector<int>& simplex, + std::vector<int>::const_iterator end) + { + if (curr_l == end) + return false; + bool will_be_active = false; + std::vector<int>::const_iterator l_it = curr_l; + std::vector<double>::const_iterator d_it = curr_d; + if (dim > 0) + for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) { + simplex.push_back(*l_it); + if (sc.find(simplex) != sc.null_simplex()) + will_be_active = add_all_faces_of_dimension(dim-1, + alpha, + norelax_dist, + d_it+1, + l_it+1, + simplex, + end) || will_be_active; + simplex.pop_back(); + // If norelax_dist is infinity, change to first omitted distance + if (*d_it <= norelax_dist) + norelax_dist = *d_it; + will_be_active = add_all_faces_of_dimension(dim-1, + alpha, + norelax_dist, + d_it+1, + l_it+1, + simplex, + end) || will_be_active; + } + else if (dim == 0) + for (; *d_it - alpha <= norelax_dist && l_it != end; ++l_it, ++d_it) { + simplex.push_back(*l_it); + double filtration_value = 0; + // if norelax_dist is infinite, relaxation is 0. + if (*d_it > norelax_dist) + filtration_value = *d_it - norelax_dist; + if (all_faces_in(simplex, &filtration_value)) { + will_be_active = true; + sc.insert_simplex(simplex, filtration_value); + } + simplex.pop_back(); + // If norelax_dist is infinity, change to first omitted distance + if (*d_it < norelax_dist) + norelax_dist = *d_it; + } + return will_be_active; + } + + /** \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 + */ + bool all_faces_in(std::vector<int>& simplex, double* filtration_value) + { + std::vector< int > facet; + for (std::vector<int>::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it) + { + facet.clear(); + for (std::vector<int>::iterator it = simplex.begin(); it != simplex.end(); ++it) + if (it != not_it) + facet.push_back(*it); + Simplex_handle facet_sh = sc.find(facet); + if (facet_sh == sc.null_simplex()) + return false; + else if (sc.filtration(facet_sh) > *filtration_value) + *filtration_value = sc.filtration(facet_sh); + } + return true; + } + + bool is_face(Simplex_handle face, Simplex_handle coface) + { + // vertex range is sorted in decreasing order + auto fvr = sc.simplex_vertex_range(face); + auto cfvr = sc.simplex_vertex_range(coface); + auto fv_it = fvr.begin(); + auto cfv_it = cfvr.begin(); + while (fv_it != fvr.end() && cfv_it != cfvr.end()) { + if (*fv_it < *cfv_it) + ++cfv_it; + else if (*fv_it == *cfv_it) { + ++cfv_it; + ++fv_it; + } + else + return false; + + } + return (fv_it == fvr.end()); + } + + // void erase_simplex(Simplex_handle sh) + // { + // auto siblings = sc.self_siblings(sh); + // auto oncles = siblings->oncles(); + // int prev_vertex = siblings->parent(); + // siblings->members().erase(sh->first); + // if (siblings->members().empty()) { + // typename typedef Simplicial_complex::Siblings Siblings; + // oncles->members().find(prev_vertex)->second.assign_children(new Siblings(oncles, prev_vertex)); + // assert(!sc.has_children(oncles->members().find(prev_vertex))); + // //delete siblings; + // } + + // } + + void elementary_collapse(Simplex_handle face_sh, Simplex_handle coface_sh) + { + erase_simplex(coface_sh); + erase_simplex(face_sh); + } + +public: + // void collapse(std::vector<Simplex_handle>& simplices) + // { + // // Get a vector of simplex handles ordered by filtration value + // std::cout << sc << std::endl; + // //std::vector<Simplex_handle> simplices; + // for (Simplex_handle sh: sc.filtration_simplex_range()) + // simplices.push_back(sh); + // // std::sort(simplices.begin(), + // // simplices.end(), + // // [&](Simplex_handle sh1, Simplex_handle sh2) + // // { double f1 = sc.filtration(sh1), f2 = sc.filtration(sh2); + // // return (f1 > f2) || (f1 >= f2 && sc.dimension(sh1) > sc.dimension(sh2)); }); + // // Double iteration + // auto face_it = simplices.rbegin(); + // while (face_it != simplices.rend() && sc.filtration(*face_it) != 0) { + // int coface_count = 0; + // auto reduced_coface = simplices.rbegin(); + // for (auto coface_it = simplices.rbegin(); coface_it != simplices.rend() && sc.filtration(*coface_it) != 0; ++coface_it) + // if (face_it != coface_it && is_face(*face_it, *coface_it)) { + // coface_count++; + // if (coface_count == 1) + // reduced_coface = coface_it; + // else + // break; + // } + // if (coface_count == 1) { + // std::cout << "Erase ( "; + // for (auto v: sc.simplex_vertex_range(*(--reduced_coface.base()))) + // std::cout << v << " "; + + // simplices.erase(--(reduced_coface.base())); + // //elementary_collapse(*face_it, *reduced_coface); + // std::cout << ") and then ( "; + // for (auto v: sc.simplex_vertex_range(*(--face_it.base()))) + // std::cout << v << " "; + // std::cout << ")\n"; + // simplices.erase(--((face_it++).base())); + // //face_it = simplices.rbegin(); + // //std::cout << "Size of vector: " << simplices.size() << "\n"; + // } + // else + // face_it++; + // } + // sc.initialize_filtration(); + // //std::cout << sc << std::endl; + // } + + template <class Dim_lists> + void collapse(Dim_lists& dim_lists) + { + dim_lists.collapse(); + } + +private: + + /** Collapse recursively boundary faces of the given simplex + * if its filtration is bigger than alpha_lim. + */ + void rec_boundary_collapse(Simplex_handle sh, FT alpha_lim) + { + for (Simplex_handle face_it : sc.boundary_simplex_range()) { + + } + + } + +}; //class Weak_relaxed_witness_complex + +} // namespace witness_complex + +} // namespace Gudhi + +#endif |