def test_sycamore_decomposer_reject_0_controlled(): c = cirq.Circuit(cirq.X(a1).controlled_by(a2, control_values=[0])) decomposer = ct.SycamoreDecomposer() with pytest.raises(ct.DeviceMappingError): decomposer.optimize_circuit(c)
def sample_with_ancilla( self, num_samples: int) -> Tuple[List[int], List[Dict[str, int]]]: """Samples the board and returns square and ancilla measurements. Sends the current circuit to the sampler then retrieves the results. May return less samples than num_samples due to post-selection. Returns the results as a tuple. The first entry is the list of measured squares, as represented by a 64-bit int bitboard. The second value is a list of ancilla values, as represented as a dictionary from ancilla name to value (0 or 1). """ t0 = time.perf_counter() measure_circuit = self.circuit.copy() ancilla = [] error_count = 0 noise_count = 0 post_count = 0 if self.entangled_squares: qubits = sorted(self.entangled_squares) measure_moment = cirq.Moment( cirq.measure(q, key=q.name) for q in qubits) measure_circuit.append(measure_moment) # Try to guess the appropriate number of repetitions needed # Assume that each post_selection is about 50/50 # Noise and error mitigation will discard reps, so increase # the total number of repetitions to compensate if len(self.post_selection) > 1: num_reps = num_samples * (2**(len(self.post_selection) + 1)) else: num_reps = num_samples if self.error_mitigation == enums.ErrorMitigation.Correct: num_reps *= 2 noise_threshold = self.noise_mitigation * num_samples if self.noise_mitigation > 0: num_reps *= 3 if num_reps < 100: num_reps = 100 self.debug_log += (f'Running circuit with {num_reps} reps ' f'to get {num_samples} samples:\n' f'{str(measure_circuit)}\n') # Translate circuit to grid qubits and sqrtISWAP gates if self.device is not None: # Decompose 3-qubit operations ct.SycamoreDecomposer().optimize_circuit(measure_circuit) # Create NamedQubit to GridQubit mapping and transform measure_circuit = self.transformer.transform(measure_circuit) # For debug, ensure that the circuit correctly validates self.device.validate_circuit(measure_circuit) # Run the circuit using the provided sampler (simulator or hardware) results = self.sampler.run(measure_circuit, repetitions=num_reps) # Parse the results rtn = [] noise_buffer = {} data = results.data for rep in range(num_reps): new_sample = self.state new_ancilla = {} # Go through the results and discard any results # that disagree with our pre-defined post-selection criteria post_selected = True for qubit in self.post_selection.keys(): key = qubit.name if key in data.columns: result = data.at[rep, key] if result != self.post_selection[qubit]: post_selected = False if not post_selected: post_count += 1 continue # Translate qubit results into a 64-bit chess board for qubit in qubits: key = qubit.name result = data.at[rep, key] # Ancilla bits should not be part of the chess board if 'anc' not in key: bit = qubit_to_bit(qubit) new_sample = set_nth_bit(bit, new_sample, result) else: new_ancilla[key] = result # Perform Error Mitigation if self.error_mitigation != enums.ErrorMitigation.Nothing: # Discard boards that have the wrong number of pieces if num_ones(new_sample) not in self.allowed_pieces: if self.error_mitigation == enums.ErrorMitigation.Error: raise ValueError( 'Error detected, ' f'pieces allowed = {self.allowed_pieces}' f'but got {num_ones(new_sample)}') if self.error_mitigation == enums.ErrorMitigation.Correct: error_count += 1 continue # Noise mitigation if self.noise_mitigation > 0.0: # Ignore samples up to a threshold if new_sample not in noise_buffer: noise_buffer[new_sample] = 0 noise_buffer[new_sample] += 1 if noise_buffer[new_sample] < noise_threshold: noise_count += 1 continue # This sample has passed noise and error mitigation # Record it as a proper sample rtn.append(new_sample) ancilla.append(new_ancilla) if len(rtn) >= num_samples: self.debug_log += ( f'Discarded {error_count} from error mitigation ' f'{noise_count} from noise and ' f'{post_count} from post-selection\n') self.record_time('sample_with_ancilla', t0) return (rtn, ancilla) else: rtn = [self.state] * num_samples self.debug_log += ( f'Discarded {error_count} from error mitigation ' f'{noise_count} from noise and {post_count} from post-selection\n' ) self.record_time("sample_with_ancilla", t0) return (rtn, ancilla)