multipers 2.3.0__cp310-cp310-win_amd64.whl → 2.3.2b1__cp310-cp310-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of multipers might be problematic. Click here for more details.

Files changed (54) hide show
  1. multipers/_signed_measure_meta.py +71 -65
  2. multipers/array_api/__init__.py +39 -0
  3. multipers/array_api/numpy.py +34 -0
  4. multipers/array_api/torch.py +35 -0
  5. multipers/distances.py +6 -2
  6. multipers/{ml/convolutions.py → filtrations/density.py} +67 -13
  7. multipers/filtrations/filtrations.py +76 -17
  8. multipers/function_rips.cp310-win_amd64.pyd +0 -0
  9. multipers/grids.cp310-win_amd64.pyd +0 -0
  10. multipers/grids.pyx +144 -61
  11. multipers/gudhi/Simplex_tree_multi_interface.h +36 -1
  12. multipers/gudhi/gudhi/Multi_persistence/Box.h +3 -0
  13. multipers/gudhi/gudhi/One_critical_filtration.h +18 -9
  14. multipers/gudhi/mma_interface_h0.h +1 -1
  15. multipers/gudhi/mma_interface_matrix.h +10 -1
  16. multipers/gudhi/naive_merge_tree.h +1 -1
  17. multipers/gudhi/truc.h +555 -42
  18. multipers/io.cp310-win_amd64.pyd +0 -0
  19. multipers/io.pyx +26 -93
  20. multipers/ml/mma.py +3 -3
  21. multipers/ml/point_clouds.py +2 -2
  22. multipers/ml/signed_measures.py +63 -65
  23. multipers/mma_structures.cp310-win_amd64.pyd +0 -0
  24. multipers/mma_structures.pxd +2 -1
  25. multipers/mma_structures.pyx +56 -16
  26. multipers/mma_structures.pyx.tp +14 -5
  27. multipers/multiparameter_module_approximation/approximation.h +48 -14
  28. multipers/multiparameter_module_approximation.cp310-win_amd64.pyd +0 -0
  29. multipers/multiparameter_module_approximation.pyx +25 -7
  30. multipers/plots.py +2 -1
  31. multipers/point_measure.cp310-win_amd64.pyd +0 -0
  32. multipers/point_measure.pyx +6 -2
  33. multipers/simplex_tree_multi.cp310-win_amd64.pyd +0 -0
  34. multipers/simplex_tree_multi.pxd +1 -0
  35. multipers/simplex_tree_multi.pyx +584 -142
  36. multipers/simplex_tree_multi.pyx.tp +80 -23
  37. multipers/slicer.cp310-win_amd64.pyd +0 -0
  38. multipers/slicer.pxd +799 -197
  39. multipers/slicer.pxd.tp +24 -5
  40. multipers/slicer.pyx +5653 -1426
  41. multipers/slicer.pyx.tp +208 -48
  42. multipers/tbb12.dll +0 -0
  43. multipers/tbbbind_2_5.dll +0 -0
  44. multipers/tbbmalloc.dll +0 -0
  45. multipers/tbbmalloc_proxy.dll +0 -0
  46. multipers/tensor/tensor.h +1 -1
  47. multipers/tests/__init__.py +9 -4
  48. multipers/torch/diff_grids.py +30 -7
  49. multipers/torch/rips_density.py +1 -1
  50. {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/METADATA +4 -25
  51. {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/RECORD +54 -51
  52. {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/WHEEL +1 -1
  53. {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info/licenses}/LICENSE +0 -0
  54. {multipers-2.3.0.dist-info → multipers-2.3.2b1.dist-info}/top_level.txt +0 -0
@@ -97,6 +97,11 @@ cdef class PySummand_f64:
97
97
  return v[0].num_parameters()
98
98
  v = self.sum.get_death_list()
99
99
  return v[0].num_parameters()
100
+ def __eq__(self, PySummand_f64 other):
101
+ return self.sum == other.sum
102
+
103
+
104
+
100
105
 
101
106
  cdef inline get_summand_filtration_values_f64(Summand[double] summand):
102
107
  r"""
@@ -161,6 +166,10 @@ cdef class PyModule_f64:
161
166
 
162
167
  cdef set(self, Module[double] m):
163
168
  self.cmod = m
169
+
170
+ def __eq__(self, PyModule_f64 other):
171
+ return self.cmod == other.cmod
172
+
164
173
  def merge(self, PyModule_f64 other, int dim=-1):
165
174
  r"""
166
175
  Merges two modules into one
@@ -176,7 +185,9 @@ cdef class PyModule_f64:
176
185
  Copy module from a memory pointer. Unsafe.
177
186
  """
178
187
  self.cmod = move(dereference(<Module[double]*>(module_ptr)))
179
- def set_box(self, PyBox_f64 pybox):
188
+ def set_box(self, box):
189
+ assert len(box) == 2, "Box format is [low, hight]"
190
+ pybox = PyBox_f64(box[0], box[1])
180
191
  cdef Box[double] cbox = pybox.box
181
192
  with nogil:
182
193
  self.cmod.set_box(cbox)
@@ -580,7 +591,6 @@ cdef class PyModule_f64:
580
591
  cdef Box[double] c_box = Box[double](box)
581
592
  out = np.array(self.cmod.get_landscape(degree, k, c_box, resolution))
582
593
  if plot:
583
- plt.figure()
584
594
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
585
595
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
586
596
  plt.imshow(out.T, origin="lower", extent=extent, aspect=aspect)
@@ -614,7 +624,6 @@ cdef class PyModule_f64:
614
624
  out = np.array(self.cmod.get_landscapes(degree, ks, Box[double](box), resolution))
615
625
  if plot:
616
626
  to_plot = np.sum(out, axis=0)
617
- plt.figure()
618
627
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
619
628
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
620
629
  plt.imshow(to_plot.T, origin="lower", extent=extent, aspect=aspect)
@@ -961,8 +970,8 @@ cdef dump_summand_f64(Summand[double]& summand):
961
970
  cdef vector[One_critical_filtration[double]] births = summand.get_birth_list()
962
971
  cdef vector[One_critical_filtration[double]] deaths = summand.get_death_list()
963
972
  return (
964
- _vff21cview_f64(births, copy=True), ## copy as local variables
965
- _vff21cview_f64(deaths, copy=True),
973
+ np.array(_vff21cview_f64(births)),
974
+ np.array(_vff21cview_f64(deaths)),
966
975
  summand.get_dimension(),
967
976
  )
968
977
 
@@ -1049,6 +1058,11 @@ cdef class PySummand_f32:
1049
1058
  return v[0].num_parameters()
1050
1059
  v = self.sum.get_death_list()
1051
1060
  return v[0].num_parameters()
1061
+ def __eq__(self, PySummand_f32 other):
1062
+ return self.sum == other.sum
1063
+
1064
+
1065
+
1052
1066
 
1053
1067
  cdef inline get_summand_filtration_values_f32(Summand[float] summand):
1054
1068
  r"""
@@ -1113,6 +1127,10 @@ cdef class PyModule_f32:
1113
1127
 
1114
1128
  cdef set(self, Module[float] m):
1115
1129
  self.cmod = m
1130
+
1131
+ def __eq__(self, PyModule_f32 other):
1132
+ return self.cmod == other.cmod
1133
+
1116
1134
  def merge(self, PyModule_f32 other, int dim=-1):
1117
1135
  r"""
1118
1136
  Merges two modules into one
@@ -1128,7 +1146,9 @@ cdef class PyModule_f32:
1128
1146
  Copy module from a memory pointer. Unsafe.
1129
1147
  """
1130
1148
  self.cmod = move(dereference(<Module[float]*>(module_ptr)))
1131
- def set_box(self, PyBox_f32 pybox):
1149
+ def set_box(self, box):
1150
+ assert len(box) == 2, "Box format is [low, hight]"
1151
+ pybox = PyBox_f32(box[0], box[1])
1132
1152
  cdef Box[float] cbox = pybox.box
1133
1153
  with nogil:
1134
1154
  self.cmod.set_box(cbox)
@@ -1532,7 +1552,6 @@ cdef class PyModule_f32:
1532
1552
  cdef Box[float] c_box = Box[float](box)
1533
1553
  out = np.array(self.cmod.get_landscape(degree, k, c_box, resolution))
1534
1554
  if plot:
1535
- plt.figure()
1536
1555
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
1537
1556
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
1538
1557
  plt.imshow(out.T, origin="lower", extent=extent, aspect=aspect)
@@ -1566,7 +1585,6 @@ cdef class PyModule_f32:
1566
1585
  out = np.array(self.cmod.get_landscapes(degree, ks, Box[float](box), resolution))
1567
1586
  if plot:
1568
1587
  to_plot = np.sum(out, axis=0)
1569
- plt.figure()
1570
1588
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
1571
1589
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
1572
1590
  plt.imshow(to_plot.T, origin="lower", extent=extent, aspect=aspect)
@@ -1913,8 +1931,8 @@ cdef dump_summand_f32(Summand[float]& summand):
1913
1931
  cdef vector[One_critical_filtration[float]] births = summand.get_birth_list()
1914
1932
  cdef vector[One_critical_filtration[float]] deaths = summand.get_death_list()
1915
1933
  return (
1916
- _vff21cview_f32(births, copy=True), ## copy as local variables
1917
- _vff21cview_f32(deaths, copy=True),
1934
+ np.array(_vff21cview_f32(births)),
1935
+ np.array(_vff21cview_f32(deaths)),
1918
1936
  summand.get_dimension(),
1919
1937
  )
1920
1938
 
@@ -2001,6 +2019,11 @@ cdef class PySummand_i32:
2001
2019
  return v[0].num_parameters()
2002
2020
  v = self.sum.get_death_list()
2003
2021
  return v[0].num_parameters()
2022
+ def __eq__(self, PySummand_i32 other):
2023
+ return self.sum == other.sum
2024
+
2025
+
2026
+
2004
2027
 
2005
2028
  cdef inline get_summand_filtration_values_i32(Summand[int32_t] summand):
2006
2029
  r"""
@@ -2065,6 +2088,10 @@ cdef class PyModule_i32:
2065
2088
 
2066
2089
  cdef set(self, Module[int32_t] m):
2067
2090
  self.cmod = m
2091
+
2092
+ def __eq__(self, PyModule_i32 other):
2093
+ return self.cmod == other.cmod
2094
+
2068
2095
  def merge(self, PyModule_i32 other, int dim=-1):
2069
2096
  r"""
2070
2097
  Merges two modules into one
@@ -2080,7 +2107,9 @@ cdef class PyModule_i32:
2080
2107
  Copy module from a memory pointer. Unsafe.
2081
2108
  """
2082
2109
  self.cmod = move(dereference(<Module[int32_t]*>(module_ptr)))
2083
- def set_box(self, PyBox_i32 pybox):
2110
+ def set_box(self, box):
2111
+ assert len(box) == 2, "Box format is [low, hight]"
2112
+ pybox = PyBox_i32(box[0], box[1])
2084
2113
  cdef Box[int32_t] cbox = pybox.box
2085
2114
  with nogil:
2086
2115
  self.cmod.set_box(cbox)
@@ -2281,8 +2310,8 @@ cdef dump_summand_i32(Summand[int32_t]& summand):
2281
2310
  cdef vector[One_critical_filtration[int32_t]] births = summand.get_birth_list()
2282
2311
  cdef vector[One_critical_filtration[int32_t]] deaths = summand.get_death_list()
2283
2312
  return (
2284
- _vff21cview_i32(births, copy=True), ## copy as local variables
2285
- _vff21cview_i32(deaths, copy=True),
2313
+ np.array(_vff21cview_i32(births)),
2314
+ np.array(_vff21cview_i32(deaths)),
2286
2315
  summand.get_dimension(),
2287
2316
  )
2288
2317
 
@@ -2369,6 +2398,11 @@ cdef class PySummand_i64:
2369
2398
  return v[0].num_parameters()
2370
2399
  v = self.sum.get_death_list()
2371
2400
  return v[0].num_parameters()
2401
+ def __eq__(self, PySummand_i64 other):
2402
+ return self.sum == other.sum
2403
+
2404
+
2405
+
2372
2406
 
2373
2407
  cdef inline get_summand_filtration_values_i64(Summand[int64_t] summand):
2374
2408
  r"""
@@ -2433,6 +2467,10 @@ cdef class PyModule_i64:
2433
2467
 
2434
2468
  cdef set(self, Module[int64_t] m):
2435
2469
  self.cmod = m
2470
+
2471
+ def __eq__(self, PyModule_i64 other):
2472
+ return self.cmod == other.cmod
2473
+
2436
2474
  def merge(self, PyModule_i64 other, int dim=-1):
2437
2475
  r"""
2438
2476
  Merges two modules into one
@@ -2448,7 +2486,9 @@ cdef class PyModule_i64:
2448
2486
  Copy module from a memory pointer. Unsafe.
2449
2487
  """
2450
2488
  self.cmod = move(dereference(<Module[int64_t]*>(module_ptr)))
2451
- def set_box(self, PyBox_i64 pybox):
2489
+ def set_box(self, box):
2490
+ assert len(box) == 2, "Box format is [low, hight]"
2491
+ pybox = PyBox_i64(box[0], box[1])
2452
2492
  cdef Box[int64_t] cbox = pybox.box
2453
2493
  with nogil:
2454
2494
  self.cmod.set_box(cbox)
@@ -2649,8 +2689,8 @@ cdef dump_summand_i64(Summand[int64_t]& summand):
2649
2689
  cdef vector[One_critical_filtration[int64_t]] births = summand.get_birth_list()
2650
2690
  cdef vector[One_critical_filtration[int64_t]] deaths = summand.get_death_list()
2651
2691
  return (
2652
- _vff21cview_i64(births, copy=True), ## copy as local variables
2653
- _vff21cview_i64(deaths, copy=True),
2692
+ np.array(_vff21cview_i64(births)),
2693
+ np.array(_vff21cview_i64(deaths)),
2654
2694
  summand.get_dimension(),
2655
2695
  )
2656
2696
 
@@ -118,6 +118,11 @@ cdef class PySummand_{{SHORT}}:
118
118
  return v[0].num_parameters()
119
119
  v = self.sum.get_death_list()
120
120
  return v[0].num_parameters()
121
+ def __eq__(self, PySummand_{{SHORT}} other):
122
+ return self.sum == other.sum
123
+
124
+
125
+
121
126
 
122
127
  cdef inline get_summand_filtration_values_{{SHORT}}(Summand[{{CTYPE}}] summand):
123
128
  r"""
@@ -182,6 +187,10 @@ cdef class PyModule_{{SHORT}}:
182
187
 
183
188
  cdef set(self, Module[{{CTYPE}}] m):
184
189
  self.cmod = m
190
+
191
+ def __eq__(self, PyModule_{{SHORT}} other):
192
+ return self.cmod == other.cmod
193
+
185
194
  def merge(self, PyModule_{{SHORT}} other, int dim=-1):
186
195
  r"""
187
196
  Merges two modules into one
@@ -197,7 +206,9 @@ cdef class PyModule_{{SHORT}}:
197
206
  Copy module from a memory pointer. Unsafe.
198
207
  """
199
208
  self.cmod = move(dereference(<Module[{{CTYPE}}]*>(module_ptr)))
200
- def set_box(self, PyBox_{{SHORT}} pybox):
209
+ def set_box(self, box):
210
+ assert len(box) == 2, "Box format is [low, hight]"
211
+ pybox = PyBox_{{SHORT}}(box[0], box[1])
201
212
  cdef Box[{{CTYPE}}] cbox = pybox.box
202
213
  with nogil:
203
214
  self.cmod.set_box(cbox)
@@ -602,7 +613,6 @@ cdef class PyModule_{{SHORT}}:
602
613
  cdef Box[{{CTYPE}}] c_box = Box[{{CTYPE}}](box)
603
614
  out = np.array(self.cmod.get_landscape(degree, k, c_box, resolution))
604
615
  if plot:
605
- plt.figure()
606
616
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
607
617
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
608
618
  plt.imshow(out.T, origin="lower", extent=extent, aspect=aspect)
@@ -636,7 +646,6 @@ cdef class PyModule_{{SHORT}}:
636
646
  out = np.array(self.cmod.get_landscapes(degree, ks, Box[{{CTYPE}}](box), resolution))
637
647
  if plot:
638
648
  to_plot = np.sum(out, axis=0)
639
- plt.figure()
640
649
  aspect = (box[1][0]-box[0][0]) / (box[1][1]-box[0][1])
641
650
  extent = [box[0][0], box[1][0], box[0][1], box[1][1]]
642
651
  plt.imshow(to_plot.T, origin="lower", extent=extent, aspect=aspect)
@@ -984,8 +993,8 @@ cdef dump_summand_{{SHORT}}(Summand[{{CTYPE}}]& summand):
984
993
  cdef vector[One_critical_filtration[{{CTYPE}}]] births = summand.get_birth_list()
985
994
  cdef vector[One_critical_filtration[{{CTYPE}}]] deaths = summand.get_death_list()
986
995
  return (
987
- _vff21cview_{{SHORT}}(births, copy=True), ## copy as local variables
988
- _vff21cview_{{SHORT}}(deaths, copy=True),
996
+ np.array(_vff21cview_{{SHORT}}(births)),
997
+ np.array(_vff21cview_{{SHORT}}(deaths)),
989
998
  summand.get_dimension(),
990
999
  )
991
1000
 
@@ -28,6 +28,7 @@
28
28
  #include <limits>
29
29
  #include <oneapi/tbb/parallel_for.h>
30
30
  #include <string>
31
+ #include <type_traits>
31
32
  #include <utility>
32
33
  #include <vector>
33
34
 
@@ -88,6 +89,8 @@ class Module {
88
89
  const bool threshold);
89
90
  typename module_type::iterator begin();
90
91
  typename module_type::iterator end();
92
+ typename module_type::const_iterator begin() const;
93
+ typename module_type::const_iterator end() const;
91
94
 
92
95
  void clean();
93
96
  void fill(const value_type precision);
@@ -192,6 +195,16 @@ class Module {
192
195
 
193
196
  std::vector<int> inline get_degree_splits() const;
194
197
 
198
+ inline friend bool operator==(const Module &a, const Module &b) {
199
+ if (a.get_dimension() != b.get_dimension()) return false;
200
+ if (a.box_ != b.box_) return false;
201
+ if (a.size() != b.size()) return false;
202
+ for (auto i : std::views::iota(0u, a.size())) {
203
+ if (a[i] != b[i]) return false;
204
+ }
205
+ return true;
206
+ }
207
+
195
208
  private:
196
209
  module_type module_;
197
210
  Box<value_type> box_;
@@ -281,6 +294,10 @@ class Summand {
281
294
  // std::swap(sum1.updateDistance_, sum2.updateDistance_);
282
295
  };
283
296
 
297
+ friend bool operator==(const Summand &a, const Summand &b) {
298
+ return a.dimension_ == b.dimension_ && a.birth_corners_ == b.birth_corners_ && a.death_corners_ == b.death_corners_;
299
+ }
300
+
284
301
  bool contains(const filtration_type &x) const;
285
302
 
286
303
  inline Box<value_type> get_bounds() const {
@@ -812,11 +829,21 @@ inline typename Module<value_type>::module_type::iterator Module<value_type>::be
812
829
  return module_.begin();
813
830
  }
814
831
 
832
+ template <typename value_type>
833
+ inline typename Module<value_type>::module_type::const_iterator Module<value_type>::begin() const {
834
+ return module_.cbegin();
835
+ }
836
+
815
837
  template <typename value_type>
816
838
  inline typename Module<value_type>::module_type::iterator Module<value_type>::end() {
817
839
  return module_.end();
818
840
  }
819
841
 
842
+ template <typename value_type>
843
+ inline typename Module<value_type>::module_type::const_iterator Module<value_type>::end() const {
844
+ return module_.cend();
845
+ }
846
+
820
847
  template <typename value_type>
821
848
  inline void Module<value_type>::add_summand(Summand<value_type> summand, int degree) {
822
849
  if (degree >= 0) summand.set_dimension(degree);
@@ -2046,14 +2073,16 @@ const Gudhi::multi_filtration::Multi_critical_filtration<value_type> &Summand<va
2046
2073
 
2047
2074
  template <typename value_type>
2048
2075
  inline void Summand<value_type>::clean() {
2049
- // birth_corners_.erase(
2050
- // std::remove_if(birth_corners_.begin(), birth_corners_.end(),
2051
- // [](const std::vector<value_type> &bp) {
2052
- // return std::any_of(
2053
- // bp.begin(), bp.end(),
2054
- // [](float value) { return !std::isfinite(value); });
2055
- // }),
2056
- // birth_corners_.end());
2076
+ // birth_corners_.erase(std::remove_if(birth_corners_.begin(),
2077
+ // birth_corners_.end(),
2078
+ // [](const std::vector<value_type> &bp) {
2079
+ // // return std::any_of(
2080
+ // // bp.begin(), bp.end(),
2081
+ // // [](float value) { return !std::isfinite(value); });
2082
+ // bp.size() == 0;
2083
+ // }),
2084
+ // birth_corners_.end());
2085
+ // birth_corners_.simplify();
2057
2086
  // TODO : clean
2058
2087
  }
2059
2088
 
@@ -2064,13 +2093,15 @@ inline void Summand<value_type>::complete_birth(const value_type precision) {
2064
2093
  for (std::size_t i = 0; i < birth_corners_.num_generators(); i++) {
2065
2094
  for (std::size_t j = i + 1; j < birth_corners_.num_generators(); j++) {
2066
2095
  value_type dinf = d_inf(birth_corners_[i], birth_corners_[j]);
2067
- if (dinf < 1.1 * precision) {
2096
+ if (dinf < .99 * precision) { // for machine error ?
2068
2097
  _factorize_min(birth_corners_[i], birth_corners_[j]);
2069
- birth_corners_[j].clear();
2098
+ birth_corners_[j] = std::remove_reference_t<decltype(birth_corners_[j])>::inf();
2099
+ i++;
2070
2100
  }
2071
2101
  }
2072
2102
  }
2073
- _clean(birth_corners_);
2103
+ birth_corners_.simplify();
2104
+ // _clean(birth_corners_);
2074
2105
  }
2075
2106
 
2076
2107
  template <typename value_type>
@@ -2080,13 +2111,16 @@ inline void Summand<value_type>::complete_death(const value_type precision) {
2080
2111
  for (std::size_t i = 0; i < death_corners_.num_generators(); i++) {
2081
2112
  for (std::size_t j = i + 1; j < death_corners_.num_generators(); j++) {
2082
2113
  value_type d = d_inf(death_corners_[i], death_corners_[j]);
2083
- if (d < 1.1 * precision) {
2114
+ if (d < .99 * precision) {
2084
2115
  _factorize_max(death_corners_[i], death_corners_[j]);
2085
- death_corners_[j].clear();
2116
+ death_corners_[j] = std::remove_reference_t<decltype(death_corners_[j])>::minus_inf();
2117
+ i++;
2086
2118
  }
2087
2119
  }
2088
2120
  }
2089
- _clean(death_corners_);
2121
+
2122
+ death_corners_.simplify();
2123
+ // _clean(death_corners_);
2090
2124
  }
2091
2125
 
2092
2126
  template <typename value_type>
@@ -14,6 +14,7 @@ import numpy as np
14
14
  from typing import List
15
15
  from joblib import Parallel, delayed
16
16
  import sys
17
+ from warnings import warn
17
18
 
18
19
  ###########################################################################
19
20
  ## CPP CLASSES
@@ -56,15 +57,20 @@ def module_approximation_from_slicer(
56
57
  bool threshold=False,
57
58
  bool verbose=False,
58
59
  list[float] direction = [],
60
+ bool warnings = True,
59
61
  )->PyModule_type:
60
62
 
61
63
  cdef Module[float] mod_f32
62
64
  cdef Module[double] mod_f64
63
65
  cdef intptr_t ptr
64
66
  if not slicer.is_vine:
65
- print(r"Got a non-vine slicer as an input. Use `vineyard=True` to remove this copy.", file=sys.stderr)
67
+ if warnings:
68
+ warn(r"(copy warning) Got a non-vine slicer as an input. Use `vineyard=True` to remove this copy.")
66
69
  from multipers._slicer_meta import Slicer
67
70
  slicer = Slicer(slicer, vineyard=True, backend="matrix")
71
+ if slicer.is_squeezed:
72
+ raise ValueError("Got a squeezed slicer. Should have been unsqueezed before !")
73
+
68
74
  direction_ = np.asarray(direction, dtype=slicer.dtype)
69
75
  if slicer.dtype == np.float32:
70
76
  approx_mod = PyModule_f32()
@@ -89,14 +95,14 @@ def module_approximation(
89
95
  input:Union[SimplexTreeMulti_type,Slicer_type, tuple],
90
96
  box:Optional[np.ndarray]=None,
91
97
  float max_error=-1,
92
- int nlines=500,
98
+ int nlines=557,
93
99
  slicer_backend:Literal["matrix","clement","graph"]="matrix",
94
100
  minpres:Optional[Literal["mpfree"]]=None,
95
101
  degree:Optional[int]=None,
96
102
  bool complete=True,
97
103
  bool threshold=False,
98
104
  bool verbose=False,
99
- bool ignore_warning=False,
105
+ bool ignore_warnings=False,
100
106
  id="",
101
107
  list[float] direction = [],
102
108
  list[int] swap_box_coords = [],
@@ -156,16 +162,23 @@ def module_approximation(
156
162
  if len(input) == 0:
157
163
  return PyModule_f64()
158
164
  if n_jobs <= 1:
159
- modules = tuple(module_approximation(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords) for slicer in input)
165
+ modules = tuple(module_approximation(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warnings, id, direction, swap_box_coords) for slicer in input)
160
166
  else:
161
167
  modules = tuple(Parallel(n_jobs=n_jobs, prefer="threads")(
162
- delayed(module_approximation)(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warning, id, direction, swap_box_coords)
168
+ delayed(module_approximation)(slicer, box, max_error, nlines, slicer_backend, minpres, degree, complete, threshold, verbose, ignore_warnings, id, direction, swap_box_coords)
163
169
  for slicer in input
164
170
  ))
165
171
  mod = PyModule_f64().set_box(PyBox_f64(*modules[0].get_box()))
166
172
  for i,m in enumerate(modules):
167
173
  mod.merge(m, input[i].minpres_degree)
168
174
  return mod
175
+ if len(input) == 0:
176
+ return PyModule_f64()
177
+ if input.is_squeezed:
178
+ if not ignore_warnings:
179
+ warn("(copy warning) Got a squeezed input. ")
180
+ input = input.unsqueeze()
181
+
169
182
  if box is None:
170
183
  if is_simplextree_multi(input):
171
184
  box = input.filtration_bounds()
@@ -190,11 +203,16 @@ def module_approximation(
190
203
  if max_error <= 0:
191
204
  max_error = (prod/nlines)**(1/(num_parameters-1))
192
205
 
193
- if not ignore_warning and prod >= 10_000:
206
+ if not ignore_warnings and prod >= 10_000:
194
207
  raise ValueError(f"""
195
208
  Warning : the number of lines (around {np.round(prod)}) may be too high.
209
+ This may be due to extreme box or filtration bounds :
210
+
211
+ {box=}
212
+
196
213
  Try to increase the precision parameter, or set `ignore_warning=True` to compute this module.
197
- Returning the trivial module."""
214
+ Returning the trivial module.
215
+ """
198
216
  )
199
217
  if is_simplextree_multi(input):
200
218
  from multipers._slicer_meta import Slicer
multipers/plots.py CHANGED
@@ -137,6 +137,7 @@ def plot_signed_measure(signed_measure, threshold=None, ax=None, **plt_kwargs):
137
137
  else:
138
138
  pts_ = pts
139
139
  threshold = np.max(np.ma.masked_invalid(pts_), axis=0)
140
+ threshold = np.max([threshold, [plt.gca().get_xlim()[1], plt.gca().get_ylim()[1]]], axis=0)
140
141
  if isinstance(pts, np.ndarray):
141
142
  pass
142
143
  else:
@@ -254,7 +255,7 @@ def plot2d_PyModule(
254
255
  dimension=-1,
255
256
  separated=False,
256
257
  min_persistence=0,
257
- alpha=1,
258
+ alpha=.8,
258
259
  verbose=False,
259
260
  save=False,
260
261
  dpi=200,
Binary file
@@ -89,6 +89,7 @@ def integrate_measure(
89
89
  grid_strategy:str="regular",
90
90
  resolution:int|list[int]=100,
91
91
  bool return_grid=False,
92
+ bool plot=False,
92
93
  **get_fitration_kwargs,
93
94
  ):
94
95
  """
@@ -126,6 +127,9 @@ def integrate_measure(
126
127
  for i in range(num_pts):
127
128
  cone = tuple(slice(c,r) for r,c in zip(resolution,pts_coords[:,i]))
128
129
  out[cone] += weights[i]
130
+ if plot:
131
+ from multipers.plots import plot_surface
132
+ plot_surface(filtration_grid, out, discrete_surface=True)
129
133
  if return_grid:
130
134
  return out,filtration_grid
131
135
  return out
@@ -211,7 +215,7 @@ def zero_out_sm(pts,weights, mass_default):
211
215
  C = np.concatenate([C, np.ones((C.shape[0],1))], axis=1).astype(np.bool_)
212
216
 
213
217
  # signs of each corner
214
- Cw = 1-2*((~C).sum(axis=1)%2)
218
+ Cw = 1-2*((~C).sum(axis=1) & 1)
215
219
 
216
220
  # something useless in the end to ensure that the shape is correct (as we added 1 in pts)
217
221
  mass_default = np.concatenate([mass_default,[np.nan]])
@@ -299,7 +303,7 @@ def barcode_from_rank_sm(
299
303
  return out
300
304
 
301
305
 
302
- def estimate_rank_from_rank_sm(sm:tuple, a, b) -> int:
306
+ def estimate_rank_from_rank_sm(sm:tuple, a, b)->np.int64:
303
307
  """
304
308
  Given a rank signed measure (sm) and two points (a) and (b),
305
309
  estimates the rank between these two points.
@@ -118,6 +118,7 @@ cdef extern from "Simplex_tree_multi_interface.h" namespace "Gudhi::multiparamet
118
118
  void to_std_linear_projection(intptr_t, vector[double]) nogil
119
119
  void squeeze_filtration_inplace(vector[vector[double]] &, bool) nogil
120
120
  void squeeze_filtration(intptr_t, vector[vector[double]] &) nogil
121
+ void unsqueeze_filtration(intptr_t, vector[vector[double]] &) nogil
121
122
  vector[vector[vector[value_type]]] get_filtration_values(const vector[int]&) nogil
122
123
 
123
124