Skip to content

Commit

Permalink
wires names
Browse files Browse the repository at this point in the history
  • Loading branch information
Simone-Bordoni committed Dec 12, 2023
1 parent 5e04eff commit 8a1b964
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 7 deletions.
51 changes: 44 additions & 7 deletions src/qibo/models/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class Circuit:
- *nqubits*
- *accelerators*
- *density_matrix*.
- *density_matrix*
- *wires_names*.
queue (_Queue): List that holds the queue of gates of a circuit.
parametrized_gates (_ParametrizedGates): List of parametric gates.
Expand All @@ -133,14 +134,22 @@ class Circuit:
Defaults to ``False``.
accelerators (dict): Dictionary that maps device names to the number of times each
device will be used. Defaults to ``None``.
wires_names (list or dict): Names for each qubit,
if None the default names ``q0``, ``q1``... ``qn`` will be used.
ndevices (int): Total number of devices. Defaults to ``None``.
nglobal (int): Base two logarithm of the number of devices. Defaults to ``None``.
nlocal (int): Total number of available qubits in each device. Defaults to ``None``.
queues (DistributedQueues): Gate queues for each accelerator device.
Defaults to ``None``.
"""

def __init__(self, nqubits, accelerators=None, density_matrix=False):
def __init__(
self,
nqubits: int,
accelerators=None,
density_matrix: bool = False,
wires_names: Union[list, dict] = None,
):
if not isinstance(nqubits, int):
raise_error(
TypeError,
Expand All @@ -152,10 +161,12 @@ def __init__(self, nqubits, accelerators=None, density_matrix=False):
f"Number of qubits must be positive but is {nqubits}.",
)
self.nqubits = nqubits
self.wires_names = wires_names
self.init_kwargs = {
"nqubits": nqubits,
"accelerators": accelerators,
"density_matrix": density_matrix,
"wires_names": wires_names,
}
self.queue = _Queue(nqubits)
# Keep track of parametrized gates for the ``set_parameters`` method
Expand Down Expand Up @@ -259,6 +270,31 @@ def __add__(self, circuit):

return newcircuit

@property
def wires_names(self):
return self._wires_names

@wires_names.setter
def wires_names(self, wires_names: Union[list, dict]):
if isinstance(wires_names, list):
if len(wires_names) != self.nqubits:
raise_error(

Check warning on line 281 in src/qibo/models/circuit.py

View check run for this annotation

Codecov / codecov/patch

src/qibo/models/circuit.py#L280-L281

Added lines #L280 - L281 were not covered by tests
ValueError,
f"Number of wires names must be equal to the number of qubits but is {len(wires_names)}.",
)
self._wires_names = wires_names

Check warning on line 285 in src/qibo/models/circuit.py

View check run for this annotation

Codecov / codecov/patch

src/qibo/models/circuit.py#L285

Added line #L285 was not covered by tests
elif isinstance(wires_names, dict):
self._wires_names = [
wires_names.get(f"q{i}", f"q{i}") for i in range(self.nqubits)
]
elif isinstance(wires_names, type(None)):
self._wires_names = [f"q{i}" for i in range(self.nqubits)]
else:
raise_error(
TypeError,
f"Wire names must be a list or dict but is {type(wires_names)}.",
)

@property
def repeated_execution(self):
return self.has_collapse or (
Expand Down Expand Up @@ -1416,11 +1452,12 @@ def draw(self, line_wrap=70, legend=False) -> str:
matrix[row][col] += "─" * (1 + maxlen - len(matrix[row][col]))

# Print to terminal
max_name_len = max(len(name) for name in self.wires_names)
output = ""
for q in range(self.nqubits):
output += (
f"q{q}"
+ " " * (len(str(self.nqubits)) - len(str(q)))
self.wires_names[q]
+ " " * (max_name_len - len(self.wires_names[q]))
+ ": ─"
+ "".join(matrix[q])
+ "\n"
Expand Down Expand Up @@ -1453,7 +1490,7 @@ def chunkstring(string, length):

for row in range(self.nqubits):
chunks, nchunks = chunkstring(
loutput[row][3 + len(str(self.nqubits)) :], line_wrap
loutput[row][3 + max_name_len - 1 :], line_wrap
)
if nchunks == 1:
loutput = None
Expand All @@ -1462,8 +1499,8 @@ def chunkstring(string, length):
loutput += ["" for _ in range(self.nqubits)]
suffix = " ...\n"
prefix = (
f"q{row}"
+ " " * (len(str(self.nqubits)) - len(str(row)))
self.wires_names[row]
+ " " * (max_name_len - len(self.wires_names[row]))
+ ": "
)
if i == 0:
Expand Down
81 changes: 81 additions & 0 deletions tests/test_models_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,30 @@ def test_circuit_draw():
assert circuit.draw() == ref


def test_circuit_wires_names_error():
with pytest.raises(TypeError):
circuit = Circuit(5, wires_names=1)


def test_circuit_draw_names():
"""Test circuit text draw."""
ref = (
"a : ─H─U1─U1─U1─U1───────────────────────────x───\n"
"b : ───o──|──|──|──H─U1─U1─U1────────────────|─x─\n"
"hello: ──────o──|──|────o──|──|──H─U1─U1────────|─|─\n"
"1 : ─────────o──|───────o──|────o──|──H─U1───|─x─\n"
"q4 : ────────────o──────────o───────o────o──H─x───"
)
circuit = Circuit(5, wires_names=["a", "b", "hello", "1", "q4"])
for i1 in range(5):
circuit.add(gates.H(i1))
for i2 in range(i1 + 1, 5):
circuit.add(gates.CU1(i2, i1, theta=0))
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))
assert circuit.draw() == ref


def test_circuit_draw_line_wrap():
"""Test circuit text draw with line wrap."""
ref_line_wrap_50 = (
Expand Down Expand Up @@ -684,6 +708,63 @@ def test_circuit_draw_line_wrap():
assert circuit.draw(line_wrap=30) == ref_line_wrap_30


def test_circuit_draw_line_wrap_names():
"""Test circuit text draw with line wrap."""
ref_line_wrap_50 = (
"q0: ─H─U1─U1─U1─U1───────────────────────────x───I───f ...\n"
"a : ───o──|──|──|──H─U1─U1─U1────────────────|─x─I───| ...\n"
"q2: ──────o──|──|────o──|──|──H─U1─U1────────|─|─────| ...\n"
"q3: ─────────o──|───────o──|────o──|──H─U1───|─x───M─| ...\n"
"q4: ────────────o──────────o───────o────o──H─x───────f ...\n"
"\n"
"q0: ... ─o────gf───M─\n"
"a : ... ─U3───|──o─M─\n"
"q2: ... ────X─gf─o─M─\n"
"q3: ... ────o────o───\n"
"q4: ... ────o────X───"
)

ref_line_wrap_30 = (
"q0: ─H─U1─U1─U1─U1──────────────── ...\n"
"a : ───o──|──|──|──H─U1─U1─U1───── ...\n"
"q2: ──────o──|──|────o──|──|──H─U1 ...\n"
"q3: ─────────o──|───────o──|────o─ ...\n"
"q4: ────────────o──────────o────── ...\n"
"\n"
"q0: ... ───────────x───I───f─o────gf── ...\n"
"a : ... ───────────|─x─I───|─U3───|──o ...\n"
"q2: ... ─U1────────|─|─────|────X─gf─o ...\n"
"q3: ... ─|──H─U1───|─x───M─|────o────o ...\n"
"q4: ... ─o────o──H─x───────f────o────X ...\n"
"\n"
"q0: ... ─M─\n"
"a : ... ─M─\n"
"q2: ... ─M─\n"
"q3: ... ───\n"
"q4: ... ───"
)

import numpy as np

circuit = Circuit(5, wires_names={"q1": "a"})
for i1 in range(5):
circuit.add(gates.H(i1))
for i2 in range(i1 + 1, 5):
circuit.add(gates.CU1(i2, i1, theta=0))
circuit.add(gates.SWAP(0, 4))
circuit.add(gates.SWAP(1, 3))
circuit.add(gates.I(*range(2)))
circuit.add(gates.M(3, collapse=True))
circuit.add(gates.fSim(0, 4, 0, 0))
circuit.add(gates.CU3(0, 1, 0, 0, 0))
circuit.add(gates.TOFFOLI(4, 3, 2))
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


@pytest.mark.parametrize("legend", [True, False])
def test_circuit_draw_channels(legend):
"""Check that channels are drawn correctly."""
Expand Down

0 comments on commit 8a1b964

Please sign in to comment.