파울리 연산자를 힐베르트 부분공간에 투영하기
파울리 문자열의 가중 선형 결합을 크기 의 계산 기저 상태 부분집합으로 정의되는 부분공간에 투영하는 여러 방법을 보여 드립니다. 투영된 연산자는 scipy.sparse.coo_matrix로 저장됩니다.
예시로 주기적 경계 조건과 개의 스핀을 가진 1차원 하이젠베르크 모형의 해밀토니안을 살펴봅니다.
이 패키지는 이 투영을 수행하는 두 가지 도구를 제공합니다.
-
qiskit_addon_sqd.qubit.matrix_elements_from_pauli(): 파울리 문자열의 0이 아닌 행렬 원소와 그에 해당하는 0이 아닌 원소의 인덱스를 반환하는 저수준 함수입니다. -
qiskit_addon_sqd.qubit.project_operator_to_subspace(): a higher-level function that directly returns ascipy.sparsematrix.
이 가이드에서는 이 두 도구를 사용해 동일한 희소 연산자를 만드는 방법을 보여 드립니다.
부분공간 정의
이 예제에서는 길이 22의 무작위 비트열을 생성합니다. 투영 함수가 기대한 대로 동작하려면 부분공간을 정의하는 비트열이 서로 고유해야 하며 부호 없는 정수 표현을 기준으로 오름차순으로 정렬되어 있어야 합니다.
이는 qiskit_addon_sqd.qubit.sort_and_remove_duplicates() 함수로 달성할 수 있습니다.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_sqd": "qiskit-addon-sqd", "qiskit_addon_utils": "qiskit-addon-utils", "scipy": "scipy"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit_addon_sqd.qubit import sort_and_remove_duplicates
num_spins = 22
rand_seed = 22
np.random.seed(rand_seed)
def random_bitstrings(n_samples, n_qubits):
return (
np.round(np.random.rand(n_samples, n_qubits))
.astype("int")
.astype("bool")
)
bitstring_matrix = random_bitstrings(50_000, num_spins)
# NOTE: It is essential for the projection code to have the bitstrings sorted!
bitstring_matrix = sort_and_remove_duplicates(bitstring_matrix)
print("Subspace dimension: " + str(bitstring_matrix.shape[0]))
print("Full Hilbert space dimension: " + str(2**num_spins))
Subspace dimension: 49718
Full Hilbert space dimension: 4194304
첫 번째 방법: 0이 아닌 행렬 원소와 인덱스
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
coupling_map = CouplingMap.from_ring(num_spins)
hamiltonian = generate_xyz_hamiltonian(coupling_map)
print(hamiltonian)
SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIYY', 'IIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIYYII', 'IIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIXXIIII', 'IIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIZZIIII', 'IIIIIIIIIIIIIIXXIIIIII', 'IIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIZZIIIIII', 'IIIIIIIIIIIIXXIIIIIIII', 'IIIIIIIIIIIIYYIIIIIIII', 'IIIIIIIIIIIIZZIIIIIIII', 'IIIIIIIIIIXXIIIIIIIIII', 'IIIIIIIIIIYYIIIIIIIIII', 'IIIIIIIIIIZZIIIIIIIIII', 'IIIIIIIIXXIIIIIIIIIIII', 'IIIIIIIIYYIIIIIIIIIIII', 'IIIIIIIIZZIIIIIIIIIIII', 'IIIIIIXXIIIIIIIIIIIIII', 'IIIIIIYYIIIIIIIIIIIIII', 'IIIIIIZZIIIIIIIIIIIIII', 'IIIIXXIIIIIIIIIIIIIIII', 'IIIIYYIIIIIIIIIIIIIIII', 'IIIIZZIIIIIIIIIIIIIIII', 'IIXXIIIIIIIIIIIIIIIIII', 'IIYYIIIIIIIIIIIIIIIIII', 'IIZZIIIIIIIIIIIIIIIIII', 'XXIIIIIIIIIIIIIIIIIIII', 'YYIIIIIIIIIIIIIIIIIIII', 'ZZIIIIIIIIIIIIIIIIIIII', 'XIIIIIIIIIIIIIIIIIIIIX', 'YIIIIIIIIIIIIIIIIIIIIY', 'ZIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIYYI', 'IIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIXXIIIII', 'IIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIZZIIIII', 'IIIIIIIIIIIIIXXIIIIIII', 'IIIIIIIIIIIIIYYIIIIIII', 'IIIIIIIIIIIIIZZIIIIIII', 'IIIIIIIIIIIXXIIIIIIIII', 'IIIIIIIIIIIYYIIIIIIIII', 'IIIIIIIIIIIZZIIIIIIIII', 'IIIIIIIIIXXIIIIIIIIIII', 'IIIIIIIIIYYIIIIIIIIIII', 'IIIIIIIIIZZIIIIIIIIIII', 'IIIIIIIXXIIIIIIIIIIIII', 'IIIIIIIYYIIIIIIIIIIIII', 'IIIIIIIZZIIIIIIIIIIIII', 'IIIIIXXIIIIIIIIIIIIIII', 'IIIIIYYIIIIIIIIIIIIIII', 'IIIIIZZIIIIIIIIIIIIIII', 'IIIXXIIIIIIIIIIIIIIIII', 'IIIYYIIIIIIIIIIIIIIIII', 'IIIZZIIIIIIIIIIIIIIIII', 'IXXIIIIIIIIIIIIIIIIIII', 'IYYIIIIIIIIIIIIIIIIIII', 'IZZIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j])
from qiskit_addon_sqd.qubit import matrix_elements_from_pauli
from scipy.sparse import coo_matrix
d = bitstring_matrix.shape[0]
# Initialize the coo_matrix object
operator_from_matrix_elements = coo_matrix((d, d), dtype="complex128")
for pauli in hamiltonian.paulis:
matrix_elements, row_indices, col_indices = matrix_elements_from_pauli(
bitstring_matrix, pauli
)
operator_from_matrix_elements += coo_matrix(
(matrix_elements, (row_indices, col_indices)), (d, d)
)
상위 수준 구현
from qiskit_addon_sqd.qubit import project_operator_to_subspace
operator = project_operator_to_subspace(
bitstring_matrix, hamiltonian, verbose=True
)
Projecting term 1 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIIXX ...
Projecting term 2 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIIYY ...
Projecting term 3 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIIZZ ...
Projecting term 4 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIXXII ...
Projecting term 5 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIYYII ...
Projecting term 6 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIZZII ...
Projecting term 7 out of 66: (1+0j) * IIIIIIIIIIIIIIIIXXIIII ...
Projecting term 8 out of 66: (1+0j) * IIIIIIIIIIIIIIIIYYIIII ...
Projecting term 9 out of 66: (1+0j) * IIIIIIIIIIIIIIIIZZIIII ...
Projecting term 10 out of 66: (1+0j) * IIIIIIIIIIIIIIXXIIIIII ...
Projecting term 11 out of 66: (1+0j) * IIIIIIIIIIIIIIYYIIIIII ...
Projecting term 12 out of 66: (1+0j) * IIIIIIIIIIIIIIZZIIIIII ...
Projecting term 13 out of 66: (1+0j) * IIIIIIIIIIIIXXIIIIIIII ...
Projecting term 14 out of 66: (1+0j) * IIIIIIIIIIIIYYIIIIIIII ...
Projecting term 15 out of 66: (1+0j) * IIIIIIIIIIIIZZIIIIIIII ...
Projecting term 16 out of 66: (1+0j) * IIIIIIIIIIXXIIIIIIIIII ...
Projecting term 17 out of 66: (1+0j) * IIIIIIIIIIYYIIIIIIIIII ...
Projecting term 18 out of 66: (1+0j) * IIIIIIIIIIZZIIIIIIIIII ...
Projecting term 19 out of 66: (1+0j) * IIIIIIIIXXIIIIIIIIIIII ...
Projecting term 20 out of 66: (1+0j) * IIIIIIIIYYIIIIIIIIIIII ...
Projecting term 21 out of 66: (1+0j) * IIIIIIIIZZIIIIIIIIIIII ...
Projecting term 22 out of 66: (1+0j) * IIIIIIXXIIIIIIIIIIIIII ...
Projecting term 23 out of 66: (1+0j) * IIIIIIYYIIIIIIIIIIIIII ...
Projecting term 24 out of 66: (1+0j) * IIIIIIZZIIIIIIIIIIIIII ...
Projecting term 25 out of 66: (1+0j) * IIIIXXIIIIIIIIIIIIIIII ...
Projecting term 26 out of 66: (1+0j) * IIIIYYIIIIIIIIIIIIIIII ...
Projecting term 27 out of 66: (1+0j) * IIIIZZIIIIIIIIIIIIIIII ...
Projecting term 28 out of 66: (1+0j) * IIXXIIIIIIIIIIIIIIIIII ...
Projecting term 29 out of 66: (1+0j) * IIYYIIIIIIIIIIIIIIIIII ...
Projecting term 30 out of 66: (1+0j) * IIZZIIIIIIIIIIIIIIIIII ...
Projecting term 31 out of 66: (1+0j) * XXIIIIIIIIIIIIIIIIIIII ...
Projecting term 32 out of 66: (1+0j) * YYIIIIIIIIIIIIIIIIIIII ...
Projecting term 33 out of 66: (1+0j) * ZZIIIIIIIIIIIIIIIIIIII ...
Projecting term 34 out of 66: (1+0j) * XIIIIIIIIIIIIIIIIIIIIX ...
Projecting term 35 out of 66: (1+0j) * YIIIIIIIIIIIIIIIIIIIIY ...
Projecting term 36 out of 66: (1+0j) * ZIIIIIIIIIIIIIIIIIIIIZ ...
Projecting term 37 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIXXI ...
Projecting term 38 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIYYI ...
Projecting term 39 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIIIZZI ...
Projecting term 40 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIXXIII ...
Projecting term 41 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIYYIII ...
Projecting term 42 out of 66: (1+0j) * IIIIIIIIIIIIIIIIIZZIII ...
Projecting term 43 out of 66: (1+0j) * IIIIIIIIIIIIIIIXXIIIII ...
Projecting term 44 out of 66: (1+0j) * IIIIIIIIIIIIIIIYYIIIII ...
Projecting term 45 out of 66: (1+0j) * IIIIIIIIIIIIIIIZZIIIII ...
Projecting term 46 out of 66: (1+0j) * IIIIIIIIIIIIIXXIIIIIII ...
Projecting term 47 out of 66: (1+0j) * IIIIIIIIIIIIIYYIIIIIII ...
Projecting term 48 out of 66: (1+0j) * IIIIIIIIIIIIIZZIIIIIII ...
Projecting term 49 out of 66: (1+0j) * IIIIIIIIIIIXXIIIIIIIII ...
Projecting term 50 out of 66: (1+0j) * IIIIIIIIIIIYYIIIIIIIII ...
Projecting term 51 out of 66: (1+0j) * IIIIIIIIIIIZZIIIIIIIII ...
Projecting term 52 out of 66: (1+0j) * IIIIIIIIIXXIIIIIIIIIII ...
Projecting term 53 out of 66: (1+0j) * IIIIIIIIIYYIIIIIIIIIII ...
Projecting term 54 out of 66: (1+0j) * IIIIIIIIIZZIIIIIIIIIII ...
Projecting term 55 out of 66: (1+0j) * IIIIIIIXXIIIIIIIIIIIII ...
Projecting term 56 out of 66: (1+0j) * IIIIIIIYYIIIIIIIIIIIII ...
Projecting term 57 out of 66: (1+0j) * IIIIIIIZZIIIIIIIIIIIII ...
Projecting term 58 out of 66: (1+0j) * IIIIIXXIIIIIIIIIIIIIII ...
Projecting term 59 out of 66: (1+0j) * IIIIIYYIIIIIIIIIIIIIII ...
Projecting term 60 out of 66: (1+0j) * IIIIIZZIIIIIIIIIIIIIII ...
Projecting term 61 out of 66: (1+0j) * IIIXXIIIIIIIIIIIIIIIII ...
Projecting term 62 out of 66: (1+0j) * IIIYYIIIIIIIIIIIIIIIII ...
Projecting term 63 out of 66: (1+0j) * IIIZZIIIIIIIIIIIIIIIII ...
Projecting term 64 out of 66: (1+0j) * IXXIIIIIIIIIIIIIIIIIII ...
Projecting term 65 out of 66: (1+0j) * IYYIIIIIIIIIIIIIIIIIII ...
Projecting term 66 out of 66: (1+0j) * IZZIIIIIIIIIIIIIIIIIII ...
두 구현이 동일한 coo_matrix를 만들어 내는지 확인합니다.
print((operator.power(2) - operator_from_matrix_elements.power(2)).sum())
0j