From 518acce63202c7b89fa3f76467e50eee7630cf62 Mon Sep 17 00:00:00 2001 From: vrouvrea Date: Thu, 16 Feb 2017 14:58:11 +0000 Subject: Remove pandas examples and use of OFF files interfaces to be more consistent (pandas interface is not that hard to be done) Add of distance matrix in Rips git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/ST_cythonize@2081 636b058d-ea47-450e-bf9e-a15bfbe3eedb Former-commit-id: 3a3b24f0824eed2710edb5bf17d120039973bf62 --- src/cython/CMakeLists.txt | 1 + src/cython/cython/rips_complex.pyx | 40 +++++-- src/cython/doc/installation.rst | 6 +- src/cython/doc/persistent_cohomology_user.rst | 3 +- src/cython/doc/rips_complex_user.rst | 126 +++++++++++++++++++-- ...ersistence_from_distance_matrix_file_example.py | 71 ++++++++++++ ...ex_diagram_persistence_from_off_file_example.py | 71 ++++++++++++ ...am_persistence_with_pandas_interface_example.py | 69 ----------- src/cython/include/Rips_complex_interface.h | 32 ++++-- src/cython/test/test_rips_complex.py | 47 +++++++- 10 files changed, 367 insertions(+), 99 deletions(-) create mode 100755 src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py create mode 100755 src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py delete mode 100755 src/cython/example/rips_complex_diagram_persistence_with_pandas_interface_example.py (limited to 'src/cython') diff --git a/src/cython/CMakeLists.txt b/src/cython/CMakeLists.txt index 8723d731..6f7d5de7 100644 --- a/src/cython/CMakeLists.txt +++ b/src/cython/CMakeLists.txt @@ -132,6 +132,7 @@ if(PYTHON_PATH AND CYTHON_PATH) file(GLOB GUDHI_CUBICAL_PERSEUS_FILES "${CMAKE_SOURCE_DIR}/data/bitmap/*cubicalcomplexdoc.txt") file(COPY ${GUDHI_CUBICAL_PERSEUS_FILES} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc/") file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc/") + file(COPY "${CMAKE_SOURCE_DIR}/data/distance_matrix/full_square_distance_matrix.csv" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc/") # Persistence graphical tools examples file(COPY "${CMAKE_SOURCE_DIR}/data/bitmap/3d_torus.txt" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc/") file(COPY "${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc/") diff --git a/src/cython/cython/rips_complex.pyx b/src/cython/cython/rips_complex.pyx index 7e04ca4b..6bfb4482 100644 --- a/src/cython/cython/rips_complex.pyx +++ b/src/cython/cython/rips_complex.pyx @@ -33,9 +33,9 @@ __license__ = "GPL v3" cdef extern from "Rips_complex_interface.h" namespace "Gudhi": cdef cppclass Rips_complex_interface "Gudhi::rips_complex::Rips_complex_interface": - Rips_complex_interface(vector[vector[double]] points, double threshold) + Rips_complex_interface(vector[vector[double]] values, double threshold, bool euclidean) # bool from_file is a workaround for cython to find the correct signature - Rips_complex_interface(string off_file, double threshold, bool from_file) + Rips_complex_interface(string file_name, double threshold, bool euclidean, bool from_file) void create_simplex_tree(Simplex_tree_interface_full_featured* simplex_tree, int dim_max) # RipsComplex python interface @@ -49,9 +49,12 @@ cdef class RipsComplex: cdef Rips_complex_interface * thisptr # Fake constructor that does nothing but documenting the constructor - def __init__(self, points=[], off_file='', max_edge_length=float('inf')): + def __init__(self, points=None, off_file='', distance_matrix=None, csv_file='', max_edge_length=float('inf')): """RipsComplex constructor. + :param max_edge_length: Rips value. + :type max_edge_length: int + :param points: A list of points in d-Dimension. :type points: list of list of double @@ -60,21 +63,44 @@ cdef class RipsComplex: :param off_file: An OFF file style name. :type off_file: string - :param max_edge_length: Rips value. - :type max_edge_length: int + Or + + :param distance_matrix: A distance matrix (full square or lower + triangular). + :type points: list of list of double + + Or + + :param csv_file: A csv file style name containing a full square or a + lower triangular distance matrix. + :type csv_file: string """ # The real cython constructor - def __cinit__(self, points=[], off_file='', max_edge_length=float('inf')): + def __cinit__(self, points=None, off_file='', distance_matrix=None, csv_file='', max_edge_length=float('inf')): if off_file is not '': if os.path.isfile(off_file): self.thisptr = new Rips_complex_interface(off_file, max_edge_length, + True, True) else: print("file " + off_file + " not found.") + elif csv_file is not '': + if os.path.isfile(csv_file): + self.thisptr = new Rips_complex_interface(csv_file, + max_edge_length, + False, + True) + else: + print("file " + csv_file + " not found.") + elif distance_matrix is not None: + self.thisptr = new Rips_complex_interface(distance_matrix, max_edge_length, False) else: - self.thisptr = new Rips_complex_interface(points, max_edge_length) + if points is None: + # Empty Rips construction + points=[] + self.thisptr = new Rips_complex_interface(points, max_edge_length, True) def __dealloc__(self): diff --git a/src/cython/doc/installation.rst b/src/cython/doc/installation.rst index 12d35821..20d97b3c 100644 --- a/src/cython/doc/installation.rst +++ b/src/cython/doc/installation.rst @@ -112,8 +112,9 @@ The following examples require the `Matplotlib `_: * :download:`alpha_complex_diagram_persistence_from_off_file_example.py <../example/alpha_complex_diagram_persistence_from_off_file_example.py>` * :download:`gudhi_graphical_tools_example.py <../example/gudhi_graphical_tools_example.py>` * :download:`periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py <../example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py>` - * :download:`rips_complex_diagram_persistence_with_pandas_interface_example.py <../example/rips_complex_diagram_persistence_with_pandas_interface_example.py>` + * :download:`rips_complex_diagram_persistence_from_off_file_example.py <../example/rips_complex_diagram_persistence_from_off_file_example.py>` * :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>` + * :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>` * :download:`tangential_complex_plain_homology_from_off_file_example.py <../example/tangential_complex_plain_homology_from_off_file_example.py>` Numpy @@ -130,6 +131,7 @@ The following examples require the `NumPy `_: * :download:`alpha_complex_diagram_persistence_from_off_file_example.py <../example/alpha_complex_diagram_persistence_from_off_file_example.py>` * :download:`gudhi_graphical_tools_example.py <../example/gudhi_graphical_tools_example.py>` * :download:`periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py <../example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py>` - * :download:`rips_complex_diagram_persistence_with_pandas_interface_example.py <../example/rips_complex_diagram_persistence_with_pandas_interface_example.py>` + * :download:`rips_complex_diagram_persistence_from_off_file_example.py <../example/rips_complex_diagram_persistence_from_off_file_example.py>` * :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>` + * :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>` * :download:`tangential_complex_plain_homology_from_off_file_example.py <../example/tangential_complex_plain_homology_from_off_file_example.py>` diff --git a/src/cython/doc/persistent_cohomology_user.rst b/src/cython/doc/persistent_cohomology_user.rst index 4ca4805d..d264a011 100644 --- a/src/cython/doc/persistent_cohomology_user.rst +++ b/src/cython/doc/persistent_cohomology_user.rst @@ -101,8 +101,9 @@ We provide several example files: run these examples with -h for details on thei * :download:`alpha_complex_from_points_example.py <../example/alpha_complex_from_points_example.py>` * :download:`periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py <../example/periodic_cubical_complex_barcode_persistence_from_perseus_file_example.py>` - * :download:`rips_complex_diagram_persistence_with_pandas_interface_example.py <../example/rips_complex_diagram_persistence_with_pandas_interface_example.py>` + * :download:`rips_complex_diagram_persistence_from_off_file_example.py <../example/rips_complex_diagram_persistence_from_off_file_example.py>` * :download:`rips_persistence_diagram.py <../example/rips_persistence_diagram.py>` + * :download:`rips_complex_diagram_persistence_from_distance_matrix_file_example.py <../example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py>` * :download:`random_cubical_complex_persistence_example.py <../example/random_cubical_complex_persistence_example.py>` * :download:`tangential_complex_plain_homology_from_off_file_example.py <../example/tangential_complex_plain_homology_from_off_file_example.py>` diff --git a/src/cython/doc/rips_complex_user.rst b/src/cython/doc/rips_complex_user.rst index be9481de..a5d17e19 100644 --- a/src/cython/doc/rips_complex_user.rst +++ b/src/cython/doc/rips_complex_user.rst @@ -38,16 +38,16 @@ set with :math:`max(filtration(4,5), filtration(4,6), filtration(5,6))`. And so If the Rips_complex interfaces are not detailed enough for your need, please refer to rips_persistence_step_by_step.cpp example, where the graph construction over the Simplex_tree is more detailed. -Point cloud and distance function ---------------------------------- +Point cloud +----------- -Example from a point cloud and a distance function -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Example from a point cloud +^^^^^^^^^^^^^^^^^^^^^^^^^^ -This example builds the one skeleton graph from the given points, threshold value, and distance function. Then it -creates a :doc:`Simplex_tree ` with it. +This example builds the one skeleton graph from the given points, and max_edge_length value. +Then it creates a :doc:`Simplex_tree ` with it. -Then, it is asked to display information about the simplicial complex. +Finally, it is asked to display information about the simplicial complex. .. testcode:: @@ -63,7 +63,8 @@ Then, it is asked to display information about the simplicial complex. for filtered_value in simplex_tree.get_filtered_tree(): print(filtered_value) -The output is: +When launching (Rips maximal distance between 2 points is 12.0, is expanded +until dimension 1 - one skeleton graph in other words), the output is: .. testoutput:: @@ -90,10 +91,11 @@ The output is: Example from OFF file ^^^^^^^^^^^^^^^^^^^^^ -This example builds the :doc:`Rips_complex ` from the given points in an OFF file, threshold value, -and distance function. Then it creates a :doc:`Simplex_tree ` with it. +This example builds the :doc:`Rips_complex ` from the given +points in an OFF file, and max_edge_length value. +Then it creates a :doc:`Simplex_tree ` with it. -Then, it is asked to display information about the Rips complex. +Finally, it is asked to display information about the Rips complex. .. testcode:: @@ -131,3 +133,105 @@ the program output is: ([0, 3], 9.433981132056603) ([4, 6], 9.486832980505138) ([3, 6], 11.0) + +Distance matrix +--------------- + +Example from a distance matrix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example builds the one skeleton graph from the given distance matrix, and max_edge_length value. +Then it creates a :doc:`Simplex_tree ` with it. + +Finally, it is asked to display information about the simplicial complex. + +.. testcode:: + + import gudhi + rips_complex = gudhi.RipsComplex(distance_matrix=[[], + [6.0827625303], + [5.8309518948, 6.7082039325], + [9.4339811321, 6.3245553203, 5], + [13.0384048104, 15.6524758425, 8.94427191, 12.0415945788], + [18.0277563773, 19.6468827044, 13.152946438, 14.7648230602, 5.3851648071], + [17.88854382, 17.1172427686, 12.0830459736, 11, 9.4868329805, 7.2801098893]], + max_edge_length=12.0) + + simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) + result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtered_tree(): + print(filtered_value) + +When launching (Rips maximal distance between 2 points is 12.0, is expanded +until dimension 1 - one skeleton graph in other words), the output is: + +.. testoutput:: + + Rips complex is of dimension 1 - 18 simplices - 7 vertices. + ([0], 0.0) + ([1], 0.0) + ([2], 0.0) + ([3], 0.0) + ([4], 0.0) + ([5], 0.0) + ([6], 0.0) + ([2, 3], 5.0) + ([4, 5], 5.3851648071) + ([0, 2], 5.8309518948) + ([0, 1], 6.0827625303) + ([1, 3], 6.3245553203) + ([1, 2], 6.7082039325) + ([5, 6], 7.2801098893) + ([2, 4], 8.94427191) + ([0, 3], 9.4339811321) + ([4, 6], 9.4868329805) + ([3, 6], 11.0) + +Example from OFF file +^^^^^^^^^^^^^^^^^^^^^ + +This example builds the :doc:`Rips_complex ` from the given +points in an OFF file, and max_edge_length value. +Then it creates a :doc:`Simplex_tree ` with it. + +Finally, it is asked to display information about the Rips complex. + + +.. testcode:: + + import gudhi + rips_complex = gudhi.RipsComplex(csv_file='full_square_distance_matrix.csv', max_edge_length=12.0) + simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) + result_str = 'Rips complex is of dimension ' + repr(simplex_tree.dimension()) + ' - ' + \ + repr(simplex_tree.num_simplices()) + ' simplices - ' + \ + repr(simplex_tree.num_vertices()) + ' vertices.' + print(result_str) + for filtered_value in simplex_tree.get_filtered_tree(): + print(filtered_value) + +the program output is: + +.. testoutput:: + + Rips complex is of dimension 1 - 18 simplices - 7 vertices. + ([0], 0.0) + ([1], 0.0) + ([2], 0.0) + ([3], 0.0) + ([4], 0.0) + ([5], 0.0) + ([6], 0.0) + ([2, 3], 5.0) + ([4, 5], 5.3851648071) + ([0, 2], 5.8309518948) + ([0, 1], 6.0827625303) + ([1, 3], 6.3245553203) + ([1, 2], 6.7082039325) + ([5, 6], 7.2801098893) + ([2, 4], 8.94427191) + ([0, 3], 9.4339811321) + ([4, 6], 9.4868329805) + ([3, 6], 11.0) diff --git a/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py new file mode 100755 index 00000000..2b726f90 --- /dev/null +++ b/src/cython/example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +import gudhi +import argparse + +"""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): Vincent Rouvreau + + Copyright (C) 2016 INRIA + + 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 . +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 INRIA" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='RipsComplex creation from ' + 'a distance matrix read in a OFF file.', + epilog='Example: ' + 'example/rips_complex_diagram_persistence_from_distance_matrix_file_example.py ' + '-f ../data/distance_matrix/lower_triangular_distance_matrix.csv -e 12.0 -d 3' + '- Constructs a Rips complex with the ' + 'points from the given OFF file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-e", "--max_edge_length", type=float, default=0.5) +parser.add_argument("-d", "--max_dimension", type=int, default=1) +parser.add_argument('--no-diagram', default=False, action='store_true' , help='Flag for not to display the diagrams') + +args = parser.parse_args() + +with open(args.file, 'r') as f: + first_line = f.readline() + if (first_line == 'OFF\n') or (first_line == 'nOFF\n'): + print("#####################################################################") + print("RipsComplex creation from distance matrix read in a csv file") + + message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) + print(message) + + rips_complex = gudhi.RipsComplex(off_file=args.file, max_edge_length=args.max_edge_length) + simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) + + message = "Number of simplices=" + repr(simplex_tree.num_simplices()) + print(message) + + diag = simplex_tree.persistence() + + print("betti_numbers()=") + print(simplex_tree.betti_numbers()) + + if args.no_diagram == False: + gudhi.diagram_persistence(diag) + else: + print(args.file, "is not a valid OFF file") + + f.close() diff --git a/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py b/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py new file mode 100755 index 00000000..eb1c4ed5 --- /dev/null +++ b/src/cython/example/rips_complex_diagram_persistence_from_off_file_example.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +import gudhi +import argparse + +"""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): Vincent Rouvreau + + Copyright (C) 2016 INRIA + + 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 . +""" + +__author__ = "Vincent Rouvreau" +__copyright__ = "Copyright (C) 2016 INRIA" +__license__ = "GPL v3" + +parser = argparse.ArgumentParser(description='RipsComplex creation from ' + 'points read in a OFF file.', + epilog='Example: ' + 'example/rips_complex_diagram_persistence_from_off_file_example.py ' + '-f ../data/points/tore3D_300.off -a 0.6' + '- Constructs a Rips complex with the ' + 'points from the given OFF file.') +parser.add_argument("-f", "--file", type=str, required=True) +parser.add_argument("-e", "--max_edge_length", type=float, default=0.5) +parser.add_argument("-d", "--max_dimension", type=int, default=1) +parser.add_argument('--no-diagram', default=False, action='store_true' , help='Flag for not to display the diagrams') + +args = parser.parse_args() + +with open(args.file, 'r') as f: + first_line = f.readline() + if (first_line == 'OFF\n') or (first_line == 'nOFF\n'): + print("#####################################################################") + print("RipsComplex creation from points read in a OFF file") + + message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) + print(message) + + rips_complex = gudhi.RipsComplex(off_file=args.file, max_edge_length=args.max_edge_length) + simplex_tree = rips_complex.create_simplex_tree(max_dimension=args.max_dimension) + + message = "Number of simplices=" + repr(simplex_tree.num_simplices()) + print(message) + + diag = simplex_tree.persistence() + + print("betti_numbers()=") + print(simplex_tree.betti_numbers()) + + if args.no_diagram == False: + gudhi.diagram_persistence(diag) + else: + print(args.file, "is not a valid OFF file") + + f.close() diff --git a/src/cython/example/rips_complex_diagram_persistence_with_pandas_interface_example.py b/src/cython/example/rips_complex_diagram_persistence_with_pandas_interface_example.py deleted file mode 100755 index 8af1b767..00000000 --- a/src/cython/example/rips_complex_diagram_persistence_with_pandas_interface_example.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python - -import gudhi -import pandas -import argparse - -"""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): Vincent Rouvreau - - Copyright (C) 2016 INRIA - - 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 . -""" - -__author__ = "Vincent Rouvreau" -__copyright__ = "Copyright (C) 2016 INRIA" -__license__ = "GPL v3" - -print("#####################################################################") -print("RipsComplex creation from points read in a file") - -parser = argparse.ArgumentParser(description='RipsComplex creation from ' - 'points read in a file.', - epilog='Example: ' - 'example/rips_complex_diagram_persistence_with_pandas_interface_example.py ' - '../data/2000_random_points_on_3D_Torus.csv ' - '- Constructs a rips complex with the ' - 'points from the given file. File format ' - 'is X1, X2, ..., Xn') -parser.add_argument("-f", "--file", type=str, required=True) -parser.add_argument("-e", "--max-edge-length", type=float, default=0.5) -parser.add_argument('--no-diagram', default=False, action='store_true' , help='Flag for not to display the diagrams') - -args = parser.parse_args() - -points = pandas.read_csv(args.file, header=None) - -message = "RipsComplex with max_edge_length=" + repr(args.max_edge_length) -print(message) - -rips_complex = gudhi.RipsComplex(points=points.values, - max_edge_length=args.max_edge_length) - -simplex_tree = rips_complex.create_simplex_tree(max_dimension=len(points.values[0])) - -message = "Number of simplices=" + repr(simplex_tree.num_simplices()) -print(message) - -diag = simplex_tree.persistence() - -print("betti_numbers()=") -print(simplex_tree.betti_numbers()) - -if args.no_diagram == False: - gudhi.diagram_persistence(diag) diff --git a/src/cython/include/Rips_complex_interface.h b/src/cython/include/Rips_complex_interface.h index 7e897b1d..9295906c 100644 --- a/src/cython/include/Rips_complex_interface.h +++ b/src/cython/include/Rips_complex_interface.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "Simplex_tree_interface.h" @@ -41,17 +42,34 @@ namespace rips_complex { class Rips_complex_interface { using Point_d = std::vector; + using Distance_matrix = std::vector::Filtration_value>>; public: - Rips_complex_interface(std::vector>&points, double threshold) { - rips_complex_ = new Rips_complex::Filtration_value>(points, threshold, - Euclidean_distance()); + Rips_complex_interface(std::vector>&values, double threshold, bool euclidean) { + if (euclidean) { + // Rips construction where values is a vector of points + rips_complex_ = new Rips_complex::Filtration_value>(values, threshold, + Euclidean_distance()); + } else { + // Rips construction where values is a distance matrix + rips_complex_ = new Rips_complex::Filtration_value>(values, threshold); + + } } - Rips_complex_interface(std::string off_file_name, double threshold, bool from_file = true) { - Gudhi::Points_off_reader off_reader(off_file_name); - rips_complex_ = new Rips_complex::Filtration_value>(off_reader.get_point_cloud(), - threshold, Euclidean_distance()); + Rips_complex_interface(std::string file_name, double threshold, bool euclidean, bool from_file = true) { + if (euclidean) { + // Rips construction where file_name is an OFF file + Gudhi::Points_off_reader off_reader(file_name); + rips_complex_ = new Rips_complex::Filtration_value>(off_reader.get_point_cloud(), + threshold, Euclidean_distance()); + } else { + // Rips construction where values is a distance matrix + Distance_matrix distances = read_lower_triangular_matrix_from_csv_file::Filtration_value>(file_name); + rips_complex_ = new Rips_complex::Filtration_value>(distances, threshold); + + } + } void create_simplex_tree(Simplex_tree_interface<>* simplex_tree, int dim_max) { diff --git a/src/cython/test/test_rips_complex.py b/src/cython/test/test_rips_complex.py index 687e8529..464c69e5 100755 --- a/src/cython/test/test_rips_complex.py +++ b/src/cython/test/test_rips_complex.py @@ -1,4 +1,5 @@ from gudhi import RipsComplex +from math import sqrt """This file is part of the Gudhi Library. The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic C++ @@ -31,7 +32,7 @@ def test_empty_rips(): rips_complex = RipsComplex() assert rips_complex.__is_defined() == True -def test_rips(): +def test_rips_from_points(): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] rips_complex = RipsComplex(points=point_list, max_edge_length=42) @@ -55,7 +56,7 @@ def test_rips(): [([0, 1], 1.0), ([0, 2], 1.0), ([0, 3], 1.4142135623730951)] -def test_filtered_rips(): +def test_filtered_rips_from_points(): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] filtered_rips = RipsComplex(points=point_list, max_edge_length=1.0) @@ -66,3 +67,45 @@ def test_filtered_rips(): assert simplex_tree.num_simplices() == 8 assert simplex_tree.num_vertices() == 4 + +def test_rips_from_distance_matrix(): + distance_matrix = [[0], + [1, 0], + [1, sqrt(2), 0], + [sqrt(2), 1, 1, 0]] + rips_complex = RipsComplex(distance_matrix=distance_matrix, max_edge_length=42) + + simplex_tree = rips_complex.create_simplex_tree(max_dimension=1) + + assert simplex_tree.__is_defined() == True + assert simplex_tree.__is_persistence_defined() == False + + assert simplex_tree.num_simplices() == 10 + assert simplex_tree.num_vertices() == 4 + + assert simplex_tree.get_filtered_tree() == \ + [([0], 0.0), ([1], 0.0), ([2], 0.0), ([3], 0.0), + ([0, 1], 1.0), ([0, 2], 1.0), ([1, 3], 1.0), + ([2, 3], 1.0), ([1, 2], 1.4142135623730951), + ([0, 3], 1.4142135623730951)] + assert simplex_tree.get_star_tree([0]) == \ + [([0], 0.0), ([0, 1], 1.0), ([0, 2], 1.0), + ([0, 3], 1.4142135623730951)] + assert simplex_tree.get_coface_tree([0], 1) == \ + [([0, 1], 1.0), ([0, 2], 1.0), + ([0, 3], 1.4142135623730951)] + +def test_filtered_rips_from_distance_matrix(): + distance_matrix = [[0], + [1, 0], + [1, sqrt(2), 0], + [sqrt(2), 1, 1, 0]] + filtered_rips = RipsComplex(distance_matrix=distance_matrix, max_edge_length=1.0) + + simplex_tree = filtered_rips.create_simplex_tree(max_dimension=1) + + assert simplex_tree.__is_defined() == True + assert simplex_tree.__is_persistence_defined() == False + + assert simplex_tree.num_simplices() == 8 + assert simplex_tree.num_vertices() == 4 -- cgit v1.2.3