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

Fix documentation #74

Merged
merged 16 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[![PyPI version](https://badge.fury.io/py/persim.svg)](https://badge.fury.io/py/persim)
[![Downloads](https://pypip.in/download/persim/badge.svg)](https://pypi.python.org/pypi/persim/)
![PyPI - Downloads](https://img.shields.io/pypi/dm/persim)
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/persim.svg)](https://anaconda.org/conda-forge/persim)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/persim.svg)](https://anaconda.org/conda-forge/persim)
[![Build Status](https://travis-ci.org/scikit-tda/persim.svg?branch=master)](https://travis-ci.org/scikit-tda/persim)
[![codecov](https://codecov.io/gh/scikit-tda/persim/branch/master/graph/badge.svg)](https://codecov.io/gh/scikit-tda/persim)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Expand Down
37 changes: 21 additions & 16 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
# -*- coding: utf-8 -*-
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
from persim import __version__

sys.path.insert(0, os.path.abspath("."))
from sktda_docs_config import *

project = u'Persim'
copyright = u'2019, Nathaniel Saul'
author = u'Nathaniel Saul'
from persim import __version__

project = "Persim"
copyright = "2019, Nathaniel Saul"
author = "Nathaniel Saul"

version = __version__
release = __version__

html_theme_options.update({
# Google Analytics info
'ga_ua': 'UA-124965309-3',
'ga_domain': '',
'gh_url': 'scikit-tda/persim'
})
language = "en"

html_theme_options.update(
{
"collapse_naviation": False,
# Google Analytics info
"ga_ua": "UA-124965309-3",
"ga_domain": "",
"gh_url": "scikit-tda/persim",
}
)

html_short_title = project
htmlhelp_basename = 'Persimdoc'
htmlhelp_basename = "Persimdoc"

autodoc_default_options = {
'members': True
}
autodoc_default_options = {"members": False, "maxdepth": 1}

autodoc_member_order = 'groupwise'
autodoc_member_order = "groupwise"
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Documentation

notebooks/Persistence images
notebooks/distances
notebooks/Persistence landscapes
reference/index


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"The experiment is to determine if persistent homology can distinguish between spheres of different dimensions. Here we restrict to differentiating $S^2$ from $S^3$. We will further restrict ourselves to persistent homology in degree one (but one can use all relevant homological degrees as well). A priori, we would not expect this to be an effective discriminator, since the ordinary first homology of both spheres is trivial. Note that this is a simplified version of the experiment from Bubenik and Dlotko's *A persistence landscapes toolbox for topological statistics* [1]. \n",
"\n",
"In detail: \n",
"\n",
"- Repeat the following `num_runs = 100` times:\n",
" - Sample `num_pts = 100` points from the 2-sphere and the 3-sphere. We rescale the spheres so the average distance between the points on each sphere is approximately 1.\n",
" - Compute the VR persistent homology (using `ripser`) and compute the associated landscapes. Store each of these landscapes.\n",
Expand Down Expand Up @@ -356,7 +357,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -370,7 +371,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
"version": "3.12.0"
}
},
"nbformat": 4,
Expand Down
76 changes: 58 additions & 18 deletions docs/notebooks/Persistence Landscapes and Machine Learning.ipynb

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/notebooks/Persistence images.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "persimenv",
"display_name": "Python 3",
"language": "python",
"name": "persimenv"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -508,7 +508,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
"version": "3.9.1"
}
},
"nbformat": 4,
Expand Down
1,012 changes: 1,012 additions & 0 deletions docs/notebooks/Persistence landscapes.ipynb

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions persim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from .images import *
from .sliced_wasserstein import *
from ._version import __version__
from .bottleneck import *
from .wasserstein import *
from .heat import *
from .gromov_hausdorff import *
from .heat import *
from .images import *
from .landscapes.approximate import PersLandscapeApprox
from .landscapes.exact import PersLandscapeExact
from .landscapes.transformer import PersistenceLandscaper
from .sliced_wasserstein import *
from .visuals import *
from .wasserstein import *

from ._version import __version__
__all__ = ["PersLandscapeApprox", "PersistenceLandscaper", "PersLandscapeExact"]
5 changes: 2 additions & 3 deletions persim/landscapes/approximate.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class are much faster compared to `PersLandscapeExact` in general.

ValueError: Start values of grids do not coincide

>>> from persim import snap_PL
>>> [snapped_pla, snapped_wide_pl] = snap_PL([pla,wide_pl])
>>> from persim import snap_pl
>>> [snapped_pla, snapped_wide_pl] = snap_pl([pla,wide_pl])
>>> print(snapped_pla, snapped_wide_pl)

Approximate persistence landscape in homological degree 0 on grid from -1 to 4 with 1000 steps Approximate persistence landscape in homological degree 0 on grid from -1 to 4 with 1000 steps
Expand Down Expand Up @@ -128,7 +128,6 @@ def __init__(
values=np.array([]),
compute: bool = True,
) -> None:

super().__init__(dgms=dgms, hom_deg=hom_deg)
if not dgms and values.size == 0:
raise ValueError("dgms and values cannot both be emtpy")
Expand Down
7 changes: 5 additions & 2 deletions persim/landscapes/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ def union_crit_pairs(A, B):
else:
result_pairs.append(
slope_to_pos_interp(
sum_slopes(pos_to_slope_interp(a), pos_to_slope_interp(b),)
sum_slopes(
pos_to_slope_interp(a),
pos_to_slope_interp(b),
)
)
)
return result_pairs
Expand Down Expand Up @@ -141,7 +144,7 @@ def ndsnap_regular(points, *grid_axes):

def _p_norm(p: float, critical_pairs: list = []):
"""
Compute `p` norm of interpolated piecewise linear function defined from list of
Compute `p` norm of interpolated piecewise linear function defined from list of
critical pairs.
"""
result = 0.0
Expand Down
155 changes: 70 additions & 85 deletions persim/landscapes/exact.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
"""

import itertools
import numpy as np
from operator import itemgetter

import numpy as np

from .approximate import PersLandscapeApprox
from .auxiliary import union_crit_pairs, _p_norm
from .auxiliary import _p_norm, union_crit_pairs
from .base import PersLandscape

__all__ = ["PersLandscapeExact"]
Expand All @@ -16,114 +17,99 @@
class PersLandscapeExact(PersLandscape):
"""Persistence Landscape Exact class.

This class implements an exact version of Persistence Landscapes. The landscape
functions are stored as a list of critical pairs, and the actual function is the
linear interpolation of these critical pairs. All
computations done with these classes are exact. For much faster but
approximate methods that should suffice for most applications, consider
`PersLandscapeApprox`.

Parameters
----------
dgms : list of (-,2) numpy.ndarrays, optional
A nested list of numpy arrays, e.g., [array( array([:]), array([:]) ),..., array([:])]
Each entry in the list corresponds to a single homological degree.
Each array represents the birth-death pairs in that homological degree. This is
the output format from ripser.py: ripser(data_user)['dgms']. Only
one of diagrams or critical pairs should be specified.

hom_deg : int
Represents the homology degree of the persistence diagram.

critical_pairs : list, optional
List of lists of critical pairs (points, values) for specifying a persistence landscape.
These do not necessarily have to arise from a persistence
diagram. Only one of diagrams or critical pairs should be specified.
This class implements an exact version of Persistence Landscapes. The landscape
functions are stored as a list of critical pairs, and the actual function is the
linear interpolation of these critical pairs. All
computations done with these classes are exact. For much faster but
approximate methods that should suffice for most applications, consider
`PersLandscapeApprox`.

compute : bool, optional
Flag determining whether landscape functions are computed upon instantiation.
Parameters
----------
dgms : list of (-,2) numpy.ndarrays, optional
A nested list of numpy arrays, e.g., [array( array([:]), array([:]) ),..., array([:])]
Each entry in the list corresponds to a single homological degree.
Each array represents the birth-death pairs in that homological degree. This is
the output format from ripser.py: ripser(data_user)['dgms']. Only
one of diagrams or critical pairs should be specified.

hom_deg : int
Represents the homology degree of the persistence diagram.

Examples
--------
Define a persistence diagram and instantiate the landscape::
critical_pairs : list, optional
List of lists of critical pairs (points, values) for specifying a persistence landscape.
These do not necessarily have to arise from a persistence
diagram. Only one of diagrams or critical pairs should be specified.

>>> from persim import PersLandscapeExact
>>> import numpy as np
>>> pd = [ np.array([[0,3],[1,4]]), np.array([[1,4]]) ]
>>> ple = PersLandscapeExact(dgms=pd, hom_deg=0)
>>> ple
compute : bool, optional
Flag determining whether landscape functions are computed upon instantiation.

`PersLandscapeExact` instances store the critical pairs of the landscape as a list of lists in the `critical_pairs` attribute. The `i`-th entry corresponds to the critical values of the depth `i` landscape::

>>> ple.critical_pairs
Examples
--------
Define a persistence diagram and instantiate the landscape::

[[[0, 0], [1.5, 1.5], [2.0, 1.0], [2.5, 1.5], [4, 0]],
[[1, 0], [2.0, 1.0], [3, 0]]]
>>> from persim import PersLandscapeExact
>>> import numpy as np
>>> pd = [ np.array([[0,3],[1,4]]), np.array([[1,4]]) ]
>>> ple = PersLandscapeExact(dgms=pd, hom_deg=0)
>>> ple

Addition, subtraction, and scalar multiplication between landscapes is implemented::
`PersLandscapeExact` instances store the critical pairs of the landscape as a list of lists in the `critical_pairs` attribute. The `i`-th entry corresponds to the critical values of the depth `i` landscape::

>>> pd2 = [ np.array([[0.5,7],[3,5],[4.1,6.5]]), np.array([[1,4]])]
>>> pl2 = PersLandscapeExact(dgms=pd2,hom_deg=0)
>>> pl_sum = ple + pl2
>>> pl_sum.critical_pairs
>>> ple.critical_pairs

[[[0, 0], [0.5, 0.5], [1.5, 2.5], [2.0, 2.5],
[2.5, 3.5], [3.75, 3.5],[4, 3.0], [7.0, 0.0]],
[[1, 0], [2.0, 1.0], [3, 0.0], [4.0, 1.0],
[4.55, 0.45], [5.3, 1.2], [6.5, 0.0]],
[[4.1, 0], [4.55, 0.45], [5.0, 0]]]
[[[0, 0], [1.5, 1.5], [2.0, 1.0], [2.5, 1.5], [4, 0]],
[[1, 0], [2.0, 1.0], [3, 0]]]

>>> diff_pl = ple - pl2
>>> diff_pl.critical_pairs
Addition, subtraction, and scalar multiplication between landscapes is implemented::

[[[0, 0], [0.5, 0.5], [1.5, 0.5], [2.0, -0.5],
[2.5, -0.5], [3.75, -3.0], [4, -3.0], [7.0, 0.0]],
[[1, 0], [2.0, 1.0], [3, 0.0], [4.0, -1.0],
[4.55, -0.45], [5.3, -1.2], [6.5, 0.0]],
[[4.1, 0], [4.55, -0.45], [5.0, 0]]]
>>> pd2 = [ np.array([[0.5,7],[3,5],[4.1,6.5]]), np.array([[1,4]])]
>>> pl2 = PersLandscapeExact(dgms=pd2,hom_deg=0)
>>> pl_sum = ple + pl2
>>> pl_sum.critical_pairs

>>> (5*ple).critical_pairs
[[[0, 0], [0.5, 0.5], [1.5, 2.5], [2.0, 2.5],
[2.5, 3.5], [3.75, 3.5],[4, 3.0], [7.0, 0.0]],
[[1, 0], [2.0, 1.0], [3, 0.0], [4.0, 1.0],
[4.55, 0.45], [5.3, 1.2], [6.5, 0.0]],
[[4.1, 0], [4.55, 0.45], [5.0, 0]]]

[[(0, 0), (1.5, 7.5), (2.0, 5.0), (2.5, 7.5), (4, 0)],
[(1, 0), (2.0, 5.0), (3, 0)]]
>>> diff_pl = ple - pl2
>>> diff_pl.critical_pairs

Landscapes are sliced by depth and slicing returns the critical pairs in the range specified::
[[[0, 0], [0.5, 0.5], [1.5, 0.5], [2.0, -0.5],
[2.5, -0.5], [3.75, -3.0], [4, -3.0], [7.0, 0.0]],
[[1, 0], [2.0, 1.0], [3, 0.0], [4.0, -1.0],
[4.55, -0.45], [5.3, -1.2], [6.5, 0.0]],
[[4.1, 0], [4.55, -0.45], [5.0, 0]]]

>>> ple[0]
>>> (5*ple).critical_pairs

[[0, 0], [1.5, 1.5], [2.0, 1.0], [2.5, 1.5], [4, 0]]
[[(0, 0), (1.5, 7.5), (2.0, 5.0), (2.5, 7.5), (4, 0)],
[(1, 0), (2.0, 5.0), (3, 0)]]

>>> pl2[1:]
Landscapes are sliced by depth and slicing returns the critical pairs in the range specified::

[[[3.0, 0], [4.0, 1.0], [4.55, 0.4500000000000002],
[5.3, 1.2000000000000002], [6.5, 0]],
[[4.1, 0], [4.55, 0.4500000000000002], [5.0, 0]]]
>>> ple[0]

`p` norms are implemented for all `p` as well as the supremum norms::
[[0, 0], [1.5, 1.5], [2.0, 1.0], [2.5, 1.5], [4, 0]]

>>> ple.p_norm(p=3)
>>> pl2[1:]

1.7170713638299977
[[[3.0, 0], [4.0, 1.0], [4.55, 0.4500000000000002],
[5.3, 1.2000000000000002], [6.5, 0]],
[[4.1, 0], [4.55, 0.4500000000000002], [5.0, 0]]]

>>> pl2.sup_norm()
`p` norms are implemented for all `p` as well as the supremum norm::

3.25
>>> ple.p_norm(p=3)

1.7170713638299977

>>> pl2.sup_norm()

Methods
-------
compute_landscape : computes the set of critical pairs and stores them in
the attribute `critical_pairs`

compute_landscape_by_depth : compute the set of critical pairs in a certain
range.

p_norm : returns p-norm of a landscape

sup_norm : returns sup norm of a landscape

3.25
"""

def __init__(
Expand Down Expand Up @@ -240,7 +226,7 @@ def __getitem__(self, key: slice) -> list:
list
The critical pairs of the landscape function corresponding
to depths given by key

Note
----
If the slice is beyond `self.max_depth` an IndexError is raised.
Expand Down Expand Up @@ -307,7 +293,6 @@ def compute_landscape(self, verbose: bool = False) -> list:
break

while L[landscape_idx][-1] != [np.inf, 0]:

# if d is > = all remaining pairs, then end lambda
# includes edge case with (b,d) pairs with the same death time
if all(d >= _[1] for _ in A):
Expand Down
Loading
Loading