Skip to main content
IBM Quantum Platform

QkObs

typedef struct QkObs QkObs

데이터를 큐비트-스페어 형식으로 저장하는 폴리 기반에 대한 옵저버블입니다.


수학

이 관측 가능성은 폴리 연산자와 폴리 고유 상태 프로젝터의 문자열에 대한 합을 나타내며, 각 항에 복소수 가중치를 부여합니다. 즉, 전체 관찰 가능 범위는 다음과 같습니다

QkObs=icinAi(n)\text{\texttt{QkObs}} = \sum_i c_i \bigotimes_n A^{(n)}_i

복소수 cic_i 및 제한된 알파벳 Ai(n)A^{(n)}_i 에서 큐비트 nn 에 작용하는 단일 큐비트 연산자. ii 의 합은 개별 항의 합이며, 텐서 곱은 연산자 문자열을 생성합니다. 허용되는 단일 큐비트 연산자의 알파벳은 Ai(n)A^{(n)}_i 폴리 연산자와 폴리 고유 상태 투영 연산자입니다. 명시적으로는 다음과 같습니다:

연산자
QkBitTerm
숫자 값
II (신원)저장되지 않습니다.저장되지 않습니다.
XX (폴리 엑스)QkBitTerm_X0b0010 (2)
YY (Pauli Y)QkBitTerm_Y0b0011 (3)
ZZ (폴리 Z)QkBitTerm_Z0b0001 (1)
++\lvert+\rangle\langle+\rvert (X의 양의 고유 상태로 투영)QkBitTerm_Plus0b1010 (10)
\lvert-\rangle\langle-\rvert (X의 음의 고유 상태로 프로젝터)QkBitTerm_Minus0b0110 (6)
rr\lvert r\rangle\langle r\rvert (Y의 양의 고유 상태로 투영)QkBitTerm_Right0b1011 (11)
ll\lvert l\rangle\langle l\rvert (Y의 음의 고유 상태로 투영)QkBitTerm_Left0b0111 (7)
00\lvert0\rangle\langle0\rvert (Z의 양의 고유 상태로 투영)QkBitTerm_Zero0b1001 (9)
11\lvert1\rangle\langle1\rvert (Z의 음의 고유 상태로 투영)QkBitTerm_One0b0101 (5)

폴리스와 프로젝터를 모두 허용하기 때문에 허용된 알파벳은 연산자 공간의 지나치게 불완전한 기초를 형성합니다. 즉, 주어진 관측값을 나타내는 고유한 합이 없다는 뜻입니다. 따라서 비교에는 추가적인 주의가 필요하며 수학적으로 동등한 두 개의 관측값에 qk_obs_canonicalize 을 사용하면 동일한 표현이 되지 않을 수 있습니다.

QkObs 는 '측정의 효율성'을 '표현의 효율성'과 동등하게 만들기 위해 특별히 불완전한 기반을 사용합니다. 예를 들어, 관측 가능한 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} 은 간단한 ZZ 측정으로 하드웨어에서 효율적으로 측정할 수 있지만, 폴리스에서는 (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n 로만 표현할 수 있으므로 2n2^n 저장된 용어가 필요합니다. QkObs 를 저장하는 데는 단 하나의 용어만 필요합니다. 이 방법의 단점은 임의의 행렬을 사용하여 최상의 QkObs 표현을 찾는 것이 비현실적이라는 것입니다. 일반적으로 QkObs 을 분해하는 대신 직접 구성하는 것이 좋습니다.


표현

QkObs 의 내부 표현은 비신원 큐비트 연산자만 저장합니다. 따라서 nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; QkObs 과 같은 관측값을 표현하는 데 훨씬 더 효율적입니다. 용어는 스파스 행렬의 압축 스파스 행 형식과 유사하게 압축되어 저장됩니다. 이 비유에서 합계의 용어는 '행'이고 큐비트 용어는 '열'이며, 없는 항목은 0이 아닌 신원을 나타냅니다. 보다 명확하게 표현하면, 이 표현은 4개의 인접한 배열로 구성됩니다:

액세스 가능한 속성
길이
설명
qk_obs_coeffstt각 용어에 대한 복소 스칼라 승수입니다.
qk_obs_bit_termsss모든 연산자에 대한 비식별 단일 큐비트 용어 각각을 순서대로 나열합니다. 이는 합계 설명에서 비아이덴티티 Ai(n)A^{(n)}_i 에 해당하며, 항목은 먼저 ii 이 증가하는 순서로 저장되고 각 용어 내에서 nn 이 증가하는 순서로 저장됩니다.
qk_obs_indicesss각 비트 용어에 해당하는 큐비트( nn )입니다. QkObs 를 사용하려면 이 목록이 용어별로 정렬되어야 하며 알고리즘은 이 불변성이 유지되는지 확인할 수 있습니다.
qk_obs_boundariest+1t+1비트 용어와 인덱스를 완전한 용어로 분할하는 인덱스입니다. 용어 번호 ii 의 경우 복소수 계수는 인덱스 i 에 저장되며, 비식별 단일 큐비트 연산자와 해당 큐비트는 비트 용어와 인덱스에서 각각 [boundaries[i], boundaries[i+1]) 범위에 있습니다. 경계는 항상 명시적으로 0을 첫 번째 요소로 사용합니다.

길이 매개변수 tt 는 합계의 용어 수이며 qk_obs_num_terms 을 사용하여 쿼리할 수 있습니다. 매개변수 ss 는 비식별 단일 큐비트 용어의 총 개수이며 qk_obs_len 를 사용하여 쿼리할 수 있습니다.

예시적인 예로

  • 영 연산자의 경우 경계는 길이 1(단일 0)이고 다른 모든 벡터는 비어 있습니다.
  • 완전히 단순화된 ID 연산자의 경우 경계는 {0, 0}, 계수에는 단일 항목이 있으며 비트 항과 인덱스는 모두 비어 있습니다.
  • 연산자 Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1 의 경우 경계는 {0, 2, 4}, 코오프는 {1.0, -1.0}, 비트 용어는 {QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X} , 인덱스는 {0, 2, 1, 3} 입니다. 운영자는 큐비트 수에 따라 4개 이상의 큐비트에 대해 작업할 수 있습니다( qk_obs_num_qubits 참조). 단일 비트 용어와 인덱스는 용어별로 정렬된 순서로 정렬된다는 점에 유의하세요.

이러한 경우는 특별한 경우가 아니며 규칙에 완전히 부합하므로 특별한 처리가 필요하지 않습니다.

정규 순서

주어진 수학적 관측값에 대해 QkObs 로 표현하는 방법에는 여러 가지가 있습니다. 예를 들어, 동일한 단일 비트 용어 집합과 해당 인덱스가 관찰 가능 항목에 여러 번 나타날 수 있습니다. 수학적으로 이것은 모든 계수를 합산한 단일 항만 있는 것과 같습니다. 마찬가지로, QkObs 에서의 합의 조건은 동일한 관측값을 나타내면서 어떤 순서로든 될 수 있습니다(부동소수점 덧셈은 연관성이 없지만 QkObs 은 합산 순서에 대해 보장하지 않습니다).

이러한 두 가지 범주의 표현 퇴화는 연산자 같음( qk_obs_equal)이 동일한 객체를 표현함에도 불구하고 두 관측값이 같지 않다고 주장하게 만들 수 있습니다. 이러한 경우, 관측값을 구조적으로 비교할 수 있는 표준 형식을 정의하는 것이 편리할 수 있습니다. qk_obs_canonicalize 함수를 사용하여 QkObs 을 정식 형식으로 입력할 수 있습니다. 표준 순서의 정확한 용어 순서는 지정되어 있지 않으며, 키스킷 버전에 따라 변경될 수 있습니다. 그러나 동일한 버전의 키스킷 내에서는 두 개의 관측값을 단순화된 형태로 비교하여 구조적으로 비교할 수 있습니다.

참고

비교에서 부동 소수점 허용 오차를 고려하려면 다음과 같은 레시피를 사용하는 것이 가장 안전합니다:

bool equivalent(QkObs *left, QkObs *right, double tol) {
  // compare a canonicalized version of left - right to the zero observable
  QkObs *neg_right = qk_obs_multiply(right, &(QkComplex64){-1, 0});
  QkObs *diff = qk_obs_add(left, neg_right);
  QkObs *canonical = qk_obs_canonicalize(diff, tol);

  QkObs *zero = qk_obs_zero(qk_obs_num_qubits(left));
  bool equiv = qk_obs_equal(diff, zero);
  // free all temporary variables
  qk_obs_free(neg_right);
  qk_obs_free(diff);
  qk_obs_free(canonical);
  qk_obs_free(zero);
  return equiv;
}
참고

qk_obs_canonicalize 에서 생성된 표준 형식만으로는 기본 알파벳이 지나치게 완전하기 때문에 동등한 모든 관측값을 보편적으로 감지할 수 없습니다.

색인화

QkObs 의 개별 관측 가능한 합계 조건은 qk_obs_term 을 통해 액세스하고 QkObsTerm 유형의 객체를 반환할 수 있습니다. 이러한 용어에는 용어의 계수, 비트 용어, 인덱스 및 정의된 큐비트 수가 있는 필드가 포함됩니다. 용어 수에 대한 정보와 함께 관찰 가능한 모든 용어를 다음과 같이 반복할 수 있습니다

size_t num_terms = qk_obs_num_terms(obs);  // obs is QkObs*
for (size_t i = 0; i < num_terms; i++) {
    QkObsTerm term;  // allocate term on stack
    int exit = qk_obs_term(obs, i, &term);  // get the term (exit > 0 upon index errors)
    // do something with the term...
}
경고

qk_obs_term 을 통해 QkObsTerm 을 채우면 원본 QkObs 의 데이터를 참조하게 됩니다. 비트 용어나 인덱스를 수정하면 관측값이 변경되어 일관성 없는 상태가 될 수 있습니다.


생성

QkObs 는 빈 옵저버블을 초기화( qk_obs_zero)하고 반복적으로 용어를 추가( qk_obs_add_term)하여 구성할 수 있습니다. 또는 모든 내부 데이터가 지정된 경우 '원시' 데이터( qk_obs_new)로 관측값을 구성할 수도 있습니다. 이를 위해서는 데이터의 일관성을 유지하고 유효한 관찰 가능한 결과를 얻을 수 있도록 주의를 기울여야 합니다.

함수
요약
qk_obs_zero주어진 수의 큐비트에 빈 옵저버블을 구축합니다.
qk_obs_identity주어진 큐비트 수에서 관찰 가능한 ID를 구성합니다.
qk_obs_new원시 데이터 배열에서 관찰 가능한 데이터를 구축합니다.

수학적 조작

QkObs 는 관측값 사이 또는 스칼라를 사용한 기본적인 산술 연산을 지원합니다. 다음과 같은 일을 할 수 있습니다.

  • 와 를 qk_obs_add 사용하여 두 개의 관측값을 추가하고 qk_obs_add_inplace
  • 복소수를 곱할 때 qk_obs_multiplyqk_obs_multiply_inplace
  • 를 통해 두 개의 관측값을 작성(곱하기)하고 qk_obs_composeqk_obs_compose_map
  • 두 개의 관측량과 복소 스칼라에 대해 다음을 left + scalar * right``qk_obs_scaled_add 계산한다: qk_obs_scaled_add_inplace

함수

qk_obs_zero

QkObs *qk_obs_zero(uint32_t num_qubits)

(조건 없이) 영 관측값을 구축합니다.

QkObs *zero = qk_obs_zero(100);

매개변수

  • 숫자_큐비트 - 관측 항목이 정의된 큐비트 수입니다.

리턴

생성된 관찰 가능 항목에 대한 포인터입니다.

qk_obs_identity

QkObs *qk_obs_identity(uint32_t num_qubits)

관찰 가능한 아이덴티티를 구축합니다.

QkObs *identity = qk_obs_identity(100);

매개변수

  • 숫자_큐비트 - 관측 항목이 정의된 큐비트 수입니다.

리턴

생성된 관찰 가능 항목에 대한 포인터입니다.

qk_obs_new

QkObs *qk_obs_new(uint32_t num_qubits, uint64_t num_terms, uint64_t num_bits, QkComplex64 *coeffs, QkBitTerm *bit_terms, uint32_t *indices, size_t *boundaries)

원시 데이터에서 새로운 관측값을 생성합니다.

포인터 인자 중 어느 것이든 해당 길이가 0일 때에만 NULL 해당할 수 있다.

// define the raw data for the 100-qubit observable |01><01|_{0, 1} - |+-><+-|_{98, 99}
uint32_t num_qubits = 100;
uint64_t num_terms = 2;  // we have 2 terms: |01><01|, -1 * |+-><+-|
uint64_t num_bits = 4; // we have 4 non-identity bits: 0, 1, +, -
QkComplex64 coeffs[] = {{1, 0}, {-1, 0}};
QkBitTerm bits[4] = {QkBitTerm_Zero, QkBitTerm_One, QkBitTerm_Plus, QkBitTerm_Minus};

uint32_t indices[4] = {0, 1, 98, 99};  // <-- e.g. {1, 0, 99, 98} would be invalid
size_t boundaries[3] = {0, 2, 4};
QkObs *obs = qk_obs_new(
    num_qubits, num_terms, num_bits, coeffs, bits, indices, boundaries
);
qk_obs_free(obs);

안전

다음 조건 중 하나라도 위반하면 동작이 정의되지 않습니다:

  • coeffsQkComplex64 길이의 배열에 대한 포인터입니다 num_terms
  • bit_terms 는 길이가 유효한 QkBitTerm 요소의 배열에 대한 포인터입니다 num_bits
  • indices 는 길이 num_bitsuint32_t 배열에 대한 포인터로, 엄격한 오름차순으로 정렬되며 모든 요소는 다음보다 작습니다 num_qubits
  • boundaries 는 오름차순으로 정렬된 num_terms + 1 길이의 size_t 배열에 대한 포인터로, 첫 번째 요소는 0이고 마지막 요소는 다음보다 작습니다 num_terms

매개변수

  • 숫자_큐비트 - 관측 항목이 정의된 큐비트 수입니다.
  • num_terms - 학기 수입니다.
  • num_bits - 비식별 비트 용어의 총 개수입니다.
  • coeffs - 길이가 num_terms 인 계수 배열의 첫 번째 요소에 대한 포인터입니다.
  • bit_terms - 비트 용어 배열의 첫 번째 요소에 대한 포인터로, 길이가 num_bits 입니다.
  • 인덱스 - 길이가 num_bits 인 인덱스 배열의 첫 번째 요소에 대한 포인터입니다. 용어별로 점진적으로 정렬해야 한다는 점에 유의하세요.
  • 경계 - 길이가 num_terms + 1 인 경계 배열의 첫 번째 요소에 대한 포인터입니다.

리턴

입력 데이터가 일관되고 구성이 성공적이었다면, 그 결과는 관찰 가능성에 대한 포인터가 됩니다. 그렇지 않으면 널 포인터가 반환됩니다.

qk_obs_free

void qk_obs_free(QkObs *obs)

관찰 가능한 것을 해제하세요.

QkObs *obs = qk_obs_zero(100);
qk_obs_free(obs);

안전

obs 이 null이 아니거나 QkObs 에 대한 유효한 포인터가 아닌 경우 동작이 정의되지 않습니다.

매개변수

  • obs - 관찰할 수 있는 무료에 대한 포인터입니다.

qk_obs_add_term

QkExitCode qk_obs_add_term(QkObs *obs, const QkObsTerm *cterm)

관찰 가능 항목에 용어를 추가합니다.

uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);

QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};

QkExitCode exit_code = qk_obs_add_term(obs, &term);

안전

다음 중 하나라도 위반하면 동작이 정의되지 않습니다:

  • obs 는 널이 아닌 유효한 포인터입니다 QkObs
  • cterm 는 널이 아닌 유효한 포인터입니다 QkObsTerm

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.
  • 학기 - 추가할 학기에 대한 포인터입니다.

리턴

종료 코드입니다. 용어가 일관성이 없거나 용어 추가에 실패한 경우 >0 입니다.

qk_obs_term

QkExitCode qk_obs_term(QkObs *obs, uint64_t index, QkObsTerm *out)

참조로 관찰 가능한 용어를 가져옵니다.

QkObsTerm 에는 해당 용어의 인덱스와 비트 용어에 대한 포인터가 포함되어 있으며, 이 포인터는 옵저버블의 내부 데이터를 수정하는 데 사용할 수 있습니다. 이렇게 하면 관찰 가능한 내용이 일관성 없는 상태로 남을 수 있으므로 세심한 주의를 기울이지 않는 한 피해야 합니다. 일반적으로 제자리에서 수정을 시도하는 대신 새 관측값을 만드는 것이 더 안전합니다.

QkObs *obs = qk_obs_identity(100);
QkObsTerm term;
QkExitCode exit_code = qk_obs_term(obs, 0, &term);
// out-of-bounds indices return an error code
// QkExitCode error = qk_obs_term(obs, 12, &term);

안전

다음 중 하나라도 위반하는 경우 동작이 정의되지 않습니다

  • obs 는 널이 아닌 유효한 포인터입니다 QkObs
  • out 는 널이 아닌 유효한 포인터입니다 QkObsTerm

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.
  • 색인 - 가져올 용어의 색인입니다.
  • out - 관찰 가능한 용어를 반환하는 데 사용되는 QkObsTerm 포인터입니다.

리턴

종료 코드입니다.

qk_obs_num_terms

size_t qk_obs_num_terms(const QkObs *obs)

관찰 가능한 용어의 개수를 가져옵니다.

QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);  // num_terms==1

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

관찰 가능한 용어의 수입니다.

qk_obs_num_qubits

uint32_t qk_obs_num_qubits(const QkObs *obs)

옵저버블이 정의된 큐비트 수를 가져옵니다.

QkObs *obs = qk_obs_identity(100);
uint32_t num_qubits = qk_obs_num_qubits(obs);  // num_qubits==100

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

옵저버블이 정의된 큐비트 수입니다.

qk_obs_len

size_t qk_obs_len(const QkObs *obs)

옵저버블의 비트 텀/인덱스 수를 가져옵니다.

QkObs *obs = qk_obs_identity(100);
size_t len = qk_obs_len(obs);  // len==0, as there are no non-trivial bit terms

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

관찰 가능한 용어의 수입니다.

qk_obs_coeffs

QkComplex64 *qk_obs_coeffs(QkObs *obs)

계수에 대한 포인터를 가져옵니다.

관측값의 계수를 읽고 수정하는 데 사용할 수 있습니다. 결과 포인터는 QkComplex64qk_obs_num_terms(obs) 요소에 대해 읽을 수 있습니다.

QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);
QkComplex64 *coeffs = qk_obs_coeffs(obs);

for (size_t i = 0; i < num_terms; i++) {
    printf("%f + i%f\n", coeffs[i].re, coeffs[i].im);
}

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

계수에 대한 포인터입니다.

qk_obs_indices

uint32_t *qk_obs_indices(QkObs *obs)

인덱스에 대한 포인터를 가져옵니다.

옵저버블의 인덱스를 읽고 수정하는 데 사용할 수 있습니다. 결과 포인터는 uint32_t 크기의 qk_obs_len(obs) 요소에 대해 읽을 수 있습니다.

uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);

QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t term_indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, term_indices, num_qubits};
qk_obs_add_term(obs, &term);

size_t len = qk_obs_len(obs);
uint32_t *indices = qk_obs_indices(obs);

for (size_t i = 0; i < len; i++) {
    printf("index %i: %i\n", i, indices[i]);
}

qk_obs_free(obs);

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

인덱스에 대한 포인터입니다.

qk_obs_boundaries

size_t *qk_obs_boundaries(QkObs *obs)

경계라는 용어에 대한 포인터를 가져옵니다.

옵저버블의 용어 경계를 읽고 수정하는 데 사용할 수 있습니다. 결과 포인터는 size_t 크기의 qk_obs_num_terms(obs) + 1 요소에 대해 읽을 수 있습니다.

uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);

QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);

size_t num_terms = qk_obs_num_terms(obs);
size_t *boundaries = qk_obs_boundaries(obs);

for (size_t i = 0; i < num_terms + 1; i++) {
    printf("boundary %i: %i\n", i, boundaries[i]);
}

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

경계를 가리키는 포인터입니다.

qk_obs_bit_terms

QkBitTerm *qk_obs_bit_terms(QkObs *obs)

비트 용어에 대한 포인터를 가져옵니다.

옵저버블의 비트 용어를 읽고 수정하는 데 사용할 수 있습니다. 결과 포인터는 uint8_t 크기의 qk_obs_len(obs) 요소에 대해 읽을 수 있습니다.

uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);

QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);

size_t len = qk_obs_len(obs);
QkBitTerm *bits = qk_obs_bit_terms(obs);

for (size_t i = 0; i < len; i++) {
    printf("bit term %i: %i\n", i, bits[i]);
}

qk_obs_free(obs);

안전

'Behavior is undefined'는 유효하지 obs 않거나 null이 아닌 포인터가 아니거나, 결과 QkBitTerm 포인터에 유효하지 QkObs 않은 값이 기록된 경우입니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

비트 용어에 대한 포인터입니다.

qk_obs_multiply

QkObs *qk_obs_multiply(const QkObs *obs, const QkComplex64 *coeff)

관측 가능 항목에 복소수 계수를 곱합니다.

QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
QkObs *result = qk_obs_multiply(obs, &coeff);

안전

다음 중 하나라도 위반하는 경우 동작이 정의되지 않습니다

  • obs 는 널이 아닌 유효한 포인터입니다 QkObs
  • coeff 는 널이 아닌 유효한 포인터입니다 QkComplex64

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.
  • coeff - 관측값에 곱할 계수입니다.

리턴

결과에 대한 obs * coeff포인터.

qk_obs_multiply_inplace

void qk_obs_multiply_inplace(QkObs *obs, const QkComplex64 *coeff)

현재 위치의 관측값에 복소수 계수를 곱합니다.

QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
qk_obs_multiply_inplace(obs, &coeff);

안전

다음 중 하나라도 위반하는 경우 동작이 정의되지 않습니다

  • obs 는 널이 아닌 유효한 포인터입니다 QkObs
  • coeff 는 널이 아닌 유효한 포인터입니다 QkComplex64

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.
  • coeff - 관측값에 곱할 계수입니다.

qk_obs_add

QkObs *qk_obs_add(const QkObs *left, const QkObs *right)

두 개의 관찰 항목을 추가합니다.

QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
QkObs *result = qk_obs_add(left, right);

안전

left 또는 rightQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 왼쪽 - 왼쪽 관찰 가능 영역에 대한 포인터입니다.
  • 오른쪽 - 오른쪽 관찰 가능 영역에 대한 포인터입니다.

리턴

결과에 대한 포인터 left + right.

qk_obs_add_inplace

void qk_obs_add_inplace(QkObs *left, const QkObs *right)

기존의 observable에 새로운 observable을 추가합니다.

QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
qk_obs_add_inplace(left, right);

안전

left 또는 rightQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 왼쪽 - 왼쪽 관찰 가능 영역에 대한 포인터입니다.
  • 오른쪽 - 오른쪽 관찰 가능 영역에 대한 포인터입니다.

qk_obs_scaled_add

QkObs *qk_obs_scaled_add(const QkObs *left, const QkObs *right, const QkComplex64 *factor)

두 개의 관측 변수를 추가하고, 오른쪽 관측 변수의 계수를 조정합니다.

QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
QkObs *result = qk_obs_scaled_add(left, right, &factor);

안전

left 또는 rightQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 왼쪽 - 왼쪽 관찰 가능 영역에 대한 포인터입니다.
  • 오른쪽 - 오른쪽 관찰 가능 영역에 대한 포인터입니다.
  • 계수 – 계수에 곱할 계수.

리턴

결과를 가리키는 소유 left + factor * right 포인터.

qk_obs_scaled_add_inplace

void qk_obs_scaled_add_inplace(QkObs *left, const QkObs *right, const QkComplex64 *factor)

기존의 관측 가능 객체에 스케일링된 관측 가능 객체를 추가합니다.

QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
qk_obs_scaled_add_inplace(left, right, &factor);

안전

left 또는 rightQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 왼쪽 - 왼쪽 관찰 가능 영역에 대한 포인터입니다.
  • 오른쪽 - 오른쪽 관찰 가능 영역에 대한 포인터입니다.
  • 계수 – 계수에 곱할 계수.

qk_obs_compose

QkObs *qk_obs_compose(const QkObs *first, const QkObs *second)

두 개의 관측값을 구성(곱하기)합니다.

QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);

안전

first 또는 secondQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 첫째 - 하나의 관찰 가능.
  • 둘째 - 다른 관찰 가능.

리턴

first.compose(second) 는 행렬 곱셈의 관점에서 관찰 가능한 result = second @ first, @ 과 동일합니다.

qk_obs_compose_map

QkObs *qk_obs_compose_map(const QkObs *first, const QkObs *second, const uint32_t *qargs)

사용자 지정 큐비트 순서에 따라 두 개의 관측값을 구성(곱하기)합니다.

특히, 크기가 다른 두 개의 관측값을 구성할 수 있습니다.

QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);

안전

이 함수를 안전하게 호출하려면

  • firstsecondQkObs\ s에 대한 널이 아닌 유효한 포인터여야 합니다
  • qargsqk_obs_num_qubits(second) 요소( second 의 큐비트 수를 의미)에 대해 읽을 수 있는 uint32_t 배열을 가리켜야 합니다

매개변수

  • 첫째 - 하나의 관찰 가능.
  • 둘째 - 다른 관찰 가능. 큐비트 수는 qargs 의 길이와 일치해야 합니다.
  • qargs - second 의 인덱스와 연결할 first 의 인덱스를 지정하는 쿼비트 인자입니다.

리턴

first.compose(second) 는 행렬 곱셈의 관점에서 관찰 가능한 result = second @ first, @ 과 동일합니다.

qk_obs_apply_layout

QkExitCode qk_obs_apply_layout(QkObs *obs, const uint32_t *layout, uint32_t num_qubits)

옵저버블에 새 큐비트 레이아웃을 적용합니다.

레이아웃은 새 인덱스의 배열 layout 로 설정되며, 현재 인덱스 i 의 큐비트가 인덱스 layout[i] 로 레이블이 변경되도록 지정합니다. 옵저버블이 작동하는 큐비트 수는 현재 옵저버블보다 큰 num_qubits 을 설정하여 확장할 수 있습니다.

이 인터페이스를 사용하면 큐비트 인덱스의 레이블을 다시 지정하고 확장할 수 있습니다:

QkObs *obs = qk_obs_zero(4);

// add a term to the observable
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t qubits[3] = {1, 2, 3};
complex double coeff = 1;
QkObsTerm term = {coeff, 3, bit_terms, qubits, 4};
qk_obs_add_term(obs, &term);

uint32_t layout[3] = {0, 10, 9};  // qubit mapping is: 0->0, 1->10, 2->9
uint32_t num_output_qubits = 11;
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);

컴파일러 워크플로에서 이 함수는 트랜스파일러 패스에서 얻은 QkTranspileLayout* (다음 예제에서는 transpile_layout )를 적용하는 데 편리하게 사용할 수 있습니다:

// get the number of output qubits
uint32_t num_output_qubits = qk_transpile_layout_num_output_qubits(transpile_layout);

// get the layout including the ancillas (hence the ``false`` in the function call)
uint32_t *layout = malloc(sizeof(uint32_t) * num_output_qubits);
qk_transpile_layout_final_layout(transpile_layout, false, layout);

// apply the layout
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);

// free the layout array
free(layout);

안전

obsQkObs 에 대한 유효하고 널이 아닌 포인터가 아니거나 layoutqk_obs_num_qubits(obs) 의 연속된 요소 시퀀스에 대한 유효하고 널이 아닌 포인터가 아닌 경우 동작이 정의되지 않습니다 uint32_t.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터로, 성공 시 이 관찰 가능 항목이 제자리에서 수정됩니다. 종료 코드를 확인하여 레이아웃이 올바르게 적용되었는지 확인합니다.
  • 레이아웃 - 레이아웃에 대한 포인터입니다. 포인터는 uint32_t 유형의 qk_obs_num_qubits(obs) 요소에 대한 배열을 가리켜야 합니다. 각 요소는 [0, num_qubits) 의 값을 가져야 합니다.
  • 숫자_큐비트 - 출력 큐비트 수입니다.

리턴

종료 코드입니다.

  • QkExitCode_Success 성공 시
  • QkExitCode_DuplicteIndexError 중복 큐비트 인덱스가 발견된 경우
  • QkExitCode_MismatchedQubits num_qubits 이 관찰 가능한 큐비트 수보다 작으면
  • QkExitCode_IndexError 의 유효하지 않은 값과 같은 다른 인덱스 오류를 확인하려면 layout.

qk_obs_canonicalize

QkObs *qk_obs_canonicalize(const QkObs *obs, double tol)

관측 가능 영역의 정식 표현을 계산합니다.

QkObs *iden = qk_obs_identity(100);
QkObs *two = qk_obs_add(iden, iden);

double tol = 1e-6;
QkObs *canonical = qk_obs_canonicalize(two, tol);

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.
  • tol - 계수가 0으로 간주되는 허용 오차 범위입니다.

리턴

관측 가능 영역의 정식 표현입니다.

qk_obs_copy

QkObs *qk_obs_copy(const QkObs *obs)

관찰 항목을 복사합니다.

QkObs *original = qk_obs_identity(100);
QkObs *copied = qk_obs_copy(original);

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

매개변수

  • obs - 관찰 가능 항목에 대한 포인터입니다.

리턴

관찰 가능 항목의 복사본에 대한 포인터입니다.

qk_obs_equal

bool qk_obs_equal(const QkObs *obs, const QkObs *other)

두 관측값의 동일성을 비교합니다.

이는 수학적 동등성을 비교하는 것이 아니라 데이터 동등성을 비교한다는 점에 유의하세요. 즉, 두 관측값은 동일한 관측값을 나타내지만 동일하게 비교할 수는 없습니다.

QkObs *observable = qk_obs_identity(100);
QkObs *other = qk_obs_identity(100);
bool are_equal = qk_obs_equal(observable, other);

안전

obs 또는 otherQkObs\ s에 대한 유효하지 않은 널이 아닌 포인터인 경우 동작이 정의되지 않습니다.

매개변수

  • 관찰 - 하나의 관찰 가능 항목에 대한 포인터입니다.
  • 기타 - 다른 관찰 가능 항목에 대한 포인터입니다.

리턴

true 관측값이 같으면 false , 그렇지 않으면.

qk_obs_str

char *qk_obs_str(const QkObs *obs)

QkObs 의 문자열 표현을 반환합니다.

QkObs *obs = qk_obs_identity(100);
char *string = qk_obs_str(obs);
qk_str_free(string);
qk_obs_free(obs);

안전

동작이 정의되지 않았습니다 obsQkObs 에 대한 유효한 널이 아닌 포인터가 아닙니다.

문자열은 일반적인 C 해제로는 해제할 수 없으며 qk_str_free 을 사용하여 문자열이 사용하는 메모리를 해제해야 합니다. qk_str_free 을 호출하지 않으면 메모리 누수가 발생할 수 있습니다.

값을 변경할 수는 있지만 문자열이 반환된 후에는 문자열 내부 어딘가에 널 바이트를 쓰거나 마지막 바이트를 제거하여 문자열의 길이를 변경하지 마세요.

매개변수

  • 관찰 - 문자열을 가져올 QkObs 에 대한 포인터입니다.

리턴

에 대한 문자열 표현의 널로 끝나는 문자 배열에 대한 포인터입니다 obs

qk_str_free

void qk_str_free(char *string)

문자열 표현을 해제합니다.

안전

strqk_obs_str 또는 qk_obsterm_str 에서 반환하는 포인터가 아닌 경우 동작이 정의되지 않습니다.

매개변수

  • 문자열 - qk_obs_str 또는 qk_obsterm_str 에서 반환된 문자열 표현에 대한 포인터입니다.

qk_obs_to_python

PyObject *qk_obs_to_python(QkObs *obs)

객체의 QkObs 소유권을 Python 에 전달합니다.

이 함수를 호출한 후에는 QkObs 포인터를 사용하는 것이 안전하지 않습니다. 특히, 이를 지우거나 해제하려고 시도해서는 안 됩니다. 호출자는 해당 객체를 소유하고 QkObs있어야 하며, 빌린 참조를 가지고 있어서는 안 됩니다(예를 들어 qk_obs_borrow_from_python , 에서 가져온 QkObs * 객체는 소유권이 없습니다).

안전

호출자는 Python 인터프리터에 연결되어 있어야 합니다. 가 초기화되고 소유권이 있는 에 대한 유효한 비공백 포인터가 QkObs 아닌 obs 경우 동작이 정의되지 않습니다.

매개변수

  • obs – 소유된 객체.

리턴

해당 객체에 대한 Python 참조.

qk_obs_borrow_from_python

QkObs *qk_obs_borrow_from_python(PyObject *ob)

Python 객체에서 QkObs 포인터를 가져옵니다.

이 코드는 Python 참조를 가져와, 해당 참조가 올바른 유형일 경우 그 QkObs 포인터를 추출합니다. 반환된 포인터는 해당 ob 포인터에서 빌려온 것입니다. 의 유형이 올바르지 않은 PyObject 경우, 반환 값은 이 NULL 되며 Python 인터프리터의 예외 상태가 설정됩니다.

이 함수를 호출하려면 Python 인터프리터가 연결되어 있어야 합니다.

또한 를 사용할 수도 있습니다 qk_obs_convert_from_python. 이는 논리적으로는 이 함수와 완전히 동일하지만, Python 변환 함수 계열에 PyArg_Parse* 대한 “변환기” 함수로 직접 사용할 수 있습니다.

안전

호출자는 Python 인터프리터에 연결되어 있어야 합니다. 가 Python 객체를 가리키는 유효한 비공백 포인터가 아닌 ob 경우 동작이 정의되지 않습니다.

매개변수

  • ob – 차용된 Python 객체.

리턴

네이티브 객체에 대한 포인터이거나, NULLPython 객체의 유형이 올바르지 않은 경우.

qk_obs_convert_from_python

int qk_obs_convert_from_python(PyObject *object, void *address)

Python 객체에서 QkObs 포인터를 가져옵니다.

이 코드는 Python 참조를 가져와, 해당 QkObs 포인터가 올바른 유형인 경우 이를 address``로 추출합니다. 반환된 포인터는 해당 object 포인터에서 빌려온 것입니다. 의 PyObject 유형이 올바르지 않은 경우, 반환 값은 1이 되며, Python 인터프리터의 예외 상태가 설정되고 는 변경되지 address 않습니다.

이 함수를 호출하려면 Python 인터프리터가 연결되어 있어야 합니다.

또한 를 qk_obs_borrow_from_python사용할 수도 있는데, 이는 논리적으로는 이와 완전히 동일하지만 직접 사용할 때 더 자연스러운 시그니처를 갖습니다.

안전

호출자는 Python 인터프리터에 연결되어 있어야 합니다. 가 유효한 null이 아닌 Python 객체 포인터가 object 아니거나, 가 올바른 유형의 쓰기 가능한 address 데이터에 대한 포인터가 아닌 경우 동작이 정의되지 않습니다.

매개변수

  • 객체 – 빌려온 Python 객체.
  • 주소 – 출력을 기록할 위치.

리턴

성공 시 1, 실패 시 0.

이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.