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

Always treat bars with infinite death as essential bars #37

Closed
ulupo opened this issue Oct 31, 2021 · 4 comments · Fixed by #53
Closed

Always treat bars with infinite death as essential bars #37

ulupo opened this issue Oct 31, 2021 · 4 comments · Fixed by #53
Projects

Comments

@ulupo
Copy link
Collaborator

ulupo commented Oct 31, 2021

During work on this PR #29, @MonkeyBreaker and I realized that the current core logic in the matrix reduction algorithm makes it so that we break the following promise to the user: that passing a dense matrix with a few np.inf will lead to exactly the same output as passing a sparse version where the np.inf entries are just missing entries. This was never noticed at the level of barcodes because a "finite" bar with death equal to infinity looks just the same as an infinite bar with the same birth. But flag generators don't lie: we now end up telling the user there are never any generators for essential classes if the matrix is dense, no matter what the matrix is or represents.

Because changing this requires potentially delicate changes to the reduction routine, we decided to discuss what to do about this separately, and open a separate PR if necessary after this one is merged.

Originally posted by @ulupo in #29 (comment)

@ulupo
Copy link
Collaborator Author

ulupo commented Oct 31, 2021

A preliminary approach is in ulupo#1

@MonkeyBreaker
Copy link
Collaborator

MonkeyBreaker commented Oct 31, 2021

Maybe we could add the diamond example and the output when running in sparse and dense, where we can observe an unexpected difference ?

@ulupo
Copy link
Collaborator Author

ulupo commented Oct 31, 2021

@MonkeyBreaker indeed. Here goes:

import numpy as np
from gph.python import ripser_parallel

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([[1, 0, 5, 4]], dtype=int64)],
 array([0], dtype=int64),
 [array([], shape=(0, 2), dtype=int64), array([], shape=(0, 2), dtype=int64)])

The sparse version

from scipy.sparse import coo_matrix

diamond_dm = np.where(diamond_dm == np.inf, 0, diamond_dm)
diamond_dm = coo_matrix(diamond_dm)

gives the correct

(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([], shape=(0, 4), dtype=int64)],
 array([0], dtype=int64),
 [array([], shape=(0, 2), dtype=int64), array([[1, 0]], dtype=int64)])

@MonkeyBreaker
Copy link
Collaborator

Perfect, I will just edit your comment to add the python language highlight

@ulupo ulupo added this to To do in v0.3.0 via automation Nov 3, 2021
ulupo added a commit to ulupo/giotto-ph that referenced this issue Nov 21, 2021
MonkeyBreaker pushed a commit to ulupo/giotto-ph that referenced this issue Jan 7, 2022
Signed-off-by: julian <julian.burellaperez@heig-vd.ch>
@MonkeyBreaker MonkeyBreaker moved this from To do to In progress in v0.3.0 Feb 6, 2022
@MonkeyBreaker MonkeyBreaker linked a pull request Feb 6, 2022 that will close this issue
v0.3.0 automation moved this from In progress to Done Feb 6, 2022
MonkeyBreaker added a commit that referenced this issue Feb 6, 2022
* Proposal to deal with explicit infinite edges

Addresses issue #37

* Use if-continue as suggested by @MonkeyBreaker

* [TEST] Add regression test for issue #37

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

* [CPP] Slight format and move comment to new relevant section

Signed-off-by: julian <monkeybreaker@protonmail.com>

* Replace all numeric... by a inf variable at the top of the file

Much easier to write :)

Signed-off-by: julian <monkeybreaker@protonmail.com>

* [CPP] Remove unecessary variables and apply format

Signed-off-by: julian <monkeybreaker@protonmail.com>

* Revert deletion of death variable and use it when necessary

Signed-off-by: julian <monkeybreaker@protonmail.com>

Co-authored-by: julian <julian.burellaperez@heig-vd.ch>
Co-authored-by: julian <monkeybreaker@protonmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging a pull request may close this issue.

2 participants