Skip to content

Commit

Permalink
Fix global-phase of copied BlueprintCircuits
Browse files Browse the repository at this point in the history
Using `BlueprintCircuit.copy()` or `.copy_empty_like()` would previously
erase the global phase as part of the rebuild operation.  This overrides
`BlueprintCircuit.copy_empty_like()` to ensure that it is always
propagated through.
  • Loading branch information
jakelishman committed Dec 21, 2023
1 parent 4b30598 commit a27b6bf
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
10 changes: 10 additions & 0 deletions qiskit/circuit/library/blueprintcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ def num_connected_components(self, unitary_only=False):
self._build()
return super().num_connected_components(unitary_only=unitary_only)

def copy_empty_like(self, name=None):
if not self._is_built:
self._build()
cpy = super().copy_empty_like(name=name)
# The base `copy_empty_like` will typically trigger code that `BlueprintCircuit` treats as
# an "invalidation", so we have to manually restore properties deleted by that that
# `copy_empty_like` is supposed to propagate.
cpy.global_phase = self.global_phase
return cpy

def copy(self, name=None):
if not self._is_built:
self._build()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Calling :meth:`~.QuantumCircuit.copy` or :meth:`~.QuantumCircuit.copy_empty_like` on a
:class:¬.BlueprintCircuit` will now correctly propagate the
:attr:`~.QuantumCircuit.global_phase` to the copy. Previously, the global phase would always be zero after the copy.
35 changes: 35 additions & 0 deletions test/python/circuit/library/test_blueprintcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

"""Test the blueprint circuit."""

import math
import unittest
from ddt import ddt, data

Expand Down Expand Up @@ -174,6 +175,40 @@ def _build(self):
mock._append(CircuitInstruction(XGate(), (qr[0],), ()))
self.assertEqual(expected, mock)

def test_global_phase_copied(self):
"""Test that a global-phase parameter is correctly propagated through."""

class DummyBlueprint(BlueprintCircuit):
"""Dummy circuit."""

def _check_configuration(self, raise_on_failure=True):
return True

def _build(self):
# We don't need to do anything, we just need `_build` to be non-abstract.
# pylint: disable=useless-parent-delegation
return super()._build()

base = DummyBlueprint()
base.global_phase = math.pi / 2

self.assertEqual(base.copy_empty_like().global_phase, math.pi / 2)
self.assertEqual(base.copy().global_phase, math.pi / 2)

# Verify that a parametric global phase can be assigned after the copy.
a = Parameter("a")
parametric = DummyBlueprint()
parametric.global_phase = a

self.assertEqual(
parametric.copy_empty_like().assign_parameters({a: math.pi / 2}).global_phase,
math.pi / 2,
)
self.assertEqual(
parametric.copy().assign_parameters({a: math.pi / 2}).global_phase,
math.pi / 2,
)


if __name__ == "__main__":
unittest.main()

0 comments on commit a27b6bf

Please sign in to comment.