Skip to main content
IBM Quantum Platform

QkObs

typedef struct QkObs QkObs

Un observable sobre bases Pauli que almacena sus datos en un formato de qubit disperso.


mathematics

Este observable representa una suma sobre cadenas de operadores de Pauli y proyectores de estados propios de Pauli, con cada término ponderado por algún número complejo. Es decir, el observable completo es

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

para números complejos cic_i y operadores single-qubit que actúan sobre qubit nn a partir de un alfabeto restringido Ai(n)A^{(n)}_i. La suma sobre ii es la suma de los términos individuales, y el producto tensorial produce las cadenas de operadores. El alfabeto de operadores de un solo qubit permitido del que se extraen los Ai(n)A^{(n)}_i son los operadores de Pauli y los operadores de proyección Pauli-eigen-estado. Explícitamente, estos son:

Operador
QkBitTerm
Valor numérico
II (identidad)No guardado.No guardado.
XX (Pauli X)QkBitTerm_X0b0010 (2)
YY (Pauli Y)QkBitTerm_Y0b0011 (3)
ZZ (Pauli Z)QkBitTerm_Z0b0001 (1)
++\lvert+\rangle\langle+\rvert (proyector a estado propio positivo de X)QkBitTerm_Plus0b1010 (10)
\lvert-\rangle\langle-\rvert (proyector a estado propio negativo de X)QkBitTerm_Minus0b0110 (6)
rr\lvert r\rangle\langle r\rvert (proyector a estado propio positivo de Y)QkBitTerm_Right0b1011 (11)
ll\lvert l\rangle\langle l\rvert (proyector a estado propio negativo de Y)QkBitTerm_Left0b0111 (7)
00\lvert0\rangle\langle0\rvert (proyector a estado propio positivo de Z)QkBitTerm_Zero0b1001 (9)
11\lvert1\rangle\langle1\rvert (proyector a estado propio negativo de Z)QkBitTerm_One0b0101 (5)

Debido a que se permiten tanto los Paulis como sus proyectores, el alfabeto permitido forma una base sobrecompleta del espacio de operadores. Esto significa que no existe una suma única para representar un observable dado. Como consecuencia, la comparación requiere un cuidado adicional y el uso de qk_obs_canonicalize en dos observables matemáticamente equivalentes podría no dar como resultado la misma representación.

QkObs utiliza su particular base sobrecompleta con el objetivo de hacer equivalente la "eficacia de la medición" a la "eficacia de la representación". Por ejemplo, el observable 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} puede medirse eficientemente en hardware con simples mediciones de ZZ, pero sólo puede representarse en términos de Paulis como (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, lo que requiere términos almacenados en 2n2^n. QkObs requiere un único término para almacenarlo. El inconveniente es que no resulta práctico tomar una matriz arbitraria y encontrar la mejor representación QkObs . Por lo general, querrá construir un QkObs directamente, en lugar de intentar descomponerlo en uno.


Representación

La representación interna de un QkObs almacena únicamente los operadores qubit no identitarios. Esto hace que sea significativamente más eficiente representar observables como nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; QkObs requiere una cantidad de memoria lineal en el número total de qubits. Los términos se almacenan comprimidos, de forma similar al formato de filas dispersas comprimido de las matrices dispersas. En esta analogía, los términos de la suma son las "filas", y los términos del qubit son las "columnas", donde una entrada ausente representa la identidad en lugar de un cero. Más explícitamente, la representación se compone de cuatro matrices contiguas:

Atributo accesible por
Longitud
Descripción
qk_obs_coeffsttEl multiplicador escalar complejo para cada término.
qk_obs_bit_termsssCada uno de los términos single-qubit no idénticos para todos los operadores, en orden. Corresponden a la no-identidad Ai(n)A^{(n)}_i en la descripción de la suma, donde las entradas se almacenan en orden creciente ii primero, y en orden creciente nn dentro de cada término.
qk_obs_indicesssEl qubit correspondiente ( nn ) para cada uno de los términos del bit. QkObs requiere que esta lista esté ordenada por términos, y los algoritmos pueden confiar en que esta invariante se mantenga.
qk_obs_boundariest+1t+1Los índices que dividen los términos e índices de bits en términos completos. Para el término número ii, su coeficiente complejo se almacena en el índice i, y sus operadores single-qubit no-idénticos y sus qubits correspondientes están en el rango [boundaries[i], boundaries[i+1]) en los términos e índices de bits, respectivamente. Los límites siempre tienen un 0 explícito como primer elemento.

El parámetro de longitud tt es el número de términos de la suma y puede consultarse mediante qk_obs_num_terms. El parámetro ss es el número total de términos single-qubit sin identidad y puede consultarse mediante qk_obs_len.

Como ejemplos ilustrativos:

  • en el caso de un operador cero, los límites son de longitud 1 (un único 0) y todos los demás vectores están vacíos.
  • en el caso de un operador de identidad totalmente simplificado, los límites son {0, 0}, los coeficientes tienen una sola entrada, y tanto los términos de bits como los índices están vacíos.
  • para el operador Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1, los límites son {0, 2, 4}, los coeficientes son {1.0, -1.0}, los términos de bits son {QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X} y los índices son {0, 2, 1, 3}. El operador puede actuar sobre más de cuatro qubits, dependiendo del número de qubits (véase qk_obs_num_qubits). Obsérvese que los términos e índices de un bit se ordenan por términos.

Estos casos no son especiales, son totalmente coherentes con las normas y no deberían necesitar un tratamiento especial.

Orden canónico

Para cualquier observable matemático dado, existen varias formas de representarlo con QkObs. Por ejemplo, el mismo conjunto de términos de un solo bit y sus índices correspondientes pueden aparecer varias veces en el observable. Matemáticamente, esto equivale a tener un único término con todos los coeficientes sumados. Del mismo modo, los términos de la suma en un QkObs pueden estar en cualquier orden mientras representan el mismo observable, ya que la suma es conmutativa (aunque mientras que la suma en coma flotante no es asociativa, QkObs no ofrece garantías sobre el orden de la suma).

Estas dos categorías de degeneración de la representación pueden hacer que el operador igualdad, qk_obs_equal, afirme que dos observables no son iguales, a pesar de representar el mismo objeto. En estos casos, puede ser conveniente definir alguna forma canónica que permita comparar estructuralmente los observables. Puede poner un QkObs en forma canónica utilizando la función qk_obs_canonicalize . El orden preciso de los términos en el orden canónico no está especificado, y puede cambiar entre versiones de Qiskit. Sin embargo, dentro de la misma versión de Qiskit, puedes comparar dos observables estructuralmente comparando sus formas simplificadas.

Nota

Si desea tener en cuenta la tolerancia de coma flotante en la comparación, lo más seguro es utilizar una receta 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

La forma canónica producida por qk_obs_canonicalize por sí sola no detectará universalmente todos los observables que son equivalentes debido al alfabeto de bases sobrecompleto.

Indexación

Se puede acceder a los términos de suma observables individuales en QkObs a través de qk_obs_term y devolver objetos de tipo QkObsTerm. Estos términos contienen campos con el coeficiente del término, sus términos de bits, índices y el número de qubits en los que está definido. Junto con la información del número de términos, puede iterar sobre todos los términos observables 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

Al rellenar un QkObsTerm a través de qk_obs_term se hará referencia a los datos del QkObs original. Modificar los términos de bits o los índices cambiará el observable y puede dejarlo en un estado incoherente.


Construcción

QkObs puede construirse inicializando un observable vacío (con qk_obs_zero) e iterativamente añadiendo términos (con qk_obs_add_term). Alternativamente, se puede construir un observable a partir de datos "brutos" (con qk_obs_new) si se especifican todos los datos internos. Para ello hay que tener cuidado de que los datos sean coherentes y den lugar a un observable válido.

Función
Resumen
qk_obs_zeroConstruir un observable vacío en un número dado de qubits.
qk_obs_identityConstruir el observable de identidad en un número dado de qubits.
qk_obs_newConstruir un observable a partir de las matrices de datos brutos.

Manipulación matemática

QkObs admite operaciones aritméticas fundamentales entre observables o con escalares. Puede:

  • añadir dos observables utilizando qk_obs_add y qk_obs_add_inplace
  • multiplicar por un número complejo con qk_obs_multiply y qk_obs_multiply_inplace
  • componer (multiplicar) dos observables a través de qk_obs_compose y qk_obs_compose_map
  • calcular left + scalar * right para dos observables y un escalar complejo con qk_obs_scaled_add y qk_obs_scaled_add_inplace

Funciones

qk_obs_zero

QkObs *qk_obs_zero(uint32_t num_qubits)

Construir el observable cero (sin términos).

Ejemplo

QkObs *zero = qk_obs_zero(100);

Parámetros

  • num_qubits - El número de qubits en los que se define el observable.

Devuelve

Un puntero al observable creado.

qk_obs_identity

QkObs *qk_obs_identity(uint32_t num_qubits)

Construye el observable de identidad.

Ejemplo

QkObs *identity = qk_obs_identity(100);

Parámetros

  • num_qubits - El número de qubits en los que se define el observable.

Devuelve

Un puntero al observable creado.

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 un nuevo observable a partir de datos brutos.

Cualquiera de los argumentos de tipo puntero puede serlo NULL si y solo si su longitud correspondiente es cero.

Ejemplo

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

Seguridad

El comportamiento es indefinido si se incumple alguna de las siguientes condiciones:

  • coeffs es un puntero a una matriz QkComplex64 de longitud num_terms
  • bit_terms es un puntero a una matriz de elementos válidos de QkBitTerm de longitud num_bits
  • indices es un puntero a una matriz uint32_t de longitud num_bits, que está ordenada por términos en estricto orden ascendente, y cada elemento es menor que num_qubits
  • boundaries es un puntero a una matriz size_t de longitud num_terms + 1, que está ordenada en orden ascendente, el primer elemento es 0 y el último elemento es menor que num_terms

Parámetros

  • num_qubits - El número de qubits en los que se define el observable.
  • num\terms - El número de términos.
  • num_bits - El número total de términos de bits no identificativos.
  • coeffs - Puntero al primer elemento de la matriz de coeficientes, cuya longitud es num_terms.
  • bit_terms - Puntero al primer elemento de la matriz de términos de bits, cuya longitud es num_bits.
  • indices - Un puntero al primer elemento de la matriz indices, que tiene la longitud num_bits. Tenga en cuenta que, por término, deben ordenarse de forma incremental.
  • boundaries - Puntero al primer elemento de la matriz boundaries, cuya longitud es num_terms + 1.

Devuelve

Si los datos de entrada eran coherentes y la construcción tuvo éxito, el resultado es un puntero al observable. En caso contrario, se devuelve un puntero nulo.

qk_obs_free

void qk_obs_free(QkObs *obs)

Libera lo observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido si obs no es null o un puntero válido a QkObs.

Parámetros

  • obs - Un puntero al observable a liberar.

qk_obs_add_term

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

Añade un término al observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido si se incumple alguna de las siguientes condiciones:

  • obs es un puntero válido y no nulo a un archivo QkObs
  • cterm es un puntero válido y no nulo a un archivo QkObsTerm

Parámetros

  • obs - Puntero al observable.
  • cterm - Un puntero al término a añadir.

Devuelve

Un código de salida. Esto es >0 si el término es incoherente o la adición del término falla.

qk_obs_term

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

Obtener un término observable por referencia.

Un QkObsTerm contiene punteros a los índices y términos de bits del término, que pueden utilizarse para modificar los datos internos del observable. Esto puede dejar el observable en un estado incoherente y debe evitarse, a menos que se tenga mucho cuidado. Generalmente es más seguro construir un nuevo observable en lugar de intentar modificaciones in situ.

Ejemplo

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

Seguridad

El comportamiento es indefinido si se incumple alguna de las siguientes condiciones

  • obs es un puntero válido y no nulo a un archivo QkObs
  • out es un puntero válido y no nulo a un archivo QkObsTerm

Parámetros

  • obs - Puntero al observable.
  • index - El índice del término a obtener.
  • out - Un puntero a QkObsTerm utilizado para devolver el término observable.

Devuelve

Un código de salida.

qk_obs_num_terms

size_t qk_obs_num_terms(const QkObs *obs)

Obtiene el número de términos del observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

El número de términos del observable.

qk_obs_num_qubits

uint32_t qk_obs_num_qubits(const QkObs *obs)

Obtiene el número de qubits en los que está definido el observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

El número de qubits en los que se define el observable.

qk_obs_len

size_t qk_obs_len(const QkObs *obs)

Obtiene el número de términos/índices de bits en el observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

El número de términos del observable.

qk_obs_coeffs

QkComplex64 *qk_obs_coeffs(QkObs *obs)

Obtener un puntero a los coeficientes.

Permite leer y modificar los coeficientes del observable. El puntero resultante es válido para leer qk_obs_num_terms(obs) elementos de QkComplex64.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

Un puntero a los coeficientes.

qk_obs_indices

uint32_t *qk_obs_indices(QkObs *obs)

Obtener un puntero a los índices.

Permite leer y modificar los índices del observable. El puntero resultante es válido para leer qk_obs_len(obs) elementos de tamaño uint32_t.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

Un puntero a los índices.

qk_obs_boundaries

size_t *qk_obs_boundaries(QkObs *obs)

Obtener un puntero a los límites del término.

Puede utilizarse para leer y modificar los límites de los términos del observable. El puntero resultante es válido para leer qk_obs_num_terms(obs) + 1 elementos de tamaño size_t.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

Un puntero a los límites.

qk_obs_bit_terms

QkBitTerm *qk_obs_bit_terms(QkObs *obs)

Obtener un puntero a los términos de bits.

Permite leer y modificar los términos de bits del observable. El puntero resultante es válido para leer qk_obs_len(obs) elementos de tamaño uint8_t.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs si el puntero no es válido QkObs o no es nulo, o si se escriben valores no válidos en el puntero QkBitTerm resultante.

Parámetros

  • obs - Puntero al observable.

Devuelve

Un puntero a los términos de bits.

qk_obs_multiply

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

Multiplica el observable por un coeficiente complejo.

Ejemplo

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

Seguridad

El comportamiento es indefinido si se incumple alguna de las siguientes condiciones

  • obs es un puntero válido y no nulo a un archivo QkObs
  • coeff es un puntero válido y no nulo a un archivo QkComplex64

Parámetros

  • obs - Puntero al observable.
  • coeff - Coeficiente por el que se multiplica el observable.

Devuelve

Un puntero al resultado obs * coeff.

qk_obs_multiply_inplace

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

Multiplica la variable observable in situ por un coeficiente complejo.

Ejemplo

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

Seguridad

El comportamiento es indefinido si se incumple alguna de las siguientes condiciones

  • obs es un puntero válido y no nulo a un archivo QkObs
  • coeff es un puntero válido y no nulo a un archivo QkComplex64

Parámetros

  • obs - Puntero al observable.
  • coeff - Coeficiente por el que se multiplica el observable.

qk_obs_add

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

Añade dos observables.

Ejemplo

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

Seguridad

El comportamiento es indefinido si left o right no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • left - Puntero al observable izquierdo.
  • right - Un puntero al observable derecho.

Devuelve

Un puntero al resultado left + right.

qk_obs_add_inplace

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

Añadir un observable a uno ya existente.

Ejemplo

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

Seguridad

El comportamiento es indefinido si left o right no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • left - Puntero al observable izquierdo.
  • right - Un puntero al observable derecho.

qk_obs_scaled_add

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

Añade dos observables y, al mismo tiempo, escala los coeficientes del de la derecha.

Ejemplo

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

Seguridad

El comportamiento es indefinido si left o right no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • left - Puntero al observable izquierdo.
  • right - Un puntero al observable derecho.
  • factor : el factor por el que se multiplican los coeficientes.

Devuelve

Un puntero propio al resultado left + factor * right.

qk_obs_scaled_add_inplace

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

Añadir un observable escalado a uno ya existente.

Ejemplo

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

Seguridad

El comportamiento es indefinido si left o right no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • left - Puntero al observable izquierdo.
  • right - Un puntero al observable derecho.
  • factor : el factor por el que se multiplican los coeficientes.

qk_obs_compose

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

Componer (multiplicar) dos observables.

Ejemplo

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

Seguridad

El comportamiento es indefinido si first o second no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • primero - Un observable.
  • segundo - El otro observable.

Devuelve

first.compose(second) que es igual al observable result = second @ first, en términos de la multiplicación matricial @.

qk_obs_compose_map

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

Componer (multiplicar) dos observables según un orden de qubit personalizado.

En particular, esto permite componer dos observables de diferente tamaño.

Ejemplo

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

Seguridad

Para llamar a esta función de forma segura

  • first y second deben ser punteros válidos y no nulos a QkObs\ s
  • qargs debe apuntar a una matriz de uint32_t, legible para qk_obs_num_qubits(second) elementos (lo que significa el número de qubits en second)

Parámetros

  • primero - Un observable.
  • segundo - El otro observable. El número de qubits debe coincidir con la longitud de qargs.
  • qargs - Los argumentos qubit especifican qué índices de first asociar con los de second.

Devuelve

first.compose(second) que es igual al observable result = second @ first, en términos de la multiplicación matricial @.

qk_obs_apply_layout

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

Aplicar una nueva disposición de qubits al observable.

La disposición se establece mediante una matriz layout de nuevos índices, especificando que el qubit en el índice actual i se reetiqueta en el índice layout[i]. El número de qubits sobre los que actúa el observable puede ampliarse estableciendo un num_qubits mayor que el que tiene el observable actual.

Ejemplo

Esta interfaz permite reetiquetar y ampliar los índices de los 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);

En un flujo de trabajo de compilador, esta función puede utilizarse convenientemente para aplicar un QkTranspileLayout* obtenido de un pase de transpilador, llamado transpile_layout en el siguiente ejemplo:

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

Seguridad

El comportamiento es indefinido si obs no es un puntero válido y no nulo a QkObs o si layout no es un puntero válido y no nulo a una secuencia de qk_obs_num_qubits(obs) elementos consecutivos de uint32_t.

Parámetros

  • obs - Un puntero al observable, este observable se modificará en su lugar en caso de éxito. Compruebe el código de salida para asegurarse de que el diseño se ha aplicado correctamente.
  • diseño - Un puntero al diseño. El puntero debe apuntar a una matriz a qk_obs_num_qubits(obs) elementos de tipo uint32_t. Cada elemento debe tener valores en [0, num_qubits).
  • num_qubits - El número de qubits de salida.

Devuelve

Un código de salida.

  • QkExitCode_Success tras el éxito
  • QkExitCode_DuplicteIndexError si se han encontrado índices de qubits duplicados
  • QkExitCode_MismatchedQubits si num_qubits es menor que el número de qubits del observable
  • QkExitCode_IndexError para cualquier otro error de índice, como valores no válidos en layout.

qk_obs_canonicalize

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

Calcular la representación canónica del observable.

Ejemplo

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

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.
  • tol - Tolerancia por debajo de la cual se considera que los coeficientes son cero.

Devuelve

La representación canónica del observable.

qk_obs_copy

QkObs *qk_obs_copy(const QkObs *obs)

Copia el observable.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

Parámetros

  • obs - Puntero al observable.

Devuelve

Un puntero a una copia del observable.

qk_obs_equal

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

Comparar dos observables para la igualdad.

Tenga en cuenta que no se compara la igualdad matemática, sino la igualdad de datos. Esto significa que dos observables pueden representar el mismo observable pero no compararse como iguales.

Ejemplo

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

Seguridad

El comportamiento es indefinido si obs o other no son válidos, punteros no nulos a QkObs\ s.

Parámetros

  • obs - Puntero a un observable.
  • other - Un puntero a otro observable.

Devuelve

true si los observables son iguales, false en caso contrario.

qk_obs_str

char *qk_obs_str(const QkObs *obs)

Devuelve una representación de cadena de un QkObs.

Ejemplo

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

Seguridad

El comportamiento es indefinido obs no es un puntero válido no nulo a QkObs.

La cadena no debe ser liberada con el free normal de C, debes usar qk_str_free para liberar la memoria consumida por la Cadena. Si no se llama a qk_str_free se producirá una fuga de memoria.

No cambie la longitud de la cadena después de que sea devuelta (escribiendo un byte nul en algún lugar dentro de la cadena o eliminando el último), aunque los valores pueden ser mutados.

Parámetros

  • obs - Puntero a QkObs para obtener la cadena.

Devuelve

Un puntero a una matriz de caracteres sin terminación de la representación de cadena para obs

qk_str_free

void qk_str_free(char *string)

Libera una representación de cadena.

Seguridad

El comportamiento es indefinido si str no es un puntero devuelto por qk_obs_str o qk_obsterm_str.

Parámetros

  • string - Un puntero a la representación de cadena devuelta desde qk_obs_str o qk_obsterm_str.

qk_obs_to_python

PyObject *qk_obs_to_python(QkObs *obs)

Pasa la propiedad de un QkObs objeto a « Python ».

No es seguro utilizar el QkObs puntero después de llamar a esta función. En particular, no debes intentar borrarlo ni liberarlo. El autor de la llamada debe ser el propietario del objeto QkObs, y no tener una referencia prestada (por ejemplo, un objeto QkObs * recuperado de no qk_obs_borrow_from_python es de su propiedad).

Seguridad

La persona que llama debe estar conectada a un intérprete de Python. El comportamiento es indefinido si no obs es un puntero válido y no nulo a un objeto inicializado y del que se tiene propiedad QkObs.

Parámetros

  • obs – El objeto en cuestión.

Devuelve

Una referencia de tipo « Python » al objeto.

qk_obs_borrow_from_python

QkObs *qk_obs_borrow_from_python(PyObject *ob)

Obtener un QkObs puntero de un objeto Python.

Esto toma prestada una referencia de tipo « Python » y extrae el QkObs puntero correspondiente, siempre que sea del tipo adecuado. El puntero devuelto se toma prestado del ob puntero. Si el PyObject tipo no es el correcto, el valor de retorno es NULL y se establece el estado de excepción del intérprete de Python.

Para llamar a esta función, debes estar conectado a un intérprete de Python.

También puedes utilizar qk_obs_convert_from_python, que lógicamente es exactamente igual que esta función, pero que se puede emplear directamente como función «convertidora» para la PyArg_Parse* familia de funciones de conversión de Python.

Seguridad

La persona que llama debe estar conectada a un intérprete de Python. El comportamiento es indefinido si no ob es un puntero válido y no nulo a un objeto Python.

Parámetros

  • ob : un objeto de tipo « Python » tomado de otro lenguaje.

Devuelve

Un puntero al objeto nativo, o bien, NULL si el objeto Python es de un tipo incorrecto.

qk_obs_convert_from_python

int qk_obs_convert_from_python(PyObject *object, void *address)

Obtener un QkObs puntero de un objeto Python.

Esto toma prestada una referencia de tipo « Python » y extrae el QkObs puntero correspondiente a address, siempre que sea del tipo correcto. El puntero devuelto se toma prestado del object puntero. Si no es PyObject del tipo correcto, el valor de retorno es 1, se establece el estado de excepción del intérprete de Python, y address no sufre cambios.

Para llamar a esta función, debes estar conectado a un intérprete de Python.

También puedes usar qk_obs_borrow_from_python, que, lógicamente, es exactamente lo mismo que esto, pero con una sintaxis más natural para su uso directo.

Seguridad

La persona que llama debe estar conectada a un intérprete de Python. El comportamiento es indefinido si no object es un puntero válido y no nulo a un objeto Python, o si no address es un puntero a datos modificables del tipo correcto.

Parámetros

  • objeto : un objeto de tipo Python tomado en préstamo.
  • dirección : la ubicación en la que se escribirá la salida.

Devuelve

1 si se realiza correctamente, 0 si falla.

¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.