Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Circuit.draw to display string directly #1434

Merged
merged 41 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ec9810a
modifications
renatomello Sep 4, 2024
d2fec4c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
6278b0e
fix tests and change examples
renatomello Sep 4, 2024
e9a21ec
Merge branch 'draw' of github.com:qiboteam/qibo into draw
renatomello Sep 4, 2024
ee59bf4
fix tests and change examples
renatomello Sep 4, 2024
a0cfb96
fix more tests
renatomello Sep 4, 2024
20c2d57
Fix test
renatomello Sep 4, 2024
96e7d30
coverage
renatomello Sep 5, 2024
4aba6bf
Merge branch 'master' into draw
renatomello Sep 5, 2024
f4ea681
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 5, 2024
b888197
Merge branch 'draw' of github.com:qiboteam/qibo into draw
renatomello Sep 5, 2024
74f69b0
lint disable
renatomello Sep 5, 2024
a483ea3
Merge branch 'master' into draw
renatomello Sep 11, 2024
8c850eb
Merge branch 'master' into draw
renatomello Sep 13, 2024
7fafb22
Merge branch 'master' into draw
renatomello Sep 13, 2024
1f3ea8c
Merge branch 'master' into draw
renatomello Sep 15, 2024
ce8ca3e
Merge branch 'master' into draw
renatomello Sep 16, 2024
993c33c
Alessandro's suggestion
renatomello Sep 18, 2024
f739fd3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 18, 2024
9c09a19
Introduce warning
renatomello Sep 18, 2024
f55ec83
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 18, 2024
53b20da
fix docstring
renatomello Sep 18, 2024
c2584b8
fix test
renatomello Sep 18, 2024
a153956
Merge branch 'draw' of github.com:qiboteam/qibo into draw
renatomello Sep 18, 2024
b3c9f0f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 18, 2024
690a70e
uncomment test backends
renatomello Sep 18, 2024
b0fa293
fix tests
renatomello Sep 18, 2024
fa9bca8
Alessandro's suggestion
renatomello Sep 18, 2024
66b77f7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 18, 2024
58ec073
fix tests
renatomello Sep 18, 2024
6e51ac2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 18, 2024
0b2c4cb
Alessandro's suggestion
renatomello Sep 18, 2024
9b556d6
fix doc tests
renatomello Sep 18, 2024
3a96e3e
Update doc/source/code-examples/advancedexamples.rst
renatomello Sep 18, 2024
d3dc681
Update examples/adiabatic_qml/adiabatic-qml.ipynb
renatomello Sep 18, 2024
c89f861
Update examples/anomaly_detection/test.py
renatomello Sep 18, 2024
f32786f
fix test
renatomello Sep 18, 2024
e9041f6
fix test
renatomello Sep 18, 2024
2515b24
fix test
renatomello Sep 18, 2024
54458e3
Merge branch 'master' into draw
renatomello Sep 18, 2024
a8d007f
Update src/qibo/models/circuit.py
renatomello Sep 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions doc/source/code-examples/advancedexamples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ Additionally, one can also pass single-qubit readout error probabilities (`reado
)

print("raw circuit:")
print(circuit.draw())
circuit.draw()

parameters = {
"t1": {"0": 250*1e-06, "1": 240*1e-06},
Expand All @@ -1168,7 +1168,7 @@ Additionally, one can also pass single-qubit readout error probabilities (`reado
noisy_circuit = noise_model.apply(circuit)

print("noisy circuit:")
print(noisy_circuit.draw())
noisy_circuit.draw()

.. testoutput::
:hide:
Expand Down Expand Up @@ -1242,7 +1242,7 @@ Let's see how to use them. For starters, let's define a dummy circuit with some
circ.add(gates.M(*range(nqubits)))

# visualize the circuit
print(circ.draw())
circ.draw()

# q0: ─RZ─RX─RZ─RX─RZ─o────o────────M─
# q1: ─RZ─RX─RZ─RX─RZ─X─RZ─X─o────o─M─
Expand Down
2 changes: 1 addition & 1 deletion doc/source/code-examples/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ For example
from qibo.models import QFT

c = QFT(5)
print(c.draw())
print(c.draw(output_string=True))
# Prints
'''
q0: ─H─U1─U1─U1─U1───────────────────────────x───
Expand Down
2 changes: 1 addition & 1 deletion examples/adiabatic_qml/adiabatic-qml.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@
"circ1 = rotcirc.rotations_circuit(t=0.1)\n",
"circ2 = rotcirc.rotations_circuit(t=0.8)\n",
"\n",
"print(f\"Circuit diagram: {circ1.draw()}\")\n",
"print(f\"Circuit diagram: {circ1.draw(output_string=True)}\")\n",
"print(f\"\\nCirc1 params: {circ1.get_parameters()}\")\n",
"print(f\"\\nCirc2 params: {circ2.get_parameters()}\")"
]
Expand Down
2 changes: 1 addition & 1 deletion examples/anomaly_detection/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def compute_loss_test(encoder, vector):
encoder_test = make_encoder(n_qubits, n_layers, trained_params, q_compression)
encoder_test.compile()
print("Circuit model summary")
print(encoder_test.draw())
encoder_test.draw()

print("Computing losses...")
# Compute loss for standard data
Expand Down
2 changes: 1 addition & 1 deletion examples/anomaly_detection/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def train_step(batch_size, encoder, params, dataset):
# Create and print encoder circuit
encoder = make_encoder(n_qubits, n_layers, params, q_compression)
print("Circuit model summary")
print(encoder.draw())
encoder.draw()

# Define optimizer parameters
steps_for_epoch = math.ceil(train_size / batch_size)
Expand Down
2 changes: 1 addition & 1 deletion examples/qcnn_classifier/qcnn_demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
"source": [
"test = QuantumCNN(nqubits=4, nlayers=1, nclasses=2)\n",
"testcircuit = test._circuit\n",
"print(testcircuit.draw())"
"testcircuit.draw()"
]
},
{
Expand Down
8 changes: 4 additions & 4 deletions examples/qfiae/qfiae_demo.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/qibo/gates/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def on_qubits(self, qubit_map) -> "Gate":
c.add(gates.CNOT(2, 3).on_qubits({2: 3, 3: 0})) # equivalent to gates.CNOT(3, 0)
c.add(gates.CNOT(2, 3).on_qubits({2: 1, 3: 3})) # equivalent to gates.CNOT(1, 3)
c.add(gates.CNOT(2, 3).on_qubits({2: 2, 3: 1})) # equivalent to gates.CNOT(2, 1)
print(c.draw())
c.draw()
.. testoutput::

q0: ───X─────
Expand Down
2 changes: 1 addition & 1 deletion src/qibo/gates/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ def on_qubits(self, qubit_map) -> "Gate":
c = models.Circuit(3)
c.add(measurement.on_qubits({0: 0, 1: 2}))
assert c.queue[0].result is measurement.result
print(c.draw())
c.draw()
.. testoutput::

q0: ─M─
Expand Down
51 changes: 39 additions & 12 deletions src/qibo/models/circuit.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import collections
import copy
import sys
from typing import Dict, List, Optional, Tuple, Union

import numpy as np
Expand Down Expand Up @@ -1267,18 +1268,7 @@ def _update_draw_matrix(self, matrix, idx, gate, gate_symbol=None):

return matrix, idx

def draw(self, line_wrap=70, legend=False) -> str:
"""Draw text circuit using unicode symbols.

Args:
line_wrap (int): maximum number of characters per line. This option
split the circuit text diagram in chunks of line_wrap characters.
legend (bool): If ``True`` prints a legend below the circuit for
callbacks and channels. Default is ``False``.

Return:
String containing text circuit diagram.
"""
def __str__(self, line_wrap: int = 70, legend: bool = False) -> str:
# build string representation of gates
matrix = [[] for _ in range(self.nqubits)]
idx = [0] * self.nqubits
Expand Down Expand Up @@ -1369,3 +1359,40 @@ def chunkstring(string, length):
output += table

return output.rstrip("\n")

def draw(self, line_wrap: int = 70, legend: bool = False):
"""Draw text circuit using unicode symbols.

Args:
line_wrap (int, optional): maximum number of characters per line. This option
split the circuit text diagram in chunks of line_wrap characters.
Defaults to :math:`70`.
legend (bool, optional): If ``True`` prints a legend below the circuit for
callbacks and channels. Defaults to ``False``.

Returns:
String containing text circuit diagram.
"""
qibo.config.log.warning(
"Starting on qibo 0.2.13, ``Circuit.draw`` will work in-place. "
+ "The in-place method is currently implemented as ``Circuit.display``, but "
+ "will be renamed as ``Circuit.draw`` on release 0.2.13. "
+ "In release 0.2.12, the in-place print of circuits is accessible as "
+ "``Circuit._display``."
)
return self.__str__(line_wrap, legend)

def _display(self, line_wrap: int = 70, legend: bool = False):
"""Draw text circuit using unicode symbols.

Args:
line_wrap (int, optional): maximum number of characters per line. This option
split the circuit text diagram in chunks of line_wrap characters.
Defaults to :math:`70`.
legend (bool, optional): If ``True`` prints a legend below the circuit for
callbacks and channels. Defaults to ``False``.

Returns:
String containing text circuit diagram.
"""
sys.stdout.write(self.__str__(line_wrap, legend))
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"numpy",
"tensorflow",
"pytorch",
"qibojit-numba",
"qibojit-cupy",
"qibojit-cuquantum",
# "qibojit-numba",
# "qibojit-cupy",
# "qibojit-cuquantum",
]
# multigpu configurations to be tested (only with qibojit-cupy)
ACCELERATORS = [
Expand Down
2 changes: 1 addition & 1 deletion tests/test_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ def test_measurement_basis_list(backend):
result = backend.execute_circuit(c, nshots=100)
assert result.frequencies() == {"0011": 100}
assert (
c.draw()
c.draw(output_string=True)
== """q0: ─H─H───M─
q1: ───────M─
q2: ─X─H─H─M─
Expand Down
29 changes: 17 additions & 12 deletions tests/test_models_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ def test_circuit_draw():
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))

assert circuit.draw() == ref
assert circuit.draw(output_string=True) == ref


def test_circuit_wire_names_errors():
Expand Down Expand Up @@ -667,7 +667,7 @@ def test_circuit_draw_wire_names():
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))

assert circuit.draw() == ref
assert circuit.draw(output_string=True) == ref


def test_circuit_draw_line_wrap():
Expand Down Expand Up @@ -723,8 +723,8 @@ def test_circuit_draw_line_wrap():
circuit.add(gates.GeneralizedfSim(0, 2, np.eye(2), 0))
circuit.add(gates.X(4).controlled_by(1, 2, 3))
circuit.add(gates.M(*range(3)))
assert circuit.draw(line_wrap=50) == ref_line_wrap_50
assert circuit.draw(line_wrap=30) == ref_line_wrap_30
assert circuit.draw(line_wrap=50, output_string=True) == ref_line_wrap_50
assert circuit.draw(line_wrap=30, output_string=True) == ref_line_wrap_30


def test_circuit_draw_line_wrap_names():
Expand Down Expand Up @@ -780,8 +780,8 @@ def test_circuit_draw_line_wrap_names():
circuit.add(gates.GeneralizedfSim(0, 2, np.eye(2), 0))
circuit.add(gates.X(4).controlled_by(1, 2, 3))
circuit.add(gates.M(*range(3)))
assert circuit.draw(line_wrap=50) == ref_line_wrap_50
assert circuit.draw(line_wrap=30) == ref_line_wrap_30
assert circuit.draw(line_wrap=50, output_string=True) == ref_line_wrap_50
assert circuit.draw(line_wrap=30, output_string=True) == ref_line_wrap_30


@pytest.mark.parametrize("legend", [True, False])
Expand Down Expand Up @@ -814,7 +814,7 @@ def test_circuit_draw_channels(legend):
"| PauliNoiseChannel | PN |"
)

assert circuit.draw(legend=legend) == ref
assert circuit.draw(legend=legend, output_string=True) == ref


@pytest.mark.parametrize("legend", [True, False])
Expand All @@ -840,7 +840,7 @@ def test_circuit_draw_callbacks(legend):
"| EntanglementEntropy | EE |"
)

assert c.draw(legend=legend) == ref
assert c.draw(legend=legend, output_string=True) == ref


def test_circuit_draw_labels():
Expand All @@ -861,10 +861,10 @@ def test_circuit_draw_labels():
circuit.add(gate)
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))
assert circuit.draw() == ref
assert circuit.draw(output_string=True) == ref


def test_circuit_draw_names():
def test_circuit_draw_names(capsys):
"""Test circuit text draw."""
ref = (
"q0: ─H─cx─cx─cx─cx───────────────────────────x───\n"
Expand All @@ -882,7 +882,12 @@ def test_circuit_draw_names():
circuit.add(gate)
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))
assert circuit.draw() == ref
assert circuit.draw(output_string=True) == ref

# Testing circuit text draw when ``output_string == False``
circuit._display()
out, _ = capsys.readouterr()
assert out == ref


def test_circuit_draw_error():
Expand All @@ -894,4 +899,4 @@ def test_circuit_draw_error():
circuit.add(error_gate)

with pytest.raises(NotImplementedError):
circuit.draw()
circuit.draw(output_string=True)
2 changes: 1 addition & 1 deletion tests/test_models_circuit_fuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,4 @@ def test_fused_gate_draw():
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))
circuit = circuit.fuse()
assert circuit.draw() == ref
assert circuit.draw(output_string=True) == ref
4 changes: 3 additions & 1 deletion tests/test_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,9 @@ def test_ibmq_noise(

noisy_circuit_target = noise_model_target.apply(circuit)

assert noisy_circuit.draw() == noisy_circuit_target.draw()
assert noisy_circuit.draw(output_string=True) == noisy_circuit_target.draw(
output_string=True
)

backend.set_seed(2024)
state = backend.execute_circuit(noisy_circuit, nshots=10)
Expand Down
Loading