Skip to content

Commit

Permalink
Merge branch '0.1' into 1q_emulator_upgrades 09012025
Browse files Browse the repository at this point in the history
  • Loading branch information
jykhoo1987 committed Jan 12, 2025
2 parents d851472 + bfb48cc commit dffacf0
Show file tree
Hide file tree
Showing 34 changed files with 907 additions and 293 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repos:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/PyCQA/docformatter
rev: v1.7.5
rev: master
hooks:
- id: docformatter
additional_dependencies: [tomli]
Expand Down
4 changes: 2 additions & 2 deletions crate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use numpy::PyArray2;
use pyo3::prelude::*;
use pyo3::types::PyDict;

pub fn execute_qasm(circuit: String, platform: String, nshots: u32) -> PyResult<Array2<i32>> {
pub fn execute_qasm(circuit: String, platform: String, nshots: u32) -> PyResult<Array2<u32>> {
Python::with_gil(|py| {
let kwargs = PyDict::new(py);
kwargs.set_item("circuit", circuit)?;
kwargs.set_item("platform", platform)?;
kwargs.set_item("nshots", nshots)?;

let qibolab = PyModule::import(py, "qibolab")?;
let pyarray: &PyArray2<i32> = qibolab
let pyarray: &PyArray2<u32> = qibolab
.getattr("execute_qasm")?
.call((), Some(kwargs))?
.call_method0("samples")?
Expand Down
5 changes: 2 additions & 3 deletions doc/source/tutorials/compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,10 @@ The following example shows how to modify the compiler in order to execute a cir


# define a compiler rule that translates X to the pi-pulse
def x_rule(gate, platform):
def x_rule(qubits_ids, platform, parameters=None):
"""X gate applied with a single pi-pulse."""
qubit = gate.target_qubits[0]
sequence = PulseSequence()
sequence.add(platform.create_RX_pulse(qubit, start=0))
sequence.add(platform.create_RX_pulse(qubits_ids[1][0], start=0))
return sequence, {}


Expand Down
101 changes: 39 additions & 62 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "qibolab"
version = "0.1.10"
version = "0.1.11"
description = "Quantum hardware module and drivers for Qibo"
authors = ["The Qibo team"]
license = "Apache License 2.0"
Expand All @@ -30,7 +30,7 @@ qblox-instruments = { version = "0.12.0", optional = true }
qcodes = { version = "^0.37.0", optional = true }
qcodes_contrib_drivers = { version = "0.18.0", optional = true }
pyvisa-py = { version = "0.5.3", optional = true }
qm-qua = { version = "==1.1.6", optional = true }
qm-qua = { version = "==1.2.1", optional = true }
qualang-tools = { version = "^0.15.0", optional = true }
setuptools = { version = ">67.0.0", optional = true }
laboneq = { version = "==2.25.0", optional = true }
Expand Down
39 changes: 39 additions & 0 deletions src/qibolab/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from qibolab.execution_parameters import ExecutionParameters
from qibolab.platform import Platform, create_platform
from qibolab.platform.load import available_platforms
from qibolab.qubits import QubitId, QubitPairId
from qibolab.version import __version__ as qibolab_version


Expand Down Expand Up @@ -50,6 +51,33 @@ def __init__(self, platform):
}
self.compiler = Compiler.default()

@property
def qubits(self) -> list[QubitId]:
"""Returns the qubits in the platform."""
return list(self.platform.qubits)

@property
def connectivity(self) -> list[QubitPairId]:
"""Returns the list of connected qubits."""
return list(self.platform.pairs)

@property
def natives(self) -> list[str]:
"""Returns the list of native gates supported by the platform."""
compiler = Compiler.default()
natives = [g.__name__ for g in list(compiler.rules)]
calibrated = self.platform.pairs

check_2q = ["CZ", "CNOT"]
for gate in check_2q:
if gate in natives and all(
getattr(calibrated[p].native_gates, gate) is None
for p in self.connectivity
):
natives.remove(gate)

return natives

def apply_gate(self, gate, state, nqubits): # pragma: no cover
raise_error(NotImplementedError, "Qibolab cannot apply gates directly.")

Expand Down Expand Up @@ -97,6 +125,11 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000):
"Hardware backend only supports circuits as initial states.",
)

# This should be done in qibo side
# Temporary fix: overwrite the wire names
if not all(q in self.qubits for q in circuit.wire_names):
circuit._wire_names = self.qubits[: circuit.nqubits]

sequence, measurement_map = self.compiler.compile(circuit, self.platform)

if not self.platform.is_connected:
Expand Down Expand Up @@ -139,6 +172,12 @@ def execute_circuits(self, circuits, initial_states=None, nshots=1000):
"Hardware backend only supports circuits as initial states.",
)

# This should be done in qibo side
# Temporary fix: overwrite the wire names
for circuit in circuits:
if not all(q in self.qubits for q in circuit.wire_names):
circuit._wire_names = self.qubits[: circuit.nqubits]

# TODO: Maybe these loops can be parallelized
sequences, measurement_maps = zip(
*(self.compiler.compile(circuit, self.platform) for circuit in circuits)
Expand Down
28 changes: 23 additions & 5 deletions src/qibolab/compilers/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
u3_rule,
z_rule,
)
from qibolab.pulses import PulseSequence, ReadoutPulse
from qibolab.pulses import DrivePulse, PulseSequence


@dataclass
Expand Down Expand Up @@ -99,12 +99,24 @@ def inner(func):
return inner

def _compile_gate(
self, gate, platform, sequence, virtual_z_phases, moment_start, delays
self,
gate,
platform,
sequence,
virtual_z_phases,
moment_start,
delays,
wire_names,
):
"""Adds a single gate to the pulse sequence."""
rule = self[gate.__class__]

# get local sequence and phases for the current gate
gate_sequence, gate_phases = rule(gate, platform)
qubits_ids = (
[wire_names[qubit] for qubit in gate.control_qubits],
[wire_names[qubit] for qubit in gate.target_qubits],
)
gate_sequence, gate_phases = rule(qubits_ids, platform, gate.parameters)

# update global pulse sequence
# determine the right start time based on the availability of the qubits involved
Expand All @@ -119,7 +131,7 @@ def _compile_gate(
# shift start time and phase according to the global sequence
for pulse in gate_sequence:
pulse.start += start
if not isinstance(pulse, ReadoutPulse):
if isinstance(pulse, DrivePulse):
pulse.relative_phase += virtual_z_phases[pulse.qubit]
sequence.add(pulse)

Expand Down Expand Up @@ -154,7 +166,13 @@ def compile(self, circuit, platform):
delays[qubit] += gate.delay
continue
gate_sequence, gate_phases = self._compile_gate(
gate, platform, sequence, virtual_z_phases, moment_start, delays
gate,
platform,
sequence,
virtual_z_phases,
moment_start,
delays,
circuit.wire_names,
)
for qubit in gate.qubits:
delays[qubit] = 0
Expand Down
Loading

0 comments on commit dffacf0

Please sign in to comment.