-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into issue_11038_draw_fix
- Loading branch information
Showing
11 changed files
with
381 additions
and
27 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
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
6 changes: 6 additions & 0 deletions
6
releasenotes/notes/fix-blueprint-circuit-_append-b4d6c9c41db860f5.yaml
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,6 @@ | ||
--- | ||
fixes: | ||
- | | ||
:class:`.BlueprintCircuit` subclasses will now behave correctly when the semi-public method | ||
:meth:`.QuantumCircuit._append` is used with the blueprint in an unbuilt state, *i.e.* the | ||
circuit will be built before attempting the append. |
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,54 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2023 | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
|
||
"""Pass manager test cases.""" | ||
|
||
import contextlib | ||
import logging | ||
import re | ||
from itertools import zip_longest | ||
from logging import getLogger | ||
|
||
from qiskit.test import QiskitTestCase | ||
|
||
|
||
class PassManagerTestCase(QiskitTestCase): | ||
"""Test case for the pass manager module.""" | ||
|
||
@contextlib.contextmanager | ||
def assertLogContains(self, expected_lines): | ||
"""A context manager that capture pass manager log. | ||
Args: | ||
expected_lines (List[str]): Expected logs. Each element can be regular expression. | ||
""" | ||
try: | ||
logger = getLogger() | ||
with self.assertLogs(logger=logger, level=logging.DEBUG) as cm: | ||
yield cm | ||
finally: | ||
recorded_lines = cm.output | ||
for i, (expected, recorded) in enumerate(zip_longest(expected_lines, recorded_lines)): | ||
expected = expected or "" | ||
recorded = recorded or "" | ||
if not re.search(expected, recorded): | ||
raise AssertionError( | ||
f"Log didn't match. Mismatch found at line #{i}.\n\n" | ||
f"Expected:\n{self._format_log(expected_lines)}\n" | ||
f"Recorded:\n{self._format_log(recorded_lines)}" | ||
) | ||
|
||
def _format_log(self, lines): | ||
out = "" | ||
for i, line in enumerate(lines): | ||
out += f"#{i:02d}: {line}\n" | ||
return out |
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,143 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2023 | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
# pylint: disable=missing-class-docstring | ||
|
||
"""Pass manager test cases.""" | ||
|
||
from test.python.passmanager import PassManagerTestCase | ||
|
||
from logging import getLogger | ||
|
||
from qiskit.passmanager import GenericPass | ||
from qiskit.passmanager import PassManagerState, WorkflowStatus, PropertySet | ||
from qiskit.passmanager.compilation_status import RunState | ||
|
||
|
||
class TestGenericPass(PassManagerTestCase): | ||
"""Tests for the GenericPass subclass.""" | ||
|
||
def setUp(self): | ||
super().setUp() | ||
|
||
self.state = PassManagerState( | ||
workflow_status=WorkflowStatus(), | ||
property_set=PropertySet(), | ||
) | ||
|
||
def test_run_task(self): | ||
"""Test case: Simple successful task execution.""" | ||
|
||
class Task(GenericPass): | ||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
task = Task() | ||
data = "test_data" | ||
expected = [r"Pass: Task - (\d*\.)?\d+ \(ms\)"] | ||
|
||
with self.assertLogContains(expected): | ||
task.execute(passmanager_ir=data, state=self.state) | ||
self.assertEqual(self.state.workflow_status.count, 1) | ||
self.assertIn(task, self.state.workflow_status.completed_passes) | ||
self.assertEqual(self.state.workflow_status.previous_run, RunState.SUCCESS) | ||
|
||
def test_failure_task(self): | ||
"""Test case: Log is created regardless of success.""" | ||
|
||
class TestError(Exception): | ||
pass | ||
|
||
class RaiseError(GenericPass): | ||
def run(self, passmanager_ir): | ||
raise TestError() | ||
|
||
task = RaiseError() | ||
data = "test_data" | ||
expected = [r"Pass: RaiseError - (\d*\.)?\d+ \(ms\)"] | ||
|
||
with self.assertLogContains(expected): | ||
with self.assertRaises(TestError): | ||
task.execute(passmanager_ir=data, state=self.state) | ||
self.assertEqual(self.state.workflow_status.count, 0) | ||
self.assertNotIn(task, self.state.workflow_status.completed_passes) | ||
self.assertEqual(self.state.workflow_status.previous_run, RunState.FAIL) | ||
|
||
def test_requires(self): | ||
"""Test case: Dependency tasks are run in advance to user provided task.""" | ||
|
||
class TaskA(GenericPass): | ||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
class TaskB(GenericPass): | ||
def __init__(self): | ||
super().__init__() | ||
self.requires = [TaskA()] | ||
|
||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
task = TaskB() | ||
data = "test_data" | ||
expected = [ | ||
r"Pass: TaskA - (\d*\.)?\d+ \(ms\)", | ||
r"Pass: TaskB - (\d*\.)?\d+ \(ms\)", | ||
] | ||
with self.assertLogContains(expected): | ||
task.execute(passmanager_ir=data, state=self.state) | ||
self.assertEqual(self.state.workflow_status.count, 2) | ||
|
||
def test_requires_in_list(self): | ||
"""Test case: Dependency tasks are not executed multiple times.""" | ||
|
||
class TaskA(GenericPass): | ||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
class TaskB(GenericPass): | ||
def __init__(self): | ||
super().__init__() | ||
self.requires = [TaskA()] | ||
|
||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
task = TaskB() | ||
data = "test_data" | ||
expected = [ | ||
r"Pass: TaskB - (\d*\.)?\d+ \(ms\)", | ||
] | ||
self.state.workflow_status.completed_passes.add(task.requires[0]) # already done | ||
with self.assertLogContains(expected): | ||
task.execute(passmanager_ir=data, state=self.state) | ||
self.assertEqual(self.state.workflow_status.count, 1) | ||
|
||
def test_run_with_callable(self): | ||
"""Test case: Callable is called after generic pass is run.""" | ||
|
||
# pylint: disable=unused-argument | ||
def test_callable(task, passmanager_ir, property_set, running_time, count): | ||
logger = getLogger() | ||
logger.info("%s is running on %s", task.name(), passmanager_ir) | ||
|
||
class Task(GenericPass): | ||
def run(self, passmanager_ir): | ||
return passmanager_ir | ||
|
||
task = Task() | ||
data = "test_data" | ||
expected = [ | ||
r"Pass: Task - (\d*\.)?\d+ \(ms\)", | ||
r"Task is running on test_data", | ||
] | ||
with self.assertLogContains(expected): | ||
task.execute(passmanager_ir=data, state=self.state, callback=test_callable) |
Oops, something went wrong.