diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07a348b..05d5b2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: python -m pip install --upgrade pip pip install nox pip install uv - uv sync + uv sync --group dev - name: Run pre-commit run: | uv run pre-commit install diff --git a/examples/GHZ_measure.py b/examples/GHZ_measure.py new file mode 100644 index 0000000..441ceba --- /dev/null +++ b/examples/GHZ_measure.py @@ -0,0 +1,40 @@ +# GHZ State generation and measurement + +import os + +import matplotlib.pyplot as plt +from dotenv import load_dotenv +from mqss.qiskit_adapter import MQSSQiskitAdapter +from qiskit import QuantumCircuit, transpile +from qiskit.visualization import plot_histogram + +# Load environment variables +load_dotenv() +token = os.getenv("MQP_TOKEN") +backend_name = os.getenv("MQP_BACKEND") + +adapter = MQSSQiskitAdapter(token=token) +backend = adapter.get_backend(backend_name) + +# Parameters +qubits = 8 +shots = 200 + +# Build GHZ circuit +qc = QuantumCircuit(qubits, qubits) +qc.h(0) +for i in range(1, qubits): + qc.cx(0, i) +qc.measure_all(add_bits=False) + +# Transpile if needed +trans_qc = transpile(qc, backend, optimization_level=3) + +# Run job +job = backend.run(trans_qc, no_modify=True, shots=shots, queued=True) +counts = job.result().get_counts() +print("Result:", counts) + +# Plot +plot_histogram(counts, figsize=(12, 6)) +plt.show() diff --git a/examples/inverse_unitary_test.py b/examples/inverse_unitary_test.py new file mode 100644 index 0000000..1b7883a --- /dev/null +++ b/examples/inverse_unitary_test.py @@ -0,0 +1,50 @@ +# Inverse Unitary Test +# Demonstrates how reversible a circuit is on simulator vs real hardware. + +import os + +import matplotlib.pyplot as plt +import numpy as np +from dotenv import load_dotenv +from mqss.qiskit_adapter import MQSSQiskitAdapter +from qiskit import QuantumCircuit +from qiskit.visualization import plot_histogram + +# Load environment variables +load_dotenv() +token = os.getenv("MQP_TOKEN") +backend_name = os.getenv("MQP_BACKEND") + +adapter = MQSSQiskitAdapter(token=token) +backend = adapter.get_backend(backend_name) + +n = 3 +x = 3 # |011⟩ + +qc = QuantumCircuit(n) + +# Prepare |x⟩ +for i in range(n): + if (x >> i) & 1: + qc.x(i) + +# Unitaries +for qubit in range(n): + qc.h(qubit) + for target in range(qubit + 1, n): + qc.crz(np.pi / 2 ** (target - qubit), qubit, target) + +# Inverse unitaries +for qubit in reversed(range(n)): + for target in reversed(range(qubit + 1, n)): + qc.crz(-np.pi / 2 ** (target - qubit), qubit, target) + qc.h(qubit) + +qc.measure_all() + +job = backend.run(qc, shots=200, qasm3=False, queued=True) +counts = job.result().get_counts() +print("results:", counts) + +plot_histogram(counts) +plt.show() diff --git a/examples/shor_period_find.py b/examples/shor_period_find.py new file mode 100644 index 0000000..0380a37 --- /dev/null +++ b/examples/shor_period_find.py @@ -0,0 +1,85 @@ +# Shor period finding example +# Find the period of f(x) = 13^x mod 15 + +import math +import os + +import matplotlib.pyplot as plt +from dotenv import load_dotenv +from mqss.qiskit_adapter import MQSSQiskitAdapter +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister + +# Load environment variables +load_dotenv() +token = os.getenv("MQP_TOKEN") +backend_name = os.getenv("MQP_BACKEND") + +adapter = MQSSQiskitAdapter(token=token) +backend = adapter.get_backend(backend_name) + +# Parameters +n = 4 # number of qubits in x-register +shots = 200 + + +def f(x): + return pow(13, x, 15) + + +# Build circuit +qr_x = QuantumRegister(n, "x") +qr_fx = QuantumRegister(4, "f(x)") +cr_x = ClassicalRegister(n, "c_x") +qc = QuantumCircuit(qr_x, qr_fx, cr_x) + +# Superposition +for q in range(n): + qc.h(qr_x[q]) +qc.barrier() + +# f(x) implementation +qc.x(qr_fx[0]) +qc.x(qr_fx[2]) +qc.x(qr_x[0]) +qc.ccx(qr_x[0], qr_x[1], qr_fx[0]) +qc.x(qr_x[0]) +qc.ccx(qr_x[0], qr_x[1], qr_fx[1]) +qc.x(qr_x[0]) +qc.x(qr_x[1]) +qc.ccx(qr_x[0], qr_x[1], qr_fx[2]) +qc.x(qr_x[0]) +qc.ccx(qr_x[0], qr_x[1], qr_fx[3]) +qc.x(qr_x[1]) +qc.barrier() + +# QFT +for q in range(n - 1, -1, -1): + qc.h(q) + for k in range(1, q + 1): + qc.cp(math.pi / 2**k, q - k, q) + qc.barrier() +for q in range(n // 2): + qc.swap(q, (n - 1) - q) +qc.barrier() + +qc.measure(qr_x, cr_x) + +# Run job +job = backend.run(qc, shots=shots, queued=True) +counts = job.result().get_counts() +print("Results:", counts) + +# Normalize and plot +keys = list(counts.keys()) +x_vals = [int(k, 2) for k in keys] +probs = [v / sum(counts.values()) for v in counts.values()] + +x_sorted, p_sorted = zip(*sorted(zip(x_vals, probs))) + +plt.figure() +plt.grid(zorder=0, axis="y", linestyle="--") +plt.bar(x_sorted, p_sorted, zorder=3) +plt.xticks(rotation=65) +plt.ylabel("Probability") +plt.xlabel("x") +plt.show() diff --git a/pyproject.toml b/pyproject.toml index dbd4e24..b7303ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,4 +68,6 @@ dev = [ "mkdocstrings[python]", "ruff>=0.11.5", "pytest-cov>=6.1.1", + "matplotlib", + "python-dotenv", ]