跳转至

mps_site

QuICT.simulation.matrix_product_state.mps_site

MPSSiteStructure

MPSSiteStructure(device: str = 'CPU', precision: str = 'double')

The Structure of Matrix Product State.

Q0 -- O -- Q1 -- O -- ... -- O -- Qn-1 -- O -- Qn | | | | U U ... ---- U ---- | | | | Q0-- O -- Q1-- O -- ... -- O -- Qn-1-- O -- Qn`

Initial the MPSSiteStructure Class

Parameters:

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

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

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

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

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def __init__(
    self,
    device: str = "CPU",
    precision: str = "double"
):
    """ Initial the MPSSiteStructure Class

    Args:
        device (str, optional): The device type, one of [CPU, GPU]. Defaults to "CPU".
        precision (str, optional): The precision type, one of [single, double]. Defaults to "double".
    """
    # based properties
    assert device in ["CPU", "GPU"]
    self._device = device
    assert precision in ["double", "single"]
    self._precision = precision
    self._dtype = np.complex128 if self._precision == "double" else np.complex64
    self._qubits = 0

    # matrix product state structure
    self._product_state = []
    self._norms = []
    self._groups = []   # List of the interval of entangle states, e.g. [(0, 3), (5, 7)]

    # algorithm Module
    self._linear_algorithm = LinAlgLoader(device=device)
    if self._device == "GPU":
        import cupy as cp

        self._array_helper = cp
    else:
        self._array_helper = np
apply_double_gate
apply_double_gate(qubit_indexes: list, gate_matrix: ndarray)

Apply bi-qubits quantum gate into MPS.

Parameters:

  • qubit_indexes (list) –

    The list of qubits' indexes

  • gate_matrix (ndarray) –

    The matrix of the quantum gate

  • inverse (bool) –

    Need Extra inverse? only for CRx and Unitary. Defaults to False.

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def apply_double_gate(self, qubit_indexes: list, gate_matrix: np.ndarray):
    """ Apply bi-qubits quantum gate into MPS.

    Args:
        qubit_indexes (list): The list of qubits' indexes
        gate_matrix (np.ndarray): The matrix of the quantum gate
        inverse (bool, optional): Need Extra inverse? only for CRx and Unitary. Defaults to False.
    """
    q0, q1 = qubit_indexes
    if abs(q0 - q1) == 1:
        # Apply consecutive bi-qubits gate
        self._apply_consecutive_double_gate(qubit_indexes, gate_matrix)
    else:
        # Apply swap gate for un-consecutive bi-qubits gate
        min_q = min(qubit_indexes)
        max_q = max(qubit_indexes)
        for i in range(min_q, max_q - 1):
            self._apply_consecutive_double_gate([i, i + 1], self.__SWAP_MATRIX)

        qubit_indexes = [max_q, max_q - 1] if q0 > q1 else [max_q - 1, max_q]
        self._apply_consecutive_double_gate(qubit_indexes, gate_matrix)
        for i in range(max_q - 1, min_q, -1):
            self._apply_consecutive_double_gate([i - 1, i], self.__SWAP_MATRIX)

    self._update_groups()
apply_single_gate
apply_single_gate(qubit_index: int, gate_matrix: ndarray)

Apply single gate into MPS

Parameters:

  • qubit_index (int) –

    The index of qubit

  • gate_matrix (ndarray) –

    The matrix of the quantum gate

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def apply_single_gate(self, qubit_index: int, gate_matrix: np.ndarray):
    """ Apply single gate into MPS

    Args:
        qubit_index (int): The index of qubit
        gate_matrix (np.ndarray): The matrix of the quantum gate
    """
    assert qubit_index < self.qubits
    target_qubit = self._product_state[qubit_index]
    target_qubit.tensor_data = self._array_helper.tensordot(
        target_qubit.tensor_data, self._array_helper.array(gate_matrix, dtype=self._dtype), [[1], [1]]
    ).transpose([0, 2, 1])
initial_mps
initial_mps(qubits: int, quantum_state: Union[str, ndarray] = None)

Generate the initial state for MPS by given quantum state or default state.

Parameters:

  • qubits (int) –

    The number of qubits.

  • quantum_state (Union[str, ndarray], default: None ) –

    The initial quantum state. Defaults to None.

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def initial_mps(self, qubits: int, quantum_state: Union[str, np.ndarray] = None):
    """ Generate the initial state for MPS by given quantum state or default state.

    Args:
        qubits (int): The number of qubits.
        quantum_state (Union[str, np.ndarray], optional): The initial quantum state. Defaults to None.
    """
    self._qubits = qubits
    if quantum_state is not None:
        # TODO: add special quantum state like GHZ or ... later
        if not isinstance(quantum_state, str):
            quantum_state = self._array_helper.array(quantum_state)
            self._quantum_state_schmidt_decomposition(quantum_state)
    else:
        self._product_state = [QubitTensor(self._initial_qtensor()) for _ in range(self._qubits)]
        self._norms = [Normalize(self._initial_normalize())for _ in range(1, self._qubits)] if qubits > 1 else []
        self._groups = []
sample
sample(shots: int)

Sample the measured result from current Matrix Product State.

Parameters:

  • shots (int) –

    The sample times.

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def sample(self, shots: int):
    """ Sample the measured result from current Matrix Product State.

    Args:
        shots (int): The sample times.
    """
    # Get State Vector
    state_vector = self.to_statevector()
    state_list = [0] * (1 << self._qubits)

    # Sample from State Vector
    measured_prob = self._array_helper.square(self._array_helper.abs(state_vector))
    if self._device == "GPU":
        measured_prob = measured_prob.get()

    sample_result = np.random.choice(
        np.arange(1 << self._qubits), shots, p=measured_prob
    )
    for res in sample_result:
        state_list[res] += 1

    return state_list
single_amplitude_calculate
single_amplitude_calculate(state_index: int)

Calculate single amplitude for current MPS.

Parameters:

  • state_index (int) –

    The index of quantum state which want to be calculate.

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def single_amplitude_calculate(self, state_index: int):
    """ Calculate single amplitude for current MPS.

    Args:
        state_index (int): The index of quantum state which want to be calculate.
    """
    assert state_index < (1 << self._qubits)
    # Index divided by qubits per each circuit blocks
    bit_index = "{0:0b}".format(state_index)
    bit_index = bit_index.zfill(self._qubits)
    # bit_index = [bit_index[i] for i in range(0, self._qubits, 1)]

    q0_state = int(bit_index[0], 2)
    single_state = self._product_state[0].tensor_data[:, q0_state, :]
    for i in range(1, self._qubits):
        # multiply the norm
        single_state = np.einsum('ij,j->ij', single_state, self._norms[i - 1].matrix_data)

        # choice qubits' state
        qmps = self._product_state[i]
        q_state = int(bit_index[i], 2)
        target_value = qmps.tensor_data[:, q_state, :]
        single_state = np.einsum('ij,jk->ik', single_state, target_value)

    return single_state.flatten()
to_statevector
to_statevector(interval: list = None) -> np.ndarray

Transfer MPS into State Vector. WARNING: it will generate an vector with size 2**n, where n is the number of qubits.

Returns:

  • ndarray

    np.ndarray: The state vector from MPS

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def to_statevector(self, interval: list = None) -> np.ndarray:
    """ Transfer MPS into State Vector. WARNING: it will generate an vector with size 2**n, where n is the
     number of qubits.

    Returns:
        np.ndarray: The state vector from MPS
    """
    if not interval:
        start, end = 0, self.qubits
    else:
        assert len(interval) == 2
        start, end = interval

    state_vector = self._product_state[start].tensor_data
    for i in range(start + 1, end):
        state_vector = self._array_helper.tensordot(
            state_vector, self._array_helper.diag(self._norms[i - 1].matrix_data), [[-1], [0]]
        )
        state_vector = self._array_helper.tensordot(state_vector, self._product_state[i].tensor_data, [[-1], [0]])
        ldim, rdim = state_vector.shape[0], state_vector.shape[-1]
        state_vector = state_vector.reshape([ldim, -1, rdim])

    return state_vector.flatten('C')

QubitTensor

QubitTensor(state: ndarray)

The tensor data structure for qubit in MPS simulation.

Parameters:

  • state (ndarray) –

    The Tensor data of qubit.

Source code in QuICT/simulation/matrix_product_state/mps_site.py
def __init__(self, state: np.ndarray):
    """
    Args:
        state (np.ndarray): The Tensor data of qubit.
    """
    self._tensor_data = state
dim property
dim: int

Return the qubit dimension.

ldim property
ldim: int

Return the left dimension.

rdim property
rdim: int

Return the right dimension.