From 80b37346d7462be4e9a3c5c264406ee5f0af28ae Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 09:11:09 -0600 Subject: [PATCH 01/10] add reverse_bits option to user_config --- qiskit/user_config.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/qiskit/user_config.py b/qiskit/user_config.py index 8da0d8e27668..dd068f59a933 100644 --- a/qiskit/user_config.py +++ b/qiskit/user_config.py @@ -30,6 +30,7 @@ class UserConfig: circuit_drawer = mpl circuit_mpl_style = default circuit_mpl_style_path = ~/.qiskit: + circuit_reverse_bits = True transpile_optimization_level = 1 parallel = False num_processes = 4 @@ -117,6 +118,18 @@ def read_config_file(self): ) self.settings["circuit_mpl_style_path"] = cpath_list + # Parse circuit_reverse_bits + try: + circuit_reverse_bits = self.config_parser.getboolean( + "default", "circuit_reverse_bits", fallback=None + ) + except ValueError as err: + raise exceptions.QiskitUserConfigError( + f"Value assigned to circuit_reverse_bits is not valid. {str(err)}" + ) + if circuit_reverse_bits is not None: + self.settings["circuit_reverse_bits"] = circuit_reverse_bits + # Parse transpile_optimization_level transpile_optimization_level = self.config_parser.getint( "default", "transpile_optimization_level", fallback=-1 From d86b26eb8d1a7944a90149ff2bf56196d1b9d70f Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 09:24:48 -0600 Subject: [PATCH 02/10] check in circuit_visualization if circuit_reverse_bits option in present user configuration --- qiskit/visualization/circuit/circuit_visualization.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qiskit/visualization/circuit/circuit_visualization.py b/qiskit/visualization/circuit/circuit_visualization.py index 1aaa42c32d4f..1bde19c90763 100644 --- a/qiskit/visualization/circuit/circuit_visualization.py +++ b/qiskit/visualization/circuit/circuit_visualization.py @@ -51,7 +51,7 @@ def circuit_drawer( output=None, interactive=False, plot_barriers=True, - reverse_bits=False, + reverse_bits=None, justify=None, vertical_compression="medium", idle_wires=True, @@ -180,8 +180,10 @@ def circuit_drawer( config = user_config.get_config() # Get default from config file else use text default_output = "text" + default_reverse_bits = False if config: default_output = config.get("circuit_drawer", "text") + default_reverse_bits = config.get("circuit_reverse_bits", False) if default_output == "auto": if _optionals.HAS_MATPLOTLIB: default_output = "mpl" @@ -190,6 +192,9 @@ def circuit_drawer( if output is None: output = default_output + if reverse_bits is None: + reverse_bits = default_reverse_bits + if wire_order is not None and reverse_bits: raise VisualizationError( "The wire_order option cannot be set when the reverse_bits option is True." From 01c09a1535f3c8725ea400102a71355f1dd5e3a0 Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 09:31:20 -0600 Subject: [PATCH 03/10] in quantumcircuit.py, change default value of reverse_bits to None --- qiskit/circuit/quantumcircuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index fd8f57defe36..d7830d487391 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1743,7 +1743,7 @@ def draw( style: Optional[Union[dict, str]] = None, interactive: bool = False, plot_barriers: bool = True, - reverse_bits: bool = False, + reverse_bits: bool = None, justify: Optional[str] = None, vertical_compression: Optional[str] = "medium", idle_wires: bool = True, From 2b3ee9d93e7774d751c85c0a2ae4fb1365c16287 Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 09:37:59 -0600 Subject: [PATCH 04/10] reno --- ...ts-to-user-config-options-0e465e6e92d5b49f.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml diff --git a/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml new file mode 100644 index 000000000000..afc75cd53e08 --- /dev/null +++ b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + The user_config file has a new configuration option, + ``circuit_reverse_bits``. This allows users to set the local behavior of + the `reverse_bits` option of the ``circuitdrawer`` to default to ``True``. + For example, the format of the config file ``settings.conf`` should be: + + .. code-block:: text + + [default] + circuit_drawer = mpl + circuit_mpl_style = default + circuit_reverse_bits = True \ No newline at end of file From d070a11f0a9fcb053cb2332450c9e6c51359b201 Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 10:01:17 -0600 Subject: [PATCH 05/10] update docstrings --- qiskit/circuit/quantumcircuit.py | 4 +++- qiskit/visualization/circuit/circuit_visualization.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index d7830d487391..0e0d266f7c0c 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1804,7 +1804,9 @@ def draw( `latex_source` output type this has no effect and will be silently ignored. Defaults to False. reverse_bits (bool): when set to True, reverse the bit order inside - registers for the output visualization. Defaults to False. + registers for the output visualization. Defaults to False unless the + user config file (usually ``~/.qiskit/settings.conf``) has an + alternative value set. For example, ``circuit_reverse_bits = True``. plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): options are ``left``, ``right`` or ``none``. If diff --git a/qiskit/visualization/circuit/circuit_visualization.py b/qiskit/visualization/circuit/circuit_visualization.py index 1bde19c90763..fcade67d2ed3 100644 --- a/qiskit/visualization/circuit/circuit_visualization.py +++ b/qiskit/visualization/circuit/circuit_visualization.py @@ -111,7 +111,9 @@ def circuit_drawer( `latex_source` output type this has no effect and will be silently ignored. Defaults to False. reverse_bits (bool): when set to True, reverse the bit order inside - registers for the output visualization. Defaults to False. + registers for the output visualization. Defaults to False unless the + user config file (usually ``~/.qiskit/settings.conf``) has an + alternative value set. For example, ``circuit_reverse_bits = True``. plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): options are ``left``, ``right`` or ``none``. If From 9aff3cd9b83b03c04cdf5d14dc78eca8314ba324 Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 10:30:57 -0600 Subject: [PATCH 06/10] add tests to test_user_config.py, and run testing --- qiskit/user_config.py | 1 + test/python/test_user_config.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/qiskit/user_config.py b/qiskit/user_config.py index dd068f59a933..666bf53d962b 100644 --- a/qiskit/user_config.py +++ b/qiskit/user_config.py @@ -190,6 +190,7 @@ def set_config(key, value, section=None, file_path=None): "circuit_drawer", "circuit_mpl_style", "circuit_mpl_style_path", + "circuit_reverse_bits", "transpile_optimization_level", "parallel", "num_processes", diff --git a/test/python/test_user_config.py b/test/python/test_user_config.py index 4bb272d27140..b122c18b88ff 100644 --- a/test/python/test_user_config.py +++ b/test/python/test_user_config.py @@ -69,6 +69,31 @@ def test_circuit_drawer_valid(self): config.read_config_file() self.assertEqual({"circuit_drawer": "latex"}, config.settings) + def test_invalid_circuit_reverse_bits(self): + test_config = """ + [default] + circuit_reverse_bits = Neither + """ + self.addCleanup(os.remove, self.file_path) + with open(self.file_path, "w") as file: + file.write(test_config) + file.flush() + config = user_config.UserConfig(self.file_path) + self.assertRaises(exceptions.QiskitUserConfigError, config.read_config_file) + + def test_circuit_reverse_bits_valid(self): + test_config = """ + [default] + circuit_reverse_bits = false + """ + self.addCleanup(os.remove, self.file_path) + with open(self.file_path, "w") as file: + file.write(test_config) + file.flush() + config = user_config.UserConfig(self.file_path) + config.read_config_file() + self.assertEqual({"circuit_reverse_bits": False}, config.settings) + def test_optimization_level_valid(self): test_config = """ [default] @@ -126,6 +151,7 @@ def test_all_options_valid(self): circuit_drawer = latex circuit_mpl_style = default circuit_mpl_style_path = ~:~/.qiskit + circuit_reverse_bits = false transpile_optimization_level = 3 suppress_packaging_warnings = true parallel = false @@ -143,6 +169,7 @@ def test_all_options_valid(self): "circuit_drawer": "latex", "circuit_mpl_style": "default", "circuit_mpl_style_path": ["~", "~/.qiskit"], + "circuit_reverse_bits": False, "transpile_optimization_level": 3, "num_processes": 15, "parallel_enabled": False, @@ -156,6 +183,7 @@ def test_set_config_all_options_valid(self): user_config.set_config("circuit_drawer", "latex", file_path=self.file_path) user_config.set_config("circuit_mpl_style", "default", file_path=self.file_path) user_config.set_config("circuit_mpl_style_path", "~:~/.qiskit", file_path=self.file_path) + user_config.set_config("circuit_reverse_bits", "false", file_path=self.file_path) user_config.set_config("transpile_optimization_level", "3", file_path=self.file_path) user_config.set_config("parallel", "false", file_path=self.file_path) user_config.set_config("num_processes", "15", file_path=self.file_path) @@ -169,6 +197,7 @@ def test_set_config_all_options_valid(self): "circuit_drawer": "latex", "circuit_mpl_style": "default", "circuit_mpl_style_path": ["~", "~/.qiskit"], + "circuit_reverse_bits": False, "transpile_optimization_level": 3, "num_processes": 15, "parallel_enabled": False, From 5deab708749e6e80a83a3e68f9ba02d70843979b Mon Sep 17 00:00:00 2001 From: diemilio Date: Wed, 23 Nov 2022 11:12:05 -0600 Subject: [PATCH 07/10] reno update --- ...d-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml index afc75cd53e08..8a2f6a26cf3f 100644 --- a/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml +++ b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml @@ -11,4 +11,5 @@ features: [default] circuit_drawer = mpl circuit_mpl_style = default - circuit_reverse_bits = True \ No newline at end of file + circuit_reverse_bits = True + \ No newline at end of file From 75e5c0e0176c514facea6b27badfed2999ff048b Mon Sep 17 00:00:00 2001 From: diemilio Date: Sat, 10 Dec 2022 12:48:27 -0500 Subject: [PATCH 08/10] Add conditional to set `default_reverse_bits` to value in user config file only if `wire_order` option is not passed to drawer This avoids confusion when user tries to pass `wire_order` to the drawer, but reverse_bits has been set to `True` in the user config file, which will then throw an error. This means that the `wire_order` option passed to the drawer takes precedence over the `reverse_bits` option set in the user config file. --- qiskit/visualization/circuit/circuit_visualization.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit/visualization/circuit/circuit_visualization.py b/qiskit/visualization/circuit/circuit_visualization.py index fcade67d2ed3..368a1c3b70c0 100644 --- a/qiskit/visualization/circuit/circuit_visualization.py +++ b/qiskit/visualization/circuit/circuit_visualization.py @@ -185,12 +185,13 @@ def circuit_drawer( default_reverse_bits = False if config: default_output = config.get("circuit_drawer", "text") - default_reverse_bits = config.get("circuit_reverse_bits", False) if default_output == "auto": if _optionals.HAS_MATPLOTLIB: default_output = "mpl" else: default_output = "text" + if wire_order is None: + default_reverse_bits = config.get("circuit_reverse_bits", False) if output is None: output = default_output From 5abf4fde0c4625ee32c0aeac7945cdd7fb1ac373 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 17 Jan 2023 18:31:00 +0000 Subject: [PATCH 09/10] Add test of loading default-override from config --- .../visualization/test_circuit_text_drawer.py | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py index 839193934a7f..6e70edc783d4 100644 --- a/test/python/visualization/test_circuit_text_drawer.py +++ b/test/python/visualization/test_circuit_text_drawer.py @@ -12,8 +12,10 @@ """ `_text_circuit_drawer` "draws" a circuit in "ascii art" """ +import pathlib import os -import unittest +import tempfile +import unittest.mock from codecs import encode from math import pi @@ -25,6 +27,7 @@ from qiskit.quantum_info.random import random_unitary from qiskit.test import QiskitTestCase from qiskit.transpiler.layout import Layout, TranspileLayout +from qiskit.visualization import circuit_drawer from qiskit.visualization.circuit import text as elements from qiskit.visualization.circuit.circuit_visualization import _text_circuit_drawer from qiskit.extensions import UnitaryGate, HamiltonianGate @@ -382,6 +385,53 @@ def test_text_swap_reverse_bits(self): circuit.swap(qr1, qr2) self.assertEqual(str(_text_circuit_drawer(circuit, reverse_bits=True)), expected) + def test_text_reverse_bits_read_from_config(self): + """Swap drawing with reverse_bits set in the configuration file.""" + expected_forward = "\n".join( + [ + " ", + "q1_0: ─X────", + " │ ", + "q1_1: ─┼──X─", + " │ │ ", + "q2_0: ─X──┼─", + " │ ", + "q2_1: ────X─", + " ", + ] + ) + expected_reverse = "\n".join( + [ + " ", + "q2_1: ────X─", + " │ ", + "q2_0: ─X──┼─", + " │ │ ", + "q1_1: ─┼──X─", + " │ ", + "q1_0: ─X────", + " ", + ] + ) + qr1 = QuantumRegister(2, "q1") + qr2 = QuantumRegister(2, "q2") + circuit = QuantumCircuit(qr1, qr2) + circuit.swap(qr1, qr2) + + self.assertEqual(str(circuit_drawer(circuit, output="text")), expected_forward) + + config_content = """ + [default] + circuit_reverse_bits = true + """ + with tempfile.TemporaryDirectory() as dir_path: + file_path = pathlib.Path(dir_path) / "qiskit.conf" + with open(file_path, "w") as fptr: + fptr.write(config_content) + with unittest.mock.patch.dict(os.environ, {"QISKIT_SETTINGS": str(file_path)}): + test_reverse = str(circuit_drawer(circuit, output="text")) + self.assertEqual(test_reverse, expected_reverse) + def test_text_cswap(self): """CSwap drawing.""" expected = "\n".join( From 3d43c660c00440031f488e78420902f737e36ff6 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 17 Jan 2023 18:35:06 +0000 Subject: [PATCH 10/10] Reword release note --- ...s-to-user-config-options-0e465e6e92d5b49f.yaml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml index 8a2f6a26cf3f..b01167ee5064 100644 --- a/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml +++ b/releasenotes/notes/add-reverse-bits-to-user-config-options-0e465e6e92d5b49f.yaml @@ -1,15 +1,14 @@ --- features: - | - The user_config file has a new configuration option, - ``circuit_reverse_bits``. This allows users to set the local behavior of - the `reverse_bits` option of the ``circuitdrawer`` to default to ``True``. - For example, the format of the config file ``settings.conf`` should be: + The user configuration file has a new option ``circuit_reverse_bits``, which takes a Boolean + value. This allows users to set their preferred default behavior of the ``reverse_bits`` option + of the circuit drawers :meth:`.QuantumCircuit.draw` and :func:`.circuit_drawer`. For example, + adding a section to ``~/.qiskit/settings.conf`` with: - .. code-block:: text + .. code-block:: text [default] - circuit_drawer = mpl - circuit_mpl_style = default circuit_reverse_bits = True - \ No newline at end of file + + will change the default to display the bits in reverse order.