Skip to content

cochain

Cochain

A cochain data structure.

A discrete version of the mathematical notion of differential k-form. Defined on a discrete version of the notion of manifold.

Attributes:

Name Type Description
_complex simplicialcomplex

The simplicial complex the cochain is defined on.

_dim int

The topological dimension at which the cochain is defined.

_val ndarray(float)

The value of the cochain on the associated simplices.

_dual bool

Default is False. If True the cochain is defined on the dual complex.

Notes
  • The values of the Cochain can be scalars or vectors.
  • We can also define values as sparse matrices but this is mostly used to define differential operators on a whole SimplicialComplex.
Source code in src/dxtr/cochains/cochain.py
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
class Cochain:
    """A cochain data structure.

    A discrete version of the mathematical notion of differential k-form.
    Defined on a discrete version of the notion of manifold.

    Attributes
    ----------
    _complex : dxtr.complexes.simplicialcomplex
        The simplicial complex the cochain is defined on.
    _dim : int
        The topological dimension at which the cochain is defined.
    _val : numpy.ndarray(float)
        The value of the cochain on the associated simplices.
    _dual : bool
        Default is False. If True the cochain is defined on the dual complex.

    Notes
    -----
    * The values of the `Cochain` can be scalars or vectors.
    * We can also define values as sparse matrices but this is mostly used 
      to define differential operators on a whole `SimplicialComplex`.
    """

    def __init__(self, complex: SimplicialComplex, dim: int, 
                 values: Optional[Iterable[float]] = None, dual: bool = False,
                 name: Optional[str] = None) -> None:
        """Instantiates a `Cochain` object.

        Parameters
        ----------
        complex : SimplicialComplex
            The simplicial complex the cochain is defined on.
        dim : int
            The topological dimension at which the cochain is defined.
        values : iterable of float, optional
            The value of the cochain on the associated simplices. Default is None.
        dual : bool, optional
            If True the cochain is defined on the dual complex. Default is False.
        name : str, optional
            The name of the cochain. Default is None.

        Notes
        -----
        * If no dim is specified, we look for the k-Module with
          the same dimension as the provided values.
        """

        self._complex:SimplicialComplex = complex
        self._dim = dim
        self._dual = dual

        n = complex.dim
        k = np.clip(dim, 0, n)
        mdl = complex[k] if not dual else complex[n-k]
        self._indices, self._values = _format_indices_values(values, mdl)

        if name is None:
            self._name = f'Dual ' if self.isdual else 'Primal '
            self._name += f'{self.dim}-cochain'
        else:
            self._name = name

    @classmethod
    def from_file(cls, path: str | Path, name: Optional[str] = None) -> Cochain:
        """Instantiates a `Cochain` from a `.vtk` file.

        Parameters
        ----------
        path : str or Path
            The path to the `.vtk` file.
        name : str, optional
            The name of the cochain. Default is None.

        Notes
        -----
        * For now can only work with primal `Cochain` objects.
        """
        from dxtr.io import read_vtk

        simplices, vertices, property = read_vtk(path)
        manifold = SimplicialManifold(simplices, vertices)

        name = property.name if name is None else name
        dual = False

        return cls(manifold, property.dim, property.values, 
                    dual=dual, name=name)

    @valid_input
    def to_file(self, file_name: str, format: str = '.ply', 
                folder: Optional[str | Path] = None) -> None:
        """
        Saves the `Cochain` instance on disk in the `.vtk` format.

        Parameters
        ----------
        file_name : str
            The name of the file to write on disk.
        format : str, optional
            The type of file to write, see Notes. Default is `.ply`.
        folder : str or Path, optional
            The location where to write the file. Default is the current working directory.

        Notes
        -----
        * `Cochain` instances can only be saved in the `vtk` format.
        * If no folder is provided, the file will be recorded in the current working directory.
        """
        from dxtr.io.write import format_path_properly
        from dxtr.utils.wrappers import UGrid

        path = format_path_properly(folder, file_name, '.vtk')

        ugrid = UGrid.generate_from(self)
        ugrid.save(path)


    def __is_compatible_with__(self, other: Cochain) -> bool:
        """Checks if algebraic operations can be performed between two cochains.

        Parameters
        ----------
        other : Cochain
            The other cochain to check compatibility with.

        Returns
        -------
        bool
            True if the cochains are compatible, False otherwise.
        """
        try:
            assert isinstance(other, Cochain), (
                'Addition only implented between Cochains.')
            assert other.complex is self.complex, (
                    'Cochains defined on different complexes.')
            assert other.dim == self.dim, (
                f'Dimensions do not match: {other.dim} != {self.dim}')
            assert other.shape == self.shape, (
                f'Shapes do not match: {other.shape} != {self.shape}')
            assert other.isdual == self.isdual, (
                'Cannot combine primal and dual cochains together.')
            assert isinstance(other.values, type(self.values)), (
                'Cannot add Cochains with values of different types.')
            np.testing.assert_array_equal(other.indices, self.indices, 
                        err_msg='Cochains not defined on the same simplices.') 

            return True

        except AssertionError as msg:
            logger.warning(msg)
            return False


    def __str__(self) -> str:
        return f'{self.name}, defined on {self.complex.name}.'


    def __add__(self, other: Cochain) -> Optional[Cochain]:
        """Enables to add two cochains together.

        Parameters
        ----------
        other : Cochain
            The other cochain to add.

        Returns
        -------
        Cochain or None
            The resulting cochain if compatible, None otherwise.
        """
        if not self.__is_compatible_with__(other):
            return None

        if isinstance(self._values, sp.spmatrix):
            new_values = self.values + other.values
        else:
            new_values = dict(zip(self.indices, self.values + other.values))

        return Cochain(self.complex, self.dim, values=new_values,
                        dual=self.isdual)


    def __sub__(self, other: Cochain) -> Optional[Cochain]:
        """Enables to subtract two cochains from one another.

        Parameters
        ----------
        other : Cochain
            The other cochain to subtract.

        Returns
        -------
        Cochain or None
            The resulting cochain if compatible, None otherwise.
        """
        if not self.__is_compatible_with__(other):
            return None

        if isinstance(self._values, sp.spmatrix):
            new_values = self.values - other.values
        else:
            new_values = dict(zip(self.indices, self.values - other.values))

        return Cochain(self.complex, self.dim, values=new_values,
                        dual=self.isdual)


    def __mul__(self, other: float | int | np.ndarray[float] | Cochain) -> Optional[Cochain]:
        """Enables the multiplication on the right.

        Parameters
        ----------
        other : float, int, np.ndarray of float, or Cochain
            The value or cochain to multiply with.

        Returns
        -------
        Cochain or None
            The resulting cochain if compatible, None otherwise.

        Notes
        -----
        * WARNING: when multiplying a `Cochain` by a `np.ndarray`, one must
          keep the `Cochain` on the left side of the `*` operator: 
          ```C2 = C1 * arr```
          The inverse would not work for the array will try to multiply term 
          by term.
        """
        if isinstance(other, (float, int)):
            if isinstance(self.values, sp.spmatrix):
                new_values = other * self.values
                new_values = new_values.tocsr()
            else: 
                new_values = dict(zip(self.indices, other * self.values))

        if isinstance(other, np.ndarray):
            new_values = other * self.values

        elif isinstance(other, Cochain):
            if not self.__is_compatible_with__(other):
                return None

            if isinstance(self.values, sp.spmatrix):
                new_values = self.values @ other.values

            else:
                new_vals = np.multiply(self.values, other.values)
                new_values = dict(zip(self.indices, new_vals))


        return Cochain(self.complex, self.dim, values=new_values,
                    dual=self.isdual)


    def __rmul__(self, other: float | int | np.ndarray[float] | Cochain) -> Optional[Cochain]:
        """Enables the multiplication with a number on the left.

        Parameters
        ----------
        other : float, int, np.ndarray of float, or Cochain
            The value or cochain to multiply with.

        Returns
        -------
        Cochain or None
            The resulting cochain if compatible, None otherwise.
        """
        return self.__mul__(other)


    def __truediv__(self, other: float | int | np.ndarray[float]) -> Optional[Cochain]:
        """Enables the division on the right.

        Parameters
        ----------
        other : float, int, or np.ndarray of float
            The value to divide by.

        Returns
        -------
        Cochain or None
            The resulting cochain if compatible, None otherwise.

        Notes
        -----
        * The division is not implemented between `Cochain` instances yet.
        """
        if isinstance(other, (float, int, np.ndarray)):
            inv_other = 1 / other
            return self * inv_other

        elif isinstance(other, Cochain):
            logger.warning('Cannot divide `Cochains` together for now')
            return None


    @property
    def complex(self) -> SimplicialComplex:
        """Gets the `SimplicialComplex` on which the `Cochain` is defined.

        Returns
        -------
        SimplicialComplex
            The simplicial complex.
        """
        return self._complex

    @property
    def name(self) -> str:
        """Gets the name of the `Cochain`.

        Returns
        -------
        str
            The name of the cochain.
        """
        return self._name

    @property
    def dim(self) -> int:
        """The topological dimension of the `Cochain`.

        Returns
        -------
        int
            The topological dimension.
        """
        return self._dim

    @property
    def shape(self) -> tuple[int] | None:
        """Gets the `Cochain` shape.

        Returns
        -------
        tuple of int or None
            The shape of the cochain.

        Notes
        -----
        * The shape is given as a tuple.
          The second number is 0 for a scalar-valued cochain,
          1 for a vector, 2 for a tensor, etc...
        """
        if self._values is None:
            return None
        else:
            return self._values.shape

    @property
    def indices(self) -> list[int]:
        """Gets the indices of the k-simplices where the `Cochain` is defined.

        Returns
        -------
        list of int
            The indices of the k-simplices.
        """
        return self._indices

    @property
    def values(self) -> Optional[np.ndarray[float] | sp.spmatrix | dict]:
        """Gets the values of the `Cochain`.

        Returns
        -------
        np.ndarray of float, sp.spmatrix, or dict, optional
            The values of the cochain.
        """
        return self._values

    @property
    def positions(self) -> Optional[np.ndarray[float]]:
        """Gets the vertices of the simplices where cochain values are defined.

        Returns
        -------
        np.ndarray of float, optional
            The vertices of the simplices.

        Notes
        -----
        * Returns None if the `Cochain` is defined on an `AbstractSimplicialComplex`.
        """

        if self.complex.isabstract:
            logger.warning('cochain defined on an abstract simplicial complex.')
            return None

        k = self.complex.dim - self.dim if self.isdual else self.dim
        pos = self.complex[k].circumcenters

        return pos[self.indices]

    @property
    def isdual(self) -> bool:
        """Checks if the `Cochain` is defined on the dual complex.

        Returns
        -------
        bool
            True if the cochain is defined on the dual complex, False otherwise.
        """
        return self._dual

    @property
    def isvectorvalued(self) -> bool:
        """Checks if the values of the `Cochain` are vectors.

        Returns
        -------
        bool
            True if the values are vectors, False otherwise.
        """
        if not isinstance(self.values, np.ndarray):
            return False
        else:
            return self.values.ndim == 2


    def items(self) -> Generator[tuple[int, float], None, None]:
        """Enables to iterate over `Cochain` indices and values.

        Yields
        ------
        tuple of int and float
            Indices of the k-simplices where values are defined and the values of the cochain.
        """

        for idx, val in zip(self._indices, self._values):
            yield idx, val


    def toarray(self) -> Optional[np.ndarray[float]]:
        """Gets the values of the cochain as a numpy array.

        Returns
        -------
        np.ndarray of float, optional
            The values of the cochain as a numpy array.
        """
        if isinstance(self._values, sp.spmatrix):
            return self._values.toarray()
        else:
            return np.asarray(self._values)


    def value_closest_to(self, position: np.ndarray[float]) -> float:
        """Gets the value closest to a provided position.

        Parameters
        ----------
        position : np.ndarray of float
            The position to find the closest value to.

        Returns
        -------
        float
            The value closest to the provided position.
        """
        cplx = self.complex
        dim = self.dim

        sidx = cplx[dim].closest_simplex_to(position, index_only=True)

        return self.values[sidx]

complex property

Gets the SimplicialComplex on which the Cochain is defined.

Returns:

Type Description
SimplicialComplex

The simplicial complex.

dim property

The topological dimension of the Cochain.

Returns:

Type Description
int

The topological dimension.

indices property

Gets the indices of the k-simplices where the Cochain is defined.

Returns:

Type Description
list of int

The indices of the k-simplices.

isdual property

Checks if the Cochain is defined on the dual complex.

Returns:

Type Description
bool

True if the cochain is defined on the dual complex, False otherwise.

isvectorvalued property

Checks if the values of the Cochain are vectors.

Returns:

Type Description
bool

True if the values are vectors, False otherwise.

name property

Gets the name of the Cochain.

Returns:

Type Description
str

The name of the cochain.

positions property

Gets the vertices of the simplices where cochain values are defined.

Returns:

Type Description
np.ndarray of float, optional

The vertices of the simplices.

Notes
  • Returns None if the Cochain is defined on an AbstractSimplicialComplex.

shape property

Gets the Cochain shape.

Returns:

Type Description
tuple of int or None

The shape of the cochain.

Notes
  • The shape is given as a tuple. The second number is 0 for a scalar-valued cochain, 1 for a vector, 2 for a tensor, etc...

values property

Gets the values of the Cochain.

Returns:

Type Description
np.ndarray of float, sp.spmatrix, or dict, optional

The values of the cochain.

__add__(other)

Enables to add two cochains together.

Parameters:

Name Type Description Default
other Cochain

The other cochain to add.

required

Returns:

Type Description
Cochain or None

The resulting cochain if compatible, None otherwise.

Source code in src/dxtr/cochains/cochain.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def __add__(self, other: Cochain) -> Optional[Cochain]:
    """Enables to add two cochains together.

    Parameters
    ----------
    other : Cochain
        The other cochain to add.

    Returns
    -------
    Cochain or None
        The resulting cochain if compatible, None otherwise.
    """
    if not self.__is_compatible_with__(other):
        return None

    if isinstance(self._values, sp.spmatrix):
        new_values = self.values + other.values
    else:
        new_values = dict(zip(self.indices, self.values + other.values))

    return Cochain(self.complex, self.dim, values=new_values,
                    dual=self.isdual)

__init__(complex, dim, values=None, dual=False, name=None)

Instantiates a Cochain object.

Parameters:

Name Type Description Default
complex SimplicialComplex

The simplicial complex the cochain is defined on.

required
dim int

The topological dimension at which the cochain is defined.

required
values iterable of float

The value of the cochain on the associated simplices. Default is None.

None
dual bool

If True the cochain is defined on the dual complex. Default is False.

False
name str

The name of the cochain. Default is None.

None
Notes
  • If no dim is specified, we look for the k-Module with the same dimension as the provided values.
Source code in src/dxtr/cochains/cochain.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def __init__(self, complex: SimplicialComplex, dim: int, 
             values: Optional[Iterable[float]] = None, dual: bool = False,
             name: Optional[str] = None) -> None:
    """Instantiates a `Cochain` object.

    Parameters
    ----------
    complex : SimplicialComplex
        The simplicial complex the cochain is defined on.
    dim : int
        The topological dimension at which the cochain is defined.
    values : iterable of float, optional
        The value of the cochain on the associated simplices. Default is None.
    dual : bool, optional
        If True the cochain is defined on the dual complex. Default is False.
    name : str, optional
        The name of the cochain. Default is None.

    Notes
    -----
    * If no dim is specified, we look for the k-Module with
      the same dimension as the provided values.
    """

    self._complex:SimplicialComplex = complex
    self._dim = dim
    self._dual = dual

    n = complex.dim
    k = np.clip(dim, 0, n)
    mdl = complex[k] if not dual else complex[n-k]
    self._indices, self._values = _format_indices_values(values, mdl)

    if name is None:
        self._name = f'Dual ' if self.isdual else 'Primal '
        self._name += f'{self.dim}-cochain'
    else:
        self._name = name

__is_compatible_with__(other)

Checks if algebraic operations can be performed between two cochains.

Parameters:

Name Type Description Default
other Cochain

The other cochain to check compatibility with.

required

Returns:

Type Description
bool

True if the cochains are compatible, False otherwise.

Source code in src/dxtr/cochains/cochain.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def __is_compatible_with__(self, other: Cochain) -> bool:
    """Checks if algebraic operations can be performed between two cochains.

    Parameters
    ----------
    other : Cochain
        The other cochain to check compatibility with.

    Returns
    -------
    bool
        True if the cochains are compatible, False otherwise.
    """
    try:
        assert isinstance(other, Cochain), (
            'Addition only implented between Cochains.')
        assert other.complex is self.complex, (
                'Cochains defined on different complexes.')
        assert other.dim == self.dim, (
            f'Dimensions do not match: {other.dim} != {self.dim}')
        assert other.shape == self.shape, (
            f'Shapes do not match: {other.shape} != {self.shape}')
        assert other.isdual == self.isdual, (
            'Cannot combine primal and dual cochains together.')
        assert isinstance(other.values, type(self.values)), (
            'Cannot add Cochains with values of different types.')
        np.testing.assert_array_equal(other.indices, self.indices, 
                    err_msg='Cochains not defined on the same simplices.') 

        return True

    except AssertionError as msg:
        logger.warning(msg)
        return False

__mul__(other)

Enables the multiplication on the right.

Parameters:

Name Type Description Default
other float, int, np.ndarray of float, or Cochain

The value or cochain to multiply with.

required

Returns:

Type Description
Cochain or None

The resulting cochain if compatible, None otherwise.

Notes
  • WARNING: when multiplying a Cochain by a np.ndarray, one must keep the Cochain on the left side of the * operator: C2 = C1 * arr The inverse would not work for the array will try to multiply term by term.
Source code in src/dxtr/cochains/cochain.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def __mul__(self, other: float | int | np.ndarray[float] | Cochain) -> Optional[Cochain]:
    """Enables the multiplication on the right.

    Parameters
    ----------
    other : float, int, np.ndarray of float, or Cochain
        The value or cochain to multiply with.

    Returns
    -------
    Cochain or None
        The resulting cochain if compatible, None otherwise.

    Notes
    -----
    * WARNING: when multiplying a `Cochain` by a `np.ndarray`, one must
      keep the `Cochain` on the left side of the `*` operator: 
      ```C2 = C1 * arr```
      The inverse would not work for the array will try to multiply term 
      by term.
    """
    if isinstance(other, (float, int)):
        if isinstance(self.values, sp.spmatrix):
            new_values = other * self.values
            new_values = new_values.tocsr()
        else: 
            new_values = dict(zip(self.indices, other * self.values))

    if isinstance(other, np.ndarray):
        new_values = other * self.values

    elif isinstance(other, Cochain):
        if not self.__is_compatible_with__(other):
            return None

        if isinstance(self.values, sp.spmatrix):
            new_values = self.values @ other.values

        else:
            new_vals = np.multiply(self.values, other.values)
            new_values = dict(zip(self.indices, new_vals))


    return Cochain(self.complex, self.dim, values=new_values,
                dual=self.isdual)

__rmul__(other)

Enables the multiplication with a number on the left.

Parameters:

Name Type Description Default
other float, int, np.ndarray of float, or Cochain

The value or cochain to multiply with.

required

Returns:

Type Description
Cochain or None

The resulting cochain if compatible, None otherwise.

Source code in src/dxtr/cochains/cochain.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
def __rmul__(self, other: float | int | np.ndarray[float] | Cochain) -> Optional[Cochain]:
    """Enables the multiplication with a number on the left.

    Parameters
    ----------
    other : float, int, np.ndarray of float, or Cochain
        The value or cochain to multiply with.

    Returns
    -------
    Cochain or None
        The resulting cochain if compatible, None otherwise.
    """
    return self.__mul__(other)

__sub__(other)

Enables to subtract two cochains from one another.

Parameters:

Name Type Description Default
other Cochain

The other cochain to subtract.

required

Returns:

Type Description
Cochain or None

The resulting cochain if compatible, None otherwise.

Source code in src/dxtr/cochains/cochain.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def __sub__(self, other: Cochain) -> Optional[Cochain]:
    """Enables to subtract two cochains from one another.

    Parameters
    ----------
    other : Cochain
        The other cochain to subtract.

    Returns
    -------
    Cochain or None
        The resulting cochain if compatible, None otherwise.
    """
    if not self.__is_compatible_with__(other):
        return None

    if isinstance(self._values, sp.spmatrix):
        new_values = self.values - other.values
    else:
        new_values = dict(zip(self.indices, self.values - other.values))

    return Cochain(self.complex, self.dim, values=new_values,
                    dual=self.isdual)

__truediv__(other)

Enables the division on the right.

Parameters:

Name Type Description Default
other float, int, or np.ndarray of float

The value to divide by.

required

Returns:

Type Description
Cochain or None

The resulting cochain if compatible, None otherwise.

Notes
  • The division is not implemented between Cochain instances yet.
Source code in src/dxtr/cochains/cochain.py
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def __truediv__(self, other: float | int | np.ndarray[float]) -> Optional[Cochain]:
    """Enables the division on the right.

    Parameters
    ----------
    other : float, int, or np.ndarray of float
        The value to divide by.

    Returns
    -------
    Cochain or None
        The resulting cochain if compatible, None otherwise.

    Notes
    -----
    * The division is not implemented between `Cochain` instances yet.
    """
    if isinstance(other, (float, int, np.ndarray)):
        inv_other = 1 / other
        return self * inv_other

    elif isinstance(other, Cochain):
        logger.warning('Cannot divide `Cochains` together for now')
        return None

from_file(path, name=None) classmethod

Instantiates a Cochain from a .vtk file.

Parameters:

Name Type Description Default
path str or Path

The path to the .vtk file.

required
name str

The name of the cochain. Default is None.

None
Notes
  • For now can only work with primal Cochain objects.
Source code in src/dxtr/cochains/cochain.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@classmethod
def from_file(cls, path: str | Path, name: Optional[str] = None) -> Cochain:
    """Instantiates a `Cochain` from a `.vtk` file.

    Parameters
    ----------
    path : str or Path
        The path to the `.vtk` file.
    name : str, optional
        The name of the cochain. Default is None.

    Notes
    -----
    * For now can only work with primal `Cochain` objects.
    """
    from dxtr.io import read_vtk

    simplices, vertices, property = read_vtk(path)
    manifold = SimplicialManifold(simplices, vertices)

    name = property.name if name is None else name
    dual = False

    return cls(manifold, property.dim, property.values, 
                dual=dual, name=name)

items()

Enables to iterate over Cochain indices and values.

Yields:

Type Description
tuple of int and float

Indices of the k-simplices where values are defined and the values of the cochain.

Source code in src/dxtr/cochains/cochain.py
459
460
461
462
463
464
465
466
467
468
469
def items(self) -> Generator[tuple[int, float], None, None]:
    """Enables to iterate over `Cochain` indices and values.

    Yields
    ------
    tuple of int and float
        Indices of the k-simplices where values are defined and the values of the cochain.
    """

    for idx, val in zip(self._indices, self._values):
        yield idx, val

to_file(file_name, format='.ply', folder=None)

Saves the Cochain instance on disk in the .vtk format.

Parameters:

Name Type Description Default
file_name str

The name of the file to write on disk.

required
format str

The type of file to write, see Notes. Default is .ply.

'.ply'
folder str or Path

The location where to write the file. Default is the current working directory.

None
Notes
  • Cochain instances can only be saved in the vtk format.
  • If no folder is provided, the file will be recorded in the current working directory.
Source code in src/dxtr/cochains/cochain.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
@valid_input
def to_file(self, file_name: str, format: str = '.ply', 
            folder: Optional[str | Path] = None) -> None:
    """
    Saves the `Cochain` instance on disk in the `.vtk` format.

    Parameters
    ----------
    file_name : str
        The name of the file to write on disk.
    format : str, optional
        The type of file to write, see Notes. Default is `.ply`.
    folder : str or Path, optional
        The location where to write the file. Default is the current working directory.

    Notes
    -----
    * `Cochain` instances can only be saved in the `vtk` format.
    * If no folder is provided, the file will be recorded in the current working directory.
    """
    from dxtr.io.write import format_path_properly
    from dxtr.utils.wrappers import UGrid

    path = format_path_properly(folder, file_name, '.vtk')

    ugrid = UGrid.generate_from(self)
    ugrid.save(path)

toarray()

Gets the values of the cochain as a numpy array.

Returns:

Type Description
np.ndarray of float, optional

The values of the cochain as a numpy array.

Source code in src/dxtr/cochains/cochain.py
472
473
474
475
476
477
478
479
480
481
482
483
def toarray(self) -> Optional[np.ndarray[float]]:
    """Gets the values of the cochain as a numpy array.

    Returns
    -------
    np.ndarray of float, optional
        The values of the cochain as a numpy array.
    """
    if isinstance(self._values, sp.spmatrix):
        return self._values.toarray()
    else:
        return np.asarray(self._values)

value_closest_to(position)

Gets the value closest to a provided position.

Parameters:

Name Type Description Default
position np.ndarray of float

The position to find the closest value to.

required

Returns:

Type Description
float

The value closest to the provided position.

Source code in src/dxtr/cochains/cochain.py
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
def value_closest_to(self, position: np.ndarray[float]) -> float:
    """Gets the value closest to a provided position.

    Parameters
    ----------
    position : np.ndarray of float
        The position to find the closest value to.

    Returns
    -------
    float
        The value closest to the provided position.
    """
    cplx = self.complex
    dim = self.dim

    sidx = cplx[dim].closest_simplex_to(position, index_only=True)

    return self.values[sidx]

cochain_base(complex, dim, dual=False)

Generates The k-cochain base on a given manifold.

Parameters:

Name Type Description Default
complex SimplicialComplex

The simplicial manifold to work on.

required
dim int

The topological dimension (k) of the desired k-cochain base.

required
dual bool

If True the returned Cochain is dual. Default is False.

False

Returns:

Type Description
Cochain or None

A k-Cochain with the Nk-identity matrix as value. Nk being the number of k-cochains in the provided simplicial manifold.

Notes
  • The identity matrix is implemented as a scipy.sparse.identity() one.
Source code in src/dxtr/cochains/cochain.py
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
def cochain_base(complex: SimplicialComplex, dim: int, 
                 dual: bool = False) -> Optional[Cochain]:
    """Generates The k-cochain base on a given manifold.

    Parameters
    ----------
    complex : SimplicialComplex
        The simplicial manifold to work on.
    dim : int
        The topological dimension (k) of the desired k-cochain base.
    dual : bool, optional
        If True the returned `Cochain` is dual. Default is False.

    Returns
    -------
    Cochain or None
        A k-`Cochain` with the Nk-identity matrix as value. Nk being the number of 
        k-cochains in the provided simplicial manifold.

    Notes
    -----
    * The identity matrix is implemented as a `scipy.sparse.identity()` one.
    """

    try:
        if dual:
            assert isinstance(complex, SimplicialManifold), (
            'dual `Cochain` can only be defined on a `SimplicialManifold`.')

        assert dim is not None, 'Please specify a dimension.'

        k, n = dim, complex.dim
        Nk = complex.shape[n-k] if dual else complex.shape[k]

        return Cochain(complex, k, sp.identity(Nk), dual=dual)

    except AssertionError as msg:
        logger.warning(msg)
        return None