Skip to main content
IBM Quantum Platform

Comprender las opciones de «capa abierta» frente a «capa cerrada» y su efecto en la construcción de subespacios

En esta guía, mostraremos cómo elegir las dimensiones del subespacio en el qiskit_addon_sqd paquete para procesar posteriormente muestras cuánticas utilizando la técnica de recuperación de configuración autoconsistente.

Y lo que es más importante, esta guía también destaca algunas diferencias en el comportamiento de la construcción del subespacio cuando se ejecuta en open_shell = False los modos o open_shell = True :

  • open_shell = False solo funciona cuando el número de electrones en fase de aceleración y de desaceleración es el mismo.

  • open_shell = True Debe utilizarse cuando el número de electrones en fase de aceleración y de desaceleración es diferente. También se puede utilizar cuando el número de electrones en estado de aceleración y de desaceleración es el mismo. Sin embargo, en este último caso, existe una diferencia en el tamaño de los subespacios generados entre open_shell = False y open_shell = True, tal y como se explica en esta guía.

NOTA: Algunas de las manipulaciones de la configuración electrónica (cadena de bits) de este paquete tienen como objetivo preservar la simetría de espín total S2S^2. Los solucionadores estándar de la Interacción de Configuración Seleccionada (SCI) no pueden imponer exactamente la conservación de S2S^2. Por consiguiente, lo hacen, aproximadamente, mediante un multiplicador de Lagrange.

La elección de las configuraciones electrónicas que se introducen en el solucionador de estados propios también puede tener un gran impacto en la conservación del espín. Por ejemplo, en un sistema (2 electrones, 2 orbitales), se puede muestrear la configuración 1001|1001\rangle (que presenta una única excitación de espín hacia arriba sobre el estado RHF 0101|0101\rangle ), la cual es una combinación lineal de los estados de singulete y triplete de capa abierta, respectivamente (1001±0110)/2(|1001\rangle ± |0110\rangle) /\sqrt{2}. Si no se incluye la configuración |0110⟩, no es posible construir ninguna de las funciones propias del espín total, lo que da lugar a contaminación o redundancia de espín (la configuración |1001⟩ está incluida en un cálculo de CI, pero tiene coeficiente 0 en el vector CI). Dado que en el ordenador cuántico se genera una única muestra 1001|1001\rangle, así es como el sqd paquete gestiona esta situación:

  • open_shell = False:

    1. La cadena de bits « 10011001 » se divide en dos partes, que representan las configuraciones de «spin-up» y «spin-down»: « 1010 » (arriba) y « 0101 » (abajo).

    2. Se ha elaborado la lista de configuraciones únicas con polarización de espín: U=[01,10]\mathcal{U} = [01, 10].

    3. A continuación, consideramos todas las combinaciones posibles de elementos de la función de U\mathcal{U} para formar la base: {0101,0110,1001,1010}\left \{ |0101\rangle, |0110\rangle , |1001\rangle , |1010\rangle \right \}, que contiene los estados de singulete y de triplete.

  • open_shell = True:

    1. A diferencia de lo que open_shell = False ocurre en ese caso, no combinamos las mitades de la cadena de bits para formar la base.

De carcasa cerrada

Este ejemplo muestra cómo se manipulan las cadenas de bits en un sistema (de 2 electrones y 4 orbitales).

# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = False

Especifica manualmente un diccionario de resultados de medición:

counts_dict = {
    "00010010": 1 / 2.0 - 0.01,
    "01001000": 1 / 2.0 - 0.01,
    "00010001": 0.02,
}

Transforma los recuentos dict en una matriz de cadenas de bits y en una matriz de probabilidades para su posterior procesamiento:

from qiskit_addon_sqd.counts import counts_to_arrays

# Convert counts into bitstring and probability arrays
bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)
print(bitstring_matrix_full)
print(probs_arr_full)

Output:

[[False False False  True False False  True False]
 [False  True False False  True False False False]
 [False False False  True False False False  True]]
[0.49 0.49 0.02]

Realizar un submuestreo de un único lote de tamaño dos:

  • n_batches = 1: Número de lotes de configuraciones utilizados por las diferentes llamadas al solucionador de estados propios
  • samples_per_batch = 2: Número de configuraciones únicas que se deben incluir en cada lote
from qiskit_addon_sqd.subsampling import postselect_and_subsample

n_batches = 1
samples_per_batch = 2

# seed for random number generator
rand_seed = 48

# Generate the batches
batches = postselect_and_subsample(
    bitstring_matrix_full,
    probs_arr_full,
    hamming_right=num_elec_a,
    hamming_left=num_elec_b,
    samples_per_batch=samples_per_batch,
    num_batches=n_batches,
    rand_seed=rand_seed,
)

print(batches[0])

Output:

[[False False False  True False False  True False]
 [False  True False False  True False False False]]

Obtener la representación decimal de las cadenas de bits de «spin-up» y «spin-down» utilizadas por el solucionador de estados propios.

El primer elemento de la tupla corresponde a la representación decimal de las configuraciones de espín hacia arriba, mientras que el segundo elemento de la tupla corresponde a la representación decimal de las configuraciones de espín hacia abajo:

from qiskit_addon_sqd.fermion import bitstring_matrix_to_ci_strs

ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)
print(ci_strs)

Output:

(array([1, 2, 4, 8], dtype=int64), array([1, 2, 4, 8], dtype=int64))

Cabe señalar que, aunque el número de muestras por lote es dos, y las cadenas de bits muestreadas son: 0001001000010010 y 0100100001001000, se generan cuatro configuraciones electrónicas por especie de espín. En este caso, el conjunto de configuraciones únicas con polarización de espín viene dado por:

U={0001,0010,0100,1000}\mathcal{U} = \{ 0001, 0010, 0100, 1000 \}

cuya representación decimal base-10 es

U10={1,2,4,8}\mathcal{U}_{10} = \{ 1, 2, 4, 8 \}

Base del subespacio:

El solucionador de estados propios toma todos los pares posibles de cadenas de bits de espín hacia arriba y espín hacia abajo para construir la base B\mathcal{B} del subespacio:

  • Elemento 1: 00010001|00010001\rangle

  • Elemento 2: 00010010|00010010\rangle

  • Elemento 3: 00010100|00010100\rangle

  • Elemento 4: 00011000|00011000\rangle

  • Elemento 5: 00100001|00100001\rangle

  • Elemento 6: 00100010|00100010\rangle

  • Elemento 7: 00100100|00100100\rangle

  • Elemento 8: 00101000|00101000\rangle

  • Elemento 9: 01000001|01000001\rangle

  • Elemento 10: 01000010|01000010\rangle

  • Elemento 11: 01000100|01000100\rangle

  • Elemento 12: 01001000|01001000\rangle

  • Elemento 13: 10000001|10000001\rangle

  • Elemento 14: 10000010|10000010\rangle

  • Elemento 15: 10000100|10000100\rangle

  • Elemento 16: 10001000|10001000\rangle

ci_strs_up, ci_strs_dn = ci_strs

print("Basis elements of the subspace:")

for ci_str_up in ci_strs_up:
    for ci_str_dn in ci_strs_dn:
        format_name = "{0:0" + str(num_orbitals) + "b}"
        print(
            "|"
            + format_name.format(ci_str_up)
            + format_name.format(ci_str_dn)
            + ">"
        )

Output:

Basis elements of the subspace:
|00010001>
|00010010>
|00010100>
|00011000>
|00100001>
|00100010>
|00100100>
|00101000>
|01000001>
|01000010>
|01000100>
|01001000>
|10000001>
|10000010>
|10000100>
|10001000>

La dimensión del subespacio tiene como límite superior : 22 \cdot (samples_per_batch) 2^2.

De carcasa abierta

Este ejemplo muestra cómo se manipulan las cadenas de bits en un sistema (de 2 electrones y 4 orbitales).

# Specify molecule properties
num_orbitals = 4
num_elec_a = num_elec_b = 1
open_shell = True

Especifica manualmente un diccionario de resultados de medición:

counts_dict = {
    "00010010": 1 / 2.0 - 0.01,
    "01001000": 1 / 2.0 - 0.01,
    "00010001": 0.02,
}

Transforma los recuentos dict en una matriz de cadenas de bits y en una matriz de probabilidades para su posterior procesamiento:

# Convert counts into bitstring and probability arrays
bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)
print(bitstring_matrix_full)
print(probs_arr_full)

Output:

[[False False False  True False False  True False]
 [False  True False False  True False False False]
 [False False False  True False False False  True]]
[0.49 0.49 0.02]

Realizar un submuestreo de un único lote de tamaño dos:

  • n_batches = 1: Número de lotes de configuraciones utilizados por las diferentes llamadas al solucionador de estados propios
  • samples_per_batch = 2: Número de configuraciones únicas que se deben incluir en cada lote
n_batches = 1
samples_per_batch = 2

# seed for random number generator
rand_seed = 48

# Generate the batches
batches = postselect_and_subsample(
    bitstring_matrix_full,
    probs_arr_full,
    hamming_right=num_elec_a,
    hamming_left=num_elec_b,
    samples_per_batch=samples_per_batch,
    num_batches=n_batches,
    rand_seed=rand_seed,
)

print(batches[0])

Output:

[[False False False  True False False  True False]
 [False  True False False  True False False False]]

Obtener la representación decimal de las cadenas de bits de «spin-up» y «spin-down» utilizadas por el solucionador de estados propios.

El primer elemento de la tupla corresponde a la representación decimal de las configuraciones de espín hacia arriba, mientras que el segundo elemento de la tupla corresponde a la representación decimal de las configuraciones de espín hacia abajo:

ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)
print(ci_strs)

Output:

(array([2, 8], dtype=int64), array([1, 4], dtype=int64))

Si especificamos que open_shell = True, no incluimos todas las semicadenas de bits únicas como configuraciones de «spin-up» y «spin-down», lo que da lugar a una base más reducida que cuando se especifica open_shell = False.

Base del subespacio:

El solucionador de estados propios toma todos los pares posibles de cadenas de bits de espín hacia arriba y espín hacia abajo para construir la base B\mathcal{B} del subespacio:

  • Elemento 1: 00010010|00010010\rangle

  • Elemento 2: 00011000|00011000\rangle

  • Elemento 3: 01000010|01000010\rangle

  • Elemento 4: 01001000|01001000\rangle

ci_strs_up, ci_strs_dn = ci_strs

print("Basis elements of the subspace:")

for ci_str_up in ci_strs_up:
    for ci_str_dn in ci_strs_dn:
        format_name = "{0:0" + str(num_orbitals) + "b}"
        print(
            "|"
            + format_name.format(ci_str_up)
            + format_name.format(ci_str_dn)
            + ">"
        )

Output:

Basis elements of the subspace:
|00100001>
|00100100>
|10000001>
|10000100>

La dimensión del subespacio tiene como límite superior : (samples_per_batch) 2^2.

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