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
Beispiel #2
0
    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
Beispiel #3
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 = 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 _control_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))
    def _control_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
    def fill_buffer(self, target_state, window_size, tomography, num_samples,
                    sampling_type):
        """
        Fill the buffer of phase space points and corresponding target Wigner
        or characteristic function values. Points are produced with rejection
        sampling proportionally to the |W| or |Re[C]|.
        
        Returns:
            target_state (Tensor([1,N]), c64): tf target state
            window_size (float): size of (symmetric) phase space window
            tomography (str): either 'wigner' or 'CF'
            num_samples (int): number of samples to generate
            sampling_type (str): either 'abs' or 'sqr'
        """
        # Distributions for rejection sampling
        L = window_size / 2
        P = tfp.distributions.Uniform(low=[[-L, -L]] * num_samples,
                                      high=[[L, L]] * num_samples)
        P_v = tfp.distributions.Uniform(low=[0.0] * num_samples,
                                        high=[1.0] * num_samples)

        cond = True
        # mask for asynchronous interruption of rejection sampling
        accepted = tf.zeros([num_samples], tf.bool)
        accepted_points = tf.zeros([num_samples], tf.complex64)
        accepted_targets = tf.zeros([num_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 == 'CF':
                C_target = expectation(target_state,
                                       self.translate(-points),
                                       reduce_batch=False)
                target = tf.math.real(tf.squeeze(C_target))
            if sampling_type == 'abs':
                V = tf.math.abs(target)
            elif sampling_type == 'sqr':
                V = tf.math.abs(target)**2
            reject = P_v.sample() > V
            # 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
Beispiel #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
 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
Beispiel #10
0
    def _control_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
Beispiel #11
0
    def _control_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))