Source code for qutip.qip.models.cqed

# This file is part of QuTiP: Quantum Toolbox in Python.
#
#    Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson.
#    All rights reserved.
#
#    Redistribution and use in source and binary forms, with or without
#    modification, are permitted provided that the following conditions are
#    met:
#
#    1. Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#
#    2. Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#
#    3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names
#       of its contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
#    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
#    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
#    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
#    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################
import numpy as np
import warnings
from qutip import tensor, identity, destroy, sigmax, sigmaz, basis
from qutip.qip.circuit import QubitCircuit, Gate
from qutip.qip.models.circuitprocessor import CircuitProcessor


[docs]class DispersivecQED(CircuitProcessor): """ Representation of the physical implementation of a quantum program/algorithm on a dispersive cavity-QED system. """ def __init__(self, N, correct_global_phase=True, Nres=None, deltamax=None, epsmax=None, w0=None, wq=None, eps=None, delta=None, g=None): """ Parameters ---------- Nres: Integer The number of energy levels in the resonator. deltamax: Integer/List The sigma-x coefficient for each of the qubits in the system. epsmax: Integer/List The sigma-z coefficient for each of the qubits in the system. wo: Integer The base frequency of the resonator. wq: Integer/List The frequency of the qubits. eps: Integer/List The epsilon for each of the qubits in the system. delta: Integer/List The epsilon for each of the qubits in the system. g: Integer/List The interaction strength for each of the qubit with the resonator. """ super(DispersivecQED, self).__init__(N, correct_global_phase) # user definable if Nres is None: self.Nres = 10 else: self.Nres = Nres if deltamax is None: self.sx_coeff = np.array([1.0 * 2 * np.pi] * N) elif not isinstance(deltamax, list): self.sx_coeff = np.array([deltamax * 2 * np.pi] * N) else: self.sx_coeff = np.array(deltamax) if epsmax is None: self.sz_coeff = np.array([9.5 * 2 * np.pi] * N) elif not isinstance(epsmax, list): self.sz_coeff = np.array([epsmax * 2 * np.pi] * N) else: self.sz_coeff = np.array(epsmax) if w0 is None: self.w0 = 10 * 2 * np.pi else: self.w0 = w0 if eps is None: self.eps = np.array([9.5 * 2 * np.pi] * N) elif not isinstance(eps, list): self.eps = np.array([eps * 2 * np.pi] * N) else: self.eps = np.array(eps) if delta is None: self.delta = np.array([0.0 * 2 * np.pi] * N) elif not isinstance(delta, list): self.delta = np.array([delta * 2 * np.pi] * N) else: self.delta = np.array(delta) if g is None: self.g = np.array([0.01 * 2 * np.pi] * N) elif not isinstance(g, list): self.g = np.array([g * 2 * np.pi] * N) else: self.g = np.array(g) if wq is not None: if not isinstance(wq, list): self.wq = np.array([wq] * N) else: self.wq = np.array(wq) if wq is None: if eps is None: self.eps = np.array([9.5 * 2 * np.pi] * N) elif not isinstance(eps, list): self.eps = np.array([eps] * N) else: self.eps = np.array(eps) if delta is None: self.delta = np.array([0.0 * 2 * np.pi] * N) elif not isinstance(delta, list): self.delta = np.array([delta] * N) else: self.delta = np.array(delta) # computed self.wq = np.sqrt(self.eps ** 2 + self.delta ** 2) self.Delta = self.wq - self.w0 # rwa/dispersive regime tests if any(self.g / (self.w0 - self.wq) > 0.05): warnings.warn("Not in the dispersive regime") if any((self.w0 - self.wq) / (self.w0 + self.wq) > 0.05): warnings.warn( "The rotating-wave approximation might not be valid.") self.sx_ops = [tensor([identity(self.Nres)] + [sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.sz_ops = [tensor([identity(self.Nres)] + [sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.a = tensor([destroy(self.Nres)] + [identity(2) for n in range(N)]) self.cavityqubit_ops = [] for n in range(N): sm = tensor([identity(self.Nres)] + [destroy(2) if m == n else identity(2) for m in range(N)]) self.cavityqubit_ops.append(self.a.dag() * sm + self.a * sm.dag()) self.psi_proj = tensor([basis(self.Nres, 0)] + [identity(2) for n in range(N)])
[docs] def get_ops_and_u(self): H0 = self.a.dag() * self.a return ([H0] + self.sx_ops + self.sz_ops + self.cavityqubit_ops, np.hstack((self.w0 * np.zeros((self.sx_u.shape[0], 1)), self.sx_u, self.sz_u, self.g_u)))
[docs] def get_ops_labels(self): return ([r"$a^\dagger a$"] + [r"$\sigma_x^%d$" % n for n in range(self.N)] + [r"$\sigma_z^%d$" % n for n in range(self.N)] + [r"$g_{%d}$" % (n) for n in range(self.N)])
[docs] def optimize_circuit(self, qc): self.qc0 = qc self.qc1 = self.qc0.resolve_gates(basis=["ISWAP", "RX", "RZ"]) self.qc2 = self.dispersive_gate_correction(self.qc1) return self.qc2
def eliminate_auxillary_modes(self, U): return self.psi_proj.dag() * U * self.psi_proj
[docs] def dispersive_gate_correction(self, qc1, rwa=True): """ Method to resolve ISWAP and SQRTISWAP gates in a cQED system by adding single qubit gates to get the correct output matrix. Parameters ---------- qc: Qobj The circular spin chain circuit to be resolved rwa: Boolean Specify if RWA is used or not. Returns ---------- qc: QubitCircuit Returns QubitCircuit of resolved gates for the qubit circuit in the desired basis. """ qc = QubitCircuit(qc1.N, qc1.reverse_states) for gate in qc1.gates: qc.gates.append(gate) if rwa: if gate.name == "SQRTISWAP": qc.gates.append(Gate("RZ", [gate.targets[0]], None, arg_value=-np.pi / 4, arg_label=r"-\pi/4")) qc.gates.append(Gate("RZ", [gate.targets[1]], None, arg_value=-np.pi / 4, arg_label=r"-\pi/4")) qc.gates.append(Gate("GLOBALPHASE", None, None, arg_value=-np.pi / 4, arg_label=r"-\pi/4")) elif gate.name == "ISWAP": qc.gates.append(Gate("RZ", [gate.targets[0]], None, arg_value=-np.pi / 2, arg_label=r"-\pi/2")) qc.gates.append(Gate("RZ", [gate.targets[1]], None, arg_value=-np.pi / 2, arg_label=r"-\pi/2")) qc.gates.append(Gate("GLOBALPHASE", None, None, arg_value=-np.pi / 2, arg_label=r"-\pi/2")) return qc
[docs] def load_circuit(self, qc): gates = self.optimize_circuit(qc).gates self.global_phase = 0 self.sx_u = np.zeros((len(gates), len(self.sx_ops))) self.sz_u = np.zeros((len(gates), len(self.sz_ops))) self.g_u = np.zeros((len(gates), len(self.cavityqubit_ops))) self.T_list = [] n = 0 for gate in gates: if gate.name == "ISWAP": t0, t1 = gate.targets[0], gate.targets[1] self.sz_u[n, t0] = self.wq[t0] - self.w0 self.sz_u[n, t1] = self.wq[t1] - self.w0 self.g_u[n, t0] = self.g[t0] self.g_u[n, t1] = self.g[t1] J = self.g[t0] * self.g[t1] * (1 / self.Delta[t0] + 1 / self.Delta[t1]) / 2 T = (4 * np.pi / abs(J)) / 4 self.T_list.append(T) n += 1 elif gate.name == "SQRTISWAP": t0, t1 = gate.targets[0], gate.targets[1] self.sz_u[n, t0] = self.wq[t0] - self.w0 self.sz_u[n, t1] = self.wq[t1] - self.w0 self.g_u[n, t0] = self.g[t0] self.g_u[n, t1] = self.g[t1] J = self.g[t0] * self.g[t1] * (1 / self.Delta[t0] + 1 / self.Delta[t1]) / 2 T = (4 * np.pi / abs(J)) / 8 self.T_list.append(T) n += 1 elif gate.name == "RZ": g = self.sz_coeff[gate.targets[0]] self.sz_u[n, gate.targets[0]] = np.sign(gate.arg_value) * g T = abs(gate.arg_value) / (2 * g) self.T_list.append(T) n += 1 elif gate.name == "RX": g = self.sx_coeff[gate.targets[0]] self.sx_u[n, gate.targets[0]] = np.sign(gate.arg_value) * g T = abs(gate.arg_value) / (2 * g) self.T_list.append(T) n += 1 elif gate.name == "GLOBALPHASE": self.global_phase += gate.arg_value else: raise ValueError("Unsupported gate %s" % gate.name)