|
import numpy as np |
|
import random |
|
import io |
|
import duckdb |
|
import gradio as gr |
|
import math |
|
from datetime import datetime |
|
import PIL |
|
import matplotlib.pyplot as plt |
|
from PIL import Image |
|
import pennylane as qml |
|
import base64 |
|
|
|
from numpy import pi |
|
import numpy as np |
|
from qutip import * |
|
from qutip.qip.operations import * |
|
from qutip.qip.circuit import QubitCircuit, Gate |
|
|
|
|
|
dev = qml.device('default.qubit', wires=10) |
|
|
|
def plot_qutip_circuit(): |
|
q = QubitCircuit(2, reverse_states=False) |
|
q.add_gate("CNOT", controls=[0], targets=[1]) |
|
|
|
|
|
q.png |
|
|
|
return q |
|
|
|
|
|
|
|
def store_in_hf_dataset(data): |
|
|
|
pass |
|
|
|
def load_from_hf_dataset(): |
|
|
|
return [] |
|
|
|
|
|
def buffer_plot_and_get(fig): |
|
buf = io.BytesIO() |
|
fig.savefig(buf, format='png') |
|
buf.seek(0) |
|
return PIL.Image.open(buf) |
|
|
|
|
|
def pil_image_to_bytes(image): |
|
img_byte_arr = io.BytesIO() |
|
image.save(img_byte_arr, format='PNG') |
|
return img_byte_arr.getvalue() |
|
|
|
|
|
def generate_random_hamiltonian(num_qubits): |
|
terms = [] |
|
for _ in range(random.randint(1, 5)): |
|
coeff = round(random.uniform(-1, 1), 2) |
|
pauli_ops = [random.choice(['I', 'X', 'Y', 'Z']) for _ in range(num_qubits)] |
|
term = f"{coeff} * {' '.join(pauli_ops)}" |
|
terms.append(term) |
|
return " + ".join(terms) |
|
|
|
|
|
def hamiltonian_to_qasm(hamiltonian, num_qubits): |
|
qasm_code = f"OPENQASM 2.0;\ninclude \"qelib1.inc\";\nqreg q[{num_qubits}];\n" |
|
rotations = {i: 0.0 for i in range(num_qubits)} |
|
terms = hamiltonian.split(" + ") |
|
|
|
for term in terms: |
|
coeff, paulis = term.split(" * ") |
|
paulis = paulis.split() |
|
coeff = float(coeff) |
|
|
|
for i, pauli in enumerate(paulis): |
|
if pauli == "X": |
|
qasm_code += f"x q[{i}];\n" |
|
elif pauli == "Y": |
|
qasm_code += f"ry(pi/2) q[{i}];\n" |
|
elif pauli == "Z": |
|
rotations[i] += coeff |
|
|
|
for i, angle in rotations.items(): |
|
if angle != 0: |
|
angle_degrees = round(angle * 180 / math.pi, 2) |
|
qasm_code += f"rz({angle_degrees}) q[{i}];\n" |
|
|
|
return qasm_code |
|
|
|
|
|
def trotter_decomposition(hamiltonian, order): |
|
terms = hamiltonian.split(" + ") |
|
trotter_steps = [] |
|
|
|
for term in terms: |
|
coeff, *pauli_ops = term.split(" * ") |
|
coeff = float(coeff) |
|
for _ in range(order): |
|
trotter_steps.append(f"exp({coeff / order}) * ({' * '.join(pauli_ops)})") |
|
for _ in range(order): |
|
trotter_steps.append(f"exp({-coeff / order}) * ({' * '.join(pauli_ops)})") |
|
|
|
return " + ".join(trotter_steps) |
|
|
|
|
|
def store_in_duckdb(data, db_file='quantum_hamiltonians.duckdb'): |
|
conn = duckdb.connect(database=db_file) |
|
conn.execute("""CREATE TABLE IF NOT EXISTS hamiltonians ( |
|
id INTEGER, |
|
plot BLOB, |
|
hamiltonian VARCHAR, |
|
qasm_code VARCHAR, |
|
trotter_code VARCHAR, |
|
num_qubits INTEGER, |
|
trotter_order INTEGER, |
|
timestamp TIMESTAMP |
|
)""") |
|
conn.executemany("""INSERT INTO hamiltonians (id, plot, hamiltonian, qasm_code, trotter_code, num_qubits, trotter_order, timestamp) |
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", data) |
|
conn.close() |
|
|
|
|
|
def encode_image_from_blob(blob): |
|
img_buffer = io.BytesIO(blob) |
|
image = Image.open(img_buffer) |
|
img_str = base64.b64encode(img_buffer.getvalue()).decode("utf-8") |
|
return f'<img src="data:image/png;base64,{img_str}" style="max-width:500px;"/>' |
|
|
|
def load_from_duckdb(db_file='quantum_hamiltonians.duckdb'): |
|
conn = duckdb.connect(database=db_file) |
|
df = conn.execute("SELECT * FROM hamiltonians").df() |
|
conn.close() |
|
|
|
|
|
html_content = [] |
|
for index, row in df.iterrows(): |
|
plot_blob = row['plot'] |
|
encoded_img = encode_image_from_blob(plot_blob) |
|
|
|
html_content.append(f""" |
|
<table style='width: 100%; border-collapse: collapse; margin: 10px;'> |
|
<tr> |
|
<td style='width: 30%; text-align: center;'> |
|
<h3>Circuit {index + 1}</h3> |
|
{encoded_img} <!-- Display the image --> |
|
</td> |
|
<td style='padding: 10px;'> |
|
<table style='width: 100%; border-collapse: collapse;'> |
|
<tr> |
|
<td><strong>Hamiltonian:</strong></td><td>{row['hamiltonian']}</td> |
|
</tr> |
|
<tr> |
|
<td><strong>QASM Representation:</strong></td><td>{row['qasm_code']}</td> |
|
</tr> |
|
<tr> |
|
<td><strong>Trotter Decomposition:</strong></td><td>{row['trotter_code']}</td> |
|
</tr> |
|
<tr> |
|
<td><strong>Number of Qubits:</strong></td><td>{row['num_qubits']}</td> |
|
</tr> |
|
<tr> |
|
<td><strong>Trotter Order:</strong></td><td>{row['trotter_order']}</td> |
|
</tr> |
|
<tr> |
|
<td><strong>Timestamp:</strong></td><td>{row['timestamp']}</td> |
|
</tr> |
|
</table> |
|
</td> |
|
</tr> |
|
</table> |
|
""") |
|
|
|
return "".join(html_content) |
|
|
|
|
|
def generate_hamiltonians(num_hamiltonians, selected_qubits, selected_order, write_to_hf, write_to_duckdb): |
|
results_table = [] |
|
timestamp = datetime.now() |
|
|
|
for i in range(num_hamiltonians): |
|
num_qubits = random.choice(selected_qubits) |
|
order = selected_order |
|
hamiltonian = generate_random_hamiltonian(num_qubits) |
|
qasm_code = hamiltonian_to_qasm(hamiltonian, num_qubits) |
|
trotter_code = trotter_decomposition(hamiltonian, order) |
|
|
|
|
|
fig, ax = plt.subplots() |
|
ax.plot([0, 1], [0, 1]) |
|
circuit_plot_image = buffer_plot_and_get(fig) |
|
circuit_plot_bytes = pil_image_to_bytes(circuit_plot_image) |
|
|
|
|
|
results_table.append((i + 1, circuit_plot_bytes, hamiltonian, qasm_code, trotter_code, num_qubits, order, timestamp)) |
|
|
|
|
|
if write_to_hf: |
|
store_in_hf_dataset(results_table) |
|
|
|
|
|
if write_to_duckdb: |
|
store_in_duckdb(results_table) |
|
|
|
|
|
def load_results(load_from_hf, load_from_duckdb1): |
|
if load_from_hf: |
|
return load_from_hf_dataset() |
|
if load_from_duckdb1: |
|
return load_from_duckdb() |
|
|
|
|
|
with gr.Blocks() as app: |
|
gr.Markdown("# Quantum Hamiltonian Generator") |
|
|
|
with gr.Tab("Generate Hamiltonians"): |
|
num_hamiltonians = gr.Dropdown(label="Select number of Hamiltonians to generate", choices=[1, 10, 20, 100], value=20) |
|
qubit_choices = [1, 2, 3, 4, 5, 6] |
|
selected_qubits = gr.CheckboxGroup(label="Select number of qubits", choices=qubit_choices, value=[1]) |
|
order_choices = [1, 2, 3, 4, 5] |
|
selected_order = gr.Dropdown(label="Select Trotter order", choices=order_choices, value=1) |
|
|
|
|
|
write_to_hf = gr.Checkbox(label="Write to Hugging Face dataset", value=False) |
|
write_to_duckdb = gr.Checkbox(label="Write to DuckDB", value=True) |
|
|
|
generate_button = gr.Button("Generate Hamiltonians") |
|
status = gr.Markdown("Click 'Generate Hamiltonians' to start the process.") |
|
|
|
def update_status(num, qubits, order, write_hf, write_duckdb): |
|
generate_hamiltonians(num, qubits, order, write_hf, write_duckdb) |
|
return "Data stored as per selection." |
|
|
|
generate_button.click(update_status, inputs=[num_hamiltonians, selected_qubits, selected_order, write_to_hf, write_to_duckdb], outputs=status) |
|
|
|
with gr.Tab("View Results"): |
|
load_from_hf = gr.Checkbox(label="Load from Hugging Face dataset", value=False) |
|
load_from_duckdb1 = gr.Checkbox(label="Load from DuckDB", value=True) |
|
|
|
load_button = gr.Button("Load Results") |
|
output_display = gr.HTML() |
|
|
|
load_button.click(load_results, inputs=[load_from_hf, load_from_duckdb1], outputs=output_display) |
|
|
|
app.launch() |
|
|