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

Fix to classical registers in to_qasm #1284

Merged
merged 5 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 22 additions & 8 deletions src/qibo/models/_openqasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,7 @@ def to_circuit(
density_matrix,
wire_names=self._construct_wire_names(),
)
for gate in gates:
circ.add(gate)
self._reorder_registers(circ.measurements)
circ.add(self._merge_measurements(gates))
return circ

def _get_measurement(self, measurement):
Expand Down Expand Up @@ -267,11 +265,27 @@ def _def_gate(self, definition):
gates = [self._get_gate(gate) for gate in definition.body]
self.defined_gates.update({name: CustomQASMGate(name, gates, qubits, args)})

def _reorder_registers(self, measurements):
"""Reorders the registers of the provided :class:`qibo.gates.measurements.M`
gates according to the classical registers order defined in the QASM program."""
for meas in measurements:
meas.target_qubits = [self.c_registers[meas.register_name].pop(0)]
def _merge_measurements(self, gates):
"""Merges separated measurements of a same register into a single one.
This is needed because qibo doesn't allow to separetely define two measurements in a same register:

# not allowed
c.add(gates.M(0, register="m0"))
c.add(gates.M(1, register="m0"))
"""
updated_queue = []
for gate in gates:
if isinstance(gate, qibo.gates.M):
if gate.register_name in self.c_registers:
updated_queue.append(
qibo.gates.M(
*self.c_registers.pop(gate.register_name),
register_name=gate.register_name,
)
)
else:
updated_queue.append(gate)
return updated_queue

def _construct_wire_names(self):
"""Builds the wires names from the declared quantum registers."""
Expand Down
27 changes: 11 additions & 16 deletions src/qibo/models/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,13 +667,11 @@ def add(self, gate):
nreg = self.queue.nmeasurements - 1
gate.register_name = f"register{nreg}"
else:
registers = self.measurement_tuples
for register, qubits in registers.items():
intersection = set(qubits).intersection(set(gate.target_qubits))
if len(intersection) > 0:
name = gate.register_name
for mgate in self.measurements:
if name == mgate.register_name:
raise_error(
KeyError,
f"Qubits {tuple(intersection)} already measured in register `{register}`.",
KeyError, f"Register {name} already exists in circuit."
)

gate.result.circuit = self
Expand Down Expand Up @@ -1156,16 +1154,14 @@ def to_qasm(self):
code += [f"qreg q[{self.nqubits}];"]

# Set measurements
for measurement in self.measurements:
reg_name = measurement.register_name
reg_qubits = measurement.target_qubits
if not reg_name.islower():
for register, qubits in self.measurement_tuples.items():
if not register.islower():
raise_error(
NameError,
"OpenQASM does not support capital letters in "
+ f"register names but {reg_name} was used",
+ f"register names but {register} was used",
)
code.append(f"creg {reg_name}[{len(reg_qubits)}];")
code.append(f"creg {register}[{len(qubits)}];")

# Add gates
for gate in self.queue:
Expand All @@ -1186,10 +1182,9 @@ def to_qasm(self):
code.append(f"{name} {qubits};")

# Add measurements
for measurement in self.measurements:
reg_name = measurement.register_name
for i, q in enumerate(measurement.target_qubits):
code.append(f"measure q[{q}] -> {reg_name}[{i}];")
for register, qubits in self.measurement_tuples.items():
for i, q in enumerate(qubits):
code.append(f"measure q[{q}] -> {register}[{i}];")

return "\n".join(code)

Expand Down
11 changes: 9 additions & 2 deletions tests/test_models_circuit_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,18 @@ def test_crotations():
target = c.to_qasm()


def test_measurements():
@pytest.mark.parametrize(
"measurements",
[
[gates.M(0, 1)],
],
)
def test_measurements(measurements):
c = Circuit(2)
c.add(gates.X(0))
c.add(gates.Y(1))
c.add(gates.M(0, 1))
for m in measurements:
c.add(m)
target = f"""// Generated by QIBO {__version__}
OPENQASM 2.0;
include "qelib1.inc";
Expand Down
Loading