Skip to content

Commit

Permalink
feature: support non-contiguous qubit indices local simulator
Browse files Browse the repository at this point in the history
  • Loading branch information
WingCode committed Jun 12, 2024
1 parent a4d7f98 commit f56e466
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/braket/default_simulator/density_matrix_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def properties(self) -> GateModelSimulatorDeviceCapabilities:
],
"supportPhysicalQubits": False,
"supportsPartialVerbatimBox": False,
"requiresContiguousQubitIndices": True,
"requiresContiguousQubitIndices": False,
"requiresAllQubitsMeasurement": False,
"supportsUnassignedMeasurements": True,
"disabledQubitRewiringSupported": False,
Expand Down
45 changes: 44 additions & 1 deletion src/braket/default_simulator/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
import warnings
from abc import ABC, abstractmethod
from collections.abc import Callable
from copy import deepcopy
from typing import Any, Union

import numpy as np
from braket.device_schema import DeviceActionType
from braket.ir.jaqcd import Program as JaqcdProgram
from braket.ir.jaqcd.program_v1 import Results
from braket.ir.jaqcd.shared_models import MultiTarget, OptionalMultiTarget
from braket.ir.openqasm import Program as OpenQASMProgram
from braket.task_result import (
AdditionalMetadata,
Expand Down Expand Up @@ -386,6 +388,38 @@ def _observable_hash(observable: Observable) -> Union[str, dict[int, str]]:
else:
return str(observable.__class__.__name__)

def _map_circuit_to_contiguous_qubits(self, circuit: Circuit) -> Circuit:
"""
Maps the qubits in operations and result types to contiguous qubits.
Args:
circuit (Circuit): The circuit containing the operations and result types.
Returns:
Circuit: The circuit with qubits in operations and result types mapped to contiguous qubits.
"""
qubit_map = self._contiguous_qubit_mapping(circuit.qubit_set)

new_instructions = []
for ins in circuit.instructions:
new_ins = deepcopy(ins)
new_ins._targets = tuple([qubit_map[q] for q in ins.targets])
new_instructions.append(new_ins)

new_results = []
for result in circuit.results:
new_result = deepcopy(result)
if isinstance(new_result, (MultiTarget, OptionalMultiTarget)):
new_result.targets = [qubit_map[q] for q in result.targets]
new_results.append(new_result)

new_circuit = Circuit(new_instructions, new_results)
return new_circuit

@staticmethod
def _contiguous_qubit_mapping(qubit_set: list[int]) -> dict[int, int]:
return {q: i for i, q in enumerate(sorted(qubit_set))}

@staticmethod
def _formatted_measurements(
simulation: Simulation, measured_qubits: Union[list[int], None] = None
Expand All @@ -407,7 +441,12 @@ def _formatted_measurements(
]
# Gets the subset of measurements from the full measurements
if measured_qubits is not None and measured_qubits != []:
if any(qubit in range(simulation.qubit_count) for qubit in measured_qubits):
if max(measured_qubits) != len(measured_qubits) - 1:
qubit_map = BaseLocalSimulator._contiguous_qubit_mapping(measured_qubits)
mapped_measured_qubits = [qubit_map[q] for q in measured_qubits]
measurements = np.array(measurements)[:, mapped_measured_qubits].tolist()

elif any(qubit in range(simulation.qubit_count) for qubit in measured_qubits):
measured_qubits = np.array(measured_qubits)
in_circuit_mask = measured_qubits < simulation.qubit_count
measured_qubits_in_circuit = measured_qubits[in_circuit_mask]
Expand Down Expand Up @@ -465,6 +504,10 @@ def run_openqasm(
self._validate_input_provided(circuit)
BaseLocalSimulator._validate_shots_and_ir_results(shots, circuit.results, qubit_count)

circuit_qubit_set = circuit.qubit_set
if circuit_qubit_set and max(circuit_qubit_set) != len(circuit_qubit_set) - 1:
circuit = self._map_circuit_to_contiguous_qubits(circuit)

operations = circuit.instructions
BaseLocalSimulator._validate_operation_qubits(operations)

Expand Down
2 changes: 1 addition & 1 deletion src/braket/default_simulator/state_vector_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def properties(self) -> GateModelSimulatorDeviceCapabilities:
],
"supportPhysicalQubits": False,
"supportsPartialVerbatimBox": False,
"requiresContiguousQubitIndices": True,
"requiresContiguousQubitIndices": False,
"requiresAllQubitsMeasurement": False,
"supportsUnassignedMeasurements": True,
"disabledQubitRewiringSupported": False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def test_properties():
],
"supportPhysicalQubits": False,
"supportsPartialVerbatimBox": False,
"requiresContiguousQubitIndices": True,
"requiresContiguousQubitIndices": False,
"requiresAllQubitsMeasurement": False,
"supportsUnassignedMeasurements": True,
"disabledQubitRewiringSupported": False,
Expand Down
10 changes: 10 additions & 0 deletions test/unit_tests/braket/default_simulator/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import numpy as np
import pytest
from braket.circuits import Circuit
from braket.devices import LocalSimulator

from braket.default_simulator import observables
from braket.default_simulator.result_types import DensityMatrix, Expectation, Probability, Variance
Expand Down Expand Up @@ -64,3 +66,11 @@ def test_base_local_simulator_abstract():
)
with pytest.raises(TypeError, match=abstract_methods):
BaseLocalSimulator()


def test_discontinous_qubits_local_simulator():
circuit = Circuit().x(2).cnot(2, 9)
result = LocalSimulator().run(circuit, shots=1).result()

assert result.measured_qubits == [2, 9]
assert result.measurement_probabilities == {"11": 1.0}
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def test_properties():
],
"supportPhysicalQubits": False,
"supportsPartialVerbatimBox": False,
"requiresContiguousQubitIndices": True,
"requiresContiguousQubitIndices": False,
"requiresAllQubitsMeasurement": False,
"supportsUnassignedMeasurements": True,
"disabledQubitRewiringSupported": False,
Expand Down

0 comments on commit f56e466

Please sign in to comment.