Source code for vulqano.quantummodels.localquantumops

# This code is part of vulqano.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.


"""
Build the matrix representation of quadratic operators g_i^dag g_j for each gate,
where g_i is an annihilation operator.
"""


from collections import OrderedDict
from itertools import product
import numpy as np
import qtealeaves as qtl
from vulqano.gates.discretegates import ROT_GATES


__all__ = [
    "build_annihil_op",
    "TNGateOperators",
    "TNTimeStepOperators",
]


[docs] def build_annihil_op(index, local_dim): """ Build the matrix representation of the annihilation operator for the gate labeled by the index. **Arguments** index : int Boson favour label local_dim : int DImension of the local Hilber space **Returns** tmp : np.array Matrix representation of the annihiling operator. """ tmp = np.zeros((local_dim, local_dim)) tmp[0, index] = 1 return tmp
[docs] class TNGateOperators(qtl.operators.TNOperators): """ Class for the definition of a set of local gate operators g_i^dag g_j. **Arguments** gates : list of str The list of gates involved in the circuit, included the identity. Idenity has to be the first gate. folder_operators : str, optional DESCRIPTION. The default is "TNGateOperators". """ def __init__( self, gates, folder_operators="TNGateOperators", ): if gates[0] != "idle": raise ValueError("The first gate must be the identity") gates += ["busy"] self.folder_operators = folder_operators self.local_dim = len(gates) annihilators = {} for ii, gate in enumerate(gates): annihilators[gate] = build_annihil_op(ii, self.local_dim) self.ops = OrderedDict() self.ops["id"] = np.eye(self.local_dim) gates_couples = product(gates, gates) for gate1, gate2 in gates_couples: self.ops[gate1 + "->" + gate2] = ( annihilators[gate2].conj().T.dot(annihilators[gate1]) ) self.ops["any->any"] = sum(self.ops[gate + "->" + gate] for gate in gates) self.ops["any_rot->any_rot"] = sum( self.ops[gate + "->" + gate] for gate in set(ROT_GATES).intersection(set(gates)) )
[docs] class TNTimeStepOperators(qtl.operators.TNOperators): """ Class for the definition of a set of time step configuration transitions of the form g_i^dag g_j. **Arguments** time_step_configurations : list of str List of possible time-step configurations to be represented as states in a local Hilbert space. Each time step configuration is represented by a string like "g1|...|gn". time_step_transformations : list of str The list of transformations between time steps to be encoded as operators. Each transformation is represented by a string like "g1|...|gn->g'1|...|g'n". folder_operators : str, optional Folder where the operators are saved by qtealeaves. The default is "TNTimeStepOperators". """ def __init__( self, time_step_configurations, time_step_transformations, folder_operators="TNTimeStepOperators", ): self.folder_operators = folder_operators self.local_dim = len(time_step_configurations) annihilators = {} for ii, config in enumerate(time_step_configurations): annihilators[config] = build_annihil_op(ii, self.local_dim) self.ops = OrderedDict() self.ops["id"] = np.eye(self.local_dim) for transformation in time_step_transformations: (configuration_in, configuration_out) = transformation.split("->") self.ops[transformation] = np.zeros((self.local_dim, self.local_dim)) for new_configuration_in, new_configuration_out in self.expand_identities( time_step_configurations, configuration_in, configuration_out ): self.ops[transformation] += ( annihilators[new_configuration_in] .conj() .T.dot(annihilators[new_configuration_out]) )
[docs] @staticmethod def expand_identities( time_step_configurations, configuration_in, configuration_out ): """ Given two terms of a transformation, if these terms contain the "any" gate, expand the terms over all the possible configurations of the time step that are compatible. **Arguments** time_step_configurations : list of strings List of possible time step configurations represented by strings like "g1|...|gn". configuration_in : string Input time step configuration represented by a string like "g1|...|gn". configuration_out : string Transformed time step configuration represented by a string like "g'1|...|g'n". **Yields** new_configuration_in : string Input time step configuration where each "any" gate has been replaced in a way such that the new configuration is in time_step_configurations. new_configuration_out : string Transformed time step configuration where each "any" gate has been replaced in a way such that the new configuration is in time_step_configurations. """ splitted_configuration_in = configuration_in.split("|") splitted_configuration_out = configuration_out.split("|") if "any" in configuration_in: for possible_configuration in time_step_configurations: possible_configuration = possible_configuration.split("|") if all( gate in ("any", possible_configuration[ii]) for ii, gate in enumerate(splitted_configuration_in) ): new_configuration_in = [ gate if gate != "any" else possible_configuration[ii] for ii, gate in enumerate(splitted_configuration_in) ] new_configuration_out = [ gate if gate != "any" else possible_configuration[ii] for ii, gate in enumerate(splitted_configuration_out) ] yield "|".join(new_configuration_in), "|".join( new_configuration_out ) else: yield configuration_in, configuration_out