# Double complexes – the user's interface

We briefly review the mathematical notion of a double complex. Let $\mathcal A$ be an Abelian category. A double complex $D_{\bullet, \bullet}$ consists of a collection of objects $D_{i, j}$ in $\mathcal A$ with indices $(i, j) \in \mathbb Z^2$ and usually arranged in a matrix-like grid, together with two collections of morphisms $D_{i, j} \to D_{i \pm 1, j}$, the *horizontal* morphisms, and $D_{i, j} \to D_{i, j \pm 1}$, the *vertical* morphisms, so that both the rows and the columns of $D_{\bullet, \bullet}$ are complexes in the classical sense and such that all resulting squares of maps commute.

In practice one usually encounters complexes which are *bounded* in the sense that outside some specified area of indices $(i, j) \in \mathbb Z^2$ the entries $D_{i, j}$ are all zero. Such entries are then usually omitted.

## Basic getters and attributes

In OSCAR the generic functionality for double complexes is declared for the abstract type `AbsDoubleComplexOfMorphisms`

. These functions comprise

` getindex(D::AbsDoubleComplexOfMorphisms, i::Int, j::Int) # Get the `(i,j)`-th entry of `D``

`horizontal_map`

— Method`horizontal_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return the morphism $dc[i, j] → dc[i ± 1, j]$ (the sign depending on the `horizontal_direction`

of `dc`

).

This function is part of the experimental code in Oscar. Please read here for more details.

`vertical_map`

— Method`vertical_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return the morphism $dc[i, j] → dc[i, j ± 1]$ (the sign depending on the `vertical_direction`

of `dc`

).

This function is part of the experimental code in Oscar. Please read here for more details.

In which direction the maps in the rows and columns go can be asked with the following methods:

`horizontal_direction`

— Method`horizontal_direction(dc::AbsDoubleComplexOfMorphisms)`

Return a symbol `:chain`

or `:cochain`

depending on whether the morphisms of the rows of `dc`

decrease or increase the (co-)homological index.

This function is part of the experimental code in Oscar. Please read here for more details.

`vertical_direction`

— Method`vertical_direction(dc::AbsDoubleComplexOfMorphisms)`

Return a symbol `:chain`

or `:cochain`

depending on whether the morphisms of the columns of `dc`

decrease or increase the (co-)homological index.

This function is part of the experimental code in Oscar. Please read here for more details.

Double complexes can be bounded or unbounded. It is important to note that even if such bounds exist and are known, this is a priori **not** related to whether or not certain entries are computable! I.e. even in the case of a bounded complex `dc`

it might still be valid to call `dc[i, j]`

beyond that bound. In general, one should use the following functions to determine whether or not it is legitimate to ask for a specific entry.

`has_index`

— Method`has_index(D::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return `true`

if the `(i, j)`

-th entry of `D`

is already known, `false`

otherwise.

If the result is `false`

, then it might nevertheless still be possible to compute `D[i, j]`

; use `can_compute_index`

for such queries.

This function is part of the experimental code in Oscar. Please read here for more details.

`can_compute_index`

— Method`can_compute_index(D::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return `true`

if the entry `D[i, j]`

is known or `D`

knows how to compute it.

This function is part of the experimental code in Oscar. Please read here for more details.

`has_horizontal_map`

— Method`has_horizontal_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Checks whether the double complex `dc`

has the horizontal morphism `dc[i, j] → dc[i ± 1, j]`

, the sign depending on the `horizontal_direction`

of `dc`

.

If this returns `false`

this might just mean that the map has not been computed, yet. Use `can_compute_horizontal_map`

to learn whether or not this is possible.

This function is part of the experimental code in Oscar. Please read here for more details.

`can_compute_horizontal_map`

— Method`can_compute_horizontal_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return `true`

if `dc`

can compute the horizontal morphism `dc[i, j] → dc[i ± 1, j]`

, the sign depending on the `horizontal_direction`

of `dc`

, and `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

`has_vertical_map`

— Method`has_vertical_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Checks whether the double complex `dc`

has the vertical morphism `dc[i, j] → dc[i, j ± 1]`

, the sign depending on the `vertical_direction`

of `dc`

.

If this returns `false`

this might just mean that the map has not been computed, yet. Use `can_compute_vertical_map`

to learn whether or not this is possible.

This function is part of the experimental code in Oscar. Please read here for more details.

`can_compute_vertical_map`

— Method`can_compute_vertical_map(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

Return `true`

if `dc`

can compute the vertical morphism `dc[i, j] → dc[i, j ± 1]`

, the sign depending on the `vertical_direction`

of `dc`

, and `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

Explicitly known bounds for the non-zero entries of a complex are nevertheless relevant for various generic functionalities. For example, computing a total complex is only possible in practice if one has an a priori estimate where the non-zero entries are located. For such purposes, we provide the following functionality:

`has_upper_bound`

— Method`has_upper_bound(D::AbsDoubleComplexOfMorphisms)`

Return `true`

if a universal upper bound $j ≤ B$ for non-zero `D[i, j]`

is known; `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

`has_lower_bound`

— Method`has_lower_bound(D::AbsDoubleComplexOfMorphisms)`

Return `true`

if a universal upper bound $B ≤ j$ for non-zero `D[i, j]`

is known; `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

`has_right_bound`

— Method`has_right_bound(D::AbsDoubleComplexOfMorphisms)`

Return `true`

if a universal upper bound $i ≤ B$ for non-zero `D[i, j]`

is known; `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

`has_left_bound`

— Method`has_left_bound(D::AbsDoubleComplexOfMorphisms)`

Return `true`

if a universal upper bound $B ≤ i$ for non-zero `D[i, j]`

is known; `false`

otherwise.

This function is part of the experimental code in Oscar. Please read here for more details.

If they exist, these bounds can be asked for using

`right_bound`

— Method`right_bound(D::AbsDoubleComplexOfMorphisms)`

Return a bound $B$ such that `D[i, j]`

can be assumed to be zero for $i > B$. Whether or not requests for `D[i, j]`

beyond that bound are legitimate can be checked using `can_compute_index`

.

This function is part of the experimental code in Oscar. Please read here for more details.

`left_bound`

— Method`left_bound(D::AbsDoubleComplexOfMorphisms)`

Return a bound $B$ such that `D[i, j]`

can be assumed to be zero for $i < B$. Whether or not requests for `D[i, j]`

beyond that bound are legitimate can be checked using `can_compute_index`

.

This function is part of the experimental code in Oscar. Please read here for more details.

`upper_bound`

— Method`upper_bound(D::AbsDoubleComplexOfMorphisms)`

Return a bound $B$ such that `D[i, j]`

can be assumed to be zero for $j > B$. Whether or not requests for `D[i, j]`

beyond that bound are legitimate can be checked using `can_compute_index`

.

This function is part of the experimental code in Oscar. Please read here for more details.

`lower_bound`

— Method`lower_bound(D::AbsDoubleComplexOfMorphisms)`

Return a bound $B$ such that `D[i, j]`

can be assumed to be zero for $j < B$. Whether or not requests for `D[i, j]`

beyond that bound are legitimate can be checked using `can_compute_index`

.

This function is part of the experimental code in Oscar. Please read here for more details.

It is also possible to query whether or not a double complex is already complete in the sense that it knows about all of its non-zero entries.

`is_complete`

— Method`is_complete(dc::AbsDoubleComplexOfMorphisms)`

Return `true`

if for all indices `(i, j)`

with `has_index(dc, i, j) = true`

and `dc[i, j]`

non-zero, the vertex `(i, j)`

is lying on an "island" of non-zero entries in the grid of the double complex, which is bounded by either zero entries or entries for indices `(i', j')`

where `can_compute_index(dc, i', j') = false`

. At least one index `dc[i, j]`

must be known for this to return `true`

.

```
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → ? → ? → ? → ? → ? → ? → ? → ? → ? → ? → ? → 0 → 0 → ? → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → ? → ? → 0 → 0 → 0 → ? → ? → 0 → 0 → 0 → 0 → * → * → 0 → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → 0 → 0 → * → * → * → 0 → ? → 0 → ? → 0 → 0 → * → * → * → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → 0 → * → * → * → 0 → ? → ? → 0 → 0 → ? → 0 → * → 0 → * → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → 0 → * → * → * → 0 → ? → 0 → 0 → 0 → 0 → * → * → 0 → 0 → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
… → ? → 0 → 0 → 0 → ? → ? → ? → ? → ? → ? → 0 → 0 → ? → ? → - → - → …
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
```

Example of a pattern of a double complex with `is_complete = true`

. `0`

: zero entry `-`

: entry can not be computed (`can_compute_index`

returns `false`

) `*`

: non-zero entry which has been computed `?`

: entry can be computed, but that has not yet been done

!!! note If the double complex has several of the above "islands", then `is_complete`

might return `true`

even though one or more of the "islands" have not yet been uncovered. Use this carefully if your full double complex might be separated by zero entries!

This function is part of the experimental code in Oscar. Please read here for more details.

## Generic functionality

`total_complex`

— Method`total_complex(D::AbsDoubleComplexOfMorphisms)`

Construct the total complex of the double complex `D`

.

Note that `D`

needs to be reasonably bounded for this to work so that the strands $⨁ ᵢ₊ⱼ₌ₖ Dᵢⱼ$ are finite for every `k`

. Moreover, the generic code uses the internal function `_direct_sum`

. See the docstring of that function to learn more.

This function is part of the experimental code in Oscar. Please read here for more details.

## Constructors

`tensor_product`

— Method`tensor_product(C::ComplexOfMorphisms{ChainType}, D::ComplexOfMorphisms{ChainType}) where {ChainType}`

Create the tensor product of two complexes `C`

and `D`

as a double complex.

In order for the generic implementation to work for your specific `ChainType`

the following needs to be implemented.

`morphism_type(ChainType)`

must produce the type of morphisms between objects of type`ChainType`

;- the call signature for
`function (fac::TensorProductFactory{ChainType})(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

needs to be overwritten for your specific instance of`ChainType`

to produce the`(i, j)`

-th entry of the double complex, i.e. the tensor product of`C[i]`

and`D[j]`

; - the call signature for
`function (fac::HorizontalTensorMapFactory{ChainType})(dc::AbsDoubleComplexOfMorphisms, i::Int, j::Int)`

needs to be overwritten to produce the map on tensor products`C[i] ⊗ D[j] → C[i±1] ⊗ D[j]`

induced by the (co-)boundary map on`C`

(the sign depending on the`typ`

of`C`

); - similarly for the
`VerticalTensorMapFactory`

.

See the file `experimental/DoubleComplex/src/tensor_products.jl`

for examples.

This function is part of the experimental code in Oscar. Please read here for more details.