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