-
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 - The decomposer/replacer now checks that every used decomposition is valid in terms of circuit matrix!
- Loading branch information
Pablo Le Hénaff
committed
Jan 29, 2024
1 parent
d6cf496
commit f5fa9f7
Showing
12 changed files
with
644 additions
and
232 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.