Uso de diferentes SDK e IDE con el estimador de recursos

En este artículo, aprenderá a trabajar con el estimador de recursos de Azure Quantum mediante distintos SDK y entornos de desarrollo. Cada ejemplo calcula y analiza las estimaciones de recursos físicos de un programa cuántico destinado a un equipo cuántico tolerante a errores.

Prerrequisitos

Ejecución del estimador de recursos

El estimador de recursos es un destino del proveedor de computación cuántica de Microsoft. El uso del estimador de recursos es exactamente el mismo que enviar un trabajo con otros destinos de proveedor de software y hardware en Azure Quantum: defina el programa, establezca un destino y envíe el trabajo para su cálculo. El target_id del estimador de recursos es microsoft.estimator.

Al establecer el destino, puede proporcionar parámetros opcionales adicionales, como el tipo de cúbit, un tiempo de puerta de cúbit, etc. El estimador de recursos devuelve una salida detallada que se puede representar visualmente o analizar mediante programación. Para obtener más información sobre los parámetros de entrada y salida, consulte Personalización de las estimaciones de recursos en las características de la máquina.

  • Tipo de trabajo: simulación (estimación)
  • Id. de proveedor: microsoft
  • Id. de destino: microsoft.estimator

Estimación de recursos con Q# y Python

En este ejemplo, creará un multiplicador y calculará sus costos en un equipo cuántico tolerante a errores.

Creación de un nuevo cuaderno en el área de trabajo

  1. Inicie sesión en Azure Portal y seleccione el área de trabajo del paso anterior.
  2. En la hoja de la izquierda, seleccione Cuadernos.
  3. Haga clic en Mis cuadernos y, luego, en Agregar nuevo.
  4. En Tipo de kernel, seleccione IPython.
  5. Escriba un nombre para el archivo y haga clic en Crear archivo.

Cuando se abre el nuevo cuaderno, crea automáticamente el código de la primera celda, en función de la información de suscripción y del área de trabajo.

from azure.quantum import Workspace
workspace = Workspace (
    subscription_id = <your subscription ID>, 
    resource_group = <your resource group>,   
    name = <your workspace name>,          
    location = <your location>        
    )

Carga de las importaciones necesarias

Deberá importar algunos módulos. Importe el Microsoft.Quantum.Numerics paquete necesario para este algoritmo de ejemplo y seleccione el Estimador de recursos como destino.

Haga clic en + Código para agregar una nueva celda y, a continuación, agregue y ejecute el código siguiente:

import qsharp
qsharp.packages.add("Microsoft.Quantum.Numerics") # To create the multiplier for this example
qsharp.azure.target("microsoft.estimator") # To set Resource Estimator as target

Creación del algoritmo cuántico

A continuación, cree un multiplicador mediante la operación MultiplicarI . Puede configurar el tamaño del multiplicador con un bitwidth parámetro . La operación tendrá dos registros de entrada, cada uno de los tamaños del especificado bitwidthy un registro de salida que sea el doble del tamaño del especificado bitwidth.

Haga clic en + Código para agregar una nueva celda y agregue el siguiente código de Q# mediante el comando mágico %%qsharp.

%%qsharp

open Microsoft.Quantum.Arithmetic;

operation EstimateMultiplication(bitwidth : Int) : Unit {
    use factor1 = Qubit[bitwidth];
    use factor2 = Qubit[bitwidth];
    use product = Qubit[2 * bitwidth];
    
    MultiplyI(LittleEndian(factor1), LittleEndian(factor2), LittleEndian(product));
}

Estimación del algoritmo cuántico

Para calcular una operación mediante el estimador de recursos, la operación no puede tomar ningún argumento de entrada y debe tener un Unit valor devuelto. Puede crear una nueva instancia para un bitwidth específico, por ejemplo 8 , en este caso.

%%qsharp

operation EstimateMultiplication8() : Unit {
    EstimateMultiplication(8);
}

Importante

Para enviar una operación de Q# al estimador de recursos, la operación no puede tomar ningún argumento de entrada y debe tener un Unit valor devuelto.

Ahora, calcule los recursos físicos de esta operación con las suposiciones predeterminadas. Puede enviar la operación al destino estimador de recursos mediante la qsharp.azure.execute función .

result = qsharp.azure.execute(EstimateMultiplication8)
result

Esto crea una tabla que muestra los recuentos de recursos físicos generales. Puede inspeccionar los detalles de costos contrayendo los grupos, que tienen más información. Por ejemplo, si contrae el grupo Parámetros cuánticos lógicos , puede ver más fácilmente que la distancia del código de corrección de errores es 13.

Parámetro de cúbit lógico Valor
Esquema QEC surface_code
Distancia del código 13
Cúbits físicos 338
Tiempo de ciclo lógico 5us 200ns
Frecuencia de error de cúbit lógico 3.00E-9
Cruce del prefactor 0,03
Umbral de corrección de errores 0,01
Fórmula de tiempo de ciclo lógico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Fórmula de cúbits físicos 2 * codeDistance * codeDistance

En el grupo Parámetros de cúbit físico, puede ver las propiedades de cúbit físicos que se han asumido para esta estimación. Por ejemplo, se supone que el tiempo para realizar una medición de un solo cúbit y una puerta de un solo cúbit son 100 ns y 50 ns, respectivamente.

Parámetro de cúbit físico Valor
Nombre del cúbit qubit_gate_ns_e3
Conjunto de instrucciones GateBased
Tiempo de medición de un solo cúbit 100 ns
Hora de la puerta de T 50 ns
Tasa de errores de puerta de T 0,001
Tasa de errores de medición de un solo cúbit 0,001
Tiempo de puerta de un solo cúbit 50 ns
Frecuencia de error de un solo cúbit 0,001
Tiempo de puerta de dos cúbits 50 ns
Frecuencia de error de dos cúbits 0,001

Nota

Puede acceder a la salida del estimador de recursos de Azure Quantum en formato JSON mediante el result.data() método .

result.data()

Para obtener más información, consulte la lista completa de datos de salida del estimador de recursos.

Cambiar los valores predeterminados y calcular el algoritmo

Al enviar una solicitud de estimación de recursos para el programa, puede especificar algunos parámetros opcionales. Use el jobParams campo para tener acceso a todos los valores que se pueden pasar a la ejecución del trabajo y ver qué valores predeterminados se han asumido:

result['jobParams']
{'errorBudget': 0.001,
 'qecScheme': {'crossingPrefactor': 0.03,
  'errorCorrectionThreshold': 0.01,
  'logicalCycleTime': '(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance',
  'name': 'surface_code',
  'physicalQubitsPerLogicalQubit': '2 * codeDistance * codeDistance'},
 'qubitParams': {'instructionSet': 'GateBased',
  'name': 'qubit_gate_ns_e3',
  'oneQubitGateErrorRate': 0.001,
  'oneQubitGateTime': '50 ns',
  'oneQubitMeasurementErrorRate': 0.001,
  'oneQubitMeasurementTime': '100 ns',
  'tGateErrorRate': 0.001,
  'tGateTime': '50 ns',
  'twoQubitGateErrorRate': 0.001,
  'twoQubitGateTime': '50 ns'}}

Hay tres parámetros de entrada de nivel superior que se pueden personalizar:

  • errorBudget : el presupuesto de errores permitido general.
  • qecScheme : el esquema de corrección de errores cuánticos (QEC)
  • qubitParams : los parámetros de cúbit físico

Para obtener más información, consulte Parámetros de entrada para el estimador de recursos.

Cambio del modelo de cúbits

A continuación, calcule el costo del mismo algoritmo mediante el parámetro de cúbit basado en Majorana, qubitParams, "qubit_maj_ns_e6".

result = qsharp.azure.execute(EstimateMultiplication8,
            jobParams={
                "qubitParams": {
                    "name": "qubit_maj_ns_e6"
                }})
result

Inspeccione los recuentos físicos mediante programación. Por ejemplo, puede mostrar todas las estimaciones de recursos físicos y su desglose mediante el physicalCounts campo en los datos del resultado. Aquí aprenderá qué tasas de error de estado de T lógico y de bits cuánticos lógicos son necesarias para que coincida con el presupuesto de errores. De forma predeterminada, los entornos de ejecución se muestran en nanosegundos.

result['physicalCounts']
{'breakdown': {'adjustedLogicalDepth': 608,
  'cliffordErrorRate': 1e-06,
  'logicalDepth': 608,
  'logicalQubits': 84,
  'numTfactories': 10,
  'numTfactoryRuns': 80,
  'numTsPerRotation': None,
  'numTstates': 800,
  'physicalQubitsForAlgorithm': 4200,
  'physicalQubitsForTfactories': 164160,
  'requiredLogicalQubitErrorRate': 9.790100250626566e-09,
  'requiredLogicalTstateErrorRate': 6.25e-07},
 'physicalQubits': 168360,
 'runtime': 6080000}

También puede explorar los detalles sobre la factoría de T que se creó para ejecutar el algoritmo.

result['tfactory']
{'eccDistancePerRound': [1, 1, 3],
 'logicalErrorRate': 2.5244447992120037e-07,
 'unitNamePerRound': ['15-to-1 space efficient physical',
  '15-to-1 RM prep physical',
  '15-to-1 RM prep logical'],
 'numInputTstates': 20520,
 'numUnitsPerRound': [1368, 20, 1],
 'numRounds': 3,
 'numTstates': 1,
 'physicalQubits': 16416,
 'physicalQubitsPerRound': [12, 31, 558],
 'runtime': 72900.0,
 'runtimePerRound': [4500.0, 2400.0, 66000.0]}

Puede usar estos datos para generar algunas explicaciones de cómo las factorías de T generan los estados T necesarios.

tfactory = result["tfactory"]
breakdown = result["physicalCounts"]["breakdown"]
producedTstates = breakdown["numTfactories"] * breakdown["numTfactoryRuns"] * tfactory["numTstates"]

print(f"""A single T factory produces {tfactory["numTstates"]} T state(s) with an error rate of {tfactory["logicalErrorRate"]:.2e} (required T state error rate is {breakdown["requiredLogicalTstateErrorRate"]:.2e}).""")
print(f"""{breakdown["numTfactories"]} copie(s) of a T factory are executed {breakdown["numTfactoryRuns"]} time(s) to produce {producedTstates} T states ({breakdown["numTstates"]} are required by the algorithm).""")
print(f"""A single T factory is composed of {tfactory["numRounds"]} rounds of distillation:""")
for round in range(tfactory["numRounds"]):
    print(f"""- {tfactory["numModulesPerRound"][round]} {tfactory["moduleNamePerRound"][round]} unit(s)""")
A single T factory produces 1 T state(s) with an error rate of 2.52e-07 (required T state error rate is 6.25e-07).
10 copie(s) of a T factory are executed 80 time(s) to produce 800 T states (800 are required by the algorithm).
A single T factory is composed of 3 rounds of distillation:
- 1368 15-to-1 space efficient physical unit(s)
- 20 15-to-1 RM prep physical unit(s)
- 1 15-to-1 RM prep logical unit(s)

Cambio del esquema de corrección de errores cuánticos

Puede volver a ejecutar el trabajo de estimación de recursos para el mismo ejemplo en los parámetros de cúbit basados en Majorana con un esquema QEC floqued, qecScheme.

result_maj_floquet = qsharp.azure.execute(EstimateMultiplication8,
            jobParams={
                "qubitParams": {
                    "name": "qubit_maj_ns_e6"
                },
                "qecScheme": {
                    "name": "floquet_code"
                }})
result_maj_floquet

Cambio del presupuesto de errores

A continuación, vuelva a ejecutar el mismo circuito cuántico con un errorBudget 10 %.

result_maj_floquet_e1 = qsharp.azure.execute(EstimateMultiplication8,
            jobParams={
                "qubitParams": {
                    "name": "qubit_maj_ns_e6"
                },
                "qecScheme": {
                    "name": "floquet_code"
                },
                "errorBudget": 0.1})
result_maj_floquet_e1

Análisis avanzado de los resultados de la estimación de recursos

Ahora que ha aprendido a recuperar estimaciones de recursos físicos y a acceder a ellos mediante programación, puede realizar experimentos más elaborados. En esta parte, evaluará los costos del multiplicador basado en transformación de Quantum Fourier para diferentes bitwidths, parámetros de cúbit y códigos de corrección de errores cuánticos.

Agregue una nueva celda e importe los siguientes paquetes necesarios.

from ipywidgets import IntProgress       # To show interactive progress while job submission
from IPython.display import HTML         # To display HTML inside Jupyter notebooks
import time                              # To sleep while polling for job completion
import numpy as np                       # To store experimental data from job results
from matplotlib import pyplot as plt     # To plot experimental results
from matplotlib.colors import hsv_to_rgb # To automatically find colors for plots

Usará dos de los seis modelos de parámetros de cúbit predefinidos y un modelo personalizado en función del modelo qubit_gate_nds_e3, en el que establecerá las tasas de error en 10^{-3,5}$. En sus propios experimentos, puede cambiar el número de elementos y también los parámetros. Puede usar otros modelos predefinidos o definir modelos personalizados.

Además, usted está eligiendo bitwidths que son potencias de-2, que van de 8 a 64.

input_params = {
    "Gate-based ns, 10⁻³": {"qubitParams": {"name": "qubit_gate_ns_e3"}},
    "Gate-based ns, 10⁻³ᐧ⁵": {"qubitParams": {"name": "qubit_gate_ns_e3", "oneQubitMeasurementErrorRate": 0.00032, "oneQubitGateErrorRate": 0.00032, "twoQubitGateErrorRate": 0.00032, "tGateErrorRate": 0.00032}},
    "Gate-based ns, 10⁻⁴": {"qubitParams": {"name": "qubit_gate_ns_e4"}}
}

bitwidths = [8, 16, 32, 64]

# We also store the names of the experiments; if you like to force some order
# you can explicitly initialize the list with names from the `input_params`
# dictionary.
names = list(input_params.keys())

bitwidths = [8, 16, 32, 64]

# We also store the names of the experiments; if you like to force some order
# you can explicitly initialize the list with names from the `input_params`
# dictionary.
names = list(input_params.keys())

Nota

Al enviar trabajos al Estimador de recursos, no se pueden pasar parámetros de entrada para las operaciones.

Ahora, envía el circuito cuántico al estimador de recursos de Azure Quantum para todas las combinaciones de parámetros de trabajo y argumentos de entrada.

Dado que el estimador de recursos no admite parámetros de entrada para las operaciones, creará una operación contenedora sobre la marcha insertando el bitwidth directamente en el código fuente y, a continuación, compilarlo mediante qsharp.compile. Se trata de un método genérico que puede usar para generar operaciones para la estimación de recursos de Python.

A continuación, envíe esta operación contenedora para cada configuración del experimento mediante qsharp.azure.submit. Esto devolverá un job objeto desde el que puede extraer y job_id almacenarlo en el jobs diccionario. Tenga en cuenta que el bucle no esperará a que finalicen los trabajos.

# This initializes a `jobs` dictionary with the same keys as `input_params` and
# empty arrays as values
jobs = {name: [] for name in names}

progress_bar = IntProgress(min=0, max=len(input_params) * len(bitwidths) - 1, style={'description_width': 'initial'}, layout=Layout(width='75%'))
display(progress_bar)

for bitwidth in bitwidths:
    callable = qsharp.compile(f"""operation EstimateMultiplication{bitwidth}() : Unit {{ EstimateMultiplication({bitwidth}); }}""");
    print(callable)

    for name, params in input_params.items():
        progress_bar.description = f"{bitwidth}: {name}"

        result = qsharp.azure.submit(callable, jobParams=params)
        jobs[name].append(result.id)
        progress_bar.value += 1

Todos los trabajos se han enviado ahora, pero es posible que no hayan finalizado. La celda de código siguiente extrae los resultados de la estimación de recursos de cada trabajo. Para ello, primero espera a que un trabajo se haya realizado correctamente, siempre que todavía esté en un estado en espera o en ejecución. Todos los resultados se guardan en un results diccionario, que tiene una matriz para cada nombre de experimento que tiene todos los resultados correspondientes ordenados por bitwidth.

# This initializes a `results` dictionary with the same keys as `input_params`
# and empty arrays as values
results = {name: [] for name in names}

progress_bar = IntProgress(min=0, max=len(input_params) * len(bitwidths) - 1, style={'description_width': 'initial'}, layout=Layout(width='75%'))
display(progress_bar)

for name, job_ids in jobs.items():
    for job_id in job_ids:
        progress_bar.description = job_id

        # Wait until a job has succeeded or failed
        while True:
            status = qsharp.azure.status(job_id)
            if status.status in ["Waiting", "Executing"]:
                time.sleep(1) # Waits one second
            elif status.status == "Succeeded":
                break
            else:
                raise Exception(f"{status.status} job {job_id} in {name}")

        result = qsharp.azure.output(job_id)
        results[name].append(result)
        progress_bar.value += 1

Ahora que tiene todos los resultados, puede extraer algunos datos de él, como el número de cúbits físicos, el tiempo de ejecución total en nanosegundos y la distancia de código QEC para los cúbits lógicos. Además del número total de cúbits físicos, puede extraer su desglose en el número de cúbits físicos para ejecutar el algoritmo y el número de cúbits físicos necesarios para las fábricas de T que producen los estados T necesarios.

names = list(input_params.keys())

qubits = np.zeros((len(names), len(bitwidths), 3))
runtime = np.zeros((len(names), len(bitwidths)))
distances = np.zeros((len(names), len(bitwidths)))

for bitwidth_index, bitwidth in enumerate(bitwidths):
    for name_index, name in enumerate(names):
        data = results[names[name_index]][bitwidth_index]

        qubits[(name_index, bitwidth_index, 0)] = data['physicalCounts']['physicalQubits']
        qubits[(name_index, bitwidth_index, 1)] = data['physicalCounts']['breakdown']['physicalQubitsForAlgorithm']
        qubits[(name_index, bitwidth_index, 2)] = data['physicalCounts']['breakdown']['physicalQubitsForTfactories']

        runtime[(name_index, bitwidth_index)] = data['physicalCounts']['runtime']

        distances[(name_index, bitwidth_index)] = data['logicalQubit']['codeDistance']

Por último, puede usar Matplotlib para trazar el número de cúbits físicos y el tiempo de ejecución como trazados de barras, y las distancias de código QEC como un gráfico de dispersión. En el caso de los cúbits físicos, el gráfico muestra la partición en cúbits necesarios para el algoritmo y los cúbits necesarios para las factorías de T.

fig, axs = plt.subplots(1, 3, figsize=(22, 6))

num_experiments = len(names)                         # Extract number of experiments form names (can be made smaller)
xs = np.arange(0, len(bitwidths))                    # Map bitwidths to numeric indexes for plotting
full_width = .8                                      # Total width of all bars (should be smaller than 1)
width = full_width / num_experiments                 # Fractional width of a single bar
xs_left = xs - (((num_experiments - 1) * width) / 2) # Starting x-coordinate for bars

# Split axes into qubit and runtime plots
ax_qubits, ax_runtime, ax_code_distance = axs

# Plot physical qubits
for i in range(num_experiments):
    ax_qubits.bar(xs_left + i * width, qubits[i,:,1], width, label=f"{names[i]} (Alg.)", color=hsv_to_rgb((i / num_experiments, 1.0, .8)))
    ax_qubits.bar(xs_left + i * width, qubits[i,:,2], width, bottom=qubits[i,:,1], label=f"{names[i]} (T fac.)", color=hsv_to_rgb((i / num_experiments, 0.3, .8)))
ax_qubits.set_title("#Physical qubits")
ax_qubits.set_xlabel("Bitwidth")
ax_qubits.set_xticks(xs)
ax_qubits.set_xticklabels(bitwidths)
ax_qubits.legend()

# Plot runtime
for i in range(num_experiments):
    ax_runtime.bar(xs_left + i * width, np.array(runtime[i,:]) / 1e6, width, label=names[i], color=hsv_to_rgb((i / num_experiments, 1.0, .8)))
ax_runtime.set_title("Runtime (ms)")
ax_runtime.set_xlabel("Bitwidth")
ax_runtime.set_xticks(xs)
ax_runtime.set_xticklabels(bitwidths)
ax_runtime.legend()

# Plot code distances
for i in range(num_experiments):
    ax_code_distance.scatter(xs, distances[i,:], label=names[i], marker='*', color=hsv_to_rgb((i / num_experiments, 1.0, 0.8)))
ax_code_distance.set_title("QEC code distance")
ax_code_distance.set_xlabel("Bitwidth")
ax_code_distance.set_xticks(xs)
ax_code_distance.set_xticklabels(bitwidths)
ax_code_distance.legend()

fig.suptitle("Resource estimates for multiplication")
plt.show()

Trazado que muestra un gráfico de barras de la estimación de recursos físicos de cúbits físicos, tiempo de ejecución y distancia de código para tres configuraciones diferentes de parámetros de entrada.

Cómo mostrar los datos de estimación de recursos en tablas personalizadas

Los datos necesarios para mostrar la salida de la estimación de recursos en una tabla HTML también forman parte de los resultados de la estimación de recursos. Puede acceder a esos datos mediante la reportData clave del diccionario de resultados y usar estos datos para crear sus propias tablas.

El siguiente bloque de código muestra cómo crear una tabla de comparación de lado a lado para los parámetros de fábrica de T a partir de los resultados de la estimación de recursos. Esto se hace para todos los parámetros de entrada y un bitwidth fijo.

bitwidth = 16 # Choose one of the bitwidths here
bitwidth_index = bitwidths.index(bitwidth)

# Get all results from all input parameters for given bitwidth
data = [results[name][bitwidth_index] for name in names]

# From each result get the group that contains data about "T-factory parameters"
groups = [group for result in data for group in result['reportData']['groups'] if group['title'] == "T factory parameters"]

html = "<table><thead><tr><th></th>"

# Produce a table header using the experiment names
for name in names:
    html += f"<td>{name}</th>"

html += "</tr></thead><tbody>"

# Iterate through all entries (we extract the count from the first group, and then iterate through all of them)
for entry_index in range(len(groups[0]['entries'])):
    # Extract the entry label from the first group
    html += f"""<tr><td style="text-align: left; font-weight: bold">{groups[0]['entries'][entry_index]['label']}</td>"""

    # Iterate through all experiments
    for group_index in range(len(groups)):
        # The 'path' variable in the entry is a '/'-separated path to access the
        # result dictionary. So we start from the result dictionary of the
        # current experiment and then access the field based on the path part.
        # Eventually we obtain the final value.
        value = data[group_index]
        for key in groups[group_index]['entries'][entry_index]['path'].split("/"):
            value = value[key]
        html += f"<td>{value}</td>"
    html += "</tr>"

html += "</tbody></table>"

HTML(html)
Nombre Ns basados en puertas, 10⁻³ Basado en puertas ns, 10⁻³ᐧ⁵ Ns basados en puertas, 10⁻⁴
Cúbits físicos 13520 3240 1960
Tiempo de ejecución 67us 600ns 46us 800ns 36us 400ns
Número de estados de ouput T por ejecución 1 1 1
Número de estados de entrada T por ejecución 30 15 15
Rondas de destilación 1 1 1
Unidades de destilación por ronda 2 1 1
Unidades de destilación De 15 a 1 espacio eficiente lógico De 15 a 1 espacio eficiente lógico De 15 a 1 espacio eficiente lógico
Distancias de código de destilación 13 9 7
Número de cúbits físicos por ronda 13520 3240 1960
Tiempo de ejecución por ronda 67us 600ns 46us 800ns 36us 400ns
Tasa de errores de estado T lógico 5.63e-8 8.29e-9 2.16e-9

Estimación de recursos con Qiskit en azure Quantum Notebook

En este ejemplo, creará un circuito cuántico para un multiplicador basado en la construcción presentada en Ruiz-Perez y Garcia-Escartin (arXiv:1411.5949) que usa la transformación Quantum Fourier para implementar aritmética.

Creación de un cuaderno en el área de trabajo

  1. Inicie sesión en Azure Portal y seleccione el área de trabajo de Azure Quantum.
  2. En Operaciones, seleccione Cuadernos.
  3. Haga clic en Mis cuadernos y haga clic en Agregar nuevo.
  4. En Tipo de kernel, seleccione IPython.
  5. Escriba un nombre para el archivo y haga clic en Crear archivo.

Cuando se abre el nuevo cuaderno, se crea automáticamente el código para la primera celda, en función de la información de suscripción y área de trabajo.

from azure.quantum import Workspace
workspace = Workspace (
    subscription_id = <your subscription ID>, 
    resource_group = <your resource group>,   
    name = <your workspace name>,          
    location = <your location>        
    )

Carga de las importaciones necesarias

En primer lugar, deberá importar módulos adicionales de azure-quantum y qiskit.

Haga clic en + Código para agregar una nueva celda y, a continuación, agregue y ejecute el código siguiente:

from azure.quantum.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit, transpile
from qiskit.circuit.library import RGQFTMultiplier
from qiskit.tools.monitor import job_monitor
from qiskit_qir import SUPPORTED_INSTRUCTIONS

Cree una instancia de back-end y establezca el estimador de recursos como destino.

backend = provider.get_backend('microsoft.estimator')

Creación del algoritmo cuántico

Puede ajustar el tamaño del multiplicador cambiando la bitwidth variable. La generación del circuito se ajusta en una función a la que se puede llamar con el bitwidth valor del multiplicador. La operación tendrá dos registros de entrada, cada uno del tamaño del especificado bitwidthy un registro de salida que sea el doble del tamaño del especificado bitwidth. La función también imprimirá algunos recuentos de recursos lógicos para el multiplicador extraído directamente del circuito cuántico.

def create_algorithm(bitwidth):
    print(f"[INFO] Create a QFT-based multiplier with bitwidth {bitwidth}")
    
    # Print a warning for large bitwidths that will require some time to generate and
    # transpile the circuit.
    if bitwidth > 18:
        print(f"[WARN] It will take more than one minute generate a quantum circuit with a bitwidth larger than 18")

    circ = RGQFTMultiplier(num_state_qubits=bitwidth, num_result_qubits=2 * bitwidth)

    # One could further reduce the resource estimates by increasing the optimization_level,
    # however, this will also increase the runtime to construct the algorithm.  Note, that
    # it does not affect the runtime for resource estimation.
    print(f"[INFO] Decompose circuit into intrinsic quantum operations")

    circ = transpile(circ, basis_gates=SUPPORTED_INSTRUCTIONS, optimization_level=0)

    # print some statistics
    print(f"[INFO]   qubit count: {circ.num_qubits}")
    print("[INFO]   gate counts")
    for gate, count in circ.count_ops().items():
        print(f"[INFO]   - {gate}: {count}")

    return circ

Estimación del algoritmo cuántico

Cree una instancia del algoritmo mediante la create_algorithm función . Puede ajustar el tamaño del multiplicador cambiando la bitwidth variable.

bitwidth = 4

circ = create_algorithm(bitwidth)

Calcule los recursos físicos de esta operación con las suposiciones predeterminadas. Puede enviar el circuito al back-end del estimador de recursos mediante el run método y, a continuación, ejecutar job_monitor para esperar la finalización.

job = backend.run(circ)
job_monitor(job)
result = job.result()
result

Esto crea una tabla que muestra los recuentos generales de recursos físicos. Puede inspeccionar los detalles del costo contrayendo los grupos, que tienen más información. Por ejemplo, si contrae el grupo Parámetros de cúbit lógico , puede ver más fácilmente que la distancia del código de corrección de errores es 15.

Parámetro de cúbit lógico Valor
Esquema QEC surface_code
Distancia del código 15
Cúbits físicos 450
Tiempo del ciclo lógico 6us
Tasa de errores de cúbit lógico 3.00E-10
Cruce del prefactor 0,03
Umbral de corrección de errores 0,01
Fórmula de tiempo del ciclo lógico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Fórmula de cúbits físicos 2 * codeDistance * codeDistance

En el grupo Parámetros de cúbit físico , puede ver las propiedades de cúbit físicos que se han asumido para esta estimación. Por ejemplo, el tiempo para realizar una medición de un solo cúbit y una puerta de un solo cúbit se supone que son 100 ns y 50 ns, respectivamente.

Parámetro de cúbit físico Valor
Nombre del cúbit qubit_gate_ns_e3
Conjunto de instrucciones GateBased
Tiempo de medición de un solo cúbit 100 ns
Hora de la puerta de T 50 ns
Tasa de errores de puerta T 0,001
Tasa de errores de medición de un solo cúbit 0,001
Tiempo de puerta de un solo cúbit 50 ns
Tasa de errores de un solo cúbit 0,001
Tiempo de la puerta de dos cúbits 50 ns
Tasa de errores de dos cúbits 0,001

Nota

También puede acceder a la salida del estimador de recursos en formato JSON mediante el result.data() método .

result.data()

Para obtener más información, consulte la lista completa de datos de salida del estimador de recursos.

Cambiar los valores predeterminados y calcular el algoritmo

Al enviar una solicitud de estimación de recursos para el programa, puede especificar algunos parámetros opcionales. Use el jobParams campo para tener acceso a todos los valores que se pueden pasar a la ejecución del trabajo y ver qué valores predeterminados se han asumido:

result.data()["jobParams"]
{'errorBudget': 0.001,
 'qecScheme': {'crossingPrefactor': 0.03,
  'errorCorrectionThreshold': 0.01,
  'logicalCycleTime': '(4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance',
  'name': 'surface_code',
  'physicalQubitsPerLogicalQubit': '2 * codeDistance * codeDistance'},
 'qubitParams': {'instructionSet': 'GateBased',
  'name': 'qubit_gate_ns_e3',
  'oneQubitGateErrorRate': 0.001,
  'oneQubitGateTime': '50 ns',
  'oneQubitMeasurementErrorRate': 0.001,
  'oneQubitMeasurementTime': '100 ns',
  'tGateErrorRate': 0.001,
  'tGateTime': '50 ns',
  'twoQubitGateErrorRate': 0.001,
  'twoQubitGateTime': '50 ns'}}

Hay tres parámetros de entrada de nivel superior que se pueden personalizar:

  • errorBudget : el presupuesto de errores permitido general.
  • qecScheme : el esquema de corrección de errores cuánticos (QEC)
  • qubitParams : los parámetros de cúbit físico

Para obtener más información, consulte Parámetros de entrada para el estimador de recursos.

Cambio del modelo de cúbits

A continuación, calcule el costo del mismo algoritmo mediante el parámetro de cúbit basado en Majorana. qubit_maj_ns_e6

job = backend.run(circ,
    qubitParams={
        "name": "qubit_maj_ns_e6"
    })
job_monitor(job)
result = job.result()
result

Puede respetar los recuentos físicos mediante programación. Por ejemplo, puede mostrar todas las estimaciones de recursos físicos y su desglose mediante el physicalCounts campo en los datos de resultados. Esto mostrará las tasas de error de estado T lógico y de bits cuánticos lógicos necesarios para que coincidan con el presupuesto de errores. De forma predeterminada, los entornos de ejecución se muestran en nanosegundos.

result.data()["physicalCounts"]
{'breakdown': {'adjustedLogicalDepth': 6168,
  'cliffordErrorRate': 1e-06,
  'logicalDepth': 6168,
  'logicalQubits': 45,
  'numTfactories': 23,
  'numTfactoryRuns': 523,
  'numTsPerRotation': 17,
  'numTstates': 12017,
  'physicalQubitsForAlgorithm': 2250,
  'physicalQubitsForTfactories': 377568,
  'requiredLogicalQubitErrorRate': 1.200941538165922e-09,
  'requiredLogicalTstateErrorRate': 2.773848159551746e-08},
 'physicalQubits': 379818,
 'runtime': 61680000}

También puede explorar los detalles sobre la factoría de T que se creó para ejecutar el algoritmo.

result.data()["tfactory"]
{'eccDistancePerRound': [1, 1, 5],
 'logicalErrorRate': 1.6833177305222897e-10,
 'moduleNamePerRound': ['15-to-1 space efficient physical',
  '15-to-1 RM prep physical',
  '15-to-1 RM prep logical'],
 'numInputTstates': 20520,
 'numModulesPerRound': [1368, 20, 1],
 'numRounds': 3,
 'numTstates': 1,
 'physicalQubits': 16416,
 'physicalQubitsPerRound': [12, 31, 1550],
 'runtime': 116900.0,
 'runtimePerRound': [4500.0, 2400.0, 110000.0]}

Puede usar estos datos para generar algunas explicaciones de cómo las factorías de T generan los estados T necesarios.

data = result.data()
tfactory = data["tfactory"]
breakdown = data["physicalCounts"]["breakdown"]
producedTstates = breakdown["numTfactories"] * breakdown["numTfactoryRuns"] * tfactory["numTstates"]

print(f"""A single T factory produces {tfactory["logicalErrorRate"]:.2e} T states with an error rate of (required T state error rate is {breakdown["requiredLogicalTstateErrorRate"]:.2e}).""")
print(f"""{breakdown["numTfactories"]} copie(s) of a T factory are executed {breakdown["numTfactoryRuns"]} time(s) to produce {producedTstates} T states ({breakdown["numTstates"]} are required by the algorithm).""")
print(f"""A single T factory is composed of {tfactory["numRounds"]} rounds of distillation:""")
for round in range(tfactory["numRounds"]):
    print(f"""- {tfactory["numModulesPerRound"][round]} {tfactory["moduleNamePerRound"][round]} unit(s)""")
A single T factory produces 1.68e-10 T states with an error rate of (required T state error rate is 2.77e-08).
23 copies of a T factory are executed 523 time(s) to produce 12029 T states (12017 are required by the algorithm).
A single T factory is composed of 3 rounds of distillation:
- 1368 15-to-1 space efficient physical unit(s)
- 20 15-to-1 RM prep physical unit(s)
- 1 15-to-1 RM prep logical unit(s)

Cambio del esquema de corrección de errores cuánticos

Ahora, vuelva a ejecutar el trabajo de estimación de recursos para el mismo ejemplo en los parámetros de cúbit basados en Majorana con un esquema QEC floqued, qecScheme.

job = backend.run(circ,
    qubitParams={
        "name": "qubit_maj_ns_e6"
    },
    qecScheme={
        "name": "floquet_code"
    })
job_monitor(job)
result_maj_floquet = job.result()
result_maj_floquet

Cambio del presupuesto de errores

Vamos a volver a ejecutar el mismo circuito cuántico con un errorBudget 10 %.

job = backend.run(circ,
    qubitParams={
        "name": "qubit_maj_ns_e6"
    },
    qecScheme={
        "name": "floquet_code"
    },
    errorBudget=0.1)
job_monitor(job)
result_maj_floquet_e1 = job.result()
result_maj_floquet_e1

Estimación de recursos con Q# en Visual Studio Code

En este ejemplo, creará un multiplicador y calculará sus costos en un equipo cuántico tolerante a errores.

Prerrequisitos

Conexión al área de trabajo de Azure Quantum

  1. Abra un terminal con acceso a la CLI de Azure.

  2. Inicie sesión en Azure con sus credenciales. Verá una lista de suscripciones asociadas a su cuenta.

    az login
    
  3. Especifique la suscripción que desea usar de las asociadas a su cuenta de Azure. También puede encontrar el identificador de suscripción en la información general del área de trabajo en Azure Portal.

    az account set -s <Your subscription ID>
    
  4. Establezca el grupo de recursos, el nombre del área de trabajo y la ubicación:

    az quantum workspace set -g <resource-group> -w <workspace-name> -l <location> -o table
    

Creación del algoritmo cuántico

Creará un multiplicador mediante la operación MultiplicarI . Puede configurar el tamaño del multiplicador con un bitwidth parámetro . La operación tendrá dos registros de entrada, cada uno del tamaño del especificado bitwidthy un registro de salida que sea el doble del tamaño del especificado bitwidth.

Cree un nuevo proyecto en Visual Studio Code.

  1. Seleccione Ver ->Paleta de comandos ->Q#: Crear nuevo proyecto.

  2. Seleccione Aplicación de consola independiente.

  3. Seleccione una ubicación para guardar el proyecto, asígnele el nombre EstimateMultiplication y seleccione Crear proyecto.

  4. Cuando el proyecto se haya creado correctamente, seleccione Abrir nuevo proyecto... abajo a la derecha. Esto genera dos archivos: el archivo de proyecto, EstimateMultiplication.csproj y una plantilla de programa de Q#, Program.qs.

  5. En EstimateMultiplication.csproj, si aún no existe, agregue la <referencia ItemGroup> a Microsoft. Quantum.Arithmetic:

    <Project Sdk="Microsoft.Quantum.Sdk/X.XX.XXXXXX">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.Quantum.Arithmetic" Version="X.XX.XXXXXX" />
      </ItemGroup>
    
    </Project>
    
  6. Reemplace el contenido del archivo Program.qs por el código siguiente:

    namespace QFTmultiplier {
    
        open Microsoft.Quantum.Arithmetic;
    
        @EntryPoint()
        operation EstimateMultiplication() : Unit {
            let bitwidth = 4;
    
            use factor1 = Qubit[bitwidth];
            use factor2 = Qubit[bitwidth];
            use product = Qubit[2 * bitwidth];
    
            MultiplyI(LittleEndian(factor1), LittleEndian(factor2), LittleEndian(product));
        }
    }
    

Estimación del algoritmo cuántico

  1. Abra un terminal con acceso a la CLI de Azure.

  2. Copie el siguiente comando para enviar un trabajo al destino del estimador de recursos.

    az quantum job submit --target-id microsoft.estimator -o json --query id
    
  3. La salida contendrá el identificador del trabajo. Copie el identificador de trabajo y solicite la salida del trabajo mediante -o table para mostrar la salida en la CLI como una tabla o con -o json para mostrar la salida en formato JSON.

    az quantum job output -j <job-id> -o table
    
  4. En la tabla resultante se muestran los recuentos generales de recursos físicos. Puede inspeccionar los detalles del costo contrayendo los grupos, que tienen más información. Por ejemplo, si contrae el grupo Parámetros de cúbit lógico , puede ver más fácilmente que la distancia del código de corrección de errores es 13.

Parámetro de cúbit lógico Valor
Esquema QEC surface_code
Distancia del código 13
Cúbits físicos 338
Tiempo del ciclo lógico 5us 200ns
Tasa de errores de cúbit lógico 3.00E-9
Cruce del prefactor 0,03
Umbral de corrección de errores 0,01
Fórmula de tiempo del ciclo lógico (4 * twoQubitGateTime + 2 * oneQubitMeasurementTime) * codeDistance
Fórmula de cúbits físicos 2 * codeDistance * codeDistance

En el grupo Parámetros de cúbit físico , puede ver las propiedades de cúbit físicos que se han asumido para esta estimación. Por ejemplo, el tiempo para realizar una medición de un solo cúbit y una puerta de un solo cúbit se supone que son 100 ns y 50 ns, respectivamente.

Parámetro de cúbit físico Valor
Nombre del cúbit qubit_gate_ns_e3
Conjunto de instrucciones GateBased
Tiempo de medición de un solo cúbit 100 ns
Hora de la puerta de T 50 ns
Tasa de errores de puerta T 0,001
Tasa de errores de medición de un solo cúbit 0,001
Tiempo de puerta de un solo cúbit 50 ns
Tasa de errores de un solo cúbit 0,001
Tiempo de la puerta de dos cúbits 50 ns
Tasa de errores de dos cúbits 0,001

Para obtener más información, consulte la lista completa de datos de salida del estimador de recursos.

Cambiar los valores predeterminados y calcular el algoritmo

Al enviar una solicitud de estimación de recursos para el programa, puede especificar algunos parámetros opcionales. Hay tres parámetros de entrada de nivel superior que se pueden personalizar:

  • errorBudget : el presupuesto de errores permitido general.
  • qecScheme : el esquema de corrección de errores cuánticos (QEC)
  • qubitParams : los parámetros de cúbit físico

Para obtener más información, consulte Parámetros de entrada para el estimador de recursos.

Cambio del modelo de cúbits

Vamos a calcular el costo del mismo algoritmo mediante el parámetro de cúbit basado en Majorana, qubitParams, "qubit_maj_ns_e6".

  1. Cree un archivo JSON con la configuración y asígnelo jobParams.jsonel nombre .

    {
        "qubitParams": {
            "name": "qubit_maj_ns_e6"
        },
    }
    
  2. Puede pasarlos al argumento de la --job-params siguiente manera:

    az quantum job submit --target-id microsoft.estimator -o json --query id --job-params "@jobParams.json"
    
  3. Vuelva a inspeccionar la tabla con -o table.

    az quantum job output -j <job-id> -o table
    

Por ejemplo, puede mostrar un desglose de las estimaciones haciendo clic en el grupo Desglose . Aquí verá qué tasas de error de estado de T lógico y de bits cuánticos lógicos son necesarias para que coincida con el presupuesto de errores. De forma predeterminada, los entornos de ejecución se muestran en nanosegundos.

Nombre Valor
Cúbits algorítmicos lógicos 84
Profundidad algorítmica lógica 608
Profundidad lógica ajustada 608
Número de estados T 800
Número de fábricas de T 10
Número de invocaciones de generador de T 80
Cúbits algorítmicos físicos 4200
Cúbits de fábrica de T físicos 164160
Cúbits de fábrica de T físicos (fracción) 97.50 %
Tasa de errores de cúbit lógico requerida 9.79e-9
Tasa de errores de Tstate lógica requerida 6.25e-7
Número de puertas T por rotación Sin rotaciones en el algoritmo

También puede explorar los detalles sobre la factoría de T que se creó para ejecutar el algoritmo.

Parámetros de fábrica de T Valor
Cúbits físicos 16416
Tiempo de ejecución 72us 900ns
Número de estados T de salida por ejecución 1
Número de estados de entrada T por ejecución 20520
Rondas de destilación 3
Unidades de destilación por ronda 1368, 20, 1
Unidades de destilación 15 a 1 espacio eficiente físico, físico de 15 a 1 RM prep físico, de 15 a 1 RM preparación lógica
Distancias de código de destilación 1, 1, 3
Número de cúbits físicos por ronda 12, 31, 558
Tiempo de ejecución por ronda 4us 500ns, 2us 400ns, 66us
Tasa de errores de estado T lógico 2.52e-07

Un único generador de T genera un estado T. Observe que la tasa de errores lógicos para un estado T de salida (2,52e-07) es menor que la tasa de errores de estado T necesaria en el desglose de recuentos físicos (6,25e-07). El generador de T se copia 10 veces de modo que se pueden ejecutar en paralelo para producir 10 estados T. Estas copias se ejecutan 80 veces en secuencia, lo que produce en total $10 \cdot 80 = 800$ T estados requeridos por el algoritmo. Una sola fábrica T se compone de tres rondas de destilación, donde:

  • Se utilizaron 1368 copias de módulos de destilación física eficientes de 15 a 1 espacio
  • Se usaron 20 copias de 15 a 1 módulos de destilación física de preparación de RM
  • Se usaron 1 copias de módulos lógicos de preparación de RM de 15 a 1

Cambio del esquema de corrección de errores cuánticos

Ahora, vuelva a ejecutar el trabajo de estimación de recursos para el mismo ejemplo en los parámetros de cúbit basados en Majorana con un esquema QEC floqued, qecScheme.

  1. Agregue el parámetro de esquema de corrección de errores cuánticos al jobParams.json archivo.

    {
        "qubitParams": {
            "name": "qubit_maj_ns_e6"
        },
        "qecScheme": {
          "name": "floquet_code"
        }
    }
    
  2. Pase los parámetros de entrada al --job-params argumento .

    az quantum job submit --target-id microsoft.estimator -o json --query id --job-params "@jobParams.json"
    
  3. Inspeccione el resultado con -o table.

    az quantum job output -j <job-id> -o table
    

Cambio del presupuesto de errores

Vuelva a ejecutar el mismo circuito cuántico con un errorBudget 10 %.

  1. Agregue el parámetro de presupuesto de errores cuánticos al jobParams.json archivo.

    {
        "errorBudget": 0.1,
        "qubitParams": {
            "name": "qubit_maj_ns_e6"
        },
        "qecScheme": {
          "name": "floquet_code"
        }
    }
    
  2. Pase los parámetros de entrada al --job-params argumento .

    az quantum job submit --target-id microsoft.estimator -o json --query id --job-params "@jobParams.json"
    
  3. Inspeccione el resultado con -o table.

    az quantum job output -j <job-id> -o table
    

Pasos siguientes