blob: 3361a8b7a73e29653939e2f9c545eae14016c179 [file] [log] [blame] [view]
# Parameterized Quantum Circuits and Rotation Gates
Parameterized quantum circuits (PQCs) contain gates with tunable parameters that can be optimized. Instead of using fixed angles, you use symbolic parameters that can be adjusted to find optimal values.
**Why use parameters?** Fixed angles give you one specific operation. Parameters let you:
- **Optimize**: Find the best angles for your task
- **Train**: Adjust parameters based on results (like machine learning)
- **Explore**: Try different values without rewriting the circuit
Rotation gates (Rx, Ry, Rz) are the primary parameterized gates. Use string names (e.g., `"theta"`) instead of numbers to create parameters, then bind values before execution.
## Rotation Gates
Rotation gates rotate a qubit around the X, Y, or Z axis of the Bloch sphere. Each axis controls different aspects:
- **X-axis (Rx)**: Bit-flip rotations
- **Y-axis (Ry)**: Creates superpositions (like Hadamard)
- **Z-axis (Rz)**: Phase rotations (doesn't change probabilities)
### Rx Gate
Rotates a qubit around the X-axis by angle θ.
\[ R_x(\theta) = \begin{pmatrix} \cos(\theta/2) & -i\sin(\theta/2) \\ -i\sin(\theta/2) & \cos(\theta/2) \end{pmatrix} \]
\[ R_x(\pi/2)|0\rangle = \frac{1}{\sqrt{2}}(|0\rangle - i|1\rangle) \]
```python
from qumat import QuMat
import numpy as np
backend_config = {
'backend_name': 'qiskit',
'backend_options': {'simulator_type': 'qasm_simulator', 'shots': 1000}
}
qumat = QuMat(backend_config)
qumat.create_empty_circuit(num_qubits=1)
qumat.apply_rx_gate(0, angle=np.pi / 2)
results = qumat.execute_circuit()
```
### Ry Gate
Rotates a qubit around the Y-axis by angle θ.
\[ R_y(\theta) = \begin{pmatrix} \cos(\theta/2) & -\sin(\theta/2) \\ \sin(\theta/2) & \cos(\theta/2) \end{pmatrix} \]
\[ R_y(\pi/2)|0\rangle = \frac{1}{\sqrt{2}}(|0\rangle + |1\rangle) \]
```python
qumat.create_empty_circuit(num_qubits=1)
qumat.apply_ry_gate(0, angle=np.pi / 2) # Creates (|0⟩ + |1⟩)/√2
results = qumat.execute_circuit()
```
### Rz Gate
Rotates a qubit around the Z-axis by angle θ. Changes phase without affecting probability amplitudes.
\[ R_z(\theta) = \begin{pmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{pmatrix} \]
\[ R_z(\pi/2)\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle) = \frac{1}{\sqrt{2}}(|0\rangle + i|1\rangle) \]
Probabilities remain: P(|0⟩) = P(|1⟩) = 1/2
```python
qumat.create_empty_circuit(num_qubits=1)
qumat.apply_hadamard_gate(0)
qumat.apply_rz_gate(0, angle=np.pi / 2)
results = qumat.execute_circuit()
```
**Notes**: Angles are in **radians** (π = 180°, π/2 = 90°, π/4 = 45°). Supported across all backends (Qiskit, Cirq, Braket).
## Creating Parameterized Circuits
**Fixed value** (angle is set once):
```python
qumat.apply_ry_gate(0, angle=0.5) # Fixed angle
```
**Parameterized** (angle can be changed):
```python
qumat.apply_ry_gate(0, angle="theta") # Parameter - can be optimized
```
Use string names instead of numbers to create parameters:
```python
from qumat import QuMat
import numpy as np
backend_config = {
'backend_name': 'qiskit',
'backend_options': {'simulator_type': 'qasm_simulator', 'shots': 1000}
}
qumat = QuMat(backend_config)
# Step 1: Create circuit with parameterized gates
qumat.create_empty_circuit(num_qubits=2)
qumat.apply_ry_gate(0, angle="theta") # String = parameter
qumat.apply_rz_gate(0, angle="phi")
qumat.apply_rx_gate(1, angle="alpha")
# Step 2: Parameters are automatically registered
print(list(qumat.parameters.keys())) # ['theta', 'phi', 'alpha']
# Step 3: Bind parameters before execution
qumat.bind_parameters({
"theta": np.pi / 4,
"phi": np.pi / 2,
"alpha": np.pi / 3
})
# Step 4: Execute with bound parameters
results = qumat.execute_circuit()
# Alternative: Bind during execution (skips step 3)
results = qumat.execute_circuit(parameter_values={
"theta": np.pi / 4,
"phi": np.pi / 2,
"alpha": np.pi / 3
})
```
## bind_parameters()
Assigns numerical values to symbolic parameters. Must be called before `execute_circuit()` if parameters are used.
**Raises**: `ValueError` if parameter name not found.
```python
# Create circuit with parameters
qumat.create_empty_circuit(num_qubits=1)
qumat.apply_ry_gate(0, angle="theta")
qumat.apply_rz_gate(0, angle="phi")
# Bind values to parameters
qumat.bind_parameters({"theta": 0.5, "phi": 1.0})
# Now you can execute
results = qumat.execute_circuit()
```
## Optimization Loops
The power of parameterized circuits: optimize parameters to minimize a cost function. The workflow is:
1. Create circuit with parameters
2. Try different parameter values
3. Execute and compute cost
4. Find values that minimize cost
Example:
```python
from qumat import QuMat
import numpy as np
backend_config = {
'backend_name': 'qiskit',
'backend_options': {'simulator_type': 'qasm_simulator', 'shots': 1000}
}
qumat = QuMat(backend_config)
# Create parameterized circuit once
qumat.create_empty_circuit(num_qubits=2)
qumat.apply_ry_gate(0, angle="theta")
qumat.apply_cnot_gate(0, 1)
qumat.apply_rz_gate(1, angle="phi")
# Simple optimization loop
best_cost = float('inf')
best_params = None
for iteration in range(10):
# Try different parameter values
theta = np.random.uniform(0, 2 * np.pi)
phi = np.random.uniform(0, 2 * np.pi)
# Bind and execute
qumat.bind_parameters({"theta": theta, "phi": phi})
results = qumat.execute_circuit()
# Compute cost (example: minimize probability of |00⟩)
total_shots = sum(results.values())
prob_00 = results.get("00", 0) / total_shots
cost = prob_00
# Track best result
if cost < best_cost:
best_cost = cost
best_params = {"theta": theta, "phi": phi}
print(f"Best parameters: {best_params}, cost: {best_cost}")
# With SciPy optimizer
from scipy.optimize import minimize
def cost_function(params):
theta, phi = params
qumat.bind_parameters({"theta": theta, "phi": phi})
results = qumat.execute_circuit()
total_shots = sum(results.values())
prob_00 = results.get("00", 0) / total_shots
return prob_00
result = minimize(cost_function, [0.5, 0.5], method='COBYLA')
print(f"Optimized: {result.x}, cost: {result.fun}")
```
## Key Points
- **Parameter creation**: Use string names (e.g., `"theta"`) in rotation gates to create parameters
- **Auto-registration**: Parameters are automatically registered when first used
- **Binding required**: All parameters must be bound (assigned values) before execution
- **Value types**: Parameter values must be numerical (float or int)
- **Backend support**: Works with all backends (Qiskit, Cirq, Braket)
- **Reuse**: Create circuit once, bind different parameter values for optimization loops