Source code for persunraveltorch.nn.biplane_from_intervals

from typing import Optional, Tuple
from collections.abc import Iterable
from math import pi

import itertools as it

import torch

from .biplane_from_triangles import BiplaneFromTriangles
from .raster_triangle import RasterTriangle


__all__ = [ 'BiplaneFromIntervals' ]


[docs] class BiplaneFromIntervals(torch.nn.Module): r"""Creates a *biplane* from persistence intervals within a finite range. This module takes persistence intervals within a finite range :obj:`range_intervals` as an :class:`Iterable` by degree as input. So each item of the input is a :class:`torch.Tensor` of shape :math:`([\dots,] k, 2)`, where :math:`k` is the number of persistence intervals in the corresponding degree. The output can be thought of as a 3D bitmap with a depth of :math:`2` - henceforth called *biplane* - and two channels. So the output has shape :math:`([\dots,] 2, 2, w, h)` with the width :math:`w` being equal to :obj:`padding + pixel_columns + padding`. The :math:`0`-th channel contains two sheared rasterizations of the Hilbert function of the unravelled relative homology lattice on top of each other and offset by a glide reflection corresponding to suspension. Similarly, the :math:`1`-st channel contains two sheared rasterizations of the unravelled rank invariant on top of each other and offset by a glide reflection corresponding to suspension. Parameters ---------- pixel_columns : :class:`int` The number of pixels used to raster each row or scanline of the strip supporting the relative homology lattice. range_intervals : :class:`Tuple[float, float]`, optional The finite range containing all persistence intervals, defaults to :obj:`(0.0, pi/2.0)`. padding : :class:`int` The amount of horizontal padding being added to both, the left and the right side. max_overhead : :class:`Optional[int]`, optional If this is set, then the input will be processed in batches as small as necessary to limit the number of bytes allocated as overhead to at most :obj:`max_overhead`. So if you're not already processing your data in sufficiently small batches, setting this parameter is recommended. However, if the number of bytes required to process a single sample already exceeds :obj:`max_overhead`, the input is still processed sample by sample. The default is :obj:`None`. """ def __init__(self, *, pixel_columns: int, range_intervals: Tuple[float, float] = (0.0, pi/2.0), padding: int, max_overhead: Optional[int] = None, device = None, dtype = None ) -> None: super().__init__() self._no_intervals = torch.tensor( [], device = device, dtype = dtype ) self.biplane_from_triangles = BiplaneFromTriangles( pixel_columns = pixel_columns, padding = padding, max_overhead = max_overhead, device = device, dtype = dtype ) """:class:`BiplaneFromTriangles`: The instance used internally.""" self.raster_triangle = RasterTriangle( pixel_columns = pixel_columns, range_intervals = range_intervals, max_overhead = max_overhead, device = device, dtype = dtype ) """:class:`RasterTriangle`: The instance used internally.""" @property def pixel_area(self) -> float: """:class:`float`: The area covered by each pixel.""" return self.raster_triangle.pixel_area
[docs] def forward(self, intervals: Iterable[torch.Tensor], /) -> torch.Tensor: """Biplane created from persistence intervals as described for :class:`BiplaneFromIntervals`. Parameters ---------- intervals : :class:`Iterable[torch.Tensor]` Persistence intervals by degree. Returns ------- :class:`torch.Tensor` A biplane with two channels describing the Hilbert function of the unravelled relative homology lattice and the unravelled rank invariant. """ intervals_iterator = iter( intervals ) intervals0 = next( intervals_iterator ) no_intervals = self._no_intervals.view( intervals0.shape[:-2] + (0, 2) ) return self.biplane_from_triangles( self.raster_triangle( *intervals_pair ) for intervals_pair in it.pairwise( it.chain( [intervals0], intervals_iterator, [no_intervals] ) ) )