跳转至

DensityMatrixSimulator

QuICT.simulation.density_matrix.DensityMatrixSimulator

DensityMatrixSimulator(device: str = 'CPU', precision: str = 'double', accumulated_mode: bool = False, hidden_empty_qubits: bool = False, ignore_last_measure: bool = True)

The Density Matrix Simulator

Parameters:

  • device (str, default: 'CPU' ) –

    The device type, one of [CPU, GPU]. Defaults to "CPU".

  • precision (str, default: 'double' ) –

    The precision, one of [single, double]. Defaults to "double".

  • accumulated_mode (bool, default: False ) –

    If True, calculated density matrix with Kraus Operators in NoiseGate. if True, p = \sum Ki p Ki^T.conj(). Default to be False.

  • hidden_empty_qubits (bool, default: False ) –

    Whether ignore the empty qubits or not, default to False.

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def __init__(
    self,
    device: str = "CPU",
    precision: str = "double",
    accumulated_mode: bool = False,
    hidden_empty_qubits: bool = False,
    ignore_last_measure: bool = True,
):
    """
    Args:
        device (str, optional): The device type, one of [CPU, GPU]. Defaults to "CPU".
        precision (str, optional): The precision, one of [single, double]. Defaults to "double".
        accumulated_mode (bool): If True, calculated density matrix with Kraus Operators in NoiseGate.
            if True, p = \\sum Ki p Ki^T.conj(). Default to be False.
        hidden_empty_qubits (bool, optional): Whether ignore the empty qubits or not, default to False.
    """
    self._device = device
    self._precision = precision
    self._gate_calculator = GateSimulator(device, precision, enable_gfunc=True)
    self._circuit_matrix_helper = CircuitMatrix(device, precision)
    self._accumulated_mode = accumulated_mode
    self._density_matrix = None
    self._quantum_machine = None
    self._hidden_empty_qubits = hidden_empty_qubits
    self._ignore_last_measure = ignore_last_measure

apply_gates

apply_gates(combined_gates: list)

Simulating Circuit with BasicGates

\[ D = M*D*M^\dagger \]

where M is the unitary matrix of given quantum gates.

Parameters:

  • combined_gates (list) –

    The list of quantum gates.

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def apply_gates(self, combined_gates: list):
    r""" Simulating Circuit with BasicGates

    $$ D = M*D*M^\dagger $$

    where M is the unitary matrix of given quantum gates.

    Args:
        combined_gates (list): The list of quantum gates.
    """
    if len(combined_gates) == 0:
        return

    cir_matrix = self._circuit_matrix_helper.get_unitary_matrix(combined_gates, self._qubits)
    self._density_matrix = self._gate_calculator.dot(
        self._gate_calculator.dot(cir_matrix, self._density_matrix),
        cir_matrix.conj().T
    )

apply_kraus

apply_kraus(kraus: BasicGate)

Applying the damping noise's Kraus Matrix.

Parameters:

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def apply_kraus(self, kraus: BasicGate):
    """ Applying the damping noise's Kraus Matrix.

    Args:
        kraus (BasicGate): The Kraus Gate.
    """
    gate_args = kraus.targs
    noised_matrix = self._gate_calculator.get_empty_density_matrix(self._qubits)
    kraus_matrix = kraus.matrix
    umat = matrix_product_to_circuit(kraus_matrix, gate_args, self._qubits, self._device)

    noised_matrix += self._gate_calculator.dot(
        self._gate_calculator.dot(umat, self._density_matrix),
        umat.conj().T
    )

    self._density_matrix = noised_matrix

apply_measure

apply_measure(index: int)

Simulating the MeasureGate.

Parameters:

  • index (int) –

    The index of measured qubit.

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def apply_measure(self, index: int):
    """ Simulating the MeasureGate.

    Args:
        index (int): The index of measured qubit.
    """
    _1, self._density_matrix = self._gate_calculator.apply_measure_gate_for_dm(
        index, self._density_matrix, self._qubits
    )
    if self._quantum_machine is not None:
        _1 = self._quantum_machine.apply_readout_error(index, int(_1))

    self._origin_circuit.qubits[index].measured = _1

apply_noise

apply_noise(noise_gate: NoiseGate)

Simulating NoiseGate.

\[ D = \sum_{i \in Kraus} K_i*D*K_i^\dagger \]

Where Kraus is the group of Kraus Matrix from the Noise Gate.

Parameters:

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def apply_noise(self, noise_gate: NoiseGate):
    """ Simulating NoiseGate.

    $$ D = \sum_{i \in Kraus} K_i*D*K_i^\dagger $$

    Where Kraus is the group of Kraus Matrix from the Noise Gate.

    Args:
        noise_gate (NoiseGate): The NoiseGate
    """
    gate_args = noise_gate.targs
    noised_matrix = self._gate_calculator.get_empty_density_matrix(self._qubits)
    for kraus_matrix in noise_gate.noise_matrix:
        umat = matrix_product_to_circuit(kraus_matrix, gate_args, self._qubits, self._device)
        noised_matrix += self._gate_calculator.dot(
            self._gate_calculator.dot(umat, self._density_matrix),
            umat.conj().T
        )

    self._density_matrix = noised_matrix.copy()

initial_circuit

initial_circuit(circuit: Circuit)

Initial the qubits, quantum gates and state vector by given quantum circuit.

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def initial_circuit(self, circuit: Circuit):
    """ Initial the qubits, quantum gates and state vector by given quantum circuit. """
    self._origin_circuit = circuit
    self._circuit = circuit if self._quantum_machine is None else self._quantum_machine.transpile(
        circuit, self._accumulated_mode
    )
    self._qubits = int(circuit.width())
    self._used_qubits = self._circuit._gates.qubits
    if self._hidden_empty_qubits and self._qubits != len(self._used_qubits):
        self._qubits = len(self._circuit._gates.qubits)
        self._circuit = self._circuit.to_compositegate() & list(range(self._qubits))

run

run(circuit: Circuit, quantum_state: ndarray = None, quantum_machine_model: Union[NoiseModel, VirtualQuantumMachine] = None, use_previous: bool = False) -> np.ndarray

Simulating the given circuit through density matrix simulator.

Parameters:

  • circuit (Circuit) –

    The quantum circuit.

  • density_matrix (ndarray) –

    The initial density matrix.

  • quantum_machine_model (NoiseModel, default: None ) –

    The NoiseModel contains NoiseErrors. Defaults to None.

  • use_previous (bool, default: False ) –

    Using the previous state vector. Defaults to False.

Returns:

  • ndarray

    np.ndarray: the density matrix after simulating

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def run(
    self,
    circuit: Circuit,
    quantum_state: np.ndarray = None,
    quantum_machine_model: Union[NoiseModel, VirtualQuantumMachine] = None,
    use_previous: bool = False
) -> np.ndarray:
    """ Simulating the given circuit through density matrix simulator.

    Args:
        circuit (Circuit): The quantum circuit.
        density_matrix (np.ndarray): The initial density matrix.
        quantum_machine_model (NoiseModel, optional): The NoiseModel contains NoiseErrors. Defaults to None.
        use_previous (bool, optional): Using the previous state vector. Defaults to False.

    Returns:
        np.ndarray: the density matrix after simulating
    """
    # Deal with the Physical Machine Model
    self._quantum_machine = None
    if quantum_machine_model is not None:
        noise_model = quantum_machine_model if isinstance(quantum_machine_model, NoiseModel) else \
            NoiseModel(quantum_machine_info=quantum_machine_model)
        if not noise_model.is_ideal_model():
            self._quantum_machine = noise_model

    # Initial Quantum Circuit
    self.initial_circuit(circuit)

    # Initial Density Matrix
    if quantum_state is not None:
        self._gate_calculator.validate_density_matrix(quantum_state)
        self._density_matrix = self._gate_calculator.normalized_matrix(quantum_state.copy(), self._qubits)
    elif (self._density_matrix is None or not use_previous):
        if not (quantum_machine_model is None or noise_model.is_ideal_model()):
            self._density_matrix = self._gate_calculator.get_allzero_density_matrix(self._qubits)

    if quantum_machine_model is None or noise_model.is_ideal_model():
        self._run_like_sv(self._circuit)
    else:
        self._run(self._circuit)

    return self._density_matrix

sample

sample(shots: int = 1, target_qubits: list = None, extra_output: bool = False, seed: int = -1) -> dict

Sample the current circuit and return the sample result of measured, please call simulator.run() before.

Parameters:

  • shots (int, default: 1 ) –

    The sample times.

  • target_qubits (list, default: None ) –

    The List of target sample qubits.

  • extra_output (bool, default: False ) –

    Output with extra info: measured qubits (list), and samples (list)

Returns:

  • list ( dict ) –

    The list of counts of measured result.

Source code in QuICT/simulation/density_matrix/density_matrix_simulator.py
def sample(
    self,
    shots: int = 1,
    target_qubits: list = None,
    extra_output: bool = False,
    seed: int = -1
) -> dict:
    """ Sample the current circuit and return the sample result of measured, please call simulator.run() before.

    Args:
        shots (int): The sample times.
        target_qubits (list): The List of target sample qubits.
        extra_output (bool): Output with extra info: measured qubits (list), and samples (list)

    Returns:
        list: The list of counts of measured result.
    """
    assert (self._density_matrix is not None), \
        SampleBeforeRunError("DensityMatrixSimulator sample without run any circuit.")
    if self._quantum_machine is None:
        return self._sample_with_pure_state(shots, target_qubits, extra_output, seed=seed)

    if self._accumulated_mode:
        original_dm = self._density_matrix.copy()

    sample_qubits = self._regularized_target_qubits(target_qubits)
    if sample_qubits is None:
        sample_qubits = list(range(self._qubits))

    state_dict, sample_result = defaultdict(int), []
    for _ in range(shots):
        final_state = 0
        for m_id in sample_qubits:
            measured, self._density_matrix = self._gate_calculator.apply_measure_gate_for_dm(
                m_id, self._density_matrix, self._qubits, seed=seed
            )
            final_state <<= 1
            final_state += int(measured)

        final_state = self._quantum_machine.apply_readout_error(sample_qubits, final_state)

        sample_result.append(final_state)
        state_dict[final_state] += 1
        if self._accumulated_mode:
            self._density_matrix = original_dm.copy()
        else:
            self._density_matrix = self._gate_calculator.get_allzero_density_matrix(self._qubits)
            noised_circuit = self._quantum_machine.transpile(self._origin_circuit, self._accumulated_mode) \
                if self._quantum_machine is not None else self._circuit

            self._run(noised_circuit)

    if not extra_output:
        return state_dict
    else:
        normalize_res, normalize_qorder, normalize_sample = self._sample_normalize(
            state_dict, sample_result, sample_qubits
        )

        return normalize_res, normalize_qorder, normalize_sample