from __future__ import annotations
from dataclasses import dataclass
from itertools import pairwise
from numbers import Number
import numpy as np
from .young import YoungDiagram
[docs]
@dataclass(frozen=True)
class ConjugacyClass:
'''
Represents the conjugacy class of partitions. For example,
the partition L = (5, 3, 2, 2, 2, 1, 1) can represented by
L = (1: 2, 2: 3, 3: 1, 4: 0, 5: 1) that means 2 rows of
length 1, 3 rows of length 2, 2 rows of length 3, 0 rows of
length 4 and 1 row of length 5.
To avoid cluttering, we could simply write the vector
k = (2, 3, 1, 0, 1) to describe the same partition.
We do it in an internal method below, but we will return
dictionaries to avoid confusion with the partitions.
The dictionary must be in the form {1: k1, 2: k2, ..., n: kn}
The vectors k = (k1,k2, ..., kn) represents one conjugacy class of
the symmetric group S_n, and for this reason, we call it conjugacy
class vectors.
In terms of the Heisenberg algebra, the components of these vectors
denote the power of the Heisenberg operator J_{-n} when acting on the
vacuum state |0>
'''
_conjugacy_vector: dict
def __post_init__(self) -> None:
'''
Validates the form of the dictionary: {1: k1, 2: k2, ..., n: kn}
'''
keys = tuple(self._conjugacy_vector.keys())
val_A = all(y - x == 1 for x,y in pairwise(keys))
val_B = all(isinstance(m, Number) for m in self._conjugacy_vector.values())
if keys[0] != 1 or not val_A:
raise TypeError("Argument must be a dictionary in the form {1: k1, 2: k2, ..., n: kn}")
elif not val_B:
raise TypeError("Values in the dictionary must be numeric.")
@property
def conjugacy(self) -> tuple:
'''
Getter for the conjugacy class vector
'''
return tuple(self._conjugacy_vector.values())
@property
def rows(self) -> int:
'''
Gives the number of rows in this diagram.
This is the sum over the conjugacy.
'''
return sum(self.conjugacy)
@property
def columns(self) -> int:
'''
Gives the number of columns in this diagram.
for the vector (1: k1, ..., n: kn), the number of
columns is n: the last entry in the dictionary.
(max iterates over the keys).
'''
return max(self._conjugacy_vector)
@property
def boxes(self) -> int:
'''
Gives the number of boxes in the diagram.
'''
box = 0
for x, y in self._conjugacy_vector.items():
box += x*y
return box
[docs]
def draw_diagram(self, n=0) -> None:
'''
Here we have a pictorial representation of the Young diagram
associated to the conjugacy class in French notation.
Here I just call the function for the partition states.
'''
young = YoungDiagram(self.conjugacy_partition())
young.draw_diagram(n)
[docs]
def conjugacy_partition(self) -> tuple:
'''
Converts the conjugacy class vector to the partition notation.
Example:
[1,2,0,4] is equivalent to the Young
diagram [4,4,4,4,2,2,1].
These vectors also denote the bosonic partition state that we can
build with the bosonic states
power of the operators J_{-n} that acts on the
vaccum state |0>.
The algorithm works as follows:
We first create an empty array partition = []
and we define the range for the loop to be the length of
the vector k: In our case [1,2,0,3], i = 0,1,2,3.
- loop 01: i = 0 k[0] = 1:
row = [1]
partition = [] U [1] = [1]
- loop 02: i = 1 k[1] = 2
row = [2,2]
partition = [1] U [2,2] = [1,2,2]
- loop 03: i = 2 k[2] = 0
row = []
partition = [1,2,2] U [] = [1,2,2]
- loop 04: i = 3 k[3] = 4
row = [4,4,4,4]
partition = [1,2,2] U [4,4,4,4] = [1,2,2,4,4,4,4]
Then when we put it in decreasing order we find [4,4,4,4,2,2,1]
'''
partition = np.array([])
for i in range(len(self.conjugacy)):
row = np.repeat(i+1, self.conjugacy[i])
partition = np.concatenate((partition, row), axis=0)
partition = -np.sort(-partition, axis=0) # Sorts the numpy array in decreasing order.
partition = partition.astype(int) # Converts entries into integers
return tuple(partition)