Skip to main content
IBM Quantum Platform

QESEM: Una función Qiskit de Qedma

Consulte la referencia de la API

  • El código de esta página se ha desarrollado teniendo en cuenta los siguientes requisitos. Recomendamos utilizar estas versiones o posteriores.

    qiskit[all]~=2.5.0
    qiskit-ibm-runtime~=0.47.0
    
Nota

Las funciones Qiskit son una función experimental disponible únicamente para los usuarios de los planes IBM Quantum® Premium Plan, Flex Plan y On-Prem (a través de IBM Quantum Platform API). Se trata de versiones preliminares sujetas a cambios.


Visión general

Aunque las unidades de procesamiento cuántico han mejorado considerablemente en los últimos años, los errores debidos al ruido y las imperfecciones del hardware existente siguen siendo un reto fundamental para los desarrolladores de algoritmos cuánticos. A medida que el campo se acerca a los cálculos cuánticos a escala industrial que no pueden verificarse de forma clásica, las soluciones para cancelar el ruido con una precisión garantizada cobran cada vez más importancia. Para superar este reto, Qedma ha desarrollado Quantum Error Mitigation (QESEM), perfectamente integrado en IBM Quantum Platform como una función Qiskit.

Con QESEM, los usuarios pueden ejecutar sus circuitos cuánticos en QPU con ruido para obtener resultados de gran precisión y sin errores, con una sobrecarga de tiempo de la QPU muy eficiente, cercana a los límites fundamentales. Para lograrlo, QESEM utiliza un conjunto de métodos propios desarrollados por Qedma, destinados a la caracterización y la reducción de errores. Entre las técnicas de reducción de errores se incluyen la optimización de puertas lógicas, la transpilación sensible al ruido, la supresión de errores (ES) y la mitigación de errores no sesgada (EM). Gracias a esta combinación de métodos basados en la caracterización, los usuarios pueden obtener resultados fiables y sin errores para circuitos cuánticos genéricos de gran volumen, lo que abre las puertas a aplicaciones que de otro modo no serían posibles.

Para obtener una descripción completa de los componentes subyacentes, así como una demostración a escala industrial, consulte el artículo «Mitigación fiable y de alta precisión de errores para circuitos cuánticos a escala industrial ».


Descripción

Puede utilizar la función QESEM de Qedma para estimar y ejecutar fácilmente sus circuitos con supresión y mitigación de errores, consiguiendo mayores volúmenes de circuitos y mayores precisiones. Para utilizar QESEM, se proporciona un circuito cuántico, un conjunto de observables a medir, un objetivo de precisión estadística para cada observable y una QPU elegida. Antes de ejecutar el circuito con la precisión deseada, puede estimar el tiempo de QPU necesario basándose en un cálculo analítico que no requiere la ejecución del circuito. Una vez que estés satisfecho con la estimación de tiempo QPU, puedes ejecutar el circuito con QESEM.

Cuando ejecuta un circuito, QESEM ejecuta un protocolo de caracterización de dispositivos adaptado a su circuito, lo que proporciona un modelo de ruido fiable para los errores que se producen en el circuito. Basándose en la caracterización, QESEM implementa primero una transpilación sensible al ruido para mapear el circuito de entrada en un conjunto de qubits y puertas físicas, lo que minimiza el ruido que afecta al observable objetivo. Entre ellas se incluyen las puertas disponibles de forma nativa (CX/CZ en dispositivos de e IBM® ), así como puertas adicionales optimizadas por QESEM, que conforman el conjunto ampliado de puertas de QESEM. A continuación, QESEM ejecuta un conjunto de circuitos ES y EM basados en la caracterización en la QPU y recopila los resultados de las mediciones. A continuación, se someten a un procesamiento posterior clásico para proporcionar un valor esperado imparcial y una barra de error para cada observable, en función de la precisión solicitada.

Presentación de Qedma QESEM

Se ha demostrado que la QESEM proporciona resultados de gran precisión para una gran variedad de aplicaciones cuánticas y en los mayores volúmenes de circuitos que se pueden conseguir hoy en día. QESEM ofrece las siguientes funciones de cara al usuario, demostradas en la sección de pruebas comparativas que figura a continuación:

  • Precisión garantizada: QESEM genera estimaciones imparciales para los valores esperados de los observables. Su método EM cuenta con garantías teóricas que, junto con la caracterización de vanguardia de Qedma, aseguran que la mitigación converge hacia la salida del circuito sin ruido hasta alcanzar la precisión especificada por el usuario. A diferencia de muchos métodos heurísticos EM, que son propensos a errores sistemáticos o sesgos, la precisión garantizada de QESEM es esencial para asegurar resultados fiables en circuitos cuánticos genéricos y observables.
  • Escalabilidad a QPU grandes: el tiempo de QPU de QESEM depende del volumen de los circuitos, pero por lo demás es independiente del número de qubits. Qedma ha demostrado QESEM en los dispositivos cuánticos más grandes disponibles en la actualidad, incluidos los dispositivos Eagle de 127 qubits y Heron de 133 qubits de IBM Quantum.
  • Aplicación agnóstica: QESEM se ha demostrado en una variedad de aplicaciones, incluyendo la simulación hamiltoniana, VQE, QAOA, y la estimación de la amplitud. Los usuarios pueden introducir cualquier circuito cuántico y observable que deseen medir, y obtener resultados precisos y sin errores. Las únicas limitaciones vienen dictadas por las especificaciones del hardware y el tiempo asignado a la QPU, que determinan los volúmenes de circuito accesibles y las precisiones de salida. En cambio, muchas soluciones de reducción de errores son específicas de cada aplicación o implican heurísticas incontroladas, lo que las hace inaplicables a circuitos y aplicaciones cuánticos genéricos.
  • Conjunto de puertas ampliado: QESEM admite puertas de ángulo fraccionario y proporciona puertas de ángulo fraccionario optimizadas para Qedma ( Rzz(θ)Rzz(\theta) ) en dispositivos IBM Quantum Heron y Eagle. Este conjunto de puertas ampliado permite una compilación más eficiente y desbloquea volúmenes de circuitos hasta dos veces mayores en comparación con la compilación CX/CZ predeterminada.
  • Observables multibase: QESEM admite observables de entrada compuestos por muchas cadenas de Pauli no conmutativas, como los hamiltonianos genéricos. La elección de las bases de medición y la optimización de la asignación de recursos QPU (disparos y circuitos) se realiza entonces automáticamente por QESEM para minimizar el tiempo QPU requerido para la precisión solicitada. Esta optimización, que tiene en cuenta las fidelidades del hardware y las tasas de ejecución, permite ejecutar circuitos más profundos y obtener mayores precisiones.

Referencias comparativas

QESEM se ha probado en una amplia variedad de casos de uso y aplicaciones. Los siguientes ejemplos pueden ayudarle a evaluar qué tipos de cargas de trabajo puede ejecutar con QESEM.

Un factor de mérito clave para cuantificar la dureza tanto de la mitigación de errores como de la simulación clásica para un circuito y un observable dados es el volumen activo : el número de puertas CNOT que afectan al observable en el circuito. El volumen activo depende de la profundidad y anchura del circuito, del peso del observable y de la estructura del circuito, que determina el cono de luz del observable. Para más detalles, consulte la charla de la Cumbre Cuántica de 2024 IBM. QESEM proporciona un valor particularmente grande en el régimen de alto volumen, dando resultados fiables para circuitos y observables genéricos.

Volumen activo
Aplicación
Número de qubits
Dispositivo
Descripción del circuito
Precisión
Tiempo total
Uso del tiempo de ejecución
Circuito VQE8Águila ( r3 )21 capas totales, 9 bases de medición, 1D chain98 %35 min14 minutos
Kicked Ising28Águila ( r3 )3 capas únicas x 3 pasos, 2D topología heavy-hex97 %22 minutos4 minutos
Kicked Ising28Águila ( r3 )3 capas únicas x 8 pasos, 2D topología heavy-hex97 %116 min23 minutos
Simulación hamiltoniana trotterizada40Águila ( r3 )2 capas únicas x 10 pasos Trotter, 1D cadena97 %3 horas25 min
Simulación hamiltoniana trotterizada119Águila ( r3 )3 capas únicas x 9 pasos Trotter, 2D topología heavy-hex95%6.5 horas45 min
Kicked Ising136Garza ( r2 )3 capas únicas x 15 pasos, 2D topología heavy-hex99%52 min9 min

La precisión se mide aquí en relación con el valor ideal del observable: OidealϵOideal\frac{\langle O \rangle_{ideal} - \epsilon}{\langle O \rangle_{ideal}}, donde ' ϵ\epsilon ' es la precisión absoluta de la atenuación (fijada por la entrada del usuario), y Oideal\langle O \rangle_{ideal} es el observable en el circuito sin ruido. el "uso en tiempo de ejecución" mide el uso del benchmark en modo batch (suma sobre el uso de trabajos individuales), mientras que el "tiempo total" mide el uso en modo sesión (tiempo de muro del experimento), que incluye tiempos clásicos y de comunicación adicionales. QESEM está disponible para su ejecución en ambos modos, de modo que los usuarios puedan aprovechar al máximo sus recursos disponibles.

Los circuitos Kicked Ising de 28 qubits simulan el Cuasicristal de Tiempo Discreto estudiado por Shinjo et al. (véase arXiv 2403.16718 y Q2B24 Tokio ) en tres bucles conectados de ibm_kawasaki. Los parámetros del circuito tomados aquí son (θx,θz)=(0.9π,0)(\theta_x, \theta_z) = (0.9 \pi, 0), con un estado inicial ferromagnético ψ0=0n| \psi_0 \rangle = | 0 \rangle ^{\otimes n}. El observable medido es el valor absoluto de la magnetización M=128i=027ZiM = |\frac{1}{28} \sum_{i=0}^{27} \langle Z_i \rangle|. El experimento Kicked Ising a escala comercial se ejecutó en los 136 mejores qubits de ibm_fez; este punto de referencia concreto se ejecutó en el ángulo Clifford (θx,θz)=(π,0)(\theta_x, \theta_z) = (\pi, 0), en el que el volumen activo crece lentamente con la profundidad del circuito, lo que -junto con las altas fidelidades del dispositivo- permite una alta precisión en un tiempo de ejecución corto.

Los circuitos de simulación hamiltonianos trotterizados son para un modelo Ising de campo transversal en ángulos fraccionarios: (θzz,θx)=(π/4,π/8)(\theta_{zz}, \theta_x) = (\pi / 4, \pi /8) y (θzz,θx)=(π/6,π/8)(\theta_{zz}, \theta_x) = (\pi / 6, \pi / 8) correspondientemente (véase Q2B24 Tokio ). El circuito a escala comercial se ejecutó con los 119 mejores qubits de ibm_brisbane, mientras que el experimento de 40 qubits se ejecutó con la mejor cadena disponible. La precisión se indica para la magnetización; también se obtuvieron resultados de alta precisión para observables de mayor peso.

El circuito VQE se desarrolló junto con investigadores del Centro de Tecnología y Aplicaciones Cuánticas del Deutsches Elektronen-Synchrotron (DESY). En este caso, el observable objetivo era un hamiltoniano formado por un gran número de cadenas de Pauli no conmutativas, lo que pone de relieve el rendimiento optimizado de QESEM para observables multibase. La mitigación se aplicó a un ansatz optimizado de forma clásica; aunque estos resultados aún no se han publicado, se obtendrán resultados de la misma calidad para distintos circuitos con propiedades estructurales similares.


Cómo empezar

Autentíquese utilizando su clave API IBM Quantum Platform y seleccione la función QESEM Qiskit de la siguiente manera. (En este fragmento de código se da por hecho que ya has guardado tu cuenta en tu entorno local.)

import qiskit
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# verify that you have access to the function
catalog.list()
# load the function
qesem_function = catalog.load("qedma/qesem")

Ejemplos

Ejemplo de trabajo de estimación de tiempos

backend_nameLa tarea de estimación de tiempo resulta útil para calcular el tiempo de QPU necesario para un y un determinados pub . backend_name También se puede configurar con cualquier backend de simulador; por ejemplo, fake_fez.

QESEM utiliza un método EM cuasiprobabilístico basado en la caracterización. Este método conlleva una sobrecarga de tiempo de la QPU que varía aproximadamente de la siguiente manera:

TQPU=aeαIFVaϵ2+bT_{QPU} = a \frac{e^{\alpha IF\cdot V_a}}{\epsilon^2} + b

Donde VaV_a es el volumen activo del circuito, ϵ\epsilon es la precisión deseada y IFIF es la infidelidad de las puertas nativas.

Ten en cuenta que "estimate_time_only": "empirical" utiliza unos minutos de tiempo de QPU para calcular el tiempo necesario para el trabajo (si el backend es un dispositivo real; si se trata de un simulador, no se utiliza tiempo de QPU). Esto suele tardar unos 5 minutos, pero no más de 10 minutos. Si la infidelidad varía drásticamente entre la tarea de estimación empírica del tiempo y la tarea de mitigación, el tiempo de la QPU también variará drásticamente.

Para empezar, pruebe este ejemplo básico de estimación del tiempo de QPU necesario para ejecutar QESEM para un determinado pub:

backend_name = "fake_fez"

circ = qiskit.QuantumCircuit(5)
circ.cx(0, 1)
circ.cx(2, 3)
circ.cx(1, 2)
circ.cx(3, 4)

avg_magnetization = qiskit.quantum_info.SparsePauliOp.from_sparse_list(
    [("Z", [q], 1 / 5) for q in range(5)], num_qubits=5
)
other_observable = qiskit.quantum_info.SparsePauliOp.from_sparse_list(
    [("ZZ", [0, 1], 1.0), ("XZ", [1, 4], 0.5)], num_qubits=5
)

time_estimation_job = qesem_function.run(
    pubs=[(circ, [avg_magnetization, other_observable])],
    options={
        "estimate_time_only": "empirical",
    },
    backend_name=backend_name,  # example: "fake_fez", "ibm_fez"
)
time_estimate_result = (
    time_estimation_job.result()
)  # a list of results per pub (circuit)

El siguiente fragmento de código describe cómo obtener diferentes métricas de ejecución del trabajo de estimación de tiempo (estimate_time_only está configurado):

pub_result = time_estimate_result[0]

print(
    f"The estimated QPU time for mitigation for this PUB is: {pub_result.metadata['time_estimation_sec']}"
)
print(
    f"The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}"
)
print(
    f"Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}"
)
print(f"Total shots: {pub_result.metadata['total_shots']}")
print(f"Resource usage breakdown: {pub_result.metadata['resource_usage']}")

Output:

The estimated QPU time for mitigation for this PUB is: 300
The QPU time that this time estimation job took is (here it is 0 because we used fake_fez): 0
Gates fidelity measured during the experiment: {'CZ': 0.9951354916722668, 'ID1Q': 0.9991246627329172}
Total shots: 220000
Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 33.6066133165732, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 184.53575124032795, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}

Cuando se activa la estimación empírica del tiempo, QESEM ejecuta un pequeño número de circuitos para proporcionar una estimación más precisa del tiempo de la QPU. Los resultados de mitigación de estos circuitos están disponibles en el empirical_estimation_mitigation_results campo del trabajo.

Dado que estos resultados se han obtenido a partir de una muestra limitada de circuitos, su precisión es considerablemente menor que la de los resultados finales obtenidos tras completar el proceso de mitigación con QESEM. Sin embargo, cuando el circuito es pequeño o la precisión deseada es baja, las medidas de mitigación aplicadas durante la estimación empírica del tiempo pueden ser suficientes para alcanzar la precisión deseada, por lo que quizá no sea necesario llevar a cabo el proceso completo de mitigación.

El empirical_estimation_mitigation_results campo es una lista de PrimitiveResult objetos por cada parámetro de entrada. Si el circuito no está parametrizado, la lista tendrá una longitud de 1.

empirical_estimation_mitigation_results = time_estimate_result[0].metadata[
    "empirical_estimation_mitigation_results"
][0]  # a list per parameter
print("Partial results for the observables:")

print(
    f"    Mitigated expectation values: {empirical_estimation_mitigation_results.data.evs}"
)
print(
    f"    Mitigated error bars: {empirical_estimation_mitigation_results.data.stds}"
)
print(
    f"    Number of shots used for mitigation: {empirical_estimation_mitigation_results.metadata['mitigation_shots']}"
)
transpiled_circ = empirical_estimation_mitigation_results.metadata[
    "transpiled_circ"
]
print(f"    Qubit mapping: {transpiled_circ['qubit_maps']}")
print(
    f"    Number of measurement bases: {transpiled_circ['num_measurement_bases']}\n"
)

# results per obs
emp_obs_results = empirical_estimation_mitigation_results.metadata["results"][
    0
]
# print(f"Results for each observable: {results}")
print("Results for each observable:")

for i, (obs_array, result_dict) in enumerate(emp_obs_results):
    # obs_array, result_dict = results
    print(f"Observable {i+1}: {obs_array}")
    print(
        f"    QESEM mitigated value: {result_dict['qesem']['value']} \u00b1 {result_dict['qesem']['error_bar']}"
    )

Output:

Partial results for the observables:
    Mitigated expectation values: [1.00347302 1.00693905]
    Mitigated error bars: [0.00304061 0.00714276]
    Number of shots used for mitigation: 180000
    Qubit mapping: [[[0, 136], [1, 143], [2, 142], [3, 141], [4, 140]]]
    Number of measurement bases: 2

Results for each observable:
Observable 1: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
    QESEM mitigated value: 1.003473015776871 ± 0.0030406128032204015
Observable 2: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
    QESEM mitigated value: 1.0069390542613554 ± 0.0071427606736885925

Ejemplo de tarea de mitigación en QESEM

El siguiente ejemplo ejecuta un trabajo QESEM:

sample_job = qesem_function.run(
    pubs=[(circ, [avg_magnetization, other_observable])],
    backend_name=backend_name,  # example: "ibm_fez"
    # options = {
    #     "estimate_time_only": "empirical",
    #     "default_precision": 0.2,  # Default precision is applied to all pubs that don't have a precision specified, see API reference for more details
    #     "max_execution_time": 3600,  # You can specify a maximum QPU time in seconds, see API reference for more details
    #     "transpilation_level": "standard",  # "minimal_with_layout_opt" for minimal transpilation, see API reference for more details
    #     "parallel_execution": True,  # True for parallel execution, see API reference for more details
    # },
)

Para obtener una descripción detallada de cada campo de entrada y cada opción, consulta la referencia de la API de QESEM.

Puede utilizar las conocidas API sin servidor de Qiskit para comprobar el estado de su carga de trabajo Qiskit Function o devolver resultados:

# Print the ID so you can use it later, if necessary
print(sample_job.job_id)
print(sample_job.status())
sample_result = sample_job.result()

Output:

3ac6b2df-15b0-4dc0-8f48-cf14bd20a1c8
DONE

El siguiente fragmento de código muestra cómo recuperar los resultados de la mitigación y las métricas de ejecución. Estos contienen datos esenciales que permiten comprender mejor cómo influyen los distintos parámetros en la ejecución del QESEM. También puede resultar útil a la hora de redactar un trabajo basado en tu investigación.

for pub_idx, pub_result in enumerate(
    sample_result
):  # each element in the list is a result for a different pub, here we sent only one pub
    print(f"\nPUB {pub_idx}:")
    print(
        f"  The QPU time that this job took is (here it is 0 because we used fake_fez): {pub_result.metadata['total_qpu_time']}"
    )
    print(
        f"  Gates fidelity measured during the experiment: {pub_result.metadata['gate_fidelities']}"
    )
    print(f"  Total shots: {pub_result.metadata['total_shots']}")
    print(
        f"  Number of shots used for mitigation: {pub_result.metadata['mitigation_shots']}"
    )
    print(
        f"  Resource usage breakdown: {pub_result.metadata['resource_usage']}"
    )

Output:


PUB 0:
  The QPU time that this job took is (here it is 0 because we used fake_fez): 0.0
  Gates fidelity measured during the experiment: {'CZ': 0.9953704216147041, 'ID1Q': 0.9991834123567518}
  Total shots: 446000
  Number of shots used for mitigation: 194000
  Resource usage breakdown: {'RUNNING: MAPPING': {'CPU_TIME': 32.52745003718883, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 257.850521848537, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: EXECUTING_QPU': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}, 'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.0, 'GPU_TIME': 0.0, 'QPU_TIME': 0.0}}

En metadata["results"], los resultados se agrupan primero por instancia de circuito y, a continuación, por observable.

print("Full QESEM mitigation results:")

for pub_idx, pub_result in enumerate(sample_result):
    print(f"\nPUB {pub_idx}:")

    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata.get("noisy_results")
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")

    print("  Transpiled circuits:")
    for circ_idx, transpiled_circ in enumerate(
        pub_result.metadata["transpiled_circs"]
    ):
        print(f"    Circuit {circ_idx}:")
        # print(f"      Circuit: \n {transpiled_circ['circuit']}") # not printing it because it's long but you can see the transpiled circuit itself
        print(f"      Qubit mapping: {transpiled_circ['qubit_maps']}")
        print(
            f"      Measurement bases: {transpiled_circ['num_measurement_bases']}"
        )

    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Full QESEM mitigation results:

PUB 0:
  Mitigated expectation values: [1.00648343 1.00636289]
  Mitigated error bars: [0.00253812 0.00693586]
  Unmitigated expectation values: [0.98031429 0.96357143]
  Unmitigated error bars: [0.00124128 0.00578812]
  Transpiled circuits:
    Circuit 0:
      Qubit mapping: [[[0, 140], [1, 141], [2, 142], [3, 143], [4, 136]]]
      Measurement bases: 2
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 1.0064834305181962 ± 0.002538119914534849
        Unmitigated value: 0.9803142857142859 ± 0.0012412835813609938
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.0063628870614818 ± 0.006935859820870656
        Unmitigated value: 0.9635714285714285 ± 0.005788121870526659

Desglose de los principales resultados:

  • mitigated: el valor esperado de QESEM totalmente mitigado.
  • unmitigated: el resultado bruto del ruido físico sin mitigación de errores.

Resultados de la extrapolación heurística de QESEM

En una ejecución estándar de QESEM con un único precision flotante, los resultados también incluyen puntos de escalado de ruido disponibles automáticamente que se utilizan para la heurística de QESEM. Estos puntos se calculan sin recursos adicionales de la QPU.

La escala 1.0 representa el nivel de ruido del dispositivo físico con mitigación de lectura (REM), mientras que la escala 2.0 corresponde al punto complementario con amplificación de ruido, también con REM. Estos puntos se utilizan para obtener el qesem_heuristic resultado.

  • qesem_heuristic: una estimación de tipo ZNE calculada a partir de los datos disponibles, ajustados en función del ruido. Actualmente, se utiliza una extrapolación exponencial.
  • noise_scaling.results_with_REM: valores esperados en diferentes escalas de ruido, todos con mitigación de la lectura (REM).

Un detalle sutil pero importante es que el resultado de la escala 1.0 no es el mismo que el unmitigated resultado. Ambos se refieren al nivel de ruido del dispositivo físico, pero el punto de la escala 1.0 incluye la mitigación de la lectura, mientras que unmitigated no.

print("QESEM heuristic results:")

for pub_idx, pub_result in enumerate(sample_result):
    print(f"\nPUB {pub_idx}:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"  Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"    Observable {obs_idx}: {obs_array}")
            qesem_heuristic = result_dict["qesem_heuristic"][0]
            print("      QESEM heuristic:")
            print(
                f"        Value: {qesem_heuristic['value']} ± {qesem_heuristic['error_bar']}"
            )
            print(
                f"        Extrapolation: {qesem_heuristic['extrapolation']}"
            )
            print(
                f"        Scale factors: {qesem_heuristic['scale_factors']}"
            )
            noise_scaling = result_dict["noise_scaling"]
            print("      Noise scaling results:")
            print(
                f"        Scaling method: {noise_scaling['scaling_method']}"
            )
            print("        Results with Readout mitigation (REM):")
            for rem_result in sorted(
                (
                    item
                    for item in noise_scaling["results_with_REM"]
                    if item["scale"] != 0.0
                ),
                key=lambda item: item["scale"],
            ):
                print(
                    f"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}"
                )

Output:

QESEM heuristic results:

PUB 0:
  Circuit 0:
    Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
      QESEM heuristic:
        Value: 1.0008161638888535 ± 0.0038859458884403964
        Extrapolation: exponential
        Scale factors: [1.0, 2.0]
      Noise scaling results:
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 1.0: 0.9918395459270772 ± 0.0012565417579355634
          Scale factor 2.0: 0.982943441922748 ± 0.0028919278067695018
    Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
      QESEM heuristic:
        Value: 0.9960853148925298 ± 0.013811635038961175
        Extrapolation: exponential
        Scale factors: [1.0, 2.0]
      Noise scaling results:
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 1.0: 0.9902860583785115 ± 0.005921236914723409
          Scale factor 2.0: 0.984520565414274 ± 0.006909522262347639
Note

Los siguientes ejemplos se centran en entradas y resultados específicos de cada función, por lo que no muestran las métricas completas de ejecución en cada ocasión. Los metadatos de nivel superior mostrados anteriormente, como tiempo_total_qpu, gate_fidelities, total_tiros, medidas de mitigación y uso_de_recursos, también están disponibles para estos trabajos.

Algunas variables de los ejemplos anteriores, como el backend, los observables y los parámetros del circuito base, se reutilizan a continuación para mayor concisión.

Note

Todos los ejemplos siguientes también se pueden ejecutar con una estimación empírica del tiempo. Para activarla, introduce « "estimate_time_only": "empírico" » en las opciones de la función.

Ejemplo de circuito parametrizado

Muchos algoritmos evalúan el mismo circuito con distintos valores de los parámetros. Al enviar el circuito parametrizado como un único trabajo de QESEM, este puede compartir la caracterización y la calibración entre las distintas instancias del circuito, lo que puede reducir la sobrecarga de tiempo de la QPU en comparación con la ejecución de trabajos independientes.

Para enviar un circuito parametrizado es necesario utilizar el "minimal_with_layout_opt" nivel de transpilación. Los circuitos presentados en este nivel ya deben estar expresados utilizando las puertas básicas del backend, en función del backend en cuestión. En este nivel, QESEM mantiene la estructura enviada lo más cercana posible al circuito de entrada, respeta las barreras durante la estratificación (agrupación de operaciones en capas de puertas paralelas de dos qubits) y, además, gestiona automáticamente la asignación de hardware a qubits de alta fidelidad y la conectividad de los dispositivos.

En la práctica, esto significa que debes transpilar los circuitos a las puertas básicas del backend de destino antes de enviarlos. A continuación se muestra un ejemplo sencillo de transpilación de puertas básicas.

Actualmente, QESEM solo admite una variable observable por conjunto de parámetros. Las dos filas de parámetros que aparecen a continuación están agrupadas con los dos observables: la primera fila se mide con avg_magnetization, y la segunda fila se mide con other_observable.

# Transpile to the backend basis gates only. With minimal_with_layout_opt, QESEM handles hardware mapping/connectivity and observable layout internally.
from qiskit_ibm_runtime.fake_provider import FakeFez

backend = FakeFez()
basis = backend.operation_names
print(basis)

param0 = qiskit.circuit.Parameter("param0")
param1 = qiskit.circuit.Parameter("param1")
parametrized_circ = qiskit.QuantumCircuit(5)
parametrized_circ.rx(param0, 0)
parametrized_circ.rx(param1, 1)
parametrized_circ.cx(0, 1)
parametrized_circ.cx(2, 3)
parametrized_circ.cx(1, 2)
parametrized_circ.cx(3, 4)

parametrized_circ = qiskit.transpile(
    parametrized_circ, basis_gates=basis, optimization_level=1
)
parametrized_parameter_values = [[0.5, 0.1], [0.0, 0.6]]
parametrized_observables = [avg_magnetization, other_observable]

parametrized_job = qesem_function.run(
    pubs=[
        (
            parametrized_circ,
            parametrized_observables,
            parametrized_parameter_values,
            0.1,
        )
    ],
    backend_name=backend_name,
    options={
        "max_execution_time": 300,
        "transpilation_level": "minimal_with_layout_opt",
    },
)
print(parametrized_job.job_id)
print(parametrized_job.status())

Output:

d1b0e29b-196c-4896-aec6-44a268ebd874
DONE
parametrized_result = parametrized_job.result()
print("Parameterized circuit QESEM results:")

for pub_idx, pub_result in enumerate(parametrized_result):
    print(f"\nPUB {pub_idx}:")
    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each parameter value:")
    for param_idx, param_results in enumerate(pub_result.metadata["results"]):
        print(
            f"    Parameter set {param_idx}: {parametrized_parameter_values[param_idx]}"
        )
        for obs_idx, (obs_array, result_dict) in enumerate(param_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Parameterized circuit QESEM results:

PUB 0:
  Mitigated expectation values: [0.92392021 0.82517653]
  Mitigated error bars: [0.00565281 0.00616016]
  Unmitigated expectation values: [0.9028     0.78771429]
  Unmitigated error bars: [0.00335142 0.00925413]
  Results for each parameter value:
    Parameter set 0: [0.5, 0.1]
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.923920210615709 ± 0.005652811570890183
        Unmitigated value: 0.9028 ± 0.0033514176105045447
    Parameter set 1: [0.0, 0.6]
      Observable 0: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 0.8251765289285893 ± 0.006160161743353999
        Unmitigated value: 0.7877142857142858 ± 0.009254130564027902

Ejemplo de «Multi-pub»

La ejecución en varios pubs resulta útil cuando se desea ejecutar varios circuitos relacionados en un único trabajo de QESEM. Al igual que la ejecución parametrizada, esto puede reducir la sobrecarga, ya que QESEM puede compartir la caracterización y la calibración entre las distintas instancias del circuito, en lugar de repetirlas en trabajos independientes.

Esto resulta especialmente útil para circuitos con una estructura de capas compartidas, como las cargas de trabajo de tipo Trotter, en las que diferentes circuitos reutilizan las mismas capas únicas. En ese caso, realizarlos conjuntamente puede reducir el coste de la caracterización en comparación con los trabajos independientes de QESEM.

Los trabajos en varios bares requieren "transpilation_level": "minimal_with_layout_opt". Al igual que en el ejemplo parametrizado, los circuitos deben transpilarse a las puertas básicas del backend de destino antes de su envío. A continuación, QESEM se encarga internamente de la conectividad de los dispositivos, su disposición y su asignación a qubits de alta fidelidad.

Cada PUB que aparece a continuación contiene un circuito y los mismos dos observables utilizados anteriormente en el cuaderno, por lo que el resultado devuelto PrimitiveResult contiene uno PubResult por cada circuito de entrada.

En el ejemplo siguiente se utilizan dos circuitos de Trotter sencillos con el mismo patrón de capas: circ_a tiene una capa de Trotter, y circ_b repite el mismo patrón de capas dos veces. Esto deja clara la estructura compartida.

def make_trotter_circuit(num_qubits, num_layers, zz_angle=0.2, x_angle=0.1):
    trotter_circ = qiskit.QuantumCircuit(num_qubits)
    for _ in range(num_layers):
        for q in range(num_qubits):
            trotter_circ.rx(x_angle, q)
        trotter_circ.barrier()
        for q in range(0, num_qubits - 1, 2):
            trotter_circ.rzz(zz_angle, q, q + 1)
        trotter_circ.barrier()
        for q in range(1, num_qubits - 1, 2):
            trotter_circ.rzz(zz_angle, q, q + 1)
        trotter_circ.barrier()
    return trotter_circ


circ_a = make_trotter_circuit(num_qubits=5, num_layers=1)
circ_b = make_trotter_circuit(num_qubits=5, num_layers=2)
multi_pubs = [
    (
        qiskit.transpile(qci, basis_gates=basis, optimization_level=1),
        [avg_magnetization, other_observable],
    )
    for qci in [circ_a, circ_b]
]

multi_circ_job = qesem_function.run(
    pubs=multi_pubs,
    backend_name=backend_name,
    options={
        "max_execution_time": 300,
        "transpilation_level": "minimal_with_layout_opt",
        "default_precision": 0.1,
    },
)
print(multi_circ_job.job_id)
print(multi_circ_job.status())

Output:

e34565b8-7262-4133-a120-de42ce624a99
DONE
multi_circ_result = multi_circ_job.result()
print("Multi-pub QESEM results:")

for pub_idx, pub_result in enumerate(multi_circ_result):
    print(f"\nPUB {pub_idx}:")
    print(f"  Mitigated expectation values: {pub_result.data.evs}")
    print(f"  Mitigated error bars: {pub_result.data.stds}")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            print(
                f"        QESEM mitigated value: {result_dict['qesem']['value']} ± {result_dict['qesem']['error_bar']}"
            )
            print(
                f"        Unmitigated value: {result_dict['unmitigated']['value']} ± {result_dict['unmitigated']['error_bar']}"
            )

Output:

Multi-pub QESEM results:

PUB 0:
  Mitigated expectation values: [0.99502406 1.02209332]
  Mitigated error bars: [0.00483819 0.00707488]
  Unmitigated expectation values: [0.96934286 0.97271429]
  Unmitigated error bars: [0.00124855 0.00617294]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.9950240647925642 ± 0.004838188086259301
        Unmitigated value: 0.9693428571428573 ± 0.0012485470362492692
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.0220933230604674 ± 0.007074884384355636
        Unmitigated value: 0.9727142857142859 ± 0.006172939375512439

PUB 1:
  Mitigated expectation values: [0.98850017 1.02555188]
  Mitigated error bars: [0.0077912  0.01672652]
  Unmitigated expectation values: [0.93682857 0.95371429]
  Unmitigated error bars: [0.00156245 0.00665735]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        QESEM mitigated value: 0.988500171577252 ± 0.007791203181151346
        Unmitigated value: 0.9368285714285716 ± 0.001562451883089579
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        QESEM mitigated value: 1.02555188098689 ± 0.016726524388086233
        Unmitigated value: 0.9537142857142858 ± 0.006657345655544263

Ejemplo de ajuste de errores cuasiprobabilístico (QET)

El ajuste de errores cuasiprobabilístico (QET) requiere valores esperados en factores de escala de ruido seleccionados. Esto resulta útil para estudios de escalado de ruido personalizados y flujos de trabajo de extrapolación con ruido cero. La escala 1.0 es el nivel físico de ruido; los valores comprendidos entre 0.0 y 1.0 reducen parcialmente el ruido, mientras que los valores superiores 1.0 a lo amplifican.

Para utilizar QET con la función de Qiskit, pasa un diccionario como precisión de « PUB ». El diccionario asocia cada escala de ruido solicitada a su precisión objetivo. Los resultados del factor de escala devueltos se almacenan en noise_scaling.results_with_REM e incluyen la mitigación de la lectura. Por lo tanto, el punto de escala 1.0 no es idéntico al valor sin mitigación, ya que 1.0 incluye la mitigación de la lectura, mientras unmitigated que no la incluye.

Cuando se solicita una escala, QESEM también devuelve la escala complementaria en torno a 1.0 sin un consumo adicional de QPU. Por ejemplo, al solicitar 0.5 también se puede obtener 1.5, y al solicitar 1.3 también se puede obtener 0.7. No se garantiza la precisión de la escala complementaria.

noise_scale_precision = {0.5: 0.15, 1.3: 0.2}

qet_job = qesem_function.run(
    pubs=[
        (
            circ,
            [avg_magnetization, other_observable],
            None,
            noise_scale_precision,
        )
    ],
    backend_name=backend_name,
    options={"max_execution_time": 300},
)
print(qet_job.job_id)
print(qet_job.status())

Output:

8195fa58-f037-4651-8715-36ce1cdc5521
DONE
qet_result = qet_job.result()
print("QET noise-scaling results:")

for pub_idx, pub_result in enumerate(qet_result):
    print(f"\nPUB {pub_idx}:")
    noisy_results = pub_result.metadata["noisy_results"]
    print(f"  Unmitigated expectation values: {noisy_results.evs}")
    print(f"  Unmitigated error bars: {noisy_results.stds}")
    print("  Results for each observable:")
    for circ_idx, circ_results in enumerate(pub_result.metadata["results"]):
        print(f"    Circuit {circ_idx}:")
        for obs_idx, (obs_array, result_dict) in enumerate(circ_results):
            print(f"      Observable {obs_idx}: {obs_array}")
            noise_scaling = result_dict["noise_scaling"]
            print(
                f"        Scaling method: {noise_scaling['scaling_method']}"
            )
            print("        Results with Readout mitigation (REM):")
            for rem_result in sorted(
                (
                    item
                    for item in noise_scaling["results_with_REM"]
                    if item["scale"] != 0.0
                ),
                key=lambda item: item["scale"],
            ):
                print(
                    f"          Scale factor {rem_result['scale']}: {rem_result['value']} ± {rem_result['error_bar']}"
                )

Output:

QET noise-scaling results:

PUB 0:
  Unmitigated expectation values: [0.97822857 0.96171429]
  Unmitigated error bars: [0.00123812 0.00672958]
  Results for each observable:
    Circuit 0:
      Observable 0: ObservablesArray({'IIIIZ': 0.2, 'IIIZI': 0.2, 'IIZII': 0.2, 'IZIII': 0.2, 'ZIIII': 0.2}, shape=())
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 0.5: 0.9938730340199383 ± 0.0032116907357568275
          Scale factor 0.7: 0.9963976191853445 ± 0.00036300258869586616
          Scale factor 1.0: 0.9898115079506586 ± 0.0012525947426560995
          Scale factor 1.3: 0.9864667065580341 ± 0.002633221613518526
          Scale factor 1.5: 0.9838755527197551 ± 0.002948417797996015
      Observable 1: ObservablesArray({'IIIZZ': 1.0, 'ZIIXI': 0.5}, shape=())
        Scaling method: QESEM
        Results with Readout mitigation (REM):
          Scale factor 0.5: 1.0006538544450332 ± 0.002121742014777343
          Scale factor 0.7: 1.0004159801523036 ± 0.0021671375357823794
          Scale factor 1.0: 0.9898058846339917 ± 0.00690183710903159
          Scale factor 1.3: 0.9948946719997267 ± 0.002146532859610311
          Scale factor 1.5: 0.9927220368192772 ± 0.0020875057190323882

Obtener mensajes de error

Si el estado de tu carga de trabajo es ERROR, utiliza job.result() para obtener el mensaje de error de la siguiente manera:

# Get the result and truncate for readability
result = sample_job.result()
result_str = str(result)
max_length = 500  # Adjust this value as necessary

if len(result_str) > max_length:
    truncated = (
        result_str[:max_length]
        + f"... (truncated {len(result_str) - max_length} characters)"
    )
else:
    truncated = result_str

print(truncated)

Output:

PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(2,), dtype=float64>), stds=np.ndarray(<shape=(2,), dtype=float64>), shape=(2,)), metadata={'gate_fidelities': {'CZ': 0.9979444718552628, 'ID1Q': 0.9991994239814883}, 'total_shots': 498600, 'mitigation_shots': 223400, 'transpiled_circs': [{'circuit': 'OPENQASM 3.0;\ninclude "stdgates.inc";\nbit[76] c0;\nqubit[76] q0;\nrx(0) q0[54];\nrx(0) q0[59];\nrx(0) q0[75];\nrz(pi/2) q0[54];\nrz(pi/2) q0[59];\nrz(pi/2) q0[75];\nrx(pi/2) q0[54];\nr... (truncated 3771 characters)

Obtener soporte

El equipo de asistencia de Qedma está aquí para ayudarle Si tiene algún problema o pregunta sobre el uso de la función Qiskit de QESEM, no dude en ponerse en contacto con nosotros. Nuestro amable y experto personal de asistencia está a su disposición para ayudarle con cualquier duda o consulta técnica que pueda tener.

Puede enviarnos un correo electrónico a [email protected] si necesita ayuda. Por favor, incluya tantos detalles como sea posible sobre el problema que está experimentando para ayudarnos a proporcionar una respuesta rápida y precisa. También puede ponerse en contacto con su representante POC de Qedma por correo electrónico o por teléfono.

Para ayudarnos a atenderle con mayor eficacia, le rogamos que nos facilite la siguiente información cuando se ponga en contacto con nosotros:

  • Descripción detallada del problema
  • ID de trabajo
  • Cualquier mensaje o código de error relevante

Nos comprometemos a proporcionarle una asistencia rápida y eficaz para garantizarle la mejor experiencia posible con nuestra función Qiskit.

Siempre buscamos mejorar nuestro producto y agradecemos sus sugerencias Si tiene alguna idea sobre cómo podemos mejorar nuestros servicios o funciones que le gustaría ver, envíenos sus comentarios a [email protected].


Próximos pasos

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