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 35 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
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()
renatomello marked this conversation as resolved.
Show resolved Hide resolved

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
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
54 changes: 42 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 diagram(self, line_wrap: int = 70, legend: bool = False) -> str:
renatomello marked this conversation as resolved.
Show resolved Hide resolved
# build string representation of gates
matrix = [[] for _ in range(self.nqubits)]
idx = [0] * self.nqubits
Expand Down Expand Up @@ -1369,3 +1359,43 @@ def chunkstring(string, length):
output += table

return output.rstrip("\n")

def __str__(self):
return self.diagram()

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 display of circuits is accessible as "
+ "``Circuit.display``."
)
return self.diagram(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.diagram(line_wrap, legend))
57 changes: 28 additions & 29 deletions tests/test_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import numpy as np
import pytest

from qibo import gates, models
from qibo import Circuit, gates
from qibo.measurements import MeasurementResult
from qibo.models import QFT


def assert_result(
Expand Down Expand Up @@ -62,7 +63,7 @@ def assert_register_result(
@pytest.mark.parametrize("n", [0, 1])
@pytest.mark.parametrize("nshots", [100, 1000000])
def test_measurement_gate(backend, n, nshots):
c = models.Circuit(2)
c = Circuit(2)
if n:
c.add(gates.X(1))
c.add(gates.M(1))
Expand All @@ -78,7 +79,7 @@ def test_measurement_gate(backend, n, nshots):


def test_multiple_qubit_measurement_gate(backend):
c = models.Circuit(2)
c = Circuit(2)
c.add(gates.X(0))
c.add(gates.M(0, 1))
result = backend.execute_circuit(c, nshots=100)
Expand All @@ -105,7 +106,7 @@ def test_measurement_gate_errors(backend):


def test_measurement_circuit(backend, accelerators):
c = models.Circuit(4, accelerators)
c = Circuit(4, accelerators)
c.add(gates.X(0))
c.add(gates.M(0))
result = backend.execute_circuit(c, nshots=100)
Expand All @@ -116,7 +117,7 @@ def test_measurement_circuit(backend, accelerators):

@pytest.mark.parametrize("registers", [False, True])
def test_measurement_qubit_order_simple(backend, registers):
c = models.Circuit(2)
c = Circuit(2)
c.add(gates.X(0))
if registers:
c.add(gates.M(1, 0))
Expand All @@ -134,7 +135,7 @@ def test_measurement_qubit_order_simple(backend, registers):

@pytest.mark.parametrize("nshots", [100, 1000000])
def test_measurement_qubit_order(backend, accelerators, nshots):
c = models.Circuit(6, accelerators)
c = Circuit(6, accelerators)
c.add(gates.X(0))
c.add(gates.X(1))
c.add(gates.M(1, 5, 2, 0))
Expand All @@ -154,7 +155,7 @@ def test_measurement_qubit_order(backend, accelerators, nshots):


def test_multiple_measurement_gates_circuit(backend):
c = models.Circuit(4)
c = Circuit(4)
c.add(gates.X(1))
c.add(gates.X(2))
c.add(gates.M(0, 1))
Expand All @@ -170,7 +171,7 @@ def test_multiple_measurement_gates_circuit(backend):


def test_circuit_with_unmeasured_qubits(backend, accelerators):
c = models.Circuit(5, accelerators)
c = Circuit(5, accelerators)
c.add(gates.X(4))
c.add(gates.X(2))
c.add(gates.M(0, 2))
Expand All @@ -192,11 +193,11 @@ def test_circuit_with_unmeasured_qubits(backend, accelerators):


def test_circuit_addition_with_measurements(backend):
c = models.Circuit(2)
c = Circuit(2)
c.add(gates.X(0))
c.add(gates.X(1))

meas_c = models.Circuit(2)
meas_c = Circuit(2)
c.add(gates.M(0, 1))

c += meas_c
Expand All @@ -213,12 +214,12 @@ def test_circuit_addition_with_measurements(backend):


def test_circuit_addition_with_measurements_in_both_circuits(backend, accelerators):
c1 = models.Circuit(4, accelerators)
c1 = Circuit(4, accelerators)
c1.add(gates.X(0))
c1.add(gates.X(1))
c1.add(gates.M(1, register_name="a"))

c2 = models.Circuit(4, accelerators)
c2 = Circuit(4, accelerators)
c2.add(gates.X(0))
c2.add(gates.M(0, register_name="b"))

Expand All @@ -232,7 +233,7 @@ def test_circuit_addition_with_measurements_in_both_circuits(backend, accelerato


def test_circuit_copy_with_measurements(backend, accelerators):
c1 = models.Circuit(6, accelerators)
c1 = Circuit(6, accelerators)
c1.add([gates.X(0), gates.X(1), gates.X(3)])
c1.add(gates.M(5, 1, 3, register_name="a"))
c1.add(gates.M(2, 0, register_name="b"))
Expand All @@ -250,7 +251,7 @@ def test_circuit_copy_with_measurements(backend, accelerators):


def test_measurement_compiled_circuit(backend):
c = models.Circuit(2)
c = Circuit(2)
c.add(gates.X(0))
c.add(gates.M(0))
c.add(gates.M(1))
Expand All @@ -274,14 +275,14 @@ def test_measurement_compiled_circuit(backend):

def test_final_state(backend, accelerators):
"""Check that final state is logged correctly when using measurements."""
c = models.Circuit(4, accelerators)
c = Circuit(4, accelerators)
c.add(gates.X(1))
c.add(gates.X(2))
c.add(gates.M(0, 1))
c.add(gates.M(2))
c.add(gates.X(3))
result = backend.execute_circuit(c, nshots=100)
c = models.Circuit(4, accelerators)
c = Circuit(4, accelerators)
c.add(gates.X(1))
c.add(gates.X(2))
c.add(gates.X(3))
Expand All @@ -300,7 +301,7 @@ def test_measurement_gate_bitflip_errors():


def test_register_measurements(backend):
c = models.Circuit(3)
c = Circuit(3)
c.add(gates.X(0))
c.add(gates.X(1))
c.add(gates.M(0, 2))
Expand All @@ -323,7 +324,7 @@ def test_register_measurements(backend):


def test_measurement_qubit_order_multiple_registers(backend, accelerators):
c = models.Circuit(6, accelerators)
c = Circuit(6, accelerators)
c.add(gates.X(0))
c.add(gates.X(1))
c.add(gates.X(3))
Expand Down Expand Up @@ -364,7 +365,7 @@ def test_measurement_qubit_order_multiple_registers(backend, accelerators):

def test_registers_in_circuit_with_unmeasured_qubits(backend, accelerators):
"""Check that register measurements are unaffected by unmeasured qubits."""
c = models.Circuit(5, accelerators)
c = Circuit(5, accelerators)
c.add(gates.X(1))
c.add(gates.X(2))
c.add(gates.M(0, 2, register_name="A"))
Expand All @@ -390,7 +391,7 @@ def test_registers_in_circuit_with_unmeasured_qubits(backend, accelerators):


def test_measurement_density_matrix(backend):
c = models.Circuit(2, density_matrix=True)
c = Circuit(2, density_matrix=True)
c.add(gates.X(0))
c.add(gates.M(0, 1))
result = backend.execute_circuit(c, nshots=100)
Expand All @@ -407,7 +408,7 @@ def test_measurement_density_matrix(backend):


def test_measurement_result_vs_circuit_result(backend, accelerators):
c = models.Circuit(6, accelerators)
c = Circuit(6, accelerators)
c.add([gates.X(0), gates.X(1), gates.X(3)])
ma = c.add(gates.M(5, 1, 3, register_name="a"))
mb = c.add(gates.M(2, 0, register_name="b"))
Expand All @@ -423,7 +424,7 @@ def test_measurement_result_vs_circuit_result(backend, accelerators):
@pytest.mark.parametrize("nqubits", [1, 4])
@pytest.mark.parametrize("outcome", [0, 1])
def test_measurement_basis(backend, nqubits, outcome):
c = models.Circuit(nqubits)
c = Circuit(nqubits)
if outcome:
c.add(gates.X(q) for q in range(nqubits))
c.add(gates.H(q) for q in range(nqubits))
Expand All @@ -433,7 +434,7 @@ def test_measurement_basis(backend, nqubits, outcome):


def test_measurement_basis_list(backend):
c = models.Circuit(4)
c = Circuit(4)
c.add(gates.H(0))
c.add(gates.X(2))
c.add(gates.H(2))
Expand All @@ -450,22 +451,20 @@ def test_measurement_basis_list(backend):
)


def test_measurement_basis_list_error(backend):
c = models.Circuit(4)
def test_measurement_basis_list_error():
c = Circuit(4)
with pytest.raises(ValueError):
c.add(gates.M(0, 1, 2, 3, basis=[gates.X, gates.Z, gates.X]))


def test_measurement_same_qubit_different_registers_error(backend):
c = models.Circuit(4)
def test_measurement_same_qubit_different_registers_error():
c = Circuit(4)
c.add(gates.M(0, 1, 3, register_name="a"))
with pytest.raises(KeyError):
c.add(gates.M(1, 2, 3, register_name="a"))


def test_measurementsymbol_pickling(backend):
from qibo.models import QFT

c = QFT(3)
c.add(gates.M(0, 2, basis=[gates.X, gates.Z]))
backend.execute_circuit(c).samples()
Expand Down
Loading
Loading