summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/doc/MathJax.COPYRIGHT55
-rw-r--r--src/common/doc/MathJax.js53
-rw-r--r--src/common/doc/file_formats.h59
-rw-r--r--src/common/doc/main_page.h23
-rw-r--r--src/common/example/CMakeLists.txt14
-rw-r--r--src/common/include/gudhi/Clock.h20
-rw-r--r--src/common/include/gudhi/random_point_generators.h32
-rw-r--r--src/common/include/gudhi/reader_utils.h145
-rw-r--r--src/common/test/CMakeLists.txt11
-rw-r--r--src/common/test/README2
-rw-r--r--src/common/test/persistence_intervals_with_dimension.pers5
-rw-r--r--src/common/test/persistence_intervals_with_field.pers4
-rw-r--r--src/common/test/persistence_intervals_without_dimension.pers7
-rw-r--r--src/common/test/test_distance_matrix_reader.cpp4
-rw-r--r--src/common/test/test_persistence_intervals_reader.cpp322
-rw-r--r--src/common/utilities/CMakeLists.txt17
-rw-r--r--src/common/utilities/README19
-rw-r--r--src/common/utilities/off_file_from_shape_generator.cpp189
18 files changed, 923 insertions, 58 deletions
diff --git a/src/common/doc/MathJax.COPYRIGHT b/src/common/doc/MathJax.COPYRIGHT
new file mode 100644
index 00000000..077d6dc5
--- /dev/null
+++ b/src/common/doc/MathJax.COPYRIGHT
@@ -0,0 +1,55 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ You must give any other recipients of the Work or Derivative Works a copy of this License; and
+ You must cause any modified files to carry prominent notices stating that You changed the files; and
+ You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+ If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
diff --git a/src/common/doc/MathJax.js b/src/common/doc/MathJax.js
new file mode 100644
index 00000000..35e1994e
--- /dev/null
+++ b/src/common/doc/MathJax.js
@@ -0,0 +1,53 @@
+(function () {
+ var newMathJax = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js';
+ var oldMathJax = 'cdn.mathjax.org/mathjax/latest/MathJax.js';
+
+ var replaceScript = function (script, src) {
+ //
+ // Make redirected script
+ //
+ var newScript = document.createElement('script');
+ newScript.src = newMathJax + src.replace(/.*?(\?|$)/, '$1');
+ //
+ // Move onload and onerror handlers to new script
+ //
+ newScript.onload = script.onload;
+ newScript.onerror = script.onerror;
+ script.onload = script.onerror = null;
+ //
+ // Move any content (old-style configuration scripts)
+ //
+ while (script.firstChild) newScript.appendChild(script.firstChild);
+ //
+ // Copy script id
+ //
+ if (script.id != null) newScript.id = script.id;
+ //
+ // Replace original script with new one
+ //
+ script.parentNode.replaceChild(newScript, script);
+ //
+ // Issue a console warning
+ //
+ console.warn('WARNING: cdn.mathjax.org has been retired. Check https://www.mathjax.org/cdn-shutting-down/ for migration tips.')
+ }
+
+ if (document.currentScript) {
+ var script = document.currentScript;
+ replaceScript(script, script.src);
+ } else {
+ //
+ // Look for current script by searching for one with the right source
+ //
+ var n = oldMathJax.length;
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var script = scripts[i];
+ var src = (script.src || '').replace(/.*?:\/\//,'');
+ if (src.substr(0, n) === oldMathJax) {
+ replaceScript(script, src);
+ break;
+ }
+ }
+ }
+})(); \ No newline at end of file
diff --git a/src/common/doc/file_formats.h b/src/common/doc/file_formats.h
new file mode 100644
index 00000000..d715aa4d
--- /dev/null
+++ b/src/common/doc/file_formats.h
@@ -0,0 +1,59 @@
+/* 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): Clément Jamin
+*
+* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DOC_COMMON_FILE_FORMAT_H_
+#define DOC_COMMON_FILE_FORMAT_H_
+
+namespace Gudhi {
+
+/*! \page fileformats File formats
+
+ \tableofcontents
+
+ \section FileFormatsPers Persistence Diagram
+
+ Such a file, whose extension is usually `.pers`, contains a list of persistence intervals.<br>
+ Lines starting with `#` are ignored (comments).<br>
+ Other lines might contain 2, 3 or 4 values (the number of values on each line must be the same for all lines):
+ \verbatim
+ [[field] dimension] birth death
+ \endverbatim
+
+ Here is a simple sample file:
+ \verbatim
+ # Persistence diagram example
+ 2 2.7 3.7
+ 2 9.6 14.
+ # Some comments
+ 3 34.2 34.974
+ 4 3. inf
+ \endverbatim
+
+ Other sample files can be found in the `data/persistence_diagram` folder.
+
+ Such files can be generated with `Gudhi::persistent_cohomology::Persistent_cohomology::output_diagram()` and read with
+ `Gudhi::read_persistence_intervals_and_dimension()`, `Gudhi::read_persistence_intervals_grouped_by_dimension()` or
+ `Gudhi::read_persistence_intervals_in_dimension()`.
+*/
+} // namespace Gudhi
+
+#endif // DOC_COMMON_FILE_FORMAT_H_
diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h
index 8d282fca..d48294a5 100644
--- a/src/common/doc/main_page.h
+++ b/src/common/doc/main_page.h
@@ -178,7 +178,7 @@
<b>Author:</b> Fran&ccedil;ois Godi<br>
<b>Introduced in:</b> GUDHI 2.0.0<br>
<b>Copyright:</b> GPL v3<br>
- <b>Requires:</b> \ref cgal &ge; 4.8.1 and \ref eigen3
+ <b>Requires:</b> \ref cgal &ge; 4.8.1
</td>
<td width="75%">
Bottleneck distance measures the similarity between two persistence diagrams.
@@ -347,13 +347,29 @@ make doxygen
* Alpha_complex/Alpha_complex_from_off.cpp</a>
* \li <a href="_alpha_complex_2_alpha_complex_from_points_8cpp-example.html">
* Alpha_complex/Alpha_complex_from_points.cpp</a>
+ * \li <a href="_bottleneck_distance_2alpha_rips_persistence_bottleneck_distance_8cpp-example.html">
+ * Bottleneck_distance/alpha_rips_persistence_bottleneck_distance.cpp.cpp</a>
* \li <a href="_persistent_cohomology_2alpha_complex_persistence_8cpp-example.html">
* Persistent_cohomology/alpha_complex_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2periodic_alpha_complex_3d_persistence_8cpp-example.html">
* Persistent_cohomology/periodic_alpha_complex_3d_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2custom_persistence_sort_8cpp-example.html">
* Persistent_cohomology/custom_persistence_sort.cpp</a>
- *
+ * \li <a href="_spatial_searching_2example_spatial_searching_8cpp-example.html">
+ * Spatial_searching/example_spatial_searching.cpp</a>
+ * \li <a href="_subsampling_2example_choose_n_farthest_points_8cpp-example.html">
+ * Subsampling/example_choose_n_farthest_points.cpp</a>
+ * \li <a href="_subsampling_2example_custom_kernel_8cpp-example.html">
+ * Subsampling/example_custom_kernel.cpp</a>
+ * \li <a href="_subsampling_2example_pick_n_random_points_8cpp-example.html">
+ * Subsampling/example_pick_n_random_points.cpp</a>
+ * \li <a href="_subsampling_2example_sparsify_point_set_8cpp-example.html">
+ * Subsampling/example_sparsify_point_set.cpp</a>
+ * \li <a href="_tangential_complex_2example_basic_8cpp-example.html">
+ * Tangential_complex/example_basic.cpp</a>
+ * \li <a href="_tangential_complex_2example_with_perturb_8cpp-example.html">
+ * Tangential_complex/example_with_perturb.cpp</a>
+ *
* \subsection tbb Threading Building Blocks
* <a target="_blank" href="https://www.threadingbuildingblocks.org/">Intel&reg; TBB</a> lets you easily write parallel
* C++ programs that take full advantage of multicore performance, that are portable and composable, and that have
@@ -382,6 +398,8 @@ make doxygen
* Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp</a>
* \li <a href="_simplex_tree_2simplex_tree_from_cliques_of_graph_8cpp-example.html">
* Simplex_tree/simplex_tree_from_cliques_of_graph.cpp</a>
+ * \li <a href="_simplex_tree_2graph_expansion_with_blocker_8cpp-example.html">
+ * Simplex_tree/graph_expansion_with_blocker.cpp</a>
* \li <a href="_persistent_cohomology_2alpha_complex_3d_persistence_8cpp-example.html">
* Persistent_cohomology/alpha_complex_3d_persistence.cpp</a>
* \li <a href="_persistent_cohomology_2alpha_complex_persistence_8cpp-example.html">
@@ -468,6 +486,7 @@ make doxygen
* @example Simplex_tree/simple_simplex_tree.cpp
* @example Simplex_tree/example_alpha_shapes_3_simplex_tree_from_off_file.cpp
* @example Simplex_tree/simplex_tree_from_cliques_of_graph.cpp
+ * @example Simplex_tree/graph_expansion_with_blocker.cpp
* @example Skeleton_blocker/Skeleton_blocker_from_simplices.cpp
* @example Skeleton_blocker/Skeleton_blocker_iteration.cpp
* @example Skeleton_blocker/Skeleton_blocker_link.cpp
diff --git a/src/common/example/CMakeLists.txt b/src/common/example/CMakeLists.txt
index d5311b18..afe865d4 100644
--- a/src/common/example/CMakeLists.txt
+++ b/src/common/example/CMakeLists.txt
@@ -2,21 +2,27 @@ cmake_minimum_required(VERSION 2.6)
project(Common_examples)
add_executable ( vector_double_off_reader example_vector_double_points_off_reader.cpp )
-target_link_libraries(vector_double_off_reader ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+target_link_libraries(vector_double_off_reader ${CGAL_LIBRARY})
add_test(NAME Common_example_vector_double_off_reader COMMAND $<TARGET_FILE:vector_double_off_reader>
"${CMAKE_SOURCE_DIR}/data/points/SO3_10000.off")
+install(TARGETS vector_double_off_reader DESTINATION bin)
+
if(CGAL_FOUND)
add_executable ( cgal_3D_off_reader example_CGAL_3D_points_off_reader.cpp )
- target_link_libraries(cgal_3D_off_reader ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ target_link_libraries(cgal_3D_off_reader ${CGAL_LIBRARY})
add_test(NAME Common_example_vector_cgal_3D_off_reader COMMAND $<TARGET_FILE:cgal_3D_off_reader>
"${CMAKE_SOURCE_DIR}/data/points/tore3D_300.off")
- # need CGAL 4.7and Eigen3
+ install(TARGETS cgal_3D_off_reader DESTINATION bin)
+
+ # need CGAL 4.7 and Eigen3
if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
add_executable ( cgal_off_reader example_CGAL_points_off_reader.cpp )
- target_link_libraries(cgal_off_reader ${Boost_SYSTEM_LIBRARY} ${CGAL_LIBRARY})
+ target_link_libraries(cgal_off_reader ${CGAL_LIBRARY})
add_test(NAME Common_example_vector_cgal_off_reader COMMAND $<TARGET_FILE:cgal_off_reader>
"${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off")
+ install(TARGETS cgal_off_reader DESTINATION bin)
endif (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.7.0)
+
endif()
diff --git a/src/common/include/gudhi/Clock.h b/src/common/include/gudhi/Clock.h
index 77f196ca..b83de2f5 100644
--- a/src/common/include/gudhi/Clock.h
+++ b/src/common/include/gudhi/Clock.h
@@ -23,9 +23,9 @@
#ifndef CLOCK_H_
#define CLOCK_H_
-#include <boost/date_time/posix_time/posix_time.hpp>
-
+#include <iostream>
#include <string>
+#include <chrono>
namespace Gudhi {
@@ -33,20 +33,20 @@ class Clock {
public:
// Construct and start the timer
Clock(const std::string& msg_ = std::string())
- : startTime(boost::posix_time::microsec_clock::local_time()),
+ : startTime(std::chrono::system_clock::now()),
end_called(false),
msg(msg_) { }
// Restart the timer
void begin() const {
end_called = false;
- startTime = boost::posix_time::microsec_clock::local_time();
+ startTime = std::chrono::system_clock::now();
}
// Stop the timer
void end() const {
end_called = true;
- endTime = boost::posix_time::microsec_clock::local_time();
+ endTime = std::chrono::system_clock::now();
}
std::string message() const {
@@ -62,7 +62,7 @@ class Clock {
if (!clock.msg.empty())
stream << clock.msg << ": ";
- stream << clock.num_seconds() << "s";
+ stream << clock.num_seconds() << "s\n";
return stream;
}
@@ -71,15 +71,15 @@ class Clock {
// - or now otherwise. In this case, the timer is not stopped.
double num_seconds() const {
if (!end_called) {
- auto end = boost::posix_time::microsec_clock::local_time();
- return (end - startTime).total_milliseconds() / 1000.;
+ auto end = std::chrono::system_clock::now();
+ return std::chrono::duration_cast<std::chrono::milliseconds>(end-startTime).count() / 1000.;
} else {
- return (endTime - startTime).total_milliseconds() / 1000.;
+ return std::chrono::duration_cast<std::chrono::milliseconds>(endTime-startTime).count() / 1000.;
}
}
private:
- mutable boost::posix_time::ptime startTime, endTime;
+ mutable std::chrono::time_point<std::chrono::system_clock> startTime, endTime;
mutable bool end_called;
std::string msg;
};
diff --git a/src/common/include/gudhi/random_point_generators.h b/src/common/include/gudhi/random_point_generators.h
index 2ec465ef..9df77760 100644
--- a/src/common/include/gudhi/random_point_generators.h
+++ b/src/common/include/gudhi/random_point_generators.h
@@ -282,6 +282,38 @@ std::vector<typename Kernel::Point_d> generate_points_on_sphere_d(std::size_t nu
}
template <typename Kernel>
+std::vector<typename Kernel::Point_d> generate_points_in_ball_d(std::size_t num_points, int dim, double radius) {
+ typedef typename Kernel::Point_d Point;
+ Kernel k;
+ CGAL::Random rng;
+ CGAL::Random_points_in_ball_d<Point> generator(dim, radius);
+ std::vector<Point> points;
+ points.reserve(num_points);
+ for (std::size_t i = 0; i < num_points;) {
+ Point p = *generator++;
+ points.push_back(p);
+ ++i;
+ }
+ return points;
+}
+
+template <typename Kernel>
+std::vector<typename Kernel::Point_d> generate_points_in_cube_d(std::size_t num_points, int dim, double radius) {
+ typedef typename Kernel::Point_d Point;
+ Kernel k;
+ CGAL::Random rng;
+ CGAL::Random_points_in_cube_d<Point> generator(dim, radius);
+ std::vector<Point> points;
+ points.reserve(num_points);
+ for (std::size_t i = 0; i < num_points;) {
+ Point p = *generator++;
+ points.push_back(p);
+ ++i;
+ }
+ return points;
+}
+
+template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_two_spheres_d(std::size_t num_points, int dim, double radius,
double distance_between_centers,
double radius_noise_percentage = 0.) {
diff --git a/src/common/include/gudhi/reader_utils.h b/src/common/include/gudhi/reader_utils.h
index 97a87edd..90be4fc7 100644
--- a/src/common/include/gudhi/reader_utils.h
+++ b/src/common/include/gudhi/reader_utils.h
@@ -1,8 +1,8 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
+/* 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): Clement Maria, Pawel Dlotko
+ * Author(s): Clement Maria, Pawel Dlotko, Clement Jamin
*
* Copyright (C) 2014 INRIA
*
@@ -24,7 +24,9 @@
#define READER_UTILS_H_
#include <gudhi/graph_simplicial_complex.h>
+#include <gudhi/Debug_utils.h>
+#include <boost/function_output_iterator.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
@@ -34,6 +36,9 @@
#include <string>
#include <vector>
#include <utility> // for pair
+#include <tuple> // for std::make_tuple
+
+namespace Gudhi {
// Keep this file tag for Doxygen to parse the code, otherwise, functions are not documented.
// It is required for global functions and variables.
@@ -50,7 +55,7 @@
* X21 X22 ... X2d<br>
* etc<br>
*/
-inline void read_points(std::string file_name, std::vector< std::vector< double > > & points) {
+inline void read_points(std::string file_name, std::vector<std::vector<double>>& points) {
std::ifstream in_file(file_name.c_str(), std::ios::in);
if (!in_file.is_open()) {
std::cerr << "Unable to open file " << file_name << std::endl;
@@ -60,14 +65,13 @@ inline void read_points(std::string file_name, std::vector< std::vector< double
std::string line;
double x;
while (getline(in_file, line)) {
- std::vector< double > point;
+ std::vector<double> point;
std::istringstream iss(line);
while (iss >> x) {
point.push_back(x);
}
// Check for empty lines
- if (!point.empty())
- points.push_back(point);
+ if (!point.empty()) points.push_back(point);
}
in_file.close();
}
@@ -88,17 +92,20 @@ inline void read_points(std::string file_name, std::vector< std::vector< double
* Every simplex must appear exactly once.
* Simplices of dimension more than 1 are ignored.
*/
-template< typename Graph_t, typename Filtration_value, typename Vertex_handle >
+template <typename Graph_t, typename Filtration_value, typename Vertex_handle>
Graph_t read_graph(std::string file_name) {
std::ifstream in_(file_name.c_str(), std::ios::in);
if (!in_.is_open()) {
- std::cerr << "Unable to open file " << file_name << std::endl;
+ std::string error_str("read_graph - Unable to open file ");
+ error_str.append(file_name);
+ std::cerr << error_str << std::endl;
+ throw std::invalid_argument(error_str);
}
- typedef std::pair< Vertex_handle, Vertex_handle > Edge_t;
- std::vector< Edge_t > edges;
- std::vector< Filtration_value > edges_fil;
- std::map< Vertex_handle, Filtration_value > vertices;
+ typedef std::pair<Vertex_handle, Vertex_handle> Edge_t;
+ std::vector<Edge_t> edges;
+ std::vector<Filtration_value> edges_fil;
+ std::map<Vertex_handle, Filtration_value> vertices;
std::string line;
int dim;
@@ -108,8 +115,7 @@ Graph_t read_graph(std::string file_name) {
std::istringstream iss(line);
while (iss >> dim) {
switch (dim) {
- case 0:
- {
+ case 0: {
iss >> u;
iss >> fil;
vertices[u] = fil;
@@ -118,8 +124,7 @@ Graph_t read_graph(std::string file_name) {
}
break;
}
- case 1:
- {
+ case 1: {
iss >> u;
iss >> v;
iss >> fil;
@@ -127,16 +132,13 @@ Graph_t read_graph(std::string file_name) {
edges_fil.push_back(fil);
break;
}
- default:
- {
- break;
- }
+ default: { break; }
}
}
}
in_.close();
- if ((size_t) (max_h + 1) != vertices.size()) {
+ if ((size_t)(max_h + 1) != vertices.size()) {
std::cerr << "Error: vertices must be labeled from 0 to n-1 \n";
}
@@ -164,8 +166,8 @@ Graph_t read_graph(std::string file_name) {
* Every simplex must appear exactly once.
* Simplices of dimension more than 1 are ignored.
*/
-template< typename Vertex_handle, typename Filtration_value >
-bool read_simplex(std::istream & in_, std::vector< Vertex_handle > & simplex, Filtration_value & fil) {
+template <typename Vertex_handle, typename Filtration_value>
+bool read_simplex(std::istream& in_, std::vector<Vertex_handle>& simplex, Filtration_value& fil) {
int dim = 0;
if (!(in_ >> dim)) return false;
Vertex_handle v;
@@ -189,8 +191,8 @@ bool read_simplex(std::istream & in_, std::vector< Vertex_handle > & simplex, Fi
* The key of a simplex is its position in the filtration order and also the number of its row in the file.
* Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the filtration has dimension Dimi, filtration value
* fil1 and simplices with key ki1 ... kiDimi in its boundary.*/
-template< typename Simplex_key, typename Filtration_value >
-bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundary, Filtration_value & fil) {
+template <typename Simplex_key, typename Filtration_value>
+bool read_hasse_simplex(std::istream& in_, std::vector<Simplex_key>& boundary, Filtration_value& fil) {
int dim;
if (!(in_ >> dim)) return false;
if (dim == 0) {
@@ -209,7 +211,7 @@ bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundar
/**
* @brief Read a lower triangular distance matrix from a csv file. We assume that the .csv store the whole
* (square) matrix.
- *
+ *
* @author Pawel Dlotko
*
* Square matrix file format:<br>
@@ -226,13 +228,13 @@ bool read_hasse_simplex(std::istream & in_, std::vector< Simplex_key > & boundar
* Dj1;Dj2;...;Dj(j-1);<br>
*
**/
-template< typename Filtration_value >
-std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from_csv_file(const std::string& filename,
- const char separator = ';') {
+template <typename Filtration_value>
+std::vector<std::vector<Filtration_value>> read_lower_triangular_matrix_from_csv_file(const std::string& filename,
+ const char separator = ';') {
#ifdef DEBUG_TRACES
std::cout << "Using procedure read_lower_triangular_matrix_from_csv_file \n";
#endif // DEBUG_TRACES
- std::vector< std::vector< Filtration_value > > result;
+ std::vector<std::vector<Filtration_value>> result;
std::ifstream in;
in.open(filename.c_str());
if (!in.is_open()) {
@@ -243,7 +245,7 @@ std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from
// the first line is emtpy, so we ignore it:
std::getline(in, line);
- std::vector< Filtration_value > values_in_this_line;
+ std::vector<Filtration_value> values_in_this_line;
result.push_back(values_in_this_line);
int number_of_line = 0;
@@ -251,11 +253,10 @@ std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from
// first, read the file line by line to a string:
while (std::getline(in, line)) {
// if line is empty, break
- if (line.size() == 0)
- break;
+ if (line.size() == 0) break;
// if the last element of a string is comma:
- if (line[ line.size() - 1 ] == separator) {
+ if (line[line.size() - 1] == separator) {
// then shrink the string by one
line.pop_back();
}
@@ -268,7 +269,7 @@ std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from
// and now read the doubles.
int number_of_entry = 0;
- std::vector< Filtration_value > values_in_this_line;
+ std::vector<Filtration_value> values_in_this_line;
while (iss.good()) {
double entry;
iss >> entry;
@@ -277,7 +278,7 @@ std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from
}
++number_of_entry;
}
- if (!values_in_this_line.empty())result.push_back(values_in_this_line);
+ if (!values_in_this_line.empty()) result.push_back(values_in_this_line);
++number_of_line;
}
in.close();
@@ -295,4 +296,74 @@ std::vector< std::vector< Filtration_value > > read_lower_triangular_matrix_from
return result;
} // read_lower_triangular_matrix_from_csv_file
+/**
+Reads a file containing persistence intervals.
+Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
+The output iterator `out` is used this way: `*out++ = std::make_tuple(dim, birth, death);`
+where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
+Note: the function does not check that birth <= death.
+**/
+template <typename OutputIterator>
+void read_persistence_intervals_and_dimension(std::string const& filename, OutputIterator out) {
+ std::ifstream in(filename);
+ if (!in.is_open()) {
+ std::string error_str("read_persistence_intervals_and_dimension - Unable to open file ");
+ error_str.append(filename);
+ std::cerr << error_str << std::endl;
+ throw std::invalid_argument(error_str);
+ }
+
+ while (!in.eof()) {
+ std::string line;
+ getline(in, line);
+ if (line.length() != 0 && line[0] != '#') {
+ double numbers[4];
+ int n = sscanf(line.c_str(), "%lf %lf %lf %lf", &numbers[0], &numbers[1], &numbers[2], &numbers[3]);
+ if (n >= 2) {
+ int dim = (n >= 3 ? static_cast<int>(numbers[n - 3]) : -1);
+ *out++ = std::make_tuple(dim, numbers[n - 2], numbers[n - 1]);
+ }
+ }
+ }
+}
+
+/**
+Reads a file containing persistence intervals.
+Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
+The return value is an `std::map<dim, std::vector<std::pair<birth, death>>>`
+where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
+Note: the function does not check that birth <= death.
+**/
+inline std::map<int, std::vector<std::pair<double, double>>> read_persistence_intervals_grouped_by_dimension(
+ std::string const& filename) {
+ std::map<int, std::vector<std::pair<double, double>>> ret;
+ read_persistence_intervals_and_dimension(
+ filename, boost::make_function_output_iterator([&ret](std::tuple<int, double, double> t) {
+ ret[get<0>(t)].push_back(std::make_pair(get<1>(t), get<2>(t)));
+ }));
+ return ret;
+}
+
+/**
+Reads a file containing persistence intervals.
+Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
+If `only_this_dim` = -1, dimension is ignored and all lines are returned.
+If `only_this_dim` is >= 0, only the lines where dimension = `only_this_dim`
+(or where dimension is not specified) are returned.
+The return value is an `std::vector<std::pair<birth, death>>`
+where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
+Note: the function does not check that birth <= death.
+**/
+inline std::vector<std::pair<double, double>> read_persistence_intervals_in_dimension(std::string const& filename,
+ int only_this_dim = -1) {
+ std::vector<std::pair<double, double>> ret;
+ read_persistence_intervals_and_dimension(
+ filename, boost::make_function_output_iterator([only_this_dim, &ret](std::tuple<int, double, double> t) {
+ if (only_this_dim == get<0>(t) || only_this_dim == -1) ret.emplace_back(get<1>(t), get<2>(t));
+ }));
+ return ret;
+}
+
+} // namespace Gudhi
+
#endif // READER_UTILS_H_
diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt
index c695fbf4..de3e765a 100644
--- a/src/common/test/CMakeLists.txt
+++ b/src/common/test/CMakeLists.txt
@@ -4,15 +4,22 @@ project(Common_tests)
include(GUDHI_test_coverage)
add_executable ( Common_test_points_off_reader test_points_off_reader.cpp )
-target_link_libraries(Common_test_points_off_reader ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+target_link_libraries(Common_test_points_off_reader ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
add_executable ( Common_test_distance_matrix_reader test_distance_matrix_reader.cpp )
-target_link_libraries(Common_test_distance_matrix_reader ${Boost_SYSTEM_LIBRARY} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+target_link_libraries(Common_test_distance_matrix_reader ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
+add_executable ( Common_test_persistence_intervals_reader test_persistence_intervals_reader.cpp )
+target_link_libraries(Common_test_persistence_intervals_reader ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
# Do not forget to copy test files in current binary dir
file(COPY "${CMAKE_SOURCE_DIR}/data/points/alphacomplexdoc.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
file(COPY "${CMAKE_SOURCE_DIR}/data/distance_matrix/lower_triangular_distance_matrix.csv" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
file(COPY "${CMAKE_SOURCE_DIR}/data/distance_matrix/full_square_distance_matrix.csv" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+file(COPY "${CMAKE_SOURCE_DIR}/src/common/test/persistence_intervals_with_dimension.pers" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+file(COPY "${CMAKE_SOURCE_DIR}/src/common/test/persistence_intervals_with_field.pers" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+file(COPY "${CMAKE_SOURCE_DIR}/src/common/test/persistence_intervals_without_dimension.pers" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
gudhi_add_coverage_test(Common_test_points_off_reader)
gudhi_add_coverage_test(Common_test_distance_matrix_reader)
+gudhi_add_coverage_test(Common_test_persistence_intervals_reader)
diff --git a/src/common/test/README b/src/common/test/README
index f2a7eb5a..a8e6efe9 100644
--- a/src/common/test/README
+++ b/src/common/test/README
@@ -7,7 +7,7 @@ make
To launch with details:
***********************
-./dtoffrw_UT --report_level=detailed --log_level=all
+./Common_test_points_off_reader --report_level=detailed --log_level=all
==> echo $? returns 0 in case of success (non-zero otherwise)
diff --git a/src/common/test/persistence_intervals_with_dimension.pers b/src/common/test/persistence_intervals_with_dimension.pers
new file mode 100644
index 00000000..406748c8
--- /dev/null
+++ b/src/common/test/persistence_intervals_with_dimension.pers
@@ -0,0 +1,5 @@
+# Simple persistence diagram with dimension
+0 2.7 3.7
+1 9.6 14.
+3 34.2 34.974
+1 3. inf
diff --git a/src/common/test/persistence_intervals_with_field.pers b/src/common/test/persistence_intervals_with_field.pers
new file mode 100644
index 00000000..41dd9f1e
--- /dev/null
+++ b/src/common/test/persistence_intervals_with_field.pers
@@ -0,0 +1,4 @@
+3 0 2.7 3.7
+3 1 9.6 14.
+3 3 34.2 34.974
+3 1 3. inf
diff --git a/src/common/test/persistence_intervals_without_dimension.pers b/src/common/test/persistence_intervals_without_dimension.pers
new file mode 100644
index 00000000..76fa27f3
--- /dev/null
+++ b/src/common/test/persistence_intervals_without_dimension.pers
@@ -0,0 +1,7 @@
+# Simple persistence diagram without dimension
+2.7 3.7
+9.6 14.
+# Another comment
+34.2 34.974
+3. inf
+# End of file
diff --git a/src/common/test/test_distance_matrix_reader.cpp b/src/common/test/test_distance_matrix_reader.cpp
index 95a73bd9..656e6f2e 100644
--- a/src/common/test/test_distance_matrix_reader.cpp
+++ b/src/common/test/test_distance_matrix_reader.cpp
@@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE( lower_triangular_distance_matrix )
{
Distance_matrix from_lower_triangular;
// Read lower_triangular_distance_matrix.csv file where the separator is a ','
- from_lower_triangular = read_lower_triangular_matrix_from_csv_file<double>("lower_triangular_distance_matrix.csv",
+ from_lower_triangular = Gudhi::read_lower_triangular_matrix_from_csv_file<double>("lower_triangular_distance_matrix.csv",
',');
for (auto& i : from_lower_triangular) {
for (auto j : i) {
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE( full_square_distance_matrix )
{
Distance_matrix from_full_square;
// Read full_square_distance_matrix.csv file where the separator is the default one ';'
- from_full_square = read_lower_triangular_matrix_from_csv_file<double>("full_square_distance_matrix.csv");
+ from_full_square = Gudhi::read_lower_triangular_matrix_from_csv_file<double>("full_square_distance_matrix.csv");
for (auto& i : from_full_square) {
for (auto j : i) {
std::cout << j << " ";
diff --git a/src/common/test/test_persistence_intervals_reader.cpp b/src/common/test/test_persistence_intervals_reader.cpp
new file mode 100644
index 00000000..be299376
--- /dev/null
+++ b/src/common/test/test_persistence_intervals_reader.cpp
@@ -0,0 +1,322 @@
+/* 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) 2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <gudhi/reader_utils.h>
+
+#include <iostream>
+#include <vector>
+#include <utility> // for pair
+#include <tuple>
+#include <limits> // for inf
+#include <map>
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "persistence_intervals_reader"
+#include <boost/test/unit_test.hpp>
+
+using Persistence_intervals_by_dimension = std::map<int, std::vector<std::pair<double, double>>>;
+using Persistence_intervals = std::vector<std::pair<double, double>>;
+// Test files with only 2 parameters (persistence birth and death) per line in file
+BOOST_AUTO_TEST_CASE( persistence_intervals_without_dimension )
+{
+ Persistence_intervals_by_dimension expected_intervals_by_dimension;
+ expected_intervals_by_dimension[-1].push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_by_dimension[-1].push_back(std::make_pair(9.6, 14.));
+ expected_intervals_by_dimension[-1].push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_by_dimension[-1].push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals_by_dimension persistence_intervals_by_dimension =
+ Gudhi::read_persistence_intervals_grouped_by_dimension("persistence_intervals_without_dimension.pers");
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - expected\n";
+ for (auto map_iter : expected_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - read\n";
+ for (auto map_iter : persistence_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ BOOST_CHECK(persistence_intervals_by_dimension == expected_intervals_by_dimension);
+
+ Persistence_intervals expected_intervals_in_dimension;
+ expected_intervals_in_dimension.push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_in_dimension.push_back(std::make_pair(9.6, 14.));
+ expected_intervals_in_dimension.push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_in_dimension.push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_without_dimension.pers");
+
+ std::cout << "\nread_persistence_intervals_in_dimension - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension - read\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_without_dimension.pers", 0);
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_without_dimension.pers", 1);
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_without_dimension.pers", 2);
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_without_dimension.pers", 3);
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+}
+// Test files with 3 parameters (dimension birth death) per line in file
+BOOST_AUTO_TEST_CASE( persistence_intervals_with_dimension )
+{
+ Persistence_intervals_by_dimension expected_intervals_by_dimension;
+ expected_intervals_by_dimension[0].push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_by_dimension[1].push_back(std::make_pair(9.6, 14.));
+ expected_intervals_by_dimension[3].push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_by_dimension[1].push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals_by_dimension persistence_intervals_by_dimension =
+ Gudhi::read_persistence_intervals_grouped_by_dimension("persistence_intervals_with_dimension.pers");
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - expected\n";
+ for (auto map_iter : expected_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - read\n";
+ for (auto map_iter : persistence_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ BOOST_CHECK(persistence_intervals_by_dimension == expected_intervals_by_dimension);
+
+ Persistence_intervals expected_intervals_in_dimension;
+ expected_intervals_in_dimension.push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_in_dimension.push_back(std::make_pair(9.6, 14.));
+ expected_intervals_in_dimension.push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_in_dimension.push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_dimension.pers");
+
+ std::cout << "\nread_persistence_intervals_in_dimension - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(2.7, 3.7));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_dimension.pers", 0);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 0 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 0 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(9.6, 14.));
+ expected_intervals_in_dimension.push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_dimension.pers", 1);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 1 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 1 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_dimension.pers", 2);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 2 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 2 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(34.2, 34.974));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_dimension.pers", 3);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 3 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 3 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+}
+
+// Test files with 4 parameters (field dimension birth death) per line in file
+BOOST_AUTO_TEST_CASE( persistence_intervals_with_field )
+{
+ Persistence_intervals_by_dimension expected_intervals_by_dimension;
+ expected_intervals_by_dimension[0].push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_by_dimension[1].push_back(std::make_pair(9.6, 14.));
+ expected_intervals_by_dimension[3].push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_by_dimension[1].push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals_by_dimension persistence_intervals_by_dimension =
+ Gudhi::read_persistence_intervals_grouped_by_dimension("persistence_intervals_with_field.pers");
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - expected\n";
+ for (auto map_iter : expected_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ std::cout << "\nread_persistence_intervals_grouped_by_dimension - read\n";
+ for (auto map_iter : persistence_intervals_by_dimension) {
+ std::cout << "key=" << map_iter.first;
+ for (auto vec_iter : map_iter.second)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+ }
+
+ BOOST_CHECK(persistence_intervals_by_dimension == expected_intervals_by_dimension);
+
+ Persistence_intervals expected_intervals_in_dimension;
+ expected_intervals_in_dimension.push_back(std::make_pair(2.7, 3.7));
+ expected_intervals_in_dimension.push_back(std::make_pair(9.6, 14.));
+ expected_intervals_in_dimension.push_back(std::make_pair(34.2, 34.974));
+ expected_intervals_in_dimension.push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+
+ Persistence_intervals persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_field.pers");
+
+ std::cout << "\nread_persistence_intervals_in_dimension - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(2.7, 3.7));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_field.pers", 0);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 0 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 0 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(9.6, 14.));
+ expected_intervals_in_dimension.push_back(std::make_pair(3., std::numeric_limits<double>::infinity()));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_field.pers", 1);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 1 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 1 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_field.pers", 2);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 2 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 2 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+ expected_intervals_in_dimension.clear();
+ expected_intervals_in_dimension.push_back(std::make_pair(34.2, 34.974));
+ persistence_intervals_in_dimension =
+ Gudhi::read_persistence_intervals_in_dimension("persistence_intervals_with_field.pers", 3);
+
+ std::cout << "\nread_persistence_intervals_in_dimension 3 - expected\n";
+ for (auto vec_iter : expected_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ std::cout << "\nread_persistence_intervals_in_dimension 3 - read\n";
+ for (auto vec_iter : persistence_intervals_in_dimension)
+ std::cout << " [" << vec_iter.first << " ," << vec_iter.second << "] ";
+
+ BOOST_CHECK(persistence_intervals_in_dimension == expected_intervals_in_dimension);
+
+}
diff --git a/src/common/utilities/CMakeLists.txt b/src/common/utilities/CMakeLists.txt
new file mode 100644
index 00000000..b3e4b436
--- /dev/null
+++ b/src/common/utilities/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 2.6)
+project(off_file_from_shape_generator)
+
+if (NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
+ add_executable ( off_file_from_shape_generator off_file_from_shape_generator.cpp )
+ add_test(NAME off_file_from_shape_generator_on_sphere_1000_3_15.2 COMMAND $<TARGET_FILE:off_file_from_shape_generator>
+ "on" "sphere" "onSphere.off" "1000" "3" "15.2")
+ add_test(NAME off_file_from_shape_generator_in_sphere_100_2 COMMAND $<TARGET_FILE:off_file_from_shape_generator>
+ "in" "sphere" "inSphere.off" "100" "2")
+
+ # on cube is not available in CGAL
+ add_test(NAME off_file_from_shape_generator_in_cube_10000_3_5.8 COMMAND $<TARGET_FILE:off_file_from_shape_generator>
+ "in" "cube" "inCube.off" "10000" "3" "5.8")
+
+ install(TARGETS off_file_from_shape_generator DESTINATION bin)
+
+endif(NOT CGAL_WITH_EIGEN3_VERSION VERSION_LESS 4.6.0)
diff --git a/src/common/utilities/README b/src/common/utilities/README
new file mode 100644
index 00000000..dc841521
--- /dev/null
+++ b/src/common/utilities/README
@@ -0,0 +1,19 @@
+======================= off_file_from_shape_generator ==================================
+
+Example of use :
+
+*** on|in sphere|cube|curve|torus|klein generator
+
+./off_file_from_shape_generator on sphere onSphere.off 1000 3 15.2
+
+ => generates a onSphere.off file with 1000 points randomized on a sphere of dimension 3 and radius 15.2
+
+./off_file_from_shape_generator in sphere inSphere.off 100 2
+
+ => generates a inSphere.off file with 100 points randomized in a sphere of dimension 2 (circle) and radius 1.0 (default)
+
+./off_file_from_shape_generator in cube inCube.off 10000 3 5.8
+
+ => generates a inCube.off file with 10000 points randomized in a cube of dimension 3 and side 5.8
+
+!! Warning: hypegenerator on cube is not available !!
diff --git a/src/common/utilities/off_file_from_shape_generator.cpp b/src/common/utilities/off_file_from_shape_generator.cpp
new file mode 100644
index 00000000..afcd558c
--- /dev/null
+++ b/src/common/utilities/off_file_from_shape_generator.cpp
@@ -0,0 +1,189 @@
+/* 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) 2014 INRIA Saclay (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/>.
+ */
+
+#include <gudhi/random_point_generators.h>
+
+#include <CGAL/Epick_d.h>
+#include <CGAL/algorithm.h>
+#include <CGAL/assertions.h>
+
+#include <iostream>
+#include <iterator>
+#include <vector>
+#include <fstream> // for std::ofstream
+#include <cstdlib>
+
+typedef CGAL::Epick_d< CGAL::Dynamic_dimension_tag > K;
+typedef K::Point_d Point;
+
+void usage(char * const progName) {
+ std::cerr << "Usage: " << progName << " in|on sphere|cube off_file_name points_number[integer > 0] " <<
+ "dimension[integer > 1] radius[double > 0.0 | default = 1.0]" << std::endl;
+ exit(-1);
+}
+
+int main(int argc, char **argv) {
+ // program args management
+ if ((argc != 6) && (argc != 7)) {
+ std::cerr << "Error: Number of arguments (" << argc << ") is not correct" << std::endl;
+ usage(argv[0]);
+ }
+
+ int points_number = atoi(argv[4]);
+ if (points_number <= 0) {
+ std::cerr << "Error: " << argv[4] << " is not correct" << std::endl;
+ usage(argv[0]);
+ }
+
+ int dimension = atoi(argv[5]);
+ if (dimension <= 0) {
+ std::cerr << "Error: " << argv[5] << " is not correct" << std::endl;
+ usage(argv[0]);
+ }
+
+ double radius = 1.0;
+ if (argc == 7) {
+ radius = atof(argv[6]);
+ if (radius <= 0.0) {
+ std::cerr << "Error: " << argv[6] << " is not correct" << std::endl;
+ usage(argv[0]);
+ }
+ }
+
+ bool in = false;
+ if (strcmp(argv[1], "in") == 0) {
+ in = true;
+ } else if (strcmp(argv[1], "on") != 0) {
+ std::cerr << "Error: " << argv[1] << " is not correct" << std::endl;
+ usage(argv[0]);
+ }
+
+ enum class Data_shape { sphere, cube, curve, torus, klein, undefined};
+
+ Data_shape shape = Data_shape::undefined;
+ if (memcmp(argv[2], "sphere", sizeof("sphere")) == 0) {
+ shape = Data_shape::sphere;
+ } else if (memcmp(argv[2], "cube", sizeof("cube")) == 0) {
+ shape = Data_shape::cube;
+ } else if (memcmp(argv[2], "curve", sizeof("curve")) == 0) {
+ shape = Data_shape::curve;
+ } else if (memcmp(argv[2], "torus", sizeof("torus")) == 0) {
+ shape = Data_shape::torus;
+ } else if (memcmp(argv[2], "klein", sizeof("klein")) == 0) {
+ shape = Data_shape::klein;
+ } else {
+ std::cerr << "Error: " << argv[2] << " is not correct" << std::endl;
+ usage(argv[0]);
+ }
+
+ std::ofstream diagram_out(argv[3]);
+ if (dimension == 3) {
+ diagram_out << "OFF" << std::endl;
+ diagram_out << points_number << " 0 0" << std::endl;
+ } else {
+ diagram_out << "nOFF" << std::endl;
+ diagram_out << dimension << " " << points_number << " 0 0" << std::endl;
+ }
+
+ if (diagram_out.is_open()) {
+ // Generate "points_number" random points in a vector
+ std::vector<Point> points;
+ if (in) {
+ switch (shape) {
+ case Data_shape::sphere:
+ points = Gudhi::generate_points_in_ball_d<K>(points_number, dimension, radius);
+ break;
+ case Data_shape::cube:
+ points = Gudhi::generate_points_in_ball_d<K>(points_number, dimension, radius);
+ break;
+ case Data_shape::curve:
+ std::cerr << "Sorry: in curve is not available" << std::endl;
+ usage(argv[0]);
+ break;
+ case Data_shape::torus:
+ std::cerr << "Sorry: in torus is not available" << std::endl;
+ usage(argv[0]);
+ break;
+ case Data_shape::klein:
+ std::cerr << "Sorry: in klein is not available" << std::endl;
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ } else { // means "on"
+ switch (shape) {
+ case Data_shape::sphere:
+ points = Gudhi::generate_points_on_sphere_d<K>(points_number, dimension, radius);
+ break;
+ case Data_shape::cube:
+ std::cerr << "Sorry: on cube is not available" << std::endl;
+ usage(argv[0]);
+ break;
+ case Data_shape::curve:
+ points = Gudhi::generate_points_on_moment_curve<K>(points_number, dimension, -radius/2., radius/2.);
+ break;
+ case Data_shape::torus:
+ if (dimension == 3)
+ points = Gudhi::generate_points_on_torus_3D<K>(points_number, dimension, radius, radius/2.);
+ else
+ points = Gudhi::generate_points_on_torus_d<K>(points_number, dimension, true);
+ break;
+ case Data_shape::klein:
+ switch (dimension) {
+ case 3:
+ points = Gudhi::generate_points_on_klein_bottle_3D<K>(points_number, radius, radius/2., true);
+ break;
+ case 4:
+ points = Gudhi::generate_points_on_klein_bottle_4D<K>(points_number, radius, radius/2., 0., true);
+ break;
+ case 5:
+ points = Gudhi::generate_points_on_klein_bottle_variant_5D<K>(points_number, radius, radius/2., true);
+ break;
+ default:
+ std::cerr << "Sorry: on klein is only available for dimension 3, 4 and 5" << std::endl;
+ usage(argv[0]);
+ break;
+ }
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ for (auto thePoint : points) {
+ int i = 0;
+ for (; i < dimension - 1; i++) {
+ diagram_out << thePoint[i] << " ";
+ }
+ diagram_out << thePoint[i] << std::endl; // last point + Carriage Return
+ }
+ } else {
+ std::cerr << "Error: " << argv[3] << " cannot be opened" << std::endl;
+ usage(argv[0]);
+ }
+
+ return 0;
+}
+