def test_raises_error_if_position_is_larger_or_equal_to_length(
            self, length, invalid_position):
        repeated_circuit = circuits.Circuit([circuits.X(0)])
        different_circuit = circuits.Circuit([circuits.Y(0)])

        with pytest.raises(ValueError):
            _generate_circuit_sequence(repeated_circuit, different_circuit,
                                       length, invalid_position)
class TestGeneratingCircuitSequence:
    @pytest.mark.parametrize(
        "repeated_circuit, different_circuit, length, position, expected_result",
        [
            (
                circuits.Circuit([circuits.X(0), circuits.Y(1)]),
                circuits.Circuit([circuits.Z(1)]),
                5,
                1,
                circuits.Circuit([
                    *[circuits.X(0), circuits.Y(1)],
                    circuits.Z(1),
                    *([circuits.X(0), circuits.Y(1)] * 3),
                ]),
            ),
            (
                circuits.Circuit([circuits.RX(0.5)(1)]),
                circuits.Circuit([circuits.CNOT(0, 2)]),
                3,
                0,
                circuits.Circuit([
                    circuits.CNOT(0, 2),
                    circuits.RX(0.5)(1),
                    circuits.RX(0.5)(1)
                ]),
            ),
            (
                circuits.Circuit([circuits.RX(0.5)(1)]),
                circuits.Circuit([circuits.CNOT(0, 2)]),
                3,
                2,
                circuits.Circuit([
                    circuits.RX(0.5)(1),
                    circuits.RX(0.5)(1),
                    circuits.CNOT(0, 2),
                ]),
            ),
        ],
    )
    def test_produces_correct_sequence(self, repeated_circuit,
                                       different_circuit, position, length,
                                       expected_result):
        actual_result = _generate_circuit_sequence(repeated_circuit,
                                                   different_circuit, length,
                                                   position)

        assert actual_result == expected_result

    @pytest.mark.parametrize("length, invalid_position", [(5, 5), (4, 6)])
    def test_raises_error_if_position_is_larger_or_equal_to_length(
            self, length, invalid_position):
        repeated_circuit = circuits.Circuit([circuits.X(0)])
        different_circuit = circuits.Circuit([circuits.Y(0)])

        with pytest.raises(ValueError):
            _generate_circuit_sequence(repeated_circuit, different_circuit,
                                       length, invalid_position)
 def test_cannot_sample_from_circuit_containing_free_symbols(
         self, wf_simulator, circuit_list, binding):
     circuit = circuits.Circuit(circuit_list)
     with pytest.raises(ValueError):
         wf_simulator.run_circuit_and_measure(circuit,
                                              n_samples=1000,
                                              symbol_map=binding)
示例#4
0
def _generate_circuit_sequence(
    repeated_circuit: circuits.Circuit,
    different_circuit: circuits.Circuit,
    length: int,
    position: int,
):
    """Join multiple copies of circuit, replacing one copy with a different circuit.

    Args:
        repeated_circuit: circuit which copies should be concatenated
        different_circuit: circuit that will replace one copy of `repeated_circuit
        length: total number of circuits to join
        position: which copy of repeated_circuit should be replaced by
        `different_circuit`.
    Returns:
        Concatenation of circuits C_1, ..., C_length, where C_i = `repeated_circuit`
        if i != position and C_i = `different_circuit` if i == position.
    """
    if position >= length:
        raise ValueError(f"Position {position} should be < {length}")

    return circuits.Circuit(
        list(
            chain.from_iterable([(repeated_circuit if i != position else
                                  different_circuit).operations
                                 for i in range(length)])))
示例#5
0
 def test_circuit_with_only_supported_gates_is_not_changed(self):
     original_circuit = circuits.Circuit([
         circuits.X(0),
         circuits.RX(np.pi)(2),
         circuits.SWAP(3, 0),
         circuits.RY(0.5).controlled(1)(0, 2),
     ])
     assert make_circuit_qhipster_compatible(
         original_circuit) == original_circuit
示例#6
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
示例#7
0
    def test_supported_gates_are_left_unchanged(self):
        supported_gate_indices = [1, 3]
        original_circuit = circuits.Circuit(
            [circuits.I(0),
             circuits.X(1),
             circuits.I(2),
             circuits.RX(0)(2)])
        compatible_circuit = make_circuit_qhipster_compatible(original_circuit)

        all(compatible_circuit.operations[i] == original_circuit.operations[i]
            for i in supported_gate_indices)
示例#8
0
    def test_run_circuit_and_measure_works_with_multiphase_operator(self, backend):
        params = [-0.1, 0.3, -0.5, 0.7]
        circuit = circuits.Circuit(
            [circuits.H(0), circuits.X(1), circuits.MultiPhaseOperation(params)]
        )

        measurements = backend.run_circuit_and_measure(circuit, n_samples=1000)
        counts = measurements.get_counts()
        assert len(measurements.bitstrings) == 1000
        assert all(
            bitstring in [(0, 1), (1, 1)] for bitstring in measurements.bitstrings
        )
示例#9
0
    def test_identity_gates_are_replaced_with_zero_angle_rotation(self):
        identity_gate_indices = [0, 2]
        original_circuit = circuits.Circuit(
            [circuits.I(0),
             circuits.X(1),
             circuits.I(2),
             circuits.RX(0)(2)])
        compatible_circuit = make_circuit_qhipster_compatible(original_circuit)

        assert all(compatible_circuit.operations[i].gate == circuits.RX(0)
                   and compatible_circuit.operations[i].qubit_indices ==
                   original_circuit.operations[i].qubit_indices
                   for i in identity_gate_indices)
示例#10
0
def make_circuit_qhipster_compatible(circuit: circuits.Circuit):
    unsupported_operations = [
        op for op in circuit.operations
        if op.gate.name in QHIPSTER_UNSUPPORTED_GATES
    ]
    if unsupported_operations:
        raise NotImplementedError(
            "ISWAP gates and two-qubit Pauli rotations are not supported by qHipster "
            f"integration. Offending operations: {unsupported_operations}.")
    return circuits.Circuit(
        operations=[
            circuits.RX(0)(*op.qubit_indices) if op.gate.name == "I" else op
            for op in circuit.operations
        ],
        n_qubits=circuit.n_qubits,
    )
示例#11
0
    def test_concatenate_circuits_python_objects(self, circuit_set):
        # Given
        expected_concatenated_circuit_filename = "result-circuit.json"
        expected_concatenated_circuit = sum(
            [circuit for circuit in circuit_set], new_circuits.Circuit())

        # When
        concatenate_circuits(circuit_set)

        # Then
        try:
            with open(expected_concatenated_circuit_filename) as f:
                concatenated_circuit = new_circuits.circuit_from_dict(
                    json.load(f))
            assert concatenated_circuit == expected_concatenated_circuit
        finally:
            remove_file_if_exists(expected_concatenated_circuit_filename)
示例#12
0
class TestConvertingCircuitToSimplifiedQasm:
    @pytest.mark.parametrize(
        "circuit, expected_qasm",
        [
            (circuits.Circuit(), "0\n"),
            (
                circuits.Circuit([circuits.X(0),
                                  circuits.Y(2),
                                  circuits.Z(1)]),
                "\n".join(["3", "X 0", "Y 2", "Z 1"]),
            ),
            (
                circuits.Circuit([circuits.X(0), circuits.Z(4)]),
                "\n".join(["5", "X 0", "Z 4"]),
            ),
            (
                circuits.Circuit([circuits.X(4), circuits.Z(0)]),
                "\n".join(["5", "X 4", "Z 0"]),
            ),
            (
                circuits.Circuit([circuits.X(4),
                                  circuits.CNOT(0, 3)]),
                "\n".join(["5", "X 4", "CNOT 0 3"]),
            ),
            (
                circuits.Circuit([circuits.RX(np.pi)(1),
                                  circuits.RZ(0.5)(3)]),
                "\n".join([
                    "4", "Rx 3.14159265358979311600 1",
                    "Rz 0.50000000000000000000 3"
                ]),
            ),
        ],
    )
    def test_converting_circuit_to_qasm_emits_correct_string(
            self, circuit, expected_qasm):
        assert convert_to_simplified_qasm(circuit) == expected_qasm
 def test_evolving_constant_term_qubit_operator_gives_empty_circuit(self):
     evolution_circuit = time_evolution_for_term(QubitOperator((), 1),
                                                 np.pi)
     assert evolution_circuit == circuits.Circuit()
示例#14
0
    def test_circuit_with_iswap_gate_cannot_be_made_compatible(
            self, supported_gate):
        circuit = circuits.Circuit([circuits.ISWAP(0, 2), supported_gate(1)])

        with pytest.raises(NotImplementedError):
            make_circuit_qhipster_compatible(circuit)
示例#15
0
class TestQulacs(QuantumSimulatorTests):
    @pytest.mark.parametrize(
        "circuit, target_wavefunction",
        [
            (
                circuits.Circuit(
                    [
                        circuits.H(0),
                        circuits.H(1),
                        circuits.MultiPhaseOperation([-0.1, 0.3, -0.5, 0.7]),
                        circuits.X(0),
                        circuits.X(0),
                    ]
                ),
                np.exp(1j * np.array([-0.1, 0.3, -0.5, 0.7])) / 2,
            ),
            (
                circuits.Circuit(
                    [
                        circuits.H(0),
                        circuits.H(1),
                        circuits.MultiPhaseOperation([-0.1, 0.3, -0.5, 0.7]),
                        circuits.MultiPhaseOperation([-0.2, 0.1, -0.2, -0.3]),
                        circuits.X(0),
                        circuits.X(0),
                    ]
                ),
                np.exp(1j * np.array([-0.3, 0.4, -0.7, 0.4])) / 2,
            ),
            (
                circuits.Circuit(
                    [
                        circuits.MultiPhaseOperation([-0.1, 0.3, -0.5, 0.7]),
                    ]
                ),
                np.array([np.exp(-0.1j), 0, 0, 0]),
            ),
            (
                circuits.Circuit(
                    [
                        circuits.H(0),
                        circuits.MultiPhaseOperation([-0.1, 0.3, -0.5, 0.7]),
                    ]
                ),
                np.array([np.exp(-0.1j), np.exp(0.3j), 0, 0]) / np.sqrt(2),
            ),
        ],
    )
    def test_get_wavefunction_works_with_multiphase_operator(
        self, backend, circuit, target_wavefunction
    ):
        wavefunction = backend.get_wavefunction(circuit)

        np.testing.assert_almost_equal(wavefunction, target_wavefunction)

    def test_run_circuit_and_measure_works_with_multiphase_operator(self, backend):
        params = [-0.1, 0.3, -0.5, 0.7]
        circuit = circuits.Circuit(
            [circuits.H(0), circuits.X(1), circuits.MultiPhaseOperation(params)]
        )

        measurements = backend.run_circuit_and_measure(circuit, n_samples=1000)
        counts = measurements.get_counts()
        assert len(measurements.bitstrings) == 1000
        assert all(
            bitstring in [(0, 1), (1, 1)] for bitstring in measurements.bitstrings
        )
示例#16
0
    def test_circuit_with_two_qubit_pauli_rotation_cannot_be_made_compatible(
            self, supported_gate, unsupported_gate):
        circuit = circuits.Circuit([unsupported_gate(0, 2), supported_gate(1)])

        with pytest.raises(NotImplementedError):
            make_circuit_qhipster_compatible(circuit)
示例#17
0
def time_evolution_derivatives(
    hamiltonian: QubitOperator,
    time: float,
    method: str = "Trotter",
    trotter_order: int = 1,
) -> Tuple[List[circuits.Circuit], List[float]]:
    """Generates derivative circuits for the time evolution operator defined in
    function time_evolution

    Args:
        hamiltonian: The Hamiltonian to be evolved under. It should contain numeric
            coefficients, symbolic expressions aren't supported.
        time: time duration of the evolution.
        method: time evolution method. Currently the only option is 'Trotter'.
        trotter_order: order of Trotter evolution

    Returns:
        A Circuit simulating time evolution.
    """
    if method != "Trotter":
        raise ValueError(f"The method {method} is currently not supported.")

    single_trotter_derivatives = []
    factors = [1.0, -1.0]
    output_factors = []
    terms: Iterable = list(hamiltonian.get_operators())

    for i, term_1 in enumerate(terms):
        for factor in factors:
            output = circuits.Circuit()

            try:
                if isinstance(term_1, QubitOperator):
                    r = list(term_1.terms.values())[0] / trotter_order
                else:
                    r = complex(term_1.coefficient).real / trotter_order
            except TypeError:
                raise ValueError("Term coefficients need to be numerical. "
                                 f"Offending term: {term_1}")
            output_factors.append(r * factor)
            shift = factor * (np.pi / (4.0 * r))

            for j, term_2 in enumerate(terms):
                output += time_evolution_for_term(
                    term_2,
                    (time + shift) / trotter_order if i == j else time /
                    trotter_order,
                )

            single_trotter_derivatives.append(output)

    if trotter_order > 1:
        output_circuits = []
        final_factors = []

        repeated_circuit = time_evolution(hamiltonian,
                                          time,
                                          method="Trotter",
                                          trotter_order=1)

        for position in range(trotter_order):
            for factor, different_circuit in zip(output_factors,
                                                 single_trotter_derivatives):
                output_circuits.append(
                    _generate_circuit_sequence(repeated_circuit,
                                               different_circuit,
                                               trotter_order, position))
                final_factors.append(factor)
        return output_circuits, final_factors
    else:
        return single_trotter_derivatives, output_factors