-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Circuit.merge_single_qubit_gates - mcKay decomposer is now only the decomposition - Circuit.decompose is introduced, pass it the McKay decomposer - Decomposer abstract base class - The decomposer/replacer now checks that every used decomposition is valid in terms of circuit matrix!
- Loading branch information
Pablo Le Hénaff
committed
Feb 5, 2024
1 parent
d6cf496
commit 9e59243
Showing
12 changed files
with
663 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from math import acos, atan2, cos, pi, sin, sqrt | ||
from typing import List, Optional | ||
|
||
import numpy as np | ||
|
||
from opensquirrel.common import ATOL | ||
from opensquirrel.squirrel_ir import BlochSphereRotation, Gate, Qubit, SquirrelIR | ||
|
||
|
||
def compose_bloch_sphere_rotations(a: BlochSphereRotation, b: BlochSphereRotation) -> BlochSphereRotation: | ||
"""Computes the Bloch sphere rotation resulting from the composition of two Block sphere rotations. | ||
The first rotation is applied and then the second. | ||
The resulting gate is anonymous except if `a` is the identity and `b` is not anonymous, or vice versa. | ||
Uses Rodrigues' rotation formula, see for instance https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula. | ||
""" | ||
assert a.qubit == b.qubit, "Cannot merge two BlochSphereRotation's on different qubits" | ||
|
||
combined_angle = 2 * acos( | ||
cos(a.angle / 2) * cos(b.angle / 2) - sin(a.angle / 2) * sin(b.angle / 2) * np.dot(a.axis, b.axis) | ||
) | ||
|
||
if abs(sin(combined_angle / 2)) < ATOL: | ||
return BlochSphereRotation.identity(a.qubit) | ||
|
||
combined_axis = ( | ||
1 | ||
/ sin(combined_angle / 2) | ||
* ( | ||
sin(a.angle / 2) * cos(b.angle / 2) * a.axis | ||
+ cos(a.angle / 2) * sin(b.angle / 2) * b.axis | ||
+ sin(a.angle / 2) * sin(b.angle / 2) * np.cross(a.axis, b.axis) | ||
) | ||
) | ||
|
||
combined_phase = a.phase + b.phase | ||
|
||
generator = b.generator if a.is_identity() else a.generator if b.is_identity() else None | ||
arguments = b.arguments if a.is_identity() else a.arguments if b.is_identity() else None | ||
|
||
return BlochSphereRotation( | ||
qubit=a.qubit, | ||
axis=combined_axis, | ||
angle=combined_angle, | ||
phase=combined_phase, | ||
generator=generator, | ||
arguments=arguments, | ||
) | ||
|
||
|
||
def merge_single_qubit_gates(squirrel_ir: SquirrelIR): | ||
accumulators_per_qubit: dict[Qubit, BlochSphereRotation] = { | ||
Qubit(q): BlochSphereRotation.identity(Qubit(q)) for q in range(squirrel_ir.number_of_qubits) | ||
} | ||
|
||
statement_index = 0 | ||
while statement_index < len(squirrel_ir.statements): | ||
statement = squirrel_ir.statements[statement_index] | ||
|
||
if not isinstance(statement, Gate): | ||
# Skip | ||
statement_index += 1 | ||
continue | ||
|
||
if isinstance(statement, BlochSphereRotation): | ||
# Accumulate | ||
already_accumulated = accumulators_per_qubit.get(statement.qubit) | ||
|
||
composed = compose_bloch_sphere_rotations(statement, already_accumulated) | ||
accumulators_per_qubit[statement.qubit] = composed | ||
|
||
del squirrel_ir.statements[statement_index] | ||
continue | ||
|
||
for qubit_operand in statement.get_qubit_operands(): | ||
if not accumulators_per_qubit[qubit_operand].is_identity(): | ||
squirrel_ir.statements.insert(statement_index, accumulators_per_qubit[qubit_operand]) | ||
accumulators_per_qubit[qubit_operand] = BlochSphereRotation.identity(qubit_operand) | ||
statement_index += 1 | ||
statement_index += 1 | ||
|
||
for accumulated_bloch_sphere_rotation in accumulators_per_qubit.values(): | ||
if not accumulated_bloch_sphere_rotation.is_identity(): | ||
squirrel_ir.statements.append(accumulated_bloch_sphere_rotation) |
Oops, something went wrong.