Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for dealing with explicit infinite deaths #1

Conversation

ulupo
Copy link
Owner

@ulupo ulupo commented Oct 31, 2021

Even in the case of dense matrices, any bar which has infinity as death must be considered an essential bar. Similarly, for the dimension-0 computation, we must treat an edge with value infinity as non-existent.

We did not notice this so far because we were only printing barcodes, but this mismatch gives mathematically wrong results when we want to return generators.

This is a proposal that does not yet yield the correct results in higher dimensions (and I don't know why).

For example,

diamond_dm = np.array(
    [[0,      1,      np.inf, 1,      1,      1],
     [0,      0,      1,      np.inf, 1,      1],
     [0,      0,      0,      1,      1,      1],
     [0,      0,      0,      0,      1,      1],
     [0,      0,      0,      0,      0,      np.inf],
     [0,      0,      0,      0,      0,      0]],
    dtype=np.float64
)
diamond_dm += diamond_dm.T

res = ripser_parallel(diamond_dm, metric="precomputed", maxdim=2, return_generators=True)

yields the correct barcode

[array([[ 0.,  1.],
        [ 0.,  1.],
        [ 0.,  1.],
        [ 0.,  1.],
        [ 0.,  1.],
        [ 0., inf]]),
 array([], shape=(0, 2), dtype=float64),
 array([[ 1., inf]])]

but the incorrect generators

(array([[5, 5, 3],
        [3, 5, 2],
        [2, 5, 1],
        [1, 5, 0],
        [4, 4, 3]], dtype=int64),
 [array([], shape=(0, 4), dtype=int64), array([[0, 0, 0, 0]], dtype=int64)],
 array([0], dtype=int64),
 [array([], shape=(0, 2), dtype=int64), array([], shape=(0, 2), dtype=int64)])

so I failed to create an essential generator in dimension 2 and created a corrupt finite one instead.

ulupo and others added 30 commits September 24, 2021 15:52
…ices

Currently it should not work

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
…ve simplices

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
for representative simplices

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
…codes

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
…ices

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
test added to verify this behavior

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
The link function now also returns the birth vertex and allows to simplify logic in the computation of 0-dim

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
link method works on the vertex index and the rank of the vertices
but the logic to retrieve the correct birth (value_t) value requires comparison of birth values
that IMO should not be integrated in the link method. To be discussed later
But for the moment I prefer revert this change

Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
- Extract birth using dset.get_birth
- FIXME avoid calling find twice for u and v by using an "unsafe" version of link_and_get_birth_vertex called _link_and_get_birth_vertex
@@ -1562,11 +1585,9 @@ class ripser
std::greater<>());
#endif
for (size_t i = 0; i < idx_essential; ++i) {
if (!std::isinf(essential_pair[i])) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is redundant now that I explicitly compute is_born

gph/src/ripser.h Outdated
Comment on lines 1488 to 1490
// TODO: these will need special attention, if output
// happens after the reduction, not during
break;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never really understood this comment but I wonder if it still makes sense in this new position

@@ -1340,6 +1342,7 @@ class ripser
}
diameter_entry_t e;

bool is_essential = false;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance impact? (I'd say insignificant?)

flag_persistence_generators.finite_0.push_back(
{birth_vertex.second, std::max(v1, v2),
std::min(v1, v2)});
if (get_diameter(e) != std::numeric_limits<value_t>::infinity()) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, if an edge is infinite it means it's not there, so we should not use it to link vertices.

Comment on lines +1443 to +1450
/* Pairs should only be extracted if insertion was
* first one! */
size_t location = last_diameter_index++;
diameters[location] = death;
auto first_ins =
deaths
.insert({get_index(get_entry(pivot)), location})
.second;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't yet understand these lines too well so please check that them now being inside this if cannot lead to wrong results.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an explanation of what is going on. Because the reduction is done in parallel. You can have at a certain point 2 differents workers getting the same pivot as the last reduction. If that happens, we ensure with this check that only one barcode is produced instead of two.

I think that the comment should remain for anyone looking at the code

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I wasn't complaining about the comment, just wondering about correctness of the code in this part especially.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh !
Is it more clear with my previous explanation ?

Comment on lines +1455 to +1456
if (first_ins) {
if (return_flag_persistence_generators) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be dealt with with an && as it was before

Copy link
Owner Author

@ulupo ulupo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global comment: technically we should be checking for positive infinity only, I'm not sure whether this is what's happening now with the == syntax

@MonkeyBreaker MonkeyBreaker force-pushed the feature/return_flag_persistence_generators branch from 25fd98f to 0abb23b Compare October 31, 2021 18:23
@ulupo ulupo deleted the branch feature/return_flag_persistence_generators November 1, 2021 10:07
@ulupo ulupo closed this Nov 1, 2021
@ulupo ulupo deleted the feature/return_flag_persistence_generators_temp branch November 26, 2021 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants