Example #1
0
def Hamiltonian(Ej, Ec, freq_a, V):
    """
    In the final Hamiltonian the levels should be interpreted (qubit, cavity):
    
    eigvals[0] : (0,0)
    eigvals[1] : (0,1)
    eigvals[2] : (1,0)
    eigvals[4] : (1,1)
    eigvals[5] : (2,0)
    
    """
    plot_charge_matrix = False
    plot_transmon_levels = False

    # diagonalize transmon in charge basis
    n = tf.cast(diag(tf.range(-N_qb / 2, N_qb / 2)), c64)
    cos_phi = tf.cast(
        (diag(tf.ones(N_qb - 1), k=1) + diag(tf.ones(N_qb - 1), k=-1)) / 2,
        c64)

    H = -Ej * cos_phi + 4 * Ec * n**2
    eigvals, U = tf.linalg.eigh(H)  # H = U  @ diag(eigvals) @ U_dag

    # project onto subspace of L transmon levels
    H_L = tf.linalg.diag(eigvals[:L])
    n_L = (tf.linalg.adjoint(U) @ n @ U)[:L, :L]

    # operators in joint transmon-cavity Hilbert space
    H_cav = freq_a * tensor([ops.identity(L), ops.num(N_cav)])
    H_qb = tensor([H_L, ops.identity(N_cav)])
    H_coupling = V * tensor([n_L, ops.position(N_cav)])

    if plot_transmon_levels:
        fig, ax = plt.subplots(1, 1)
        ax.set_ylabel('Transmon energy level (Hz)')
        ax.plot(range(25), eigvals[:25], marker='.', linestyle='none')

    if plot_charge_matrix:
        fig, ax = plt.subplots(1, 1)
        ax.set_title('Charge matrix in transmon basis')
        ax.pcolormesh(range(L), range(L), np.transpose(np.abs(n_L)))

    H0 = H_cav + H_qb
    H = H0 + H_coupling

    # free up that sweet memory
    del (n, cos_phi, H_L, n_L, H_cav, H_qb, H_coupling)
    return H0, H
Example #2
0
 def __call__(self, *args, **kwargs):
     this_op = self.compute(*args, **kwargs)
     if self.tensor_with is not None:
         ops = [T if T is not None else this_op for T in self.tensor_with]
         return tensor(ops)
     else:
         return this_op
Example #3
0
    def compute(self, theta, dangle=None):
        """Calculates SNAP(theta) using qubit rotation gates.
        
        Args:
            theta (Tensor([B1, ..., Bb, S], c64)): A batch of parameters.
            dangle (Tensor([B1, ..., Bb, S], c64)): A batch of offsets to
                add to qubit rotation angles to compenstate for possible
                angle offsets due to miscalibration.
        Returns:
            Tensor([B1, ..., Bb, 2N, 2N], c64): A batch of SNAP(theta)
        """
        # this part is the same as for perfect SNAP: pad the angles with zeros
        S = theta.shape[-1]  # SNAP truncation
        batch_shape = theta.shape[:-1]
        paddings = tf.constant([[0, 0]] * len(batch_shape) + [[0, self.N - S]])
        dangle = tf.zeros_like(theta) if dangle is None else dangle
        theta = tf.pad(theta, paddings)  # shape=[B,N]
        dangle = tf.pad(dangle, paddings)

        # inteded angle and phase of rotation
        angle, phase = tf.ones_like(theta) * pi + dangle, pi - theta
        # approximate angle and phase using partially selective pulses
        angle, phase = self.rotation_coeffs(angle, phase)
        angle, phase = tf.cast(angle, c64), tf.cast(phase, c64)

        # unitary corresponding to the first unselective qubit flip
        unselective_rotation = tensor([
            self.rotate_qb(tf.constant(pi), tf.constant(0)),
            identity(self.N)
        ])

        # construct a unitary corresponding to second "selective" qubit pulse
        R = self.rotate_qb(angle, phase)  # shape=[B,N,2,2]
        projectors = tf.broadcast_to(self.projectors, batch_shape +
                                     self.projectors.shape)  # shape=[B,N,N,N]
        selective_rotations = tensor([R, projectors])  # shape=[B,N,2N,2N]
        selective_rotations = tf.reduce_sum(selective_rotations,
                                            axis=-3)  # shape=[B,2N,2N]

        snap = selective_rotations @ unselective_rotation
        return snap
Example #4
0
                   x0=[Ej, Ec, freq_a, V],
                   method='Nelder-Mead',
                   options=dict(maxiter=300))
    Ej, Ec, freq_a, V = res.x
else:
    Ec = 188598981
    Ej = 21608836632
    freq_a = 4481053074
    V = 23249563

# create operators in the joint Hilbert space
H0, H = Hamiltonian(Ej, Ec, freq_a, V)
U = ops.HamiltonianEvolutionOperator(H)
U0 = ops.HamiltonianEvolutionOperator(H0)
D = ops.DisplacementOperator(N_cav, tensor_with=[ops.identity(L), None])
q = tensor([ops.identity(L), ops.position(N_cav)])
p = tensor([ops.identity(L), ops.momentum(N_cav)])

SIMULATE_TIME_EVOLUTION = False
# simulate rotation of the displaced state
# Because H=const, this can be done with large steps in time
if SIMULATE_TIME_EVOLUTION:
    dt = 10e-9
    STEPS = 100
    times = tf.range(STEPS, dtype=tf.float32) * dt

    alpha = 20
    vac = Kronecker_product([basis(0, L), basis(0, N_cav)])
    psi0 = tf.linalg.matvec(D(alpha), vac)
    psi, psi_int = psi0, psi0
    U_dt, U0_dt = U(dt), U0(dt)
Example #5
0
    def _define_fixed_operators(self):
        N = self.N
        N_large = self._N_large
        self.I = tensor([ops.identity(2), ops.identity(N)])
        self.a = tensor([ops.identity(2), ops.destroy(N)])
        self.a_dag = tensor([ops.identity(2), ops.create(N)])
        self.q = tensor([ops.identity(2), ops.position(N)])
        self.p = tensor([ops.identity(2), ops.momentum(N)])
        self.n = tensor([ops.identity(2), ops.num(N)])
        self.parity = tensor([ops.identity(2), ops.parity(N)])

        self.sx = tensor([ops.sigma_x(), ops.identity(N)])
        self.sy = tensor([ops.sigma_y(), ops.identity(N)])
        self.sz = tensor([ops.sigma_z(), ops.identity(N)])
        self.sm = tensor([ops.sigma_m(), ops.identity(N)])

        tensor_with = [ops.identity(2), None]
        self.phase = ops.Phase()
        self.translate = ops.TranslationOperator(N, tensor_with=tensor_with)
        self.displace = lambda a: self.translate(sqrt(2) * a)
        self.rotate = ops.RotationOperator(N, tensor_with=tensor_with)

        # displacement operators with larger intermediate hilbert space used for tomography
        self.translate_large = lambda a: tensor(
            [ops.identity(2), ops.TranslationOperator(N_large)(a)[:, :N, :N]]
        )
        self.displace_large = lambda a: self.translate_large(sqrt(2) * a)
        self.displaced_parity_large = lambda a: tf.linalg.matmul(
            tf.linalg.matmul(self.displace_large(a), self.parity),
            self.displace_large(-a),
        )

        tensor_with = [None, ops.identity(N)]
        self.rotate_qb_xy = ops.QubitRotationXY(tensor_with=tensor_with)
        self.rotate_qb_z = ops.QubitRotationZ(tensor_with=tensor_with)
        self.rxp = self.rotate_qb_xy(tf.constant(pi / 2), tf.constant(0))
        self.rxm = self.rotate_qb_xy(tf.constant(-pi / 2), tf.constant(0))

        # qubit sigma_z measurement projector
        self.P = {i: tensor([ops.projector(i, 2), ops.identity(N)]) for i in [0, 1]}

        self.sx_selective = tensor([ops.sigma_x(), ops.projector(0, N)]) + tensor(
            [ops.identity(2), ops.identity(N) - ops.projector(0, N)]
        )
Example #6
0
    def _define_fixed_operators(self):
        N = self.N
        self.I = tensor([ops.identity(2), ops.identity(N)])
        self.a = tensor([ops.identity(2), ops.destroy(N)])
        self.a_dag = tensor([ops.identity(2), ops.create(N)])
        self.q = tensor([ops.identity(2), ops.position(N)])
        self.p = tensor([ops.identity(2), ops.momentum(N)])
        self.n = tensor([ops.identity(2), ops.num(N)])
        self.parity = tensor([ops.identity(2), ops.parity(N)])

        self.sx = tensor([ops.sigma_x(), ops.identity(N)])
        self.sy = tensor([ops.sigma_y(), ops.identity(N)])
        self.sz = tensor([ops.sigma_z(), ops.identity(N)])
        self.sm = tensor([ops.sigma_m(), ops.identity(N)])
        self.hadamard = tensor([ops.hadamard(), ops.identity(N)])

        tensor_with = [ops.identity(2), None]
        self.phase = ops.Phase()
        self.translate = ops.TranslationOperator(N, tensor_with=tensor_with)
        self.displace = lambda a: self.translate(sqrt(2) * a)
        self.rotate = ops.RotationOperator(N, tensor_with=tensor_with)

        self.SNAP = ops.SNAP(N, tensor_with=tensor_with)
        self.SNAP_miscalibrated = ops.SNAPv3(N, chi=1e6, pulse_len=3.4e-6)

        tensor_with = [None, ops.identity(N)]
        self.rotate_qb_xy = ops.QubitRotationXY(tensor_with=tensor_with)
        self.rotate_qb_z = ops.QubitRotationZ(tensor_with=tensor_with)
        self.rxp = self.rotate_qb_xy(tf.constant(pi / 2), tf.constant(0))
        self.rxm = self.rotate_qb_xy(tf.constant(-pi / 2), tf.constant(0))

        # qubit sigma_z measurement projector
        self.P = {
            i: tensor([ops.projector(i, 2),
                       ops.identity(N)])
            for i in [0, 1]
        }

        self.sx_selective = tensor([ops.sigma_x(), ops.projector(0, N)]) + \
            tensor([ops.identity(2), ops.identity(N)-ops.projector(0, N)])
Example #7
0
    def _define_fixed_operators(self):
        N1 = self.N1
        N2 = self.N2

        self.I = tensor([ops.identity(N1), ops.identity(N2)])
        self.a1 = tensor([ops.destroy(N1), ops.identity(N2)])
        self.a1_dag = tensor([ops.create(N1), ops.identity(N2)])
        self.a2 = tensor([ops.identity(N1), ops.destroy(N2)])
        self.a2_dag = tensor([ops.identity(N1), ops.create(N2)])
        self.q1 = tensor([ops.position(N1), ops.identity(N2)])
        self.p1 = tensor([ops.momentum(N1), ops.identity(N2)])
        self.n1 = tensor([ops.num(N1), ops.identity(N2)])
        self.q2 = tensor([ops.identity(N1), ops.position(N2)])
        self.p2 = tensor([ops.identity(N1), ops.momentum(N2)])
        self.n2 = tensor([ops.identity(N1), ops.num(N2)])
        self.parity1 = tensor([ops.parity(N1), ops.identity(N2)])
        self.parity2 = tensor([ops.identity(N1), ops.parity(N2)])

        tensor_with = [None, ops.identity(N2)]
        self.translate1 = ops.TranslationOperator(N1, tensor_with=tensor_with)
        self.displace1 = lambda a: self.translate1(sqrt(2) * a)
        self.rotate1 = ops.RotationOperator(N1, tensor_with=tensor_with)

        tensor_with = [ops.identity(N1), None]
        self.translate2 = ops.TranslationOperator(N2, tensor_with=tensor_with)
        self.displace2 = lambda a: self.translate2(sqrt(2) * a)
        self.rotate2 = ops.RotationOperator(N2, tensor_with=tensor_with)