QubitOS Quickstart Notebook¶
This interactive notebook provides a hands-on introduction to QubitOS - an open-source quantum control kernel for pulse optimization.
What You'll Learn¶
- Verify your installation is working
- Generate quantum gate pulses using GRAPE
- Visualize pulse envelopes
- Execute pulses on a simulator backend
- Interpret measurement results
Prerequisites¶
- QubitOS Core installed:
pip install qubitos - HAL server running (for execution):
cargo runin qubit-os-hardware
1. Installation Check¶
Let's verify QubitOS is installed correctly.
# Check QubitOS installation
import qubitos
print(f"QubitOS version: {qubitos.__version__}")
# Import the modules we'll use
from qubitos.pulsegen import GrapeOptimizer, GrapeConfig, generate_pulse
from qubitos.pulsegen.hamiltonians import get_target_unitary
import numpy as np
import matplotlib.pyplot as plt
print("All imports successful!")
2. Your First Pulse: X Gate¶
The X gate (Pauli-X, also called NOT gate) flips a qubit from |0⟩ to |1⟩ and vice versa.
We'll use GRAPE (Gradient Ascent Pulse Engineering) to find the optimal pulse shape.
# Generate an X-gate pulse
result = generate_pulse(
gate="X",
num_qubits=1,
duration_ns=20.0,
target_fidelity=0.999,
)
print(f"Optimization complete!")
print(f" Fidelity: {result.fidelity:.6f}")
print(f" Converged: {result.converged}")
print(f" Iterations: {result.iterations}")
print(f" Pulse samples: {len(result.i_envelope)}")
3. Visualizing the Pulse¶
A quantum control pulse has two quadrature components:
- I (in-phase): Controls rotation around one axis
- Q (quadrature): Controls rotation around an orthogonal axis
# Plot the pulse envelopes
t = np.linspace(0, 20, len(result.i_envelope)) # Time in ns
fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
axes[0].plot(t, result.i_envelope, 'b-', linewidth=1.5)
axes[0].set_ylabel('I Amplitude (MHz)')
axes[0].set_title('X-Gate Pulse Envelope')
axes[0].grid(True, alpha=0.3)
axes[0].axhline(y=0, color='k', linestyle='-', linewidth=0.5)
axes[1].plot(t, result.q_envelope, 'r-', linewidth=1.5)
axes[1].set_ylabel('Q Amplitude (MHz)')
axes[1].set_xlabel('Time (ns)')
axes[1].grid(True, alpha=0.3)
axes[1].axhline(y=0, color='k', linestyle='-', linewidth=0.5)
plt.tight_layout()
plt.show()
4. Generating Different Gates¶
Let's compare pulses for different quantum gates.
# Generate pulses for multiple gates
gates = ["X", "Y", "Z", "H"]
pulses = {}
for gate in gates:
pulses[gate] = generate_pulse(
gate=gate,
duration_ns=20.0,
target_fidelity=0.999,
)
status = "[PASS]" if pulses[gate].converged else "[FAIL]"
print(f"{status} {gate}: F = {pulses[gate].fidelity:.4f}, iters = {pulses[gate].iterations}")
# Compare pulse shapes
fig, axes = plt.subplots(2, 4, figsize=(16, 6))
for i, gate in enumerate(gates):
pulse = pulses[gate]
t = np.linspace(0, 20, len(pulse.i_envelope))
axes[0, i].plot(t, pulse.i_envelope, 'b-')
axes[0, i].set_title(f"{gate} gate (I)")
axes[0, i].grid(True, alpha=0.3)
axes[1, i].plot(t, pulse.q_envelope, 'r-')
axes[1, i].set_title(f"{gate} gate (Q)")
axes[1, i].grid(True, alpha=0.3)
axes[1, i].set_xlabel('Time (ns)')
axes[0, 0].set_ylabel('I Amplitude (MHz)')
axes[1, 0].set_ylabel('Q Amplitude (MHz)')
plt.tight_layout()
plt.show()
5. Understanding Fidelity¶
Fidelity measures how close the achieved gate is to the target gate:
- F = 1.0 → Perfect gate
- F = 0.999 → 99.9% accurate (typical target)
- F = 0.5 → Random, no correlation
Let's see how fidelity evolves during optimization.
# Generate with full history
config = GrapeConfig(
num_time_steps=100,
duration_ns=20.0,
target_fidelity=0.999,
max_iterations=500,
)
optimizer = GrapeOptimizer(config)
target = get_target_unitary("X")
result = optimizer.optimize(target, num_qubits=1)
# Plot convergence
plt.figure(figsize=(10, 5))
plt.semilogy(range(len(result.fidelity_history)),
[1 - f for f in result.fidelity_history],
'b-', linewidth=1.5)
plt.axhline(y=1e-3, color='r', linestyle='--', label='Target (F=0.999)')
plt.xlabel('Iteration')
plt.ylabel('Infidelity (1 - F)')
plt.title('GRAPE Optimization Convergence')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"Final fidelity: {result.fidelity:.6f}")
print(f"Iterations needed: {result.iterations}")
6. Executing on a Backend (Optional)¶
If you have the HAL server running, you can execute the pulse on a QuTiP simulator.
Start the HAL server in another terminal:
cd qubit-os-hardware
cargo run
# Uncomment to execute (requires HAL server)
# from qubitos.client import HALClientSync
# try:
# with HALClientSync("localhost:50051") as client:
# # Check health
# health = client.health_check()
# print(f"Server status: {health.status}")
# # Execute the X-gate pulse
# result = client.execute_pulse(
# i_envelope=pulses["X"].i_envelope.tolist(),
# q_envelope=pulses["X"].q_envelope.tolist(),
# duration_ns=20,
# target_qubits=[0],
# num_shots=1000,
# )
# print(f"\nMeasurement results:")
# for bitstring, count in result.bitstring_counts.items():
# prob = count / result.total_shots * 100
# print(f" |{bitstring}⟩: {count} ({prob:.1f}%)")
# except Exception as e:
# print(f"Could not connect to HAL server: {e}")
# print("Make sure the HAL server is running.")
7. Saving and Loading Pulses¶
Save your optimized pulses for later use.
import json
# Save pulse to file
pulse_data = {
"gate": "X",
"duration_ns": 20,
"num_time_steps": len(pulses["X"].i_envelope),
"fidelity": pulses["X"].fidelity,
"i_envelope": pulses["X"].i_envelope.tolist(),
"q_envelope": pulses["X"].q_envelope.tolist(),
}
# Uncomment to save
# with open("x_gate_pulse.json", "w") as f:
# json.dump(pulse_data, f, indent=2)
# print("Pulse saved to x_gate_pulse.json")
# Show structure
print("Pulse data structure:")
for key in pulse_data:
if isinstance(pulse_data[key], list):
print(f" {key}: [{len(pulse_data[key])} values]")
else:
print(f" {key}: {pulse_data[key]}")
Summary¶
In this notebook, you learned:
- GRAPE optimization generates pulse shapes for quantum gates
- Pulse envelopes have I and Q components (quadrature control)
- Fidelity measures gate accuracy (target > 0.999)
- Different gates have different optimal pulse shapes
- HAL client executes pulses on simulator or hardware
Next Steps¶
- GRAPE Optimization - Deep dive into optimization
- Custom Hamiltonians - Advanced control scenarios
- API Reference - Full documentation