multipers 2.3.1__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 (49) 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/filtrations/density.py +23 -12
  7. multipers/filtrations/filtrations.py +74 -15
  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 +35 -0
  12. multipers/gudhi/gudhi/Multi_persistence/Box.h +3 -0
  13. multipers/gudhi/gudhi/One_critical_filtration.h +17 -9
  14. multipers/gudhi/mma_interface_matrix.h +5 -3
  15. multipers/gudhi/truc.h +488 -42
  16. multipers/io.cp310-win_amd64.pyd +0 -0
  17. multipers/io.pyx +16 -86
  18. multipers/ml/mma.py +3 -3
  19. multipers/ml/signed_measures.py +60 -62
  20. multipers/mma_structures.cp310-win_amd64.pyd +0 -0
  21. multipers/mma_structures.pxd +2 -1
  22. multipers/mma_structures.pyx +56 -12
  23. multipers/mma_structures.pyx.tp +14 -3
  24. multipers/multiparameter_module_approximation/approximation.h +45 -13
  25. multipers/multiparameter_module_approximation.cp310-win_amd64.pyd +0 -0
  26. multipers/multiparameter_module_approximation.pyx +22 -6
  27. multipers/plots.py +1 -0
  28. multipers/point_measure.cp310-win_amd64.pyd +0 -0
  29. multipers/point_measure.pyx +6 -2
  30. multipers/simplex_tree_multi.cp310-win_amd64.pyd +0 -0
  31. multipers/simplex_tree_multi.pxd +1 -0
  32. multipers/simplex_tree_multi.pyx +487 -109
  33. multipers/simplex_tree_multi.pyx.tp +67 -18
  34. multipers/slicer.cp310-win_amd64.pyd +0 -0
  35. multipers/slicer.pxd +699 -217
  36. multipers/slicer.pxd.tp +22 -6
  37. multipers/slicer.pyx +5311 -1364
  38. multipers/slicer.pyx.tp +199 -46
  39. multipers/tbb12.dll +0 -0
  40. multipers/tbbbind_2_5.dll +0 -0
  41. multipers/tbbmalloc.dll +0 -0
  42. multipers/tbbmalloc_proxy.dll +0 -0
  43. multipers/tests/__init__.py +9 -4
  44. multipers/torch/diff_grids.py +30 -7
  45. {multipers-2.3.1.dist-info → multipers-2.3.2b1.dist-info}/METADATA +4 -25
  46. {multipers-2.3.1.dist-info → multipers-2.3.2b1.dist-info}/RECORD +49 -46
  47. {multipers-2.3.1.dist-info → multipers-2.3.2b1.dist-info}/WHEEL +1 -1
  48. {multipers-2.3.1.dist-info → multipers-2.3.2b1.dist-info/licenses}/LICENSE +0 -0
  49. {multipers-2.3.1.dist-info → multipers-2.3.2b1.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -982,8 +993,8 @@ cdef dump_summand_{{SHORT}}(Summand[{{CTYPE}}]& summand):
982
993
  cdef vector[One_critical_filtration[{{CTYPE}}]] births = summand.get_birth_list()
983
994
  cdef vector[One_critical_filtration[{{CTYPE}}]] deaths = summand.get_death_list()
984
995
  return (
985
- _vff21cview_{{SHORT}}(births, copy=True), ## copy as local variables
986
- _vff21cview_{{SHORT}}(deaths, copy=True),
996
+ np.array(_vff21cview_{{SHORT}}(births)),
997
+ np.array(_vff21cview_{{SHORT}}(deaths)),
987
998
  summand.get_dimension(),
988
999
  )
989
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,14 +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 < .99 * precision) { // for machine error ?
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();
2070
2099
  i++;
2071
2100
  }
2072
2101
  }
2073
2102
  }
2074
- _clean(birth_corners_);
2103
+ birth_corners_.simplify();
2104
+ // _clean(birth_corners_);
2075
2105
  }
2076
2106
 
2077
2107
  template <typename value_type>
@@ -2083,12 +2113,14 @@ inline void Summand<value_type>::complete_death(const value_type precision) {
2083
2113
  value_type d = d_inf(death_corners_[i], death_corners_[j]);
2084
2114
  if (d < .99 * precision) {
2085
2115
  _factorize_max(death_corners_[i], death_corners_[j]);
2086
- death_corners_[j].clear();
2116
+ death_corners_[j] = std::remove_reference_t<decltype(death_corners_[j])>::minus_inf();
2087
2117
  i++;
2088
2118
  }
2089
2119
  }
2090
2120
  }
2091
- _clean(death_corners_);
2121
+
2122
+ death_corners_.simplify();
2123
+ // _clean(death_corners_);
2092
2124
  }
2093
2125
 
2094
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()
@@ -96,7 +102,7 @@ def module_approximation(
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,10 +162,10 @@ 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()))
@@ -168,6 +174,11 @@ def module_approximation(
168
174
  return mod
169
175
  if len(input) == 0:
170
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
+
171
182
  if box is None:
172
183
  if is_simplextree_multi(input):
173
184
  box = input.filtration_bounds()
@@ -192,11 +203,16 @@ def module_approximation(
192
203
  if max_error <= 0:
193
204
  max_error = (prod/nlines)**(1/(num_parameters-1))
194
205
 
195
- if not ignore_warning and prod >= 10_000:
206
+ if not ignore_warnings and prod >= 10_000:
196
207
  raise ValueError(f"""
197
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
+
198
213
  Try to increase the precision parameter, or set `ignore_warning=True` to compute this module.
199
- Returning the trivial module."""
214
+ Returning the trivial module.
215
+ """
200
216
  )
201
217
  if is_simplextree_multi(input):
202
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:
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