def flip_inversion(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': if isinstance(op.gate, ops.MeasurementGate): return [ ops.X(q) if b else ops.I(q) for q, b in zip(op.qubits, op.gate.full_invert_mask()) ] return op
def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment': """Returns self expanded to given superset of qubits by making identities explicit.""" if not self.qubits.issubset(qubits): raise ValueError(f'{qubits} is not a superset of {self.qubits}') operations = list(self.operations) for q in set(qubits) - self.qubits: operations.append(ops.I(q)) return Moment(*operations)
def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment': """Returns self expanded to given superset of qubits by making identities explicit. Args: qubits: Iterable of `cirq.Qid`s to expand this moment to. Returns: A new `cirq.Moment` with identity operations on the new qubits not currently found in the moment. Raises: ValueError: if this moments' qubits are not a subset of `qubits`. """ if not self.qubits.issubset(qubits): raise ValueError(f'{qubits} is not a superset of {self.qubits}') operations = list(self.operations) for q in set(qubits) - self.qubits: operations.append(ops.I(q)) return Moment(*operations)
def test_from_braket_non_parameterized_single_qubit_gates(): braket_circuit = BKCircuit() instructions = [ Instruction(braket_gates.I(), target=0), Instruction(braket_gates.X(), target=1), Instruction(braket_gates.Y(), target=2), Instruction(braket_gates.Z(), target=3), Instruction(braket_gates.H(), target=0), Instruction(braket_gates.S(), target=1), Instruction(braket_gates.Si(), target=2), Instruction(braket_gates.T(), target=3), Instruction(braket_gates.Ti(), target=0), Instruction(braket_gates.V(), target=1), Instruction(braket_gates.Vi(), target=2), ] for instr in instructions: braket_circuit.add_instruction(instr) cirq_circuit = from_braket(braket_circuit) for i, op in enumerate(cirq_circuit.all_operations()): assert np.allclose( instructions[i].operator.to_matrix(), protocols.unitary(op) ) qreg = LineQubit.range(4) expected_cirq_circuit = Circuit( ops.I(qreg[0]), ops.X(qreg[1]), ops.Y(qreg[2]), ops.Z(qreg[3]), ops.H(qreg[0]), ops.S(qreg[1]), ops.S(qreg[2]) ** -1, ops.T(qreg[3]), ops.T(qreg[0]) ** -1, ops.X(qreg[1]) ** 0.5, ops.X(qreg[2]) ** -0.5, ) assert _equal(cirq_circuit, expected_cirq_circuit)
def sample_from_amplitudes( self, circuit: 'cirq.AbstractCircuit', param_resolver: 'cirq.ParamResolver', seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE', repetitions: int = 1, qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT, ) -> Dict[int, int]: """Uses amplitude simulation to sample from the given circuit. This implements the algorithm outlined by Bravyi, Gosset, and Liu in https://arxiv.org/abs/2112.08499 to more efficiently calculate samples given an amplitude-based simulator. Simulators which also implement SimulatesSamples or SimulatesFullState should prefer `run()` or `simulate()`, respectively, as this method only accelerates sampling for amplitude-based simulators. Args: circuit: The circuit to simulate. param_resolver: Parameters to run with the program. seed: Random state to use as a seed. This must be provided manually - if the simulator has its own seed, it will not be used unless it is passed as this argument. repetitions: The number of repetitions to simulate. qubit_order: Determines the canonical ordering of the qubits. This is often used in specifying the initial state, i.e. the ordering of the computational basis states. Returns: A dict of bitstrings sampled from the final state of `circuit` to the number of occurrences of that bitstring. Raises: ValueError: if 'circuit' has non-unitary elements, as differences in behavior between sampling steps break this algorithm. """ prng = value.parse_random_state(seed) qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) base_circuit = circuits.Circuit(ops.I(q) for q in qubits) + circuit.unfreeze() qmap = {q: i for i, q in enumerate(qubits)} current_samples = {(0, ) * len(qubits): repetitions} solved_circuit = protocols.resolve_parameters(base_circuit, param_resolver) if not protocols.has_unitary(solved_circuit): raise ValueError( "sample_from_amplitudes does not support non-unitary behavior." ) if protocols.is_measurement(solved_circuit): raise ValueError( "sample_from_amplitudes does not support intermediate measurement." ) for m_id, moment in enumerate(solved_circuit[1:]): circuit_prefix = solved_circuit[:m_id + 1] for t, op in enumerate(moment.operations): new_samples: Dict[Tuple[int, ...], int] = collections.defaultdict(int) qubit_indices = {qmap[q] for q in op.qubits} subcircuit = circuit_prefix + circuits.Moment( moment.operations[:t + 1]) for current_sample, count in current_samples.items(): sample_set = [current_sample] for idx in qubit_indices: sample_set = [ target[:idx] + (result, ) + target[idx + 1:] for target in sample_set for result in [0, 1] ] bitstrings = [ int(''.join(map(str, sample)), base=2) for sample in sample_set ] amps = self.compute_amplitudes(subcircuit, bitstrings, qubit_order=qubit_order) weights = np.abs(np.square(np.array(amps))).astype( np.float64) weights /= np.linalg.norm(weights, 1) subsample = prng.choice(len(sample_set), p=weights, size=count) for sample_index in subsample: new_samples[sample_set[sample_index]] += 1 current_samples = new_samples return { int(''.join(map(str, k)), base=2): v for k, v in current_samples.items() }