Ejemplo n.º 1
0
    def with_state(self, basis_state: int) -> "CirqBoard":
        """Resets the board with a specific classical state."""
        self.accumulations_repetitions = None
        self.board_accumulations_repetitions = None
        self.state = basis_state
        self.allowed_pieces = set()
        self.allowed_pieces.add(num_ones(self.state))
        self.entangled_squares = set()
        self.post_selection = {}
        self.circuit = cirq.Circuit()
        self.ancilla_count = 0
        self.move_history = []
        self.full_squares = basis_state
        self.empty_squares = 0
        for i in range(64):
            self.empty_squares = set_nth_bit(
                i, self.empty_squares, not nth_bit_of(i, self.full_squares))
        # Each entry is a 2-tuple of (repetitions, probabilities) corresponding to the probabilities after each move.
        self.move_history_probabilities_cache = []

        # Store the initial basis state so that we can use it for replaying
        # the move-history when undoing moves
        self.init_basis_state = basis_state
        self.clear_debug_log()
        self.timing_stats = defaultdict(list)
        return self
Ejemplo n.º 2
0
 def with_state(self, basis_state: int) -> 'CirqBoard':
     """Resets the board with a specific classical state."""
     self.state = basis_state
     self.allowed_pieces = set()
     self.allowed_pieces.add(num_ones(self.state))
     self.entangled_squares = set()
     self.post_selection = {}
     self.circuit = cirq.Circuit()
     self.ancilla_count = 0
     self.clear_debug_log()
     return self
Ejemplo n.º 3
0
 def with_state(self, basis_state: int) -> 'CirqBoard':
     """Resets the board with a specific classical state."""
     self.accumulations_valid = False
     self.state = basis_state
     self.allowed_pieces = set()
     self.allowed_pieces.add(num_ones(self.state))
     self.entangled_squares = set()
     self.post_selection = {}
     self.circuit = cirq.Circuit()
     self.ancilla_count = 0
     self.move_history = []
     # Store the initial basis state so that we can use it for replaying
     # the move-history when undoing moves
     self.init_basis_state = basis_state
     self.clear_debug_log()
     return self
Ejemplo n.º 4
0
def test_num_ones():
    assert u.num_ones(int('1000101', 2)) == 3
    assert u.num_ones(int('0000000', 2)) == 0
    assert u.num_ones(int('0111111', 2)) == 6
Ejemplo n.º 5
0
def test_num_ones():
    assert u.num_ones(int("1000101", 2)) == 3
    assert u.num_ones(int("0000000", 2)) == 0
    assert u.num_ones(int("0111111", 2)) == 6
Ejemplo n.º 6
0
    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)