From 8cb574ec24253e908960e00d950f2b319aabf793 Mon Sep 17 00:00:00 2001 From: vrouvrea Date: Thu, 23 Jun 2016 09:49:03 +0000 Subject: Cubical complex unitary tests Using pytest because of unittest bug on __function in cython git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/branches/ST_cythonize@1332 636b058d-ea47-450e-bf9e-a15bfbe3eedb Former-commit-id: bbb829104ddb14173cdb066c40e73273fac0c720 --- src/cython/Makefile | 2 + src/cython/src/cython/cubical_complex.pyx | 42 ++++++++++++----- src/cython/test/test_cubical_complex.py | 78 +++++++++++++++++++++++++++++++ src/cython/test/test_witness_complex.py | 12 +++-- 4 files changed, 119 insertions(+), 15 deletions(-) create mode 100755 src/cython/test/test_cubical_complex.py (limited to 'src') diff --git a/src/cython/Makefile b/src/cython/Makefile index 75adbf3a..fdf4956c 100644 --- a/src/cython/Makefile +++ b/src/cython/Makefile @@ -6,6 +6,8 @@ test: python test/test_mini_simplex_tree.py python test/test_rips_complex.py python test/test_alpha_complex.py + python test/test_witness_complex.py + python -m pytest test/test_cubical_complex.py example: python example/simplex_tree_example.py diff --git a/src/cython/src/cython/cubical_complex.pyx b/src/cython/src/cython/cubical_complex.pyx index 98f0526a..375d2e0c 100644 --- a/src/cython/src/cython/cubical_complex.pyx +++ b/src/cython/src/cython/cubical_complex.pyx @@ -2,6 +2,7 @@ from cython cimport numeric from libcpp.vector cimport vector from libcpp.utility cimport pair from libcpp.string cimport string +import os """This file is part of the Gudhi Library. The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic C++ @@ -52,7 +53,8 @@ cdef class CubicalComplex: cdef Cubical_complex_persistence_interface * pcohptr - def __cinit__(self, dimensions=None, top_dimensional_cells=None, perseus_file=''): + def __cinit__(self, dimensions=None, top_dimensional_cells=None, + perseus_file=''): """CubicalComplex constructor from dimensions and top_dimensional_cells or from a perseus file style name. @@ -61,11 +63,20 @@ cdef class CubicalComplex: top_dimensional_cells (list): A list of top dimensional cells. perseus_file (string): A perseus file style name. """ - if dimensions is not None: - if top_dimensional_cells is not None: - self.thisptr = new Bitmap_cubical_complex_base_interface(dimensions, top_dimensional_cells) + if (((dimensions is not None) or (top_dimensional_cells is not None)) and + (perseus_file is not '')): + print("CubicalComplex can be constructed from dimensions and " + "top_dimensional_cells or from a perseus file style name.") else: - self.thisptr = new Bitmap_cubical_complex_base_interface(perseus_file) + if dimensions is not None: + if top_dimensional_cells is not None: + self.thisptr = new Bitmap_cubical_complex_base_interface(dimensions, top_dimensional_cells) + else: + if perseus_file is not '': + if os.path.isfile(perseus_file): + self.thisptr = new Bitmap_cubical_complex_base_interface(perseus_file) + else: + print("file " + perseus_file + " not found.") def __dealloc__(self): if self.thisptr != NULL: @@ -73,6 +84,12 @@ cdef class CubicalComplex: if self.pcohptr != NULL: del self.pcohptr + def __is_defined(self): + return self.thisptr != NULL + + def __is_persistence_defined(self): + return self.pcohptr != NULL + def persistence(self, homology_coeff_field=11, min_persistence=0): """This function returns the persistence of the simplicial complex. @@ -88,7 +105,8 @@ cdef class CubicalComplex: """ if self.pcohptr != NULL: del self.pcohptr - self.pcohptr = new Cubical_complex_persistence_interface(self.thisptr) + if self.thisptr != NULL: + self.pcohptr = new Cubical_complex_persistence_interface(self.thisptr) cdef vector[pair[int, pair[double, double]]] persistence_result if self.pcohptr != NULL: persistence_result = self.pcohptr.get_persistence(homology_coeff_field, min_persistence) @@ -98,13 +116,13 @@ cdef class CubicalComplex: """This function returns the Betti numbers of the simplicial complex. :returns: list of int -- The Betti numbers ([B0, B1, ..., Bn]). + + :warning: betti_numbers function requires persistence function to be + launched first. """ cdef vector[int] bn_result if self.pcohptr != NULL: bn_result = self.pcohptr.betti_numbers() - else: - print("betti_numbers function requires persistence function" - " to be launched first.") return bn_result def persistent_betti_numbers(self, from_value, to_value): @@ -120,11 +138,11 @@ cdef class CubicalComplex: :returns: list of int -- The persistent Betti numbers ([B0, B1, ..., Bn]). + + :warning: betti_numbers function requires persistence function to be + launched first. """ cdef vector[int] pbn_result if self.pcohptr != NULL: pbn_result = self.pcohptr.persistent_betti_numbers(from_value, to_value) - else: - print("persistent_betti_numbers function requires persistence function" - " to be launched first.") return pbn_result diff --git a/src/cython/test/test_cubical_complex.py b/src/cython/test/test_cubical_complex.py new file mode 100755 index 00000000..9f5847f9 --- /dev/null +++ b/src/cython/test/test_cubical_complex.py @@ -0,0 +1,78 @@ +from gudhi import CubicalComplex + +"""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" + + +def test_empty_constructor(): + # Try to create an empty CubicalComplex + cub = CubicalComplex() + assert cub.__is_defined() == False + assert cub.__is_persistence_defined() == False + +def test_non_existing_perseus_file_constructor(): + # Try to open a non existing file + cub = CubicalComplex(perseus_file='pouetpouettralala.toubiloubabdou') + assert cub.__is_defined() == False + assert cub.__is_persistence_defined() == False + +def test_dimension_or_perseus_file_constructor(): + # CubicalComplex can be constructed from dimensions and + # top_dimensional_cells OR from a perseus file style name. + cub = CubicalComplex(dimensions=[3, 3], + top_dimensional_cells = [1,2,3,4,5,6,7,8,9], + perseus_file='../data/bitmap/CubicalOneSphere.txt') + assert cub.__is_defined() == False + assert cub.__is_persistence_defined() == False + + cub = CubicalComplex(top_dimensional_cells = [1,2,3,4,5,6,7,8,9], + perseus_file='../data/bitmap/CubicalOneSphere.txt') + assert cub.__is_defined() == False + assert cub.__is_persistence_defined() == False + + cub = CubicalComplex(dimensions=[3, 3], + perseus_file='../data/bitmap/CubicalOneSphere.txt') + assert cub.__is_defined() == False + assert cub.__is_persistence_defined() == False + +def test_dimension_constructor(): + cub = CubicalComplex(dimensions=[3, 3], + top_dimensional_cells = [1,2,3,4,5,6,7,8,9]) + assert cub.__is_defined() == True + assert cub.__is_persistence_defined() == False + assert cub.persistence() == [(1, (0.0, 100.0)), (0, (0.0, 1.8446744073709552e+19))] + assert cub.__is_persistence_defined() == True + assert cub.betti_numbers() == [1, 0] + assert cub.persistent_betti_numbers(0, 1000) == [0, 0] + +def test_dimension_constructor(): + cub = CubicalComplex(perseus_file='../data/bitmap/CubicalOneSphere.txt') + assert cub.__is_defined() == True + assert cub.__is_persistence_defined() == False + assert cub.persistence() == [(1, (0.0, 100.0)), (0, (0.0, 1.8446744073709552e+19))] + assert cub.__is_persistence_defined() == True + assert cub.betti_numbers() == [1, 0] + assert cub.persistent_betti_numbers(0, 1000) == [1, 0] diff --git a/src/cython/test/test_witness_complex.py b/src/cython/test/test_witness_complex.py index f9bbe077..2891935d 100755 --- a/src/cython/test/test_witness_complex.py +++ b/src/cython/test/test_witness_complex.py @@ -31,11 +31,13 @@ __license__ = "GPL v3" class TestWitnessComplex(unittest.TestCase): - def test_infinite_alpha(self): + def test_witness_complex(self): point_list = [[0, 0], [1, 0], [0, 1], [1, 1]] witness = gudhi.WitnessComplex(points=point_list, number_of_landmarks=10) + # FIXME: Remove this line + witness.set_dimension(2) self.assertEqual(witness.num_simplices(), 13) self.assertEqual(witness.num_vertices(), 10) @@ -46,8 +48,12 @@ class TestWitnessComplex(unittest.TestCase): ([1, 2], 0.0), ([3], 0.0), ([4], 0.0), ([3, 4], 0.0), ([5], 0.0), ([6], 0.0), ([7], 0.0), ([8], 0.0), ([9], 0.0)]) - self.assertEqual(witness.get_star_tree([0]), []) - self.assertEqual(witness.get_coface_tree([0], 1), []) + + self.assertEqual(witness.get_coface_tree([2], 1), + [([0, 2], 0.0), ([1, 2], 0.0)]) + self.assertEqual(witness.get_star_tree([2]), + [([0, 2], 0.0), ([1, 2], 0.0), ([2], 0.0)]) + if __name__ == '__main__': unittest.main() -- cgit v1.2.3