Source code for spheres.symmetrization

"""
Symmetrization related functions, particularly in the context of
permutation symmetric multiqubit states.
"""

import numpy as np
import qutip as qt
from itertools import *

from .utils import *

[docs]def symmetrize(pieces): """ Given a list of quantum states, constructs their symmetrized tensor product. If given a multipartite quantum state instead, we sum over all permutations on the subsystems. Parameters ---------- pieces : list or qt.Qobj List of quantum states or a multipartite state. Returns ------- sym : qt.Qobj Symmetrized tensor product. """ return sum([qt.tensor(*[pieces[i] for i in perm]) for perm in permutations(range(len(pieces)))]).unit() if type(pieces) == list \ else sum([pieces.permute(perm) for perm in permutations(range(len(pieces.dims[0])))]).unit()
[docs]def spin_sym_map(j): """ Constructs an isometric linear map from spin-j states to permutation symmetric states of 2j spin-:math:`\\frac{1}{2}`'s. Parameters ---------- j : int j value. Returns ------- S : qt.Qobj Linear map from :math:`2j+1` dimensions to :math:`2^{2j}` dimensions. """ if j == 0: return qt.Qobj(1) S = qt.Qobj(np.vstack([\ components(symmetrize(\ [qt.basis(2,0)]*int(2*j-i)+\ [qt.basis(2,1)]*i))\ for i in range(int(2*j+1))]).T) S.dims =[[2]*int(2*j), [int(2*j+1)]] return S
[docs]def spin_sym(spin, map=None): """ Converts a spin-j state into a state of 2j symmetrized qubits. Constructs the linear map if not provided. Parameters ---------- spin : qt.Qobj Pure or mixed spin state. Returns ------- sym : qt.Qobj Pure or mixed state of 2j symmetrized qubits. """ j = (spin.shape[0]-1)/2 if not map: map = spin_sym_map(j) return map*spin if spin.type != 'oper' else map*spin*map.dag()
[docs]def sym_spin(sym, map=None): """ Converts a state of 2j symmetrized qubits into a spin-j state. Constructs the linear map if not provided. Parameters ---------- sym : qt.Qobj Pure or mixed state of 2j symmetrized qubits. Returns ------- spin : qt.Qobj Pure or mixed spin state. """ j = len(sym.dims[0])/2 if not map: map = spin_sym_map(j) return map.dag()*sym if sym.type != 'oper' else map.dag()*sym*map
[docs]def symmetrized_basis(n, d=2): """ Constructs a symmetrized basis set for n systems in d dimensions. Parameters ---------- n : int The number of systems to symmetrize. d : int or list Either an integer representing the dimensionality of the individual subsystems, in which case, we work in the computational basis; or else a list of basis states for the individual systems. Returns ------- sym_basis : dict ``sym_basis["labels"]`` is a list of labels for the symmetrized basis states. Each element of the list is a tuple whose length is the dimensionality of the individual subsystems, with an integer counting the number of subsystems in that basis state. ``sym_basis["basis"]`` is a dictionary mapping labels to symmetrized basis states. ``sym_basis["map"]`` is a linear transformation from the permutation symmetric subspace to the full tensor product of the n systems. The dimensionality of the symmetric subspace corresponds to the number of ways of distributing :math:`n` elements in :math:`d` boxes, where :math:`n` is the number of systems and :math:`d` is the dimensionality of an individual subsytems. In other words, the dimensionality :math:`s` of the permutation symmetric subspace is :math:`\\binom{d+n-1}{n}`. So ``sym_basis["map"]`` is a map from :math:`\\mathbb{C}^{s} \\rightarrow \\mathbb{C}^{d^{n}}`. """ if type(d) == int: d = [qt.basis(d, i) for i in range(d)] labels = list(filter(lambda b: sum(b) == n,\ list(product(range(n+1), repeat=len(d)))[::-1])) sym_basis = dict([(label, symmetrize(flatten([[d[i]]*b \ for i, b in enumerate(label)])))\ for label in labels]) sym_map = qt.Qobj(np.vstack([components(sym_basis[label])\ for label in labels]).T) sym_map.dims =[[d[0].shape[0]]*n, [len(sym_basis)]] return {"labels": labels,\ "basis": sym_basis,\ "map": sym_map}