def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha' : Tensor([batch_size,2], tf.float32),
                          'beta'  : Tensor([batch_size,2], tf.float32),
                          'phi'   : Tensor([batch_size,1], tf.float32),
                          'theta' : Tensor([batch_size,1], tf.float32))

        Returns: see parent class docs

        """
        # extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        beta = hf.vec_to_complex(action['beta'])
        phi = action['phi']
        Rotation = self.rotate(action['theta'])

        Kraus = {}
        T = {'a' : self.translate(alpha),
             'b' : self.translate(beta/2.0)}
        Kraus[0] = 1/2*(tf.linalg.adjoint(T['b']) + self.phase(phi)*T['b'])
        Kraus[1] = 1/2*(tf.linalg.adjoint(T['b']) - self.phase(phi)*T['b'])

        psi = self.simulate(psi, self.t_feedback)
        psi = batch_dot(T['a'], psi)
        psi_cached = batch_dot(Rotation, psi)
        psi = self.simulate(psi_cached, self.t_round + self.t_idle)
        psi_final, msmt = measurement(psi, Kraus)

        return psi_final, psi_cached, msmt
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha'   : Tensor([batch_size,2], tf.float32),
                          'beta'    : Tensor([batch_size,2], tf.float32),
                          'epsilon' : Tensor([batch_size,2], tf.float32))

        Returns: see parent class docs

        """
        # extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        beta = hf.vec_to_complex(action['beta'])
        epsilon = hf.vec_to_complex(action['epsilon'])

        # Construct gates
        Hadamard = tf.stack([self.hadamard] * self.batch_size)
        sx = tf.stack([self.sx] * self.batch_size)
        I = tf.stack([self.I] * self.batch_size)
        Rxp = tf.stack([self.rxp] * self.batch_size)
        Rxm = tf.stack([self.rxm] * self.batch_size)
        T, CT = {}, {}
        T['a'] = self.translate(alpha)
        T['b'] = self.translate(beta / 4.0)
        T['e'] = self.translate(epsilon / 2.0)
        CT['b'] = self.ctrl(tf.linalg.adjoint(T['b']), T['b'])
        CT['e'] = self.ctrl(tf.linalg.adjoint(T['e']), T['e'])

        # Feedback translation
        psi_cached = batch_dot(T['a'], psi)
        # Between-round wait time
        psi = self.simulate(psi_cached, self.t_idle)
        # Qubit gates
        psi = batch_dot(Hadamard, psi)
        # Conditional translation
        psi = batch_dot(CT['b'], psi)
        psi = self.simulate(psi, self.t_gate)
        psi = batch_dot(CT['b'], psi)
        # Qubit rotation
        psi = batch_dot(Rxp, psi)
        # Conditional translation
        psi = batch_dot(CT['e'], psi)
        # Qubit rotation
        psi = batch_dot(Rxm, psi)
        # Readout of finite duration
        psi = self.simulate(psi, self.t_read)
        psi, msmt = measurement(psi, self.P)
        psi = self.simulate(psi, self.t_read)
        # Feedback delay
        psi = self.simulate(psi, self.t_feedback)
        # Flip qubit conditioned on the measurement
        psi_final = psi * tf.cast((msmt == 1), c64)
        psi_final += batch_dot(sx, psi) * tf.cast((msmt == -1), c64)

        return psi_final, psi_cached, msmt
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'beta'    : Tensor([batch_size,2], tf.float32),
                          'epsilon' : Tensor([batch_size,2], tf.float32,
                          'phi'     : Tensor([batch_size,1])))

        Returns: see parent class docs

        """
        # extract parameters
        beta = hf.vec_to_complex(action['beta'])
        epsilon = hf.vec_to_complex(action['epsilon'])
        phi = tf.squeeze(action['phi'])

        # Construct gates
        Phase = self.rotate_qb_z(phi)
        T, CT = {}, {}
        T['b'] = self.translate(beta / 4.0)  # 4 because it will be troterized
        T['e'] = self.translate(epsilon / 2.0)
        CT['b'] = self.ctrl(tf.linalg.adjoint(T['b']), T['b'])
        CT['e'] = self.ctrl(tf.linalg.adjoint(T['e']), T['e'])

        # Between-round wait time
        psi = self.simulate(psi, self.t_idle)
        # Rotate qubit to |+> state
        psi = tf.linalg.matvec(self.hadamard, psi)
        # Troterized conditional translation
        psi = tf.linalg.matvec(CT['b'], psi)
        psi = self.simulate(psi, self.t_gate)
        psi = tf.linalg.matvec(CT['b'], psi)
        # Qubit rotation
        psi = tf.linalg.matvec(self.rxp, psi)
        # Conditional translation
        psi = tf.linalg.matvec(CT['e'], psi)
        # Qubit rotation
        psi = tf.linalg.matvec(self.rxm, psi)
        # Troterized conditional translation
        psi = tf.linalg.matvec(CT['b'], psi)
        psi = self.simulate(psi, self.t_gate)
        psi = tf.linalg.matvec(CT['b'], psi)
        # Qubit gates
        psi = tf.linalg.matvec(Phase, psi)
        psi = tf.linalg.matvec(self.hadamard, psi)
        # Readout of finite duration
        psi = self.simulate(psi, self.t_read)
        psi, msmt = measurement(psi, self.P)
        psi = self.simulate(psi, self.t_read)
        # Feedback delay
        psi = self.simulate(psi, self.t_feedback)
        # Flip qubit conditioned on the measurement
        psi_final = tf.where(msmt == 1, psi, tf.linalg.matvec(self.sx, psi))

        return psi_final, psi_final, msmt
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha' : Tensor([batch_size,2], tf.float32),
                          'theta' : Tensor([batch_size,7], tf.float32),
                          'phi' : Tensor([batch_size,7], tf.float32))

        Returns: see parent class docs

        """
        # Extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        theta = action['theta']
        phi = action['phi']

        # Build gates
        displace = self.displace(alpha)
        snap = self.SNAP_miscalibrated(theta, dangle=phi)

        # Apply gates
        psi = tf.linalg.matvec(displace, psi)
        psi = tf.linalg.matvec(snap, psi)
        psi = tf.linalg.matvec(tf.linalg.adjoint(displace), psi)

        # Readout with feedback to flip the qubit
        # psi, msmt = measurement(psi, self.P)
        # psi = tf.where(msmt==1, psi, tf.linalg.matvec(self.sx, psi))

        return psi, psi, tf.ones((self.batch_size,1))
Example #5
0
def fill_buffer_v2(target_state, buffer=[], target_vals=[], samples=1000):
    # Distributions for rejection sampling
    L = window_size / 2
    P = tfp.distributions.Uniform(low=[[-L, -L]] * samples,
                                  high=[[L, L]] * samples)
    P_v = tfp.distributions.Uniform(low=[0.0] * samples, high=[1.0] * samples)

    # batch rejection sampling of phase space points
    cond = True
    accepted = tf.zeros([samples], tf.bool)
    accepted_points = tf.zeros([samples], tf.complex64)
    accepted_targets = tf.zeros([samples], tf.float32)
    while cond:
        points = tf.squeeze(hf.vec_to_complex(P.sample()))
        target_state_translated = tf.linalg.matvec(T(-points), target_state)
        W_target = expectation(target_state_translated,
                               parity,
                               reduce_batch=False)
        W_target = tf.math.real(tf.squeeze(W_target))
        reject = P_v.sample() > tf.math.abs(W_target)**2
        mask = tf.logical_and(tf.logical_not(reject), tf.logical_not(accepted))
        accepted = tf.logical_or(mask, accepted)
        accepted_points = tf.where(mask, points, accepted_points)
        accepted_targets = tf.where(mask, W_target, accepted_targets)
        cond = not tf.reduce_all(accepted)

    buffer += list(accepted_points)
    target_vals += list(accepted_targets)
    return buffer, target_vals
Example #6
0
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'beta'  : Tensor([batch_size,2], tf.float32),
                          'phi'   : Tensor([batch_size,2], tf.float32))

        Returns: see parent class docs

        """
        # Extract parameters
        beta = hf.vec_to_complex(action['beta'])
        phase, angle = action['phi'][:,0], action['phi'][:,1]

        # Construct gates        
        D = self.displace(beta/2.0)
        CD = self.ctrl(D, tf.linalg.adjoint(D))
        R = self.rotate_qb_xy(angle, phase)
        flip = self.rotate_qb_xy(tf.constant(pi), tf.constant(0))
        
        # Apply gates
        psi = tf.linalg.matvec(R, psi)
        psi = tf.linalg.matvec(CD, psi)
        if self._elapsed_steps < self.T-1:
            psi = tf.linalg.matvec(flip, psi)
        
        m = tf.ones((self.batch_size,1))
        if self._elapsed_steps == self.T-1:
            psi, m = measurement(psi, self.P, sample=True)

        return psi, psi, m
Example #7
0
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'beta'    : Tensor([batch_size,2], tf.float32),
                          'epsilon' : Tensor([batch_size,2], tf.float32,
                          'phi'     : Tensor([batch_size,1])))

        Returns: see parent class docs

        """
        # extract parameters
        beta = hf.vec_to_complex(action['beta'])
        epsilon = hf.vec_to_complex(action['epsilon'])
        phi = action['phi']

        Kraus = {}
        T = {}
        T['+b'] = self.translate(beta/2.0)
        T['-b'] = tf.linalg.adjoint(T['+b'])
        T['+e'] = self.translate(epsilon/2.0)
        T['-e'] = tf.linalg.adjoint(T['+e'])


        chunk1 = 1j*batch_dot(T['-b'], batch_dot(T['+e'], T['+b'])) \
                - 1j*batch_dot(T['-b'], batch_dot(T['-e'], T['+b'])) \
                + batch_dot(T['-b'], batch_dot(T['-e'], T['-b'])) \
                + batch_dot(T['-b'], batch_dot(T['+e'], T['-b']))

        chunk2 = 1j*batch_dot(T['+b'], batch_dot(T['-e'], T['-b'])) \
                - 1j*batch_dot(T['+b'], batch_dot(T['+e'], T['-b'])) \
                + batch_dot(T['+b'], batch_dot(T['-e'], T['+b'])) \
                + batch_dot(T['+b'], batch_dot(T['+e'], T['+b']))

        Kraus[0] = 1/4*(chunk1 + self.phase(phi)*chunk2)
        Kraus[1] = 1/4*(chunk1 - self.phase(phi)*chunk2)

        psi = self.simulate(psi, self.t_round + self.t_idle)
        psi_final, msmt = measurement(normalize(psi), Kraus)

        return psi_final, psi_final, msmt
Example #8
0
 def count_code_flips(self, action, key):
     """
     Compare the 'action[key]' amplitude to one of the amplitudes that flip
     the code and increment the corresponding counter of X, Y, or Z flips.
     
     """
     amp = hf.vec_to_complex(action[key])
     ref_amps = {'alpha': ['X', 'Y', 'Z'], 'beta': ['S_x', 'S_y', 'S_z']}
     for a, b in zip(['X', 'Y', 'Z'], ref_amps[key]):
         ref = self.code_map[b]
         atol = abs(ref) / 2
         self.flips[a] += tf.where(tf.math.abs(amp - ref) < atol, 1, 0)
         self.flips[a] += tf.where(tf.math.abs(amp + ref) < atol, 1, 0)
     return
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha'   : Tensor([batch_size,2], tf.float32),
                          'beta'    : Tensor([batch_size,2], tf.float32),
                          'epsilon' : Tensor([batch_size,2], tf.float32))

        Returns: see parent class docs

        """
        # extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        beta = hf.vec_to_complex(action['beta'])
        epsilon = hf.vec_to_complex(action['epsilon'])

        Kraus = {}
        T = {}
        T['a'] = self.translate(alpha)
        T['+b'] = self.translate(beta/2.0)
        T['-b'] = tf.linalg.adjoint(T['+b'])
        T['+e'] = self.translate(epsilon/2.0)
        T['-e'] = tf.linalg.adjoint(T['+e'])


        chunk1 = batch_dot(T['-e'], T['-b']) - 1j*batch_dot(T['-e'], T['+b'])
        chunk2 = batch_dot(T['+e'], T['-b']) + 1j*batch_dot(T['+e'], T['+b'])

        Kraus[0] = 1/2/sqrt(2)*(chunk1 + chunk2)
        Kraus[1] = 1/2/sqrt(2)*(chunk1 - chunk2)

        psi = self.simulate(psi, self.t_feedback)
        psi_cached = batch_dot(T['a'], psi)
        psi = self.simulate(psi_cached, self.t_round + self.t_idle)
        psi_final, msmt = measurement(psi, Kraus)

        return psi_final, psi_cached, msmt
Example #10
0
def fill_buffer(target_state, buffer=[], target_vals=[], samples=1000):
    # Distributions for rejection sampling
    L = window_size / 2
    P = tfp.distributions.Uniform(low=[[-L, -L]], high=[[L, L]])
    P_v = tfp.distributions.Uniform(low=0.0, high=1.0)

    # rejection sampling of phase space points
    for i in range(samples):
        cond = True
        while cond:
            point = tf.squeeze(hf.vec_to_complex(P.sample()))
            target_state_translated = tf.linalg.matvec(T(-point), target_state)
            W_target = expectation(target_state_translated, parity)
            W_target = tf.math.real(tf.squeeze(W_target))
            cond = P_v.sample() > tf.math.abs(W_target)**2
        buffer.append(point)
        target_vals.append(W_target)
    return buffer, target_vals
Example #11
0
    def fill_buffer(self, target_state, window_size, tomography, samples=1000):
        # Distributions for rejection sampling
        L = window_size / 2
        P = tfp.distributions.Uniform(low=[[-L, -L]] * samples,
                                      high=[[L, L]] * samples)
        P_v = tfp.distributions.Uniform(low=[0.0] * samples,
                                        high=[1.0] * samples)

        cond = True
        # mask for asynchronous interruption of rejection sampling
        accepted = tf.zeros([samples], tf.bool)
        accepted_points = tf.zeros([samples], tf.complex64)
        accepted_targets = tf.zeros([samples], tf.float32)
        # batch rejection sampling of phase space points
        while cond:
            points = tf.squeeze(hf.vec_to_complex(P.sample()))
            if tomography == 'wigner':
                target_state_translated = tf.linalg.matvec(
                    self.translate(-points), target_state)
                W_target = expectation(target_state_translated,
                                       self.parity,
                                       reduce_batch=False)
                target = tf.math.real(tf.squeeze(W_target))
            if tomography == 'characteristic_fn':
                C_target = expectation(target_state,
                                       self.translate(-points),
                                       reduce_batch=False)
                target = tf.math.real(tf.squeeze(C_target))
            reject = P_v.sample() > tf.math.abs(target)
            # mask which streams should be interrupted at this iteration
            mask = tf.logical_and(tf.logical_not(reject),
                                  tf.logical_not(accepted))
            accepted = tf.logical_or(mask, accepted)
            accepted_points = tf.where(mask, points, accepted_points)
            accepted_targets = tf.where(mask, target, accepted_targets)
            cond = not tf.reduce_all(accepted)

        buffer = list(accepted_points)
        target_vals = list(accepted_targets)
        return buffer, target_vals
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha' : Tensor([batch_size,2], tf.float32),
                          'theta' : Tensor([batch_size,10], tf.float32))

        Returns: see parent class docs

        """
        # Extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        theta = action['theta']

        # Build gates
        displace = self.displace(alpha)
        snap = self.SNAP_miscalibrated(theta)

        # Apply gates
        psi = tf.linalg.matvec(displace, psi)
        psi = tf.linalg.matvec(snap, psi)
        psi = tf.linalg.matvec(tf.linalg.adjoint(displace), psi)

        # Either implement a measurement with a random qubit projection, or 
        # project on the specified 'self.bit_string' sequence of qubit states.
        if self.bit_string is not None:
            s = int(self.bit_string[self._elapsed_steps])
            psi = tf.linalg.matvec(self.P[s], psi)
            if s == 1: psi = tf.linalg.matvec(self.sx, psi)
            psi, norm = normalize(psi)
            self.norms.append(norm)
            msmt = tf.ones((self.batch_size,1)) * (1 if s==0 else -1)
        else: # Readout with feedback to flip the qubit
            psi, msmt = measurement(psi, self.P)
            psi = tf.where(msmt==1, psi, tf.linalg.matvec(self.sx, psi))

        return psi, psi, msmt
    def _quantum_circuit(self, psi, action):
        """
        Args:
            psi (Tensor([batch_size,N], c64)): batch of states
            action (dict, 'alpha' : Tensor([batch_size,2], tf.float32),
                          'theta' : Tensor([batch_size,7], tf.float32))

        Returns: see parent class docs

        """
        # Extract parameters
        alpha = hf.vec_to_complex(action['alpha'])
        theta = action['theta']

        # Build gates
        displace = self.displace(alpha)
        snap = self.SNAP(theta)

        # Apply gates
        psi = tf.linalg.matvec(displace, psi)
        psi = tf.linalg.matvec(snap, psi)
        psi = tf.linalg.matvec(tf.linalg.adjoint(displace), psi)

        return psi, psi, tf.ones((self.batch_size, 1))