pdhoolia / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
0 stars 0 forks source link

Cannot schedule circuits using AerSimulator and QasmSimulator #7

Open pdhoolia opened 3 hours ago

pdhoolia commented 3 hours ago

What is happening?

AerSimulator and QasmSimulator cannot transpile most gates (except for barrier and id) when using the parameter scheduling_method='asap'. The following error message is displayed:

qiskit.transpiler.exceptions.TranspilerError: 'Duration of x on qubits [0] is not found.'

This is because the node.op.duration for these gates is set to None, whereas barrier and id gates have a duration value of 0.

How can we reproduce the issue?

from qiskit.circuit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(1)
# qc.id(0)      # The value of node.op.duration is 0
# qc.barrier()  # The value of node.op.duration is 0
qc.x(0)         # The value of node.op.duration is None
qc.measure_all()# The value of node.op.duration is None

from qiskit_aer import AerSimulator, QasmSimulator
backend1 = AerSimulator() # Failed
# backend2 = QasmSimulator() # Failed

qc1 = transpile(qc, optimization_level=1, backend=backend1, scheduling_method='asap')

What should happen?

Assigning default values to all gates would be better.

se-agent commented 3 hours ago

The issue arises because the AerSimulator and QasmSimulator backends do not provide duration information for certain gates, leading to a TranspilerError when attempting to schedule a circuit with the scheduling_method='asap'. The InstructionDurations class is used to manage gate durations, and it requires duration information for all gates to schedule them correctly.

To address this issue, we can modify the InstructionDurations class to assign default duration values to gates that do not have specified durations. This will allow the transpiler to schedule circuits using the asap method without encountering errors. Here's a suggested approach:

  1. Modify InstructionDurations class: Update the get method to return a default duration for gates that do not have a specified duration.

  2. Add a default duration: Define a default duration value (e.g., 1 dt) for gates that do not have a specified duration.

Here's the proposed code change:

# In qiskit.transpiler.instruction_durations.py

class InstructionDurations:
    # Existing code...

    def __init__(
        self, instruction_durations: "InstructionDurationsType" | None = None, dt: float = None
    ):
        # Existing code...
        self.default_duration = 1  # Default duration in dt

    def get(
        self,
        inst: str | qiskit.circuit.Instruction,
        qubits: int | list[int],
        unit: str = "dt",
        parameters: list[float] | None = None,
    ) -> float:
        """Get the duration of the instruction with the name, qubits, and parameters.

        Some instructions may have a parameter dependent duration.

        Args:
            inst: An instruction or its name to be queried.
            qubits: Qubit indices that the instruction acts on.
            unit: The unit of duration to be returned. It must be 's' or 'dt'.
            parameters: The value of the parameters of the desired instruction.

        Returns:
            float|int: The duration of the instruction on the qubits.

        Raises:
            TranspilerError: No duration is defined for the instruction.
        """
        if isinstance(inst, Barrier):
            return 0
        elif isinstance(inst, Delay):
            return self._convert_unit(inst.duration, inst.unit, unit)

        if isinstance(inst, Instruction):
            inst_name = inst.name
        else:
            inst_name = inst

        if isinstance(qubits, int):
            qubits = [qubits]

        try:
            return self._get(inst_name, qubits, unit, parameters)
        except TranspilerError:
            # Return default duration if not found
            return self.default_duration if unit == "dt" else self._convert_unit(self.default_duration, "dt", unit)

    # Existing code...

Explanation:

This change should allow circuits to be scheduled using the asap method even if some gates do not have explicit duration values provided by the backend. Ensure that this change aligns with the design and requirements of the Qiskit project before implementing it in a production environment.

pdhoolia commented 3 hours ago

Since these are simulators and don't have a concept of gate durations, could fake backends be used to emulate a real device?

se-agent commented 3 hours ago

Yes, fake backends can be used to emulate real devices and provide gate duration information for simulators like AerSimulator and QasmSimulator. The fake backends in Qiskit are designed to mimic the behavior of real quantum devices, including gate durations, noise models, and other properties. This makes them useful for testing and development purposes.

To use fake backends for emulating real device behavior, you can follow these steps:

  1. Select a Fake Backend: Choose a fake backend that closely resembles the real device you want to emulate. Qiskit provides a variety of fake backends with different configurations and properties.

  2. Use the Fake Backend for Transpilation: Transpile your quantum circuit using the selected fake backend. This will ensure that the transpiler considers the gate durations and other properties of the fake backend during the transpilation process.

  3. Run the Transpiled Circuit on a Simulator: After transpiling the circuit with the fake backend, you can run it on a simulator like AerSimulator or QasmSimulator. The simulator will use the transpiled circuit, which includes the gate durations and other considerations from the fake backend.

Here's an example of how you can use a fake backend for this purpose:

from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeVigo  # Import a specific fake backend
from qiskit_aer import AerSimulator

# Create a quantum circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

# Select a fake backend
fake_backend = FakeVigo()

# Transpile the circuit for the fake backend
transpiled_circuit = transpile(qc, backend=fake_backend, scheduling_method='asap')

# Run the transpiled circuit on a simulator
simulator = AerSimulator()
job = simulator.run(transpiled_circuit)
result = job.result()
counts = result.get_counts()

# Print the result
print(counts)

Explanation:

By using fake backends, you can effectively emulate real device behavior for testing and development with simulators.