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 _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
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
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
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))