Skip to content
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
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ makedocs(;
"Optional Methods" => "interface/optional.md",
"Traits and Styles" => "interface/traits.md",
"Implementation Guidelines" => "interface/guidelines.md",
"Testing a Sector Implementation" => "interface/testsuite.md",
],
"Sector Types" => [
"Overview" => "sectors.md",
Expand Down
3 changes: 1 addition & 2 deletions docs/src/interface/optional.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ sectorscalartype
```

!!! note
While there is a fallback definition that tries to determine the result from computing the functions on the unit sector,
it is often a good idea to define this method explicitly to avoid depending on compiler heuristics to constant-fold these calls.
While there is a fallback definition that tries to determine the result from computing the functions on the unit sector, it is often a good idea to define this method explicitly to avoid depending on compiler heuristics to constant-fold these calls.

## Topological Data Symbols

Expand Down
1 change: 1 addition & 0 deletions docs/src/interface/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ The interface documentation is divided into several pages:
- **[Optional Methods](optional.md)**: Additional methods with default implementations that can be specialized
- **[Traits and Styles](traits.md)**: Compile-time properties that control behavior and optimizations
- **[Implementation Guidelines](guidelines.md)**: Practical advice and helper types for implementing sectors
- **[Testing a Sector Implementation](testsuite.md)**: A reusable test suite that checks whether a new sector type satisfies the required categorical properties and is functional with TensorKit.jl
99 changes: 99 additions & 0 deletions docs/src/interface/testsuite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
```@meta
CollapsedDocStrings = true
```

# Testing a Sector Implementation

Implementing a new `Sector` subtype means providing a family of mutually consistent methods: fusion rules, F- and R-symbols, dimensions, dualities, an ordering, ...
These have to satisfy several non-trivial categorical identities (the pentagon and hexagon equations, unitarity of the F- and R-move, ...), but must also be compatible with TensorKit.jl as a data structure.
TensorKitSectors.jl ships a reusable test suite, `SectorTestSuite`, that checks exactly these properties for any `Sector` subtype.
It is defined within the package's own tests, but can be accessed by downstream packages or users testing their own sector implementations locally.

Here, we explain how to use the test suite, what it checks, and how to add new tests.
Currently, the suite is designed to run all tests for a single sector type at a time, as every single test within the test suite necessarily must pass for compatibility with TensorKit.jl.

## Running the test suite

Since the test suite is not part of the installed package, it is loaded as follows:

```julia
import TensorKitSectors
testsuite_path = joinpath(
dirname(dirname(pathof(TensorKitSectors))), # TensorKitSectors root
"test", "testsuite.jl"
)
include(testsuite_path)

SectorTestSuite.test_sector(MySectorType)
```

`test_sector` runs one `@testsuite` per property (see [What gets tested](@ref) below) and reports which ones fail for `MySectorType`.
The suite relies on [`TestExtras.jl`](https://github.com/Jutho/TestExtras.jl) for `@testinferred`, which checks both the return value and the type stability of an expression, so downstream packages should add `TestExtras` as a test dependency.


## What gets tested

Broadly, the sector tests fall into three categories:

```@raw html
<table align="left">

<tr>
<th> Category </th> <th> Checks </th>
</tr>

<tr>
<td> Interface & type stability</td>
<td>
1) Basic properties: the required methods exist, are type-stable, and return the documented types <br>
2) Show and parse: <code>Sector</code>s are printed in a parseable manner <br>
3) Value iterator: <code>Sector</code>s are ordered within <code>values(I)</code> in a consistent and expected manner (through <code>findindex</code>)
</td>
</tr>

<tr>
<td> Category-theoretic consistency </td>
<td> The algebraic identities a unitary (braided) fusion category must satisfy: pentagon and hexagon equations, unitarity of the F- and R-move, triangle equation, ribbon condition, self-duality of the braiding, symmetric braiding condition, Artin braid equality </td>
</tr>

<tr>
<td> Cross-consistency of derived quantities </td>
<td> Whenever a quantity can be computed both directly and through a generic fallback derived from other data (e.g. <code>dim</code> versus the internal <code>dim_from_Fsymbol</code>, or <code>Bsymbol</code> versus <code>Bsymbol_from_fusiontensor</code>), the two must agree </td>
</tr>

</table>
```

Tests that only apply to a subset of sectors are skipped automatically based on traits: braiding-related testsets pass untested unless `BraidingStyle(I) isa HasBraiding`, the fusion-tensor comparisons are skipped when `fusiontensor` has no method for `I`, and so on.
A test therefore never fails simply because a sector chooses not to implement an optional method.

## Test utilities

Most tests need a handful of representative sectors rather than the full (possibly infinite) set of values of `I`.
`SectorTestSuite` exports a few helpers to construct those:

- `smallset(I, size=5, maxdim=10)`: a small, shuffled sample of sectors of type `I` with dimension below `maxdim`, biased to include a non-abelian sector when `FusionStyle(I) isa MultipleFusion` so tests don't silently degenerate to the abelian case.
- `randsector(I)`: draws a single, non-unit sector at random from `smallset(I)`.
- `random_fusion(I, N)`: draws `N` random sectors such that every consecutive pair can be fused, i.e. builds a valid fusion series `a ⊗ b ⊗ ...`.

Besides this, other utility functions are:
- `can_fuse(a, b)`: whether `a ⊗ b` is non-empty.
Allows to test only non-trivial topological data, e.g. the F-symbols of fusion vertices that actually exist.
- `hasfusiontensor(I)`: whether [`fusiontensor`](@ref) has an implementation for `I`.

Additionally, the following tests are provided as standalone functions that can be used outside of the test suite:
- `F_unitarity_test(a, b, c; kwargs...)` / `R_unitarity_test(a, b; kwargs...)`: check unitarity of the F- and R-move, forwarding `kwargs` to `isapprox`.

These are all exported by `SectorTestSuite` and are also useful when writing additional, sector-specific tests beyond what the shared suite covers.

## Adding a new test to the test suite

Users who wish to contribute new checks to this package can register them with the `@testsuite` macro, which takes a name and a function of the sector type `I`:

```julia
@testsuite "My new property" I -> begin
# test body
end
```

These should be added under `test/sectors.jl`, while additional utility functions should be added to `test/testsuite.jl` and exported from `SectorTestSuite`.
3 changes: 2 additions & 1 deletion docs/src/sectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ It is intended as a reference implementation illustrating how to build such cate

## Other packages

TensorKitSectors.jl provides the architecture for implementing new sector types, but does not implement all possible sectors. Other packages which implement additional sector types and their topological data include:
TensorKitSectors.jl provides the architecture for implementing new sector types, but does not implement all possible sectors.
Other packages which implement additional sector types and their topological data include:
- [`SUNRepresentations.jl`](https://github.com/QuantumKitHub/SUNRepresentations.jl): Implements irreducible representations of SU(N) for arbitrary N
- [`CategoryData.jl`](https://github.com/QuantumKitHub/CategoryData.jl): Provides a variety of fusion categories up to rank 7, based on the [`AnyonWiki`](https://anyonwiki.github.io/)
- [`QWignerSymbols.jl`](https://github.com/QuantumKitHub/QWignerSymbols.jl): Provides the irreps of q-deformed SU(2)
3 changes: 2 additions & 1 deletion docs/src/sectors/composite/product.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ end
# Product Sectors: `ProductSector`

`ProductSector` represents the Deligne tensor product of sector categories.
It is the standard way to combine independent symmetry or anyon labels, such as charge and parity, or two different anyon theories. For the bosonic group or representation categories, this Deligne product corresponds to the ordinary product of groups or direct product of representations.
It is the standard way to combine independent symmetry or anyon labels, such as charge and parity, or two different anyon theories.
For the bosonic group or representation categories, this Deligne product corresponds to the ordinary product of groups or direct product of representations.

## Sector type

Expand Down
3 changes: 2 additions & 1 deletion docs/src/sectors/groupelement/znelement.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ Braiding is only defined in two cases:
R^{ab}_{a+b} = \exp\left(\frac{2\pi i\, p\, a\, b}{N^2}\right),
`````

giving abelian anyonic braiding statistics for the ``ℤ_N`` charges. For example, `N = 4, p = 2` (used in the example below) yields topological spins ``θ_a = \exp(iπ a^2 / 4)``.
giving abelian anyonic braiding statistics for the ``ℤ_N`` charges.
For example, `N = 4, p = 2` (used in the example below) yields topological spins ``θ_a = \exp(iπ a^2 / 4)``.

For any other value of `p`, `BraidingStyle(ZNElement{N,p}) = NoBraiding()`.

Expand Down
9 changes: 6 additions & 3 deletions docs/src/sectors/nonabelian/cu1.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ For a two-dimensional irrep `(j, 2)` with `j > 0`, the basis is ordered as a pai
\ket{+j},\ \ket{-j}.
```

The zero-charge irreps `(0, 0)` and `(0, 1)` are one-dimensional. The label `(0, 0)` is even under charge conjugation, while `(0, 1)` is odd.
The zero-charge irreps `(0, 0)` and `(0, 1)` are one-dimensional.
The label `(0, 0)` is even under charge conjugation, while `(0, 1)` is odd.

When two equal positive-charge irreps fuse to a zero-charge irrep, the fusion tensors pick the symmetric and antisymmetric combinations:

Expand Down Expand Up @@ -94,7 +95,8 @@ For two positive charges, the sum channel is diagonal:
\ket{-j_a,-j_b}↦\ket{-(j_a+j_b)}.
```

The difference channel pairs opposite weights. If `j_a > j_b`,
The difference channel pairs opposite weights.
If `j_a > j_b`,

```math
\ket{+j_a,-j_b}↦\ket{+(j_a-j_b)},\qquad
Expand All @@ -108,7 +110,8 @@ If `j_b > j_a`, the output basis is ordered by the positive charge `j_b - j_a`,
\ket{+j_a,-j_b}↦\ket{-(j_b-j_a)}.
```

All omitted entries are zero. These conventions determine the real [`Fsymbol`](@ref) values.
All omitted entries are zero.
These conventions determine the real [`Fsymbol`](@ref) values.

## Iteration

Expand Down
Loading