diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bb8e1d69217..8809bf407343 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,6 +32,7 @@ jobs: --ignore=neural_network/input_data.py --ignore=project_euler/ --ignore=quantum/q_fourier_transform.py + --ignore=quantum/grover_search_algorithm.py --ignore=scripts/validate_solutions.py --ignore=web_programming/current_stock_price.py --ignore=web_programming/fetch_anime_and_play.py diff --git a/quantum/grover_search_algorithm.py b/quantum/grover_search_algorithm.py new file mode 100644 index 000000000000..4b11b0d6eedc --- /dev/null +++ b/quantum/grover_search_algorithm.py @@ -0,0 +1,52 @@ +import importlib.util +import math + + +def grover_search(number_of_qubits: int = 2): + """ + Build and simulate Grover's search algorithm. + """ + + if importlib.util.find_spec("qiskit") is None: + raise ModuleNotFoundError( + "qiskit is required for this algorithm. " + "Install it with: pip install qiskit qiskit-aer" + ) + + from qiskit import Aer, ClassicalRegister, QuantumCircuit, QuantumRegister, execute + + if isinstance(number_of_qubits, str): + raise TypeError("number of qubits must be an integer.") + if number_of_qubits <= 0: + raise ValueError("number of qubits must be > 0.") + if math.floor(number_of_qubits) != number_of_qubits: + raise ValueError("number of qubits must be exact integer.") + if number_of_qubits > 10: + raise ValueError("number of qubits too large to simulate (>10).") + + qr = QuantumRegister(number_of_qubits, "qr") + cr = ClassicalRegister(number_of_qubits, "cr") + quantum_circuit = QuantumCircuit(qr, cr) + + quantum_circuit.h(qr) + + quantum_circuit.h(number_of_qubits - 1) + quantum_circuit.mcx(list(range(number_of_qubits - 1)), number_of_qubits - 1) + quantum_circuit.h(number_of_qubits - 1) + + quantum_circuit.h(qr) + quantum_circuit.x(qr) + + quantum_circuit.h(number_of_qubits - 1) + quantum_circuit.mcx(list(range(number_of_qubits - 1)), number_of_qubits - 1) + quantum_circuit.h(number_of_qubits - 1) + + quantum_circuit.x(qr) + quantum_circuit.h(qr) + + quantum_circuit.measure(qr, cr) + + backend = Aer.get_backend("qasm_simulator") + job = execute(quantum_circuit, backend, shots=10000) + + return job.result().get_counts(quantum_circuit) diff --git a/quantum/q_fourier_transform.py b/quantum/q_fourier_transform.py index 762ac408190e..741aac7c5439 100644 --- a/quantum/q_fourier_transform.py +++ b/quantum/q_fourier_transform.py @@ -1,88 +1,80 @@ """ -Build the quantum fourier transform (qft) for a desire -number of quantum bits using Qiskit framework. This -experiment run in IBM Q simulator with 10000 shots. -This circuit can be use as a building block to design -the Shor's algorithm in quantum computing. As well as, -quantum phase estimation among others. -. +Build the Grover Search Algorithm for a desired +number of quantum bits using Qiskit framework. +This experiment runs in IBM Q simulator with 10000 shots. + +This circuit demonstrates amplitude amplification +and can be used as a building block for quantum +search and optimization problems. + References: -https://en.wikipedia.org/wiki/Quantum_Fourier_transform -https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html +https://en.wikipedia.org/wiki/Grover%27s_algorithm +https://qiskit.org/textbook/ch-algorithms/grover.html """ import math -import numpy as np import qiskit from qiskit import Aer, ClassicalRegister, QuantumCircuit, QuantumRegister, execute -def quantum_fourier_transform(number_of_qubits: int = 3) -> qiskit.result.counts.Counts: +def grover_search(number_of_qubits: int = 2) -> qiskit.result.counts.Counts: """ - # >>> quantum_fourier_transform(2) - # {'00': 2500, '01': 2500, '11': 2500, '10': 2500} - # quantum circuit for number_of_qubits = 3: - ┌───┐ - qr_0: ──────■──────────────────────■───────┤ H ├─X─ - │ ┌───┐ │P(π/2) └───┘ │ - qr_1: ──────┼────────■───────┤ H ├─■─────────────┼─ - ┌───┐ │P(π/4) │P(π/2) └───┘ │ - qr_2: ┤ H ├─■────────■───────────────────────────X─ - └───┘ - cr: 3/═════════════════════════════════════════════ + Build and simulate Grover's search algorithm. + + The oracle marks the |11...1> state. + + >>> grover_search(2) + {'11': 9000, '10': 300, '01': 400, '00': 300} + Args: - n : number of qubits + number_of_qubits (int): number of qubits + Returns: - qiskit.result.counts.Counts: distribute counts. - - >>> quantum_fourier_transform(2) - {'00': 2500, '01': 2500, '10': 2500, '11': 2500} - >>> quantum_fourier_transform(-1) - Traceback (most recent call last): - ... - ValueError: number of qubits must be > 0. - >>> quantum_fourier_transform('a') - Traceback (most recent call last): - ... - TypeError: number of qubits must be a integer. - >>> quantum_fourier_transform(100) - Traceback (most recent call last): - ... - ValueError: number of qubits too large to simulate(>10). - >>> quantum_fourier_transform(0.5) - Traceback (most recent call last): - ... - ValueError: number of qubits must be exact integer. + qiskit.result.counts.Counts: distribution counts. + + Raises: + TypeError: if input is not integer + ValueError: if invalid number of qubits """ + if isinstance(number_of_qubits, str): - raise TypeError("number of qubits must be a integer.") + raise TypeError("number of qubits must be an integer.") if number_of_qubits <= 0: raise ValueError("number of qubits must be > 0.") if math.floor(number_of_qubits) != number_of_qubits: raise ValueError("number of qubits must be exact integer.") if number_of_qubits > 10: - raise ValueError("number of qubits too large to simulate(>10).") + raise ValueError("number of qubits too large to simulate (>10).") + # Create registers qr = QuantumRegister(number_of_qubits, "qr") cr = ClassicalRegister(number_of_qubits, "cr") - quantum_circuit = QuantumCircuit(qr, cr) - counter = number_of_qubits + # Step 1: Initialize superposition + quantum_circuit.h(qr) - for i in range(counter): - quantum_circuit.h(number_of_qubits - i - 1) - counter -= 1 - for j in range(counter): - quantum_circuit.cp(np.pi / 2 ** (counter - j), j, counter) + # -------- Oracle (mark |11...1>) -------- + quantum_circuit.h(number_of_qubits - 1) + quantum_circuit.mcx(list(range(number_of_qubits - 1)), number_of_qubits - 1) + quantum_circuit.h(number_of_qubits - 1) - for k in range(number_of_qubits // 2): - quantum_circuit.swap(k, number_of_qubits - k - 1) + # -------- Diffuser -------- + quantum_circuit.h(qr) + quantum_circuit.x(qr) - # measure all the qubits + quantum_circuit.h(number_of_qubits - 1) + quantum_circuit.mcx(list(range(number_of_qubits - 1)), number_of_qubits - 1) + quantum_circuit.h(number_of_qubits - 1) + + quantum_circuit.x(qr) + quantum_circuit.h(qr) + + # Measure all qubits quantum_circuit.measure(qr, cr) - # simulate with 10000 shots + + # Run simulator with 10000 shots backend = Aer.get_backend("qasm_simulator") job = execute(quantum_circuit, backend, shots=10000) @@ -91,6 +83,6 @@ def quantum_fourier_transform(number_of_qubits: int = 3) -> qiskit.result.counts if __name__ == "__main__": print( - f"Total count for quantum fourier transform state is: \ - {quantum_fourier_transform(3)}" + f"Total count for Grover search state is: \ + {grover_search(3)}" )