Correct C++ update + reorganizing Module bindings - #64
Conversation
|
@codex review this PR |
There was a problem hiding this comment.
💡 Codex Review
https://github.com/DavidLapous/multipers/blob/d50dbc275f968120cd0d981a340e2cc88fb83403/multiparameter_module_approximation.py#L778-L780
Skip empty tuple components before degree merge
When tuple inputs mix a valid minpres slicer with an empty slicer that has minpres_degree == -1, the earlier all(...) check still accepts it via len(s) == 0, but this direct merge now passes -1 into the C++ merge(..., int) binding, which rejects negative degrees before seeing that the module is empty. The previous m.get_module_of_degree(-1) path produced an empty module, so these partially empty batches now fail instead of ignoring the empty component.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| static Box_t get_flat_box_from_tensor(Tensor2D box) { | ||
| Numpy_2d_span boxView(box); | ||
| auto lowerView = boxView[0]; | ||
| auto upperView = boxView[1]; |
There was a problem hiding this comment.
Validate box arrays before indexing both corners
For public calls such as mod.box = np.zeros((1, n)) or constructing a module from a malformed box array, this helper blindly indexes row 1 after wrapping the tensor. The old setter validated that a box has exactly two corners with matching dimensions; without the check, a one-row array can read past the view/crash and a three-row array is silently accepted with the extra corner ignored.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This should be handled better now in commit c1186f8.
I found that the behaviour accepting without reacting a negative dimension argument is prone to errors which are difficult to track when debugging. But it makes indeed loop mechanism less straight forward. @DavidLapous Do you prefer I replace for i, m in enumerate(modules):
mod.merge(
m, input[i].minpres_degree
)with for i, m in enumerate(modules):
if input[i].minpres_degree >= 0:
mod.merge(
m, input[i].minpres_degree
)? |
|
I think it's more a Also, could the lifetime of the box be binded to the life of the Module by transfering the ownership of the box to module? |
I guess, if the box is a numpy array, you could theoretically move ownership of the data. But it is a bit unsafe and a box is not that big to copy. Also, by copying the way it is done, you are sure to have something C-ordered and continuous. By taking ownership of the data, I would also need to copy the stride and the shape to be sure it always works. Again, feasible, but I am not sure worth the trouble in this particular case. |
| } | ||
| Module<value_type> out; | ||
| box.inflate(2 * precision); // for infinte summands | ||
| // box.inflate(2 * precision); // for infinte summands |
There was a problem hiding this comment.
the inflation is necessary to handle essential summands in the MMA algo, is there a reason to comment this?
There was a problem hiding this comment.
Because this inflation had no impact on the MMA algorithm. This box was not used after inflation in the rest of the algorithm before the latest changes from the box being moved outside of Module... So either, a bug was introduced way before and the inflation should have been done before copying into the module, or this line should have been removed before doing the latest changes (you did by updating the submodule commit number before I finished the changes).
|
|
||
| template <typename Desc, typename Wrapper, typename Value> | ||
| nb::tuple compute_persistence_on_slices(Wrapper& self, | ||
| const nb::ndarray<const Value, nb::ndim<2>, nb::any_contig>& values, |
There was a problem hiding this comment.
I think I want to enforce c_contig to all nanobind interface if I can, but I can deal with that later
There was a problem hiding this comment.
There is a api.asarray(...,contiguous=True) IIRC for this
There was a problem hiding this comment.
If you want, but the Numpy_2d_span can handle non contiguous data (as long as coherently non-contiguous like numpy arrays are). So it is not really necessary here.
| } | ||
|
|
||
| template <typename T> | ||
| nb::tuple to_flat_idx_impl(const Gudhi::multi_persistence::Module<T>& module, const std::vector<std::vector<T>>& grid) { |
There was a problem hiding this comment.
I want to keep this function as it's necessary for autodiff (although a reasonable interface is not there yet)
There was a problem hiding this comment.
The method was added back in the last commit. But as it is used nowhere, I could not test it. Could you give me a small script or notebook I could use to test it in the meantime? Otherwise I could add a small unit test on a 3 x 10 grid or similar to have at least something.
Edit: Added a small test in test_mma.py.
For homogeneity, I would do the same for
SummandandBoxas a next step. Are there some methods you would like to add to the bindings of those two classes, while I am at it? (by default I will at least add__setstate__/__getstate__for both)Note that I added the method
summands_of_dimension_rangeto the Module bindings (to use likefor s in mod.summands_of_dimension_range(d): ...), which you could use instead ofget_module_of_degreeif no copy is needed.And please verify that I didn't forgot to add the latest changes you made to the Module bindings.
Edit: Did the changes for the
SummandandBoxbindings in this PR in the end as it was quick.For the changes in the
AIDA.ipynbnotebook, I just replaced the end of box 15 with: