Skip to main content
IBM Quantum Platform

QkObs

typedef struct QkObs QkObs

Um observável sobre bases Pauli que armazena seus dados em um formato qubit-esparso.


matemática

Esse observável representa uma soma sobre cadeias de operadores de Pauli e projetores de estado próprio de Pauli, com cada termo ponderado por algum número complexo. Ou seja, o observável completo é

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

para números complexos cic_i e operadores de um único qubit atuando no qubit nn a partir de um alfabeto restrito Ai(n)A^{(n)}_i. A soma sobre ii é a soma dos termos individuais, e o produto tensorial produz as cadeias de operadores. O alfabeto de operadores de um único qubit permitido do qual o Ai(n)A^{(n)}_i é extraído são os operadores de Pauli e os operadores de projeção de estado próprio de Pauli. Explicitamente, são eles:

Operador
QkBitTerm
Valor numérico
II (identidade)Não armazenado.Não armazenado.
XX (Pauli X)QkBitTerm_X0b0010 (2)
YY (Pauli Y)QkBitTerm_Y0b0011 (3)
ZZ (Pauli Z)QkBitTerm_Z0b0001 (1)
++\lvert+\rangle\langle+\rvert (projetor para o estado próprio positivo de X)QkBitTerm_Plus0b1010 (10)
\lvert-\rangle\langle-\rvert (projetor para o estado próprio negativo de X)QkBitTerm_Minus0b0110 (6)
rr\lvert r\rangle\langle r\rvert (projetor para o estado próprio positivo de Y)QkBitTerm_Right0b1011 (11)
ll\lvert l\rangle\langle l\rvert (projetor para o estado próprio negativo de Y)QkBitTerm_Left0b0111 (7)
00\lvert0\rangle\langle0\rvert (projetor para o estado próprio positivo de Z)QkBitTerm_Zero0b1001 (9)
11\lvert1\rangle\langle1\rvert (projetor para o estado próprio negativo de Z)QkBitTerm_One0b0101 (5)

Devido ao fato de permitir tanto os Paulis quanto seus projetores, o alfabeto permitido forma uma base supercompleta do espaço do operador. Isso significa que não há um somatório único para representar um determinado observável. Como consequência, a comparação requer mais cuidado e o uso do qk_obs_canonicalize em dois observáveis matematicamente equivalentes pode não resultar na mesma representação.

QkObs usa sua base particular supercompleta com o objetivo de tornar a "eficiência da medição" equivalente à "eficiência da representação". Por exemplo, o observável 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} pode ser medido com eficiência no hardware com medições simples de ZZ, mas só pode ser representado em termos de Paulis como (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, o que requer termos armazenados em 2n2^n. QkObs requer apenas um único termo para armazenar isso. A desvantagem disso é que não é prático pegar uma matriz arbitrária e encontrar a melhor representação QkObs . Normalmente, você desejará construir um QkObs diretamente, em vez de tentar se decompor em um.


Representação

A representação interna de um QkObs armazena apenas os operadores de qubit não idênticos. Isso torna significativamente mais eficiente a representação de observáveis, como nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; QkObs requer uma quantidade de memória linear no número total de qubits. Os termos são armazenados compactados, com espírito semelhante ao formato de linha esparsa compactada de matrizes esparsas. Nessa analogia, os termos da soma são as "linhas", e os termos do qubit são as "colunas", em que uma entrada ausente representa a identidade em vez de um zero. De forma mais explícita, a representação é composta por quatro matrizes contíguas:

Atributo acessível por
Duração
Descrição
qk_obs_coeffsttO multiplicador escalar complexo para cada termo.
qk_obs_bit_termsssCada um dos termos de um único qubit sem identidade para todos os operadores, em ordem. Elas correspondem à não identidade Ai(n)A^{(n)}_i na descrição da soma, em que as entradas são armazenadas na ordem crescente de ii primeiro, e na ordem crescente de nn dentro de cada termo.
qk_obs_indicesssO qubit correspondente ( nn ) para cada um dos termos de bit. QkObs exige que essa lista seja classificada por termos, e os algoritmos podem contar com a manutenção desse invariante.
qk_obs_boundariest+1t+1Os índices que dividem os termos de bits e os índices em termos completos. Para o termo número ii, seu coeficiente complexo é armazenado no índice i, e seus operadores de qubit único não idênticos e seus qubits correspondentes estão no intervalo [boundaries[i], boundaries[i+1]) nos termos e índices de bit, respectivamente. Os limites sempre têm um 0 explícito como seu primeiro elemento.

O parâmetro de comprimento tt é o número de termos na soma e pode ser consultado usando qk_obs_num_terms. O parâmetro ss é o número total de termos de um único qubit sem identidade e pode ser consultado usando qk_obs_len.

Como exemplos ilustrativos:

  • no caso de um operador zero, os limites têm comprimento 1 (um único 0) e todos os outros vetores são vazios.
  • no caso de um operador de identidade totalmente simplificado, os limites são {0, 0}, os coeficientes têm uma única entrada e os termos de bit e os índices são vazios.
  • para o operador Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1, os limites são {0, 2, 4}, os coeficientes são {1.0, -1.0}, os termos de bits são {QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X} e os índices são {0, 2, 1, 3}. O operador pode atuar em mais de quatro qubits, dependendo do número de qubits (consulte qk_obs_num_qubits). Observe que os termos e índices de um único bit são classificados em ordem ordenada termwise.

Esses casos não são especiais, são totalmente consistentes com as regras e não devem precisar de tratamento especial.

Ordenação canônica

Para qualquer observável matemático dado, há várias maneiras de representá-lo com QkObs. Por exemplo, o mesmo conjunto de termos de um único bit e seus índices correspondentes podem aparecer várias vezes no observável. Matematicamente, isso é equivalente a ter apenas um único termo com todos os coeficientes somados. Da mesma forma, os termos da soma em um QkObs podem estar em qualquer ordem e representar o mesmo observável, já que a adição é comutativa (embora a adição de ponto flutuante não seja associativa, o QkObs não garante a ordem da soma).

Essas duas categorias de degenerescência de representação podem fazer com que o operador de igualdade, qk_obs_equal, afirme que dois observáveis não são iguais, apesar de representarem o mesmo objeto. Nesses casos, pode ser conveniente definir alguma forma canônica que permita que os observáveis sejam comparados estruturalmente. Você pode colocar um QkObs em formato canônico usando a função qk_obs_canonicalize . A ordenação precisa dos termos na ordenação canônica não é especificada e pode mudar entre as versões do Qiskit. Na mesma versão do Qiskit, no entanto, você pode comparar dois observáveis estruturalmente, comparando suas formas simplificadas.

Nota

Se você quiser levar em conta a tolerância de ponto flutuante na comparação, é mais seguro usar uma receita como:

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;
}
Nota

A forma canônica produzida apenas pelo qk_obs_canonicalize não detectará universalmente todos os observáveis que são equivalentes devido ao alfabeto de base excessivamente completo.

Indexando

Os termos de soma observáveis individuais em QkObs podem ser acessados por meio de qk_obs_term e retornam objetos do tipo QkObsTerm. Esses termos contêm campos com o coeficiente do termo, seus termos de bit, índices e o número de qubits em que ele é definido. Juntamente com a informação do número de termos, você pode iterar sobre todos os termos observáveis como

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...
}
Aviso

O preenchimento de um QkObsTerm por meio do qk_obs_term fará referência aos dados do QkObs original. A modificação dos termos ou índices de bits alterará o observável e poderá deixá-lo em um estado incoerente.


Construção

QkObs pode ser construído inicializando um observável vazio (com qk_obs_zero) e adicionando termos iterativamente (com qk_obs_add_term). Como alternativa, um observável pode ser construído a partir de dados "brutos" (com qk_obs_new) se todos os dados internos forem especificados. Isso requer cuidado para garantir que os dados sejam coerentes e resultem em um observável válido.

Função
Resumo
qk_obs_zeroConstrua um observável vazio em um determinado número de qubits.
qk_obs_identityConstrua a identidade observável em um determinado número de qubits.
qk_obs_newConstrua um observável a partir das matrizes de dados brutos.

Manipulação matemática

QkObs suporta operações aritméticas fundamentais entre observáveis ou com escalares. Agora, você pode:

  • adicionar duas variáveis observáveis usando qk_obs_add e qk_obs_add_inplace
  • multiplicar por um número complexo com qk_obs_multiply e qk_obs_multiply_inplace
  • compor (multiplicar) dois observáveis via qk_obs_compose e qk_obs_compose_map
  • calcular left + scalar * right para duas variáveis observáveis e um escalar complexo com qk_obs_scaled_add e qk_obs_scaled_add_inplace

Funções

qk_obs_zero

QkObs *qk_obs_zero(uint32_t num_qubits)

Construa o observável zero (sem nenhum termo).

Exemplo

QkObs *zero = qk_obs_zero(100);

Parâmetros

  • num_qubits - O número de qubits em que o observável está definido.

Retorna

Um ponteiro para o observável criado.

qk_obs_identity

QkObs *qk_obs_identity(uint32_t num_qubits)

Construa o observável de identidade.

Exemplo

QkObs *identity = qk_obs_identity(100);

Parâmetros

  • num_qubits - O número de qubits em que o observável está definido.

Retorna

Um ponteiro para o observável criado.

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)

Construir um novo observável a partir de dados brutos.

Qualquer um dos argumentos de ponteiro pode ser NULL se e somente se seu comprimento correspondente for zero.

Exemplo

// 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, -1};
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
);

Segurança

O comportamento é indefinido se qualquer uma das condições a seguir for violada:

  • coeffs é um ponteiro para uma matriz QkComplex64 de comprimento num_terms
  • bit_terms é um ponteiro para uma matriz de elementos QkBitTerm válidos de comprimento num_bits
  • indices é um ponteiro para uma matriz uint32_t de comprimento num_bits, que é classificada por termos em ordem estritamente crescente, e cada elemento é menor que num_qubits
  • boundaries é um ponteiro para uma matriz size_t de comprimento num_terms + 1, que é classificada em ordem crescente, o primeiro elemento é 0 e o último elemento é menor que num_terms

Parâmetros

  • num_qubits - O número de qubits em que o observável está definido.
  • num_terms - O número de termos.
  • num_bits - O número total de termos de bits não idênticos.
  • coeffs - Um ponteiro para o primeiro elemento da matriz de coeficientes, que tem o comprimento num_terms.
  • bit_terms - Um ponteiro para o primeiro elemento da matriz de termos de bits, que tem comprimento num_bits.
  • indices - Um ponteiro para o primeiro elemento da matriz de índices, que tem o comprimento num_bits. Observe que, por período, eles devem ser classificados de forma incremental.
  • boundaries - Um ponteiro para o primeiro elemento da matriz de limites, que tem o comprimento num_terms + 1.

Retorna

Se os dados de entrada forem coerentes e a construção for bem-sucedida, o resultado será um ponteiro para o observável. Caso contrário, um ponteiro nulo é retornado.

qk_obs_free

void qk_obs_free(QkObs *obs)

Liberar o observável.

Exemplo

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

Segurança

O comportamento é indefinido se obs não for nulo ou um ponteiro válido para QkObs.

Parâmetros

  • obs - Um ponteiro para o observável a ser liberado.

qk_obs_add_term

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

Adicionar um termo ao observável.

Exemplo

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);

Segurança

O comportamento é indefinido se algum dos itens a seguir for violado:

  • obs é um ponteiro válido e não nulo para um QkObs
  • cterm é um ponteiro válido e não nulo para um QkObsTerm

Parâmetros

  • obs - Um ponteiro para o observável.
  • cterm - Um ponteiro para o termo a ser adicionado.

Retorna

Um código de saída. O endereço eletrônico é >0 se o termo for incoerente ou se a adição do termo falhar.

qk_obs_term

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

Obter um termo observável por referência.

Um QkObsTerm contém ponteiros para os índices e termos de bits no termo, que podem ser usados para modificar os dados internos do observável. Isso pode deixar o observável em um estado incoerente e deve ser evitado, a menos que se tome muito cuidado. Em geral, é mais seguro construir um novo observável em vez de tentar fazer modificações no local.

Exemplo

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);

Segurança

O comportamento é indefinido se qualquer um dos itens a seguir for violado

  • obs é um ponteiro válido e não nulo para um QkObs
  • out é um ponteiro válido e não nulo para um QkObsTerm

Parâmetros

  • obs - Um ponteiro para o observável.
  • index - O índice do termo a ser obtido.
  • out - Um ponteiro para um QkObsTerm usado para retornar o termo observável.

Retorna

Um código de saída.

qk_obs_num_terms

size_t qk_obs_num_terms(const QkObs *obs)

Obtenha o número de termos no observável.

Exemplo

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

O número de termos no observável.

qk_obs_num_qubits

uint32_t qk_obs_num_qubits(const QkObs *obs)

Obtém o número de qubits em que o observável está definido.

Exemplo

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

O número de qubits em que o observável é definido.

qk_obs_len

size_t qk_obs_len(const QkObs *obs)

Obtém o número de termos/índices de bits no observável.

Exemplo

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

O número de termos no observável.

qk_obs_coeffs

QkComplex64 *qk_obs_coeffs(QkObs *obs)

Obtém um ponteiro para os coeficientes.

Isso pode ser usado para ler e modificar os coeficientes do observável. O ponteiro resultante é válido para leitura de qk_obs_num_terms(obs) elementos de QkComplex64.

Exemplo

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);
}

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

Um ponteiro para os coeficientes.

qk_obs_indices

uint32_t *qk_obs_indices(QkObs *obs)

Obtém um ponteiro para os índices.

Isso pode ser usado para ler e modificar os índices do observável. O ponteiro resultante é válido para leitura em qk_obs_len(obs) elementos de tamanho uint32_t.

Exemplo

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);

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

Um ponteiro para os índices.

qk_obs_boundaries

size_t *qk_obs_boundaries(QkObs *obs)

Obter um ponteiro para os limites do termo.

Isso pode ser usado para ler e modificar os limites de termo do observável. O ponteiro resultante é válido para leitura em qk_obs_num_terms(obs) + 1 elementos de tamanho size_t.

Exemplo

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]);
}

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

Um ponteiro para os limites.

qk_obs_bit_terms

QkBitTerm *qk_obs_bit_terms(QkObs *obs)

Obtém um ponteiro para os termos de bits.

Isso pode ser usado para ler e modificar os termos de bits do observável. O ponteiro resultante é válido para leitura em qk_obs_len(obs) elementos de tamanho uint8_t.

Exemplo

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);

Segurança

O comportamento é indefinido obs se o ponteiro não for válido QkObs ou não for nulo, ou se forem gravados valores inválidos no ponteiro QkBitTerm resultante.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

Um ponteiro para os termos de bits.

qk_obs_multiply

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

Multiplique o observável por um coeficiente complexo.

Exemplo

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

Segurança

O comportamento é indefinido se qualquer um dos itens a seguir for violado

  • obs é um ponteiro válido e não nulo para um QkObs
  • coeff é um ponteiro válido e não nulo para um QkComplex64

Parâmetros

  • obs - Um ponteiro para o observável.
  • coeff - O coeficiente com o qual multiplicar o observável.

Retorna

Um ponteiro para o resultado obs * coeff.

qk_obs_multiply_inplace

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

Multiplique a variável observável no próprio local por um coeficiente complexo.

Exemplo

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

Segurança

O comportamento é indefinido se qualquer um dos itens a seguir for violado

  • obs é um ponteiro válido e não nulo para um QkObs
  • coeff é um ponteiro válido e não nulo para um QkComplex64

Parâmetros

  • obs - Um ponteiro para o observável.
  • coeff - O coeficiente com o qual multiplicar o observável.

qk_obs_add

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

Adicione dois observáveis.

Exemplo

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

Segurança

O comportamento é indefinido se left ou right não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • left - Um ponteiro para o observável esquerdo.
  • right - Um ponteiro para o observável correto.

Retorna

Um ponteiro para o resultado left + right.

qk_obs_add_inplace

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

Adicionar um observável a um já existente.

Exemplo

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

Segurança

O comportamento é indefinido se left ou right não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • left - Um ponteiro para o observável esquerdo.
  • right - Um ponteiro para o observável correto.

qk_obs_scaled_add

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

Adicione duas variáveis observáveis enquanto ajusta os coeficientes da variável à direita.

Exemplo

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);

Segurança

O comportamento é indefinido se left ou right não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • left - Um ponteiro para o observável esquerdo.
  • right - Um ponteiro para o observável correto.
  • fator – O fator pelo qual os coeficientes devem ser multiplicados.

Retorna

Um ponteiro de propriedade para o resultado left + factor * right.

qk_obs_scaled_add_inplace

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

Adicione um observável escalonado a um já existente.

Exemplo

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

Segurança

O comportamento é indefinido se left ou right não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • left - Um ponteiro para o observável esquerdo.
  • right - Um ponteiro para o observável correto.
  • fator – O fator pelo qual os coeficientes devem ser multiplicados.

qk_obs_compose

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

Compor (multiplicar) dois observáveis.

Exemplo

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

Segurança

O comportamento é indefinido se first ou second não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • primeiro - Um observável.
  • segundo - O outro observável.

Retorna

first.compose(second) que é igual ao observável result = second @ first, em termos da multiplicação da matriz @.

qk_obs_compose_map

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

Componha (multiplique) dois observáveis de acordo com uma ordem de qubit personalizada.

Notavelmente, isso permite a composição de dois observáveis de tamanhos diferentes.

Exemplo

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

Segurança

Para chamar essa função com segurança

  • first e second devem ser ponteiros válidos e não nulos para QkObs\ s
  • qargs deve apontar para uma matriz de uint32_t, legível para os elementos de qk_obs_num_qubits(second) (ou seja, o número de qubits em second)

Parâmetros

  • primeiro - Um observável.
  • segundo - O outro observável. O número de qubits deve corresponder ao comprimento de qargs.
  • qargs - Os argumentos do qubit especificam quais índices em first devem ser associados aos índices em second.

Retorna

first.compose(second) que é igual ao observável result = second @ first, em termos da multiplicação da matriz @.

qk_obs_apply_layout

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

Aplique um novo layout de qubit ao observável.

O layout é definido por uma matriz layout de novos índices, especificando que o qubit no índice atual i é rotulado novamente para o índice layout[i]. O número de qubits em que o observável atua pode ser estendido definindo um num_qubits maior do que o observável atual tem.

Exemplo

Essa interface permite rotular novamente e ampliar os índices de qubit:

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);

Em um fluxo de trabalho do compilador, essa função pode ser convenientemente usada para aplicar um QkTranspileLayout* obtido de uma passagem do transpilador, chamado transpile_layout no exemplo a seguir:

// 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);

Segurança

O comportamento é indefinido se obs não for um ponteiro válido e não nulo para QkObs ou se layout não for um ponteiro válido e não nulo para uma sequência de qk_obs_num_qubits(obs) elementos consecutivos de uint32_t.

Parâmetros

  • obs - Um ponteiro para o observável, esse observável será modificado no local em caso de sucesso. Verifique o código de saída para garantir que o layout foi aplicado corretamente.
  • layout - Um ponteiro para o layout. O ponteiro deve apontar para uma matriz para qk_obs_num_qubits(obs) elementos do tipo uint32_t. Cada elemento deve ter valores em [0, num_qubits).
  • num_qubits - O número de qubits de saída.

Retorna

Um código de saída.

  • QkExitCode_Success após o sucesso
  • QkExitCode_DuplicteIndexError se forem encontrados índices de qubit duplicados
  • QkExitCode_MismatchedQubits se num_qubits for menor que o número de qubits no observável
  • QkExitCode_IndexError para quaisquer outros erros de índice, como valores inválidos em layout.

qk_obs_canonicalize

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

Calcule a representação canônica do observável.

Exemplo

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

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.
  • tol - A tolerância abaixo da qual os coeficientes são considerados zero.

Retorna

A representação canônica do observável.

qk_obs_copy

QkObs *qk_obs_copy(const QkObs *obs)

Copie o observável.

Exemplo

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

Parâmetros

  • obs - Um ponteiro para o observável.

Retorna

Um ponteiro para uma cópia do observável.

qk_obs_equal

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

Compare dois observáveis para verificar a igualdade.

Observe que isso não compara a igualdade matemática, mas a igualdade de dados. Isso significa que dois observáveis podem representar o mesmo observável, mas não podem ser comparados como iguais.

Exemplo

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

Segurança

O comportamento é indefinido se obs ou other não forem ponteiros válidos e não nulos para QkObs\ s.

Parâmetros

  • obs - Um ponteiro para um observável.
  • other - Um ponteiro para outro observável.

Retorna

true se os observáveis forem iguais, false caso contrário.

qk_obs_str

char *qk_obs_str(const QkObs *obs)

Retorna uma representação em string de um QkObs.

Exemplo

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

Segurança

O comportamento é indefinido obs não é um ponteiro válido e não nulo para um QkObs.

A string não deve ser liberada com o C free normal; você deve usar qk_str_free para liberar a memória consumida pela String. Não chamar o endereço qk_str_free resultará em um vazamento de memória.

Não altere o comprimento da cadeia de caracteres depois que ela for retornada (escrevendo um byte nulo em algum lugar dentro da cadeia ou removendo o byte final), embora os valores possam ser alterados.

Parâmetros

  • obs - Um ponteiro para QkObs para obter a cadeia de caracteres.

Retorna

Um ponteiro para uma matriz de caracteres com terminação nula da representação de string para obs

qk_str_free

void qk_str_free(char *string)

Libera uma representação de string.

Segurança

O comportamento é indefinido se str não for um ponteiro retornado por qk_obs_str ou qk_obsterm_str.

Parâmetros

  • string - Um ponteiro para a representação da cadeia de caracteres retornada de qk_obs_str ou qk_obsterm_str.

qk_obs_to_python

PyObject *qk_obs_to_python(QkObs *obs)

Passe a propriedade de um QkObs objeto para Python.

Não é seguro usar o QkObs ponteiro após chamar esta função. Em particular, você não deve tentar apagá-lo ou liberá-lo. O chamador deve ser o proprietário do objeto QkObs, e não possuir uma referência emprestada (por exemplo, um objeto QkObs * recuperado de um retrieved from não qk_obs_borrow_from_python é de sua propriedade).

Segurança

O chamador deve estar conectado a um intérprete do tipo Python. O comportamento é indefinido se não obs for um ponteiro válido e diferente de nulo para um objeto inicializado e de propriedade do usuário QkObs.

Parâmetros

  • obs – O objeto em questão.

Retorna

Uma referência de propriedade do tipo Python ao objeto.

qk_obs_borrow_from_python

QkObs *qk_obs_borrow_from_python(PyObject *ob)

Recuperar um QkObs ponteiro de um objeto Python.

Isso utiliza uma referência de tipo Python e extrai o QkObs ponteiro correspondente, caso seja do tipo correto. O ponteiro retornado é obtido do ponteiro ob . Se o não PyObject for do tipo correto, o valor de retorno é NULL e o estado de exceção do interpretador do Python é definido.

Você deve estar conectado a um interpretador Python para chamar esta função.

Você também pode usar qk_obs_convert_from_python, que é, em termos lógicos, exatamente igual a esta função, mas pode ser usada diretamente como uma função “conversora” para a PyArg_Parse* família de funções conversoras do Python.

Segurança

O chamador deve estar conectado a um intérprete do tipo Python. O comportamento é indefinido se não ob for um ponteiro válido e diferente de nulo para um objeto Python.

Parâmetros

  • ob – Um objeto de empréstimo do tipo Python.

Retorna

Um ponteiro para o objeto nativo, ou NULL se o objeto Python for do tipo incorreto.

qk_obs_convert_from_python

int qk_obs_convert_from_python(PyObject *object, void *address)

Recuperar um QkObs ponteiro de um objeto Python.

Isso utiliza uma referência do tipo Python e extrai o QkObs ponteiro correspondente para address``,, caso seja do tipo correto. O ponteiro retornado é obtido do ponteiro object . Se o não PyObject for do tipo correto, o valor de retorno é 1, o estado de exceção do interpretador do Python é definido e address permanece inalterado.

Você deve estar conectado a um interpretador Python para chamar esta função.

Você também pode usar qk_obs_borrow_from_python, que é, na prática, exatamente o mesmo que isto, mas com uma sintaxe mais natural para uso direto.

Segurança

O chamador deve estar conectado a um intérprete do tipo Python. O comportamento é indefinido se não object for um ponteiro válido e diferente de nulo para um objeto Python, ou se não address for um ponteiro para dados graváveis do tipo correto.

Parâmetros

  • objeto – Um objeto Python obtido por empréstimo.
  • endereço – O local onde a saída deve ser gravada.

Retorna

1 em caso de sucesso, 0 em caso de falha.

Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.