mirror of
https://github.com/kristoferssolo/grovers-visualizer.git
synced 2026-02-04 06:42:03 +00:00
chore(ui): setup dependencies
This commit is contained in:
79
src/grovers_visualizer/cli.py
Normal file
79
src/grovers_visualizer/cli.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from math import asin, sqrt
|
||||
from typing import Callable
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backend_bases import KeyEvent
|
||||
from matplotlib.gridspec import GridSpec
|
||||
from qiskit import QuantumCircuit
|
||||
from qiskit.quantum_info import Statevector
|
||||
|
||||
from .circuit import diffusion, oracle
|
||||
from .parse import Args
|
||||
from .plot import SinePlotData, plot_amplitudes, plot_circle, plot_sine
|
||||
from .utils import all_states, optimal_grover_iterations
|
||||
|
||||
|
||||
def run_cli(args: Args) -> None:
|
||||
target_state = args.target
|
||||
n_qubits = len(target_state)
|
||||
basis_states = [str(bit) for bit in all_states(n_qubits)]
|
||||
optimal_iterations = optimal_grover_iterations(n_qubits)
|
||||
theta = 2 * asin(1 / sqrt(2**n_qubits))
|
||||
state_angle = 0.5 * theta
|
||||
|
||||
plt.ion()
|
||||
fig = plt.figure(figsize=(14, 6))
|
||||
gs = GridSpec(2, 2, width_ratios=(3, 1), figure=fig)
|
||||
ax_bar = fig.add_subplot(gs[0, 0])
|
||||
ax_sine = fig.add_subplot(gs[1, 0])
|
||||
ax_circle = fig.add_subplot(gs[:, 1])
|
||||
bars = ax_bar.bar(basis_states, [0] * len(basis_states), color="skyblue")
|
||||
ax_bar.set_ylim(-1, 1)
|
||||
ax_bar.set_title("Amplitudes (example)")
|
||||
|
||||
sine_data = SinePlotData()
|
||||
|
||||
def plot_bar(
|
||||
operation: Callable[[QuantumCircuit], None] | None,
|
||||
step_label: str,
|
||||
iteration: int,
|
||||
) -> None:
|
||||
if operation is not None:
|
||||
operation(qc)
|
||||
sv = Statevector.from_instruction(qc)
|
||||
plot_amplitudes(ax_bar, bars, sv, basis_states, step_label, iteration, target_state, optimal_iterations)
|
||||
|
||||
# Start with Hadamard
|
||||
qc = QuantumCircuit(n_qubits)
|
||||
qc.h(range(n_qubits))
|
||||
plot_bar(None, "Hadamard (Initialization)", 0)
|
||||
|
||||
iteration = 1
|
||||
running = True
|
||||
|
||||
def on_key(event: KeyEvent) -> None:
|
||||
nonlocal running
|
||||
if event.key == "q":
|
||||
running = False
|
||||
|
||||
cid = fig.canvas.mpl_connect("key_press_event", on_key)
|
||||
while plt.fignum_exists(fig.number) and running:
|
||||
plot_bar(lambda qc: oracle(qc, target_state), "Oracle (Query Phase)", iteration)
|
||||
plot_bar(lambda qc: diffusion(qc, n_qubits), "Diffusion (Inversion Phase)", iteration)
|
||||
|
||||
plot_circle(ax_circle, iteration, optimal_iterations, theta, state_angle)
|
||||
sine_data.calc_and_append_probability(iteration, theta)
|
||||
plot_sine(ax_sine, sine_data)
|
||||
|
||||
plt.pause(args.speed)
|
||||
|
||||
iteration += 1
|
||||
if args.iterations > 0 and iteration > args.iterations:
|
||||
break
|
||||
|
||||
fig.canvas.mpl_disconnect(cid)
|
||||
plt.ioff()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -6,84 +6,14 @@ simulation using Qiskit's Aer simulator, and visualizes the results
|
||||
using matplotlib.
|
||||
"""
|
||||
|
||||
from math import asin, sqrt
|
||||
from typing import Callable
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backend_bases import KeyEvent
|
||||
from matplotlib.gridspec import GridSpec
|
||||
from qiskit import QuantumCircuit
|
||||
from qiskit.quantum_info import Statevector
|
||||
|
||||
from grovers_visualizer.circuit import diffusion, oracle
|
||||
from grovers_visualizer.parse import parse_args
|
||||
from grovers_visualizer.plot import SinePlotData, plot_amplitudes, plot_circle, plot_sine
|
||||
from grovers_visualizer.utils import all_states, optimal_grover_iterations
|
||||
from .cli import run_cli
|
||||
from .parse import parse_args
|
||||
from .ui import run_dpg_ui
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
|
||||
target_state = args.target
|
||||
n_qubits = len(target_state)
|
||||
basis_states = [str(bit) for bit in all_states(n_qubits)]
|
||||
optimal_iterations = optimal_grover_iterations(n_qubits)
|
||||
theta = 2 * asin(1 / sqrt(2**n_qubits))
|
||||
state_angle = 0.5 * theta
|
||||
|
||||
plt.ion()
|
||||
fig = plt.figure(figsize=(14, 6))
|
||||
gs = GridSpec(2, 2, width_ratios=(3, 1), figure=fig)
|
||||
ax_bar = fig.add_subplot(gs[0, 0])
|
||||
ax_sine = fig.add_subplot(gs[1, 0])
|
||||
ax_circle = fig.add_subplot(gs[:, 1])
|
||||
bars = ax_bar.bar(basis_states, [0] * len(basis_states), color="skyblue")
|
||||
ax_bar.set_ylim(-1, 1)
|
||||
ax_bar.set_title("Amplitudes (example)")
|
||||
|
||||
sine_data = SinePlotData()
|
||||
|
||||
def plot_bar(
|
||||
operation: Callable[[QuantumCircuit], None] | None,
|
||||
step_label: str,
|
||||
iteration: int,
|
||||
) -> None:
|
||||
if operation is not None:
|
||||
operation(qc)
|
||||
sv = Statevector.from_instruction(qc)
|
||||
plot_amplitudes(ax_bar, bars, sv, basis_states, step_label, iteration, target_state, optimal_iterations)
|
||||
|
||||
# Start with Hadamard
|
||||
qc = QuantumCircuit(n_qubits)
|
||||
qc.h(range(n_qubits))
|
||||
plot_bar(None, "Hadamard (Initialization)", 0)
|
||||
|
||||
iteration = 1
|
||||
running = True
|
||||
|
||||
def on_key(event: KeyEvent) -> None:
|
||||
nonlocal running
|
||||
if event.key == "q":
|
||||
running = False
|
||||
|
||||
cid = fig.canvas.mpl_connect("key_press_event", on_key)
|
||||
while plt.fignum_exists(fig.number) and running:
|
||||
plot_bar(lambda qc: oracle(qc, target_state), "Oracle (Query Phase)", iteration)
|
||||
plot_bar(lambda qc: diffusion(qc, n_qubits), "Diffusion (Inversion Phase)", iteration)
|
||||
|
||||
plot_circle(ax_circle, iteration, optimal_iterations, theta, state_angle)
|
||||
sine_data.calc_and_append_probability(iteration, theta)
|
||||
plot_sine(ax_sine, sine_data)
|
||||
|
||||
plt.pause(args.speed)
|
||||
|
||||
iteration += 1
|
||||
if args.iterations > 0 and iteration > args.iterations:
|
||||
break
|
||||
|
||||
fig.canvas.mpl_disconnect(cid)
|
||||
plt.ioff()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
if args.ui:
|
||||
run_dpg_ui(args)
|
||||
else:
|
||||
run_cli(args)
|
||||
|
||||
@@ -9,6 +9,7 @@ class Args:
|
||||
target: QubitState
|
||||
iterations: int
|
||||
speed: float
|
||||
ui: bool
|
||||
|
||||
|
||||
def parse_args() -> Args:
|
||||
@@ -32,9 +33,11 @@ def parse_args() -> Args:
|
||||
default=0.5,
|
||||
help="Pause duration (seconds) between steps (deafult: 0.5)",
|
||||
)
|
||||
parser.add_argument("--ui", action="store_true", help="Run with DearPyGui UI")
|
||||
ns = parser.parse_args()
|
||||
return Args(
|
||||
target=QubitState.from_str(ns.target),
|
||||
iterations=ns.iterations,
|
||||
speed=ns.speed,
|
||||
ui=ns.ui,
|
||||
)
|
||||
|
||||
16
src/grovers_visualizer/ui.py
Normal file
16
src/grovers_visualizer/ui.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from importlib.util import find_spec
|
||||
|
||||
from .parse import Args
|
||||
|
||||
|
||||
def is_dearpygui_available() -> bool:
|
||||
try:
|
||||
return find_spec("dearpygui.dearpygui") is not None
|
||||
except ModuleNotFoundError:
|
||||
return False
|
||||
|
||||
|
||||
def run_dpg_ui(_args: Args) -> None:
|
||||
if not is_dearpygui_available():
|
||||
print("DearPyGui is not installed. Install with: pip install .[ui]")
|
||||
return
|
||||
Reference in New Issue
Block a user