def create_2_qubit_x_operator(qubit1: int, qubit2: int, param):
    return Circuit(
        [
            H(qubit1),
            H(qubit2),
            CNOT(qubit1, qubit2),
            RZ(2 * param)(qubit2),
            CNOT(qubit1, qubit2),
            H(qubit1),
            H(qubit2),
        ]
    )
Beispiel #2
0
    def test_get_wavefunction_seed(self):
        # Given
        circuit = Circuit([H(0), CNOT(0, 1), CNOT(1, 2)])
        backend1 = ForestSimulator("wavefunction-simulator", seed=5324)
        backend2 = ForestSimulator("wavefunction-simulator", seed=5324)

        # When
        wavefunction1 = backend1.get_wavefunction(circuit)
        wavefunction2 = backend2.get_wavefunction(circuit)

        # Then
        for (ampl1, ampl2) in zip(wavefunction1.amplitudes,
                                  wavefunction2.amplitudes):
            assert ampl1 == ampl2
def create_XZ1_target_unitary(number_of_params, k_body_depth=1):
    thetas = create_thetas(number_of_params)
    symbols_map = create_symbols_map(number_of_params)

    target_circuit = Circuit()
    target_circuit += create_x_operator(0, thetas[0])
    target_circuit += RZ(2 * thetas[1])(0)

    target_circuit += create_x_operator(1, thetas[2])
    target_circuit += RZ(2 * thetas[3])(1)

    if k_body_depth == 2:
        target_circuit += create_2_qubit_x_operator(0, 1, thetas[4])
        target_circuit += CNOT(0, 1)
        target_circuit += RZ(2 * thetas[5])(1)
        target_circuit += CNOT(0, 1)

    return target_circuit.bind(symbols_map).to_unitary()
Beispiel #4
0
def time_evolution_for_term(
        term: QubitOperator, time: Union[float,
                                         sympy.Expr]) -> circuits.Circuit:
    """Evolves a Pauli term for a given time and returns a circuit representing it.
    Based on section 4 from https://arxiv.org/abs/1001.3855 .
    Args:
        term: Pauli term to be evolved
        time: time of evolution
    Returns:
        Circuit: Circuit representing evolved term.
    """

    if len(term.terms) != 1:
        raise ValueError("This function works only on a single term.")
    term_components = list(term.terms.keys())[0]
    base_changes = []
    base_reversals = []
    cnot_gates = []
    central_gate = None
    term_types = [component[1] for component in term_components]
    qubit_indices = [component[0] for component in term_components]
    coefficient = list(term.terms.values())[0]

    circuit = circuits.Circuit()

    # If constant term, return empty circuit.
    if not term_components:
        return circuit

    for i, (term_type, qubit_id) in enumerate(zip(term_types, qubit_indices)):
        if term_type == "X":
            base_changes.append(H(qubit_id))
            base_reversals.append(H(qubit_id))
        elif term_type == "Y":
            base_changes.append(RX(np.pi / 2)(qubit_id))
            base_reversals.append(RX(-np.pi / 2)(qubit_id))
        if i == len(term_components) - 1:
            central_gate = RZ(2 * time * coefficient)(qubit_id)
        else:
            cnot_gates.append(CNOT(qubit_id, qubit_indices[i + 1]))

    for gate in base_changes:
        circuit += gate

    for gate in cnot_gates:
        circuit += gate

    circuit += central_gate

    for gate in reversed(cnot_gates):
        circuit += gate

    for gate in base_reversals:
        circuit += gate

    return circuit
    def _build_circuit_layer(self, parameters: np.ndarray) -> Circuit:
        """Build circuit layer for the hardware efficient quantum compiling ansatz

        Args:
            parameters: The variational parameters (or symbolic parameters)

        Returns:
            Circuit containing a single layer of the Hardware Efficient Quantum Compiling Ansatz
        """
        circuit_layer = Circuit()

        # Add RZ(theta) RX(pi/2) RZ(theta') RX(pi/2) RZ(theta'')
        circuit_layer = self._build_rotational_subcircuit(
            circuit_layer, parameters[:3 * self.number_of_qubits])

        qubit_ids = list(range(self.number_of_qubits))
        # Add CNOT(x, x+1) for x in even(qubits)
        for control, target in zip(
                qubit_ids[::2],
                qubit_ids[1::2]):  # loop over qubits 0, 2, 4...
            circuit_layer += CNOT(control, target)

        # Add RZ(theta) RX(pi/2) RZ(theta') RX(pi/2) RZ(theta'')
        circuit_layer = self._build_rotational_subcircuit(
            circuit_layer,
            parameters[3 * self.number_of_qubits:6 * self.number_of_qubits],
        )

        # Add CNOT layer working "inside -> out", skipping every other qubit

        for qubit_index in qubit_ids[:int(self.number_of_qubits /
                                          2)][::-1][::2]:
            control = qubit_index
            target = self.number_of_qubits - qubit_index - 1
            circuit_layer += CNOT(control, target)

            if qubit_index != 0 or self.number_of_qubits % 4 == 0:
                control = self.number_of_qubits - qubit_index
                target = qubit_index - 1
                circuit_layer += CNOT(control, target)

        return circuit_layer
Beispiel #6
0
class TestDecompositionOfU3Gates:
    @pytest.mark.parametrize(
        "gate_to_be_decomposed, target_qubits",
        [
            *[(gate, qubits) for gate in U3_GATES for qubits in [(0,), (2,)]],
        ],
    )
    def test_gives_the_same_unitary_as_original_gate_up_to_global_phase(
        self, gate_to_be_decomposed, target_qubits
    ):
        circuit = Circuit([gate_to_be_decomposed(*target_qubits)])
        decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES)

        assert _is_scaled_identity(
            circuit.to_unitary() @ np.linalg.inv(decomposed_circuit.to_unitary()),
        )

    @pytest.mark.parametrize(
        "operations",
        [[RY(np.pi / 2)(0)], [X(3), Y(1), Z(0)], [CNOT(3, 11)]],
    )
    def test_leaves_gates_not_matching_predicate_unaffected(self, operations):
        circuit = Circuit(operations)
        decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES)

        assert circuit.operations == decomposed_circuit.operations

    @pytest.mark.parametrize("target_qubits", [(0,), (2,)])
    @pytest.mark.parametrize("gate_to_be_decomposed", U3_GATES)
    def test_U3_decomposition_comprises_only_rotations(
        self, gate_to_be_decomposed, target_qubits
    ):
        circuit = Circuit([gate_to_be_decomposed(*target_qubits)])
        decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES)

        assert all(
            isinstance(op, GateOperation) and op.gate.name in ("RZ", "RY")
            for op in decomposed_circuit.operations
        )
class SymbolicSimulatorWithNonSupportedOperations(SymbolicSimulator):
    def is_natively_supported(self, operation: Operation) -> bool:
        return super().is_natively_supported(
            operation) and operation.gate.name != "RX"


class SymbolicSimulatorWithDefaultSetOfSupportedOperations(SymbolicSimulator):
    def is_natively_supported(self, operation: Operation) -> bool:
        return QuantumSimulator.is_natively_supported(self, operation)


@pytest.mark.parametrize(
    "circuit",
    [
        Circuit([RY(0.5)(0), RX(1)(1),
                 CNOT(0, 2), RX(np.pi)(2)]),
        Circuit([RX(1)(1), CNOT(0, 2),
                 RX(np.pi)(2), RY(0.5)(0)]),
        Circuit([RX(1)(1),
                 CNOT(0, 2),
                 RX(np.pi)(2),
                 RY(0.5)(0),
                 RX(0.5)(0)]),
    ],
)
def test_quantum_simulator_switches_between_native_and_nonnative_modes_of_execution(
    circuit, ):
    simulator = SymbolicSimulatorWithNonSupportedOperations()
    reference_simulator = SymbolicSimulator()

    np.testing.assert_array_equal(
 def x_cnot_circuit(self):
     circuit = Circuit([X(0), CNOT(1, 2)])
     return circuit