Construya circuitos en el SDK - Amazon Braket

¡Aprenda los fundamentos de la computación cuántica con! AWS Inscríbase en el plan de aprendizaje digital Amazon Braket y obtenga su propia insignia digital tras completar una serie de cursos de aprendizaje y una evaluación digital.

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Construya circuitos en el SDK

En esta sección se proporcionan ejemplos sobre cómo definir un circuito, ver las compuertas disponibles, extender un circuito y ver las compuertas compatibles con cada dispositivo. También contiene instrucciones sobre cómo realizar la asignación manualqubits, indicar al compilador que ejecute los circuitos exactamente como se ha definido y crear circuitos ruidosos con un simulador de ruido.

También puedes trabajar al nivel del pulso en Braket para varias compuertas con determinadas QPUs. Para obtener más información, consulta Pulse Control en Amazon Braket.

Puertas y circuitos

Las puertas y circuitos cuánticos se definen en la braket.circuitsclase del Amazon Braket Python SDK. Desde el SDK, puedes crear una instancia de un nuevo objeto de circuito mediante una llamada. Circuit()

Ejemplo: definir un circuito

El ejemplo comienza con la definición de un circuito de muestra de cuatro qubits (denominado q0 q1q2, yq3) compuesto por puertas Hadamard estándar de un solo qubit y puertas CNOT de dos cúbits. Puede visualizar este circuito llamando a la función, tal y como se muestra en el siguiente ejemplo. print

# import the circuit module from braket.circuits import Circuit # define circuit with 4 qubits my_circuit = Circuit().h(range(4)).cnot(control=0, target=2).cnot(control=1, target=3) print(my_circuit)
T : |0| 1 | q0 : -H-C--- | q1 : -H-|-C- | | q2 : -H-X-|- | q3 : -H---X- T : |0| 1 |

Ejemplo: Defina un circuito parametrizado

En este ejemplo, definimos un circuito con puertas que dependen de parámetros libres. Podemos especificar los valores de estos parámetros para crear un nuevo circuito o, al enviar el circuito, para que se ejecute como una tarea cuántica en determinados dispositivos.

from braket.circuits import Circuit, FreeParameter #define a FreeParameter to represent the angle of a gate alpha = FreeParameter("alpha") #define a circuit with three qubits my_circuit = Circuit().h(range(3)).cnot(control=0, target=2).rx(0, alpha).rx(1, alpha) print(my_circuit)

Puede crear un circuito nuevo no parametrizado a partir de uno parametrizado proporcionando un argumento único float (que es el valor que tomarán todos los parámetros libres) o un argumento de palabra clave que especifique el valor de cada parámetro para el circuito de la siguiente manera.

my_fixed_circuit = my_circuit(1.2) my_fixed_circuit = my_circuit(alpha=1.2)

Tenga en cuenta que no my_circuit está modificado, por lo que puede usarlo para crear instancias de muchos circuitos nuevos con valores de parámetros fijos.

Ejemplo: modificar las compuertas de un circuito

El siguiente ejemplo define un circuito con compuertas que utilizan modificadores de control y potencia. Puede utilizar estas modificaciones para crear nuevas compuertas, como la Ry compuerta controlada.

from braket.circuits import Circuit # Create a bell circuit with a controlled x gate my_circuit = Circuit().h(0).x(control=0, target=1) # Add a multi-controlled Ry gate of angle .13 my_circuit.ry(angle=.13, target=2, control=(0, 1)) # Add a 1/5 root of X gate my_circuit.x(0, power=1/5) print(my_circuit)

Los modificadores de puerta solo son compatibles con el simulador local.

Ejemplo: consulte todas las puertas disponibles

El siguiente ejemplo muestra cómo ver todas las puertas disponibles en Amazon Braket.

from braket.circuits import Gate # print all available gates in Amazon Braket gate_set = [attr for attr in dir(Gate) if attr[0].isupper()] print(gate_set)

El resultado de este código muestra todas las puertas.

['CCNot', 'CNot', 'CPhaseShift', 'CPhaseShift00', 'CPhaseShift01', 'CPhaseShift10', 'CSwap', 'CV', 'CY', 'CZ', 'ECR', 'GPi', 'GPi2', 'H', 'I', 'ISwap', 'MS', 'PSwap', 'PhaseShift', 'PulseGate', 'Rx', 'Ry', 'Rz', 'S', 'Si', 'Swap', 'T', 'Ti', 'Unitary', 'V', 'Vi', 'X', 'XX', 'XY', 'Y', 'YY', 'Z', 'ZZ']

Cualquiera de estas puertas se puede añadir a un circuito llamando al método correspondiente a ese tipo de circuito. Por ejemplo, llamaría acirc.h(0), para añadir una puerta de Hadamard a la primera. qubit

nota

Las compuertas están colocadas en su sitio y en el siguiente ejemplo se agregan todas las compuertas enumeradas en el ejemplo anterior al mismo circuito.

circ = Circuit() # toffoli gate with q0, q1 the control qubits and q2 the target. circ.ccnot(0, 1, 2) # cnot gate circ.cnot(0, 1) # controlled-phase gate that phases the |11> state, cphaseshift(phi) = diag((1,1,1,exp(1j*phi))), where phi=0.15 in the examples below circ.cphaseshift(0, 1, 0.15) # controlled-phase gate that phases the |00> state, cphaseshift00(phi) = diag([exp(1j*phi),1,1,1]) circ.cphaseshift00(0, 1, 0.15) # controlled-phase gate that phases the |01> state, cphaseshift01(phi) = diag([1,exp(1j*phi),1,1]) circ.cphaseshift01(0, 1, 0.15) # controlled-phase gate that phases the |10> state, cphaseshift10(phi) = diag([1,1,exp(1j*phi),1]) circ.cphaseshift10(0, 1, 0.15) # controlled swap gate circ.cswap(0, 1, 2) # swap gate circ.swap(0,1) # phaseshift(phi)= diag([1,exp(1j*phi)]) circ.phaseshift(0,0.15) # controlled Y gate circ.cy(0, 1) # controlled phase gate circ.cz(0, 1) # Echoed cross-resonance gate applied to q0, q1 circ = Circuit().ecr(0,1) # X rotation with angle 0.15 circ.rx(0, 0.15) # Y rotation with angle 0.15 circ.ry(0, 0.15) # Z rotation with angle 0.15 circ.rz(0, 0.15) # Hadamard gates applied to q0, q1, q2 circ.h(range(3)) # identity gates applied to q0, q1, q2 circ.i([0, 1, 2]) # iswap gate, iswap = [[1,0,0,0],[0,0,1j,0],[0,1j,0,0],[0,0,0,1]] circ.iswap(0, 1) # pswap gate, PSWAP(phi) = [[1,0,0,0],[0,0,exp(1j*phi),0],[0,exp(1j*phi),0,0],[0,0,0,1]] circ.pswap(0, 1, 0.15) # X gate applied to q1, q2 circ.x([1, 2]) # Y gate applied to q1, q2 circ.y([1, 2]) # Z gate applied to q1, q2 circ.z([1, 2]) # S gate applied to q0, q1, q2 circ.s([0, 1, 2]) # conjugate transpose of S gate applied to q0, q1 circ.si([0, 1]) # T gate applied to q0, q1 circ.t([0, 1]) # conjugate transpose of T gate applied to q0, q1 circ.ti([0, 1]) # square root of not gate applied to q0, q1, q2 circ.v([0, 1, 2]) # conjugate transpose of square root of not gate applied to q0, q1, q2 circ.vi([0, 1, 2]) # exp(-iXX theta/2) circ.xx(0, 1, 0.15) # exp(i(XX+YY) theta/4), where theta=0.15 in the examples below circ.xy(0, 1, 0.15) # exp(-iYY theta/2) circ.yy(0, 1, 0.15) # exp(-iZZ theta/2) circ.zz(0, 1, 0.15) # IonQ native gate GPi with angle 0.15 applied to q0 circ.gpi(0, 0.15) # IonQ native gate GPi2 with angle 0.15 applied to q0 circ.gpi2(0, 0.15) # IonQ native gate MS with angles 0.15, 0.15, 0.15 applied to q0, q1 circ.ms(0, 1, 0.15, 0.15, 0.15)

Además del conjunto de puertas predefinido, también puede aplicar puertas unitarias autodefinidas al circuito. Pueden ser puertas de un solo qubit (como se muestra en el siguiente código fuente) o puertas de varios cúbits aplicadas a lo definido por el parámetro. qubits targets

import numpy as np # apply a general unitary my_unitary = np.array([[0, 1],[1, 0]]) circ.unitary(matrix=my_unitary, targets=[0])

Ejemplo: ampliar los circuitos existentes

Puede ampliar los circuitos existentes añadiendo instrucciones. Una Instruction es una directiva cuántica que describe la tarea cuántica que se debe realizar en un dispositivo cuántico. Instructionlos operadores incluyen Gate únicamente objetos de tipo.

# import the Gate and Instruction modules from braket.circuits import Gate, Instruction # add instructions directly. circ = Circuit([Instruction(Gate.H(), 4), Instruction(Gate.CNot(), [4, 5])]) # or with add_instruction/add functions instr = Instruction(Gate.CNot(), [0, 1]) circ.add_instruction(instr) circ.add(instr) # specify where the circuit is appended circ.add_instruction(instr, target=[3, 4]) circ.add_instruction(instr, target_mapping={0: 3, 1: 4}) # print the instructions print(circ.instructions) # if there are multiple instructions, you can print them in a for loop for instr in circ.instructions: print(instr) # instructions can be copied new_instr = instr.copy() # appoint the instruction to target new_instr = instr.copy(target=[5]) new_instr = instr.copy(target_mapping={0: 5})

Ejemplo: vea las puertas que admite cada dispositivo

Los simuladores admiten todas las compuertas del SDK de Braket, pero los dispositivos QPU admiten un subconjunto más pequeño. Puedes encontrar las compuertas compatibles de un dispositivo en las propiedades del dispositivo. A continuación se muestra un ejemplo con un dispositivo IonQ:

# import the device module from braket.aws import AwsDevice device = AwsDevice("arn:aws:braket:us-east-1::device/qpu/ionq/Harmony") # get device name device_name = device.name # show supportedQuantumOperations (supported gates for a device) device_operations = device.properties.dict()['action']['braket.ir.openqasm.program']['supportedOperations'] print('Quantum Gates supported by {}:\n {}'.format(device_name, device_operations))
Quantum Gates supported by the Harmony device: ['x', 'y', 'z', 'rx', 'ry', 'rz', 'h', 'cnot', 's', 'si', 't', 'ti', 'v', 'vi', 'xx', 'yy', 'zz', 'swap', 'i']

Es posible que las puertas compatibles deban compilarse en puertas nativas antes de que puedan ejecutarse en hardware cuántico. Cuando envías un circuito, Amazon Braket realiza esta compilación automáticamente.

Ejemplo: recupere mediante programación la fidelidad de las puertas nativas compatibles con un dispositivo

Puede ver la información de fidelidad en la página Dispositivos de la consola Braket. A veces resulta útil acceder a la misma información mediante programación. El siguiente código muestra cómo extraer la fidelidad de las dos qubit puertas entre dos puertas de una QPU.

# import the device module from braket.aws import AwsDevice device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3") #specify the qubits a=10 b=113 print(f"Fidelity of the XY gate between qubits {a} and {b}: ", device.properties.provider.specs["2Q"][f"{a}-{b}"]["fXY"])

Asignación manual qubit

Cuando ejecuta un circuito cuántico en ordenadores cuánticosRigetti, puede utilizar opcionalmente la qubit asignación manual para controlar cuáles se qubits utilizan para su algoritmo. La consola Amazon Braket y el Amazon Braket SDK le ayudan a inspeccionar los datos de calibración más recientes del dispositivo de unidad de procesamiento cuántico (QPU) que haya seleccionado, de modo que pueda seleccionar el qubits mejor para su experimento.

La qubit asignación manual le permite ejecutar los circuitos con mayor precisión e investigar las propiedades individuales. qubit Los investigadores y los usuarios avanzados optimizan el diseño de sus circuitos en función de los datos de calibración más recientes de los dispositivos y pueden obtener resultados más precisos.

El siguiente ejemplo demuestra cómo asignar de qubits forma explícita.

circ = Circuit().h(0).cnot(0, 7) # Indices of actual qubits in the QPU my_task = device.run(circ, s3_location, shots=100, disable_qubit_rewiring=True)

Para obtener más información, consulte los ejemplos de Amazon Braket sobre GitHub, o más específicamente, este cuaderno: Asignación de qubits en dispositivos QPU.

nota

El OQC compilador no admite la configuración. disable_qubit_rewiring=True Si se establece este indicador, se True produce el siguiente error:An error occurred (ValidationException) when calling the CreateQuantumTask operation: Device arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy does not support disabled qubit rewiring.

Compilación literal

Cuando ejecuta un circuito cuántico en ordenadores cuánticos desde RigettiIonQ, o Oxford Quantum Circuits (OQC), puede indicar al compilador que ejecute los circuitos exactamente como se ha definido sin ninguna modificación. Mediante la compilación literal, puede especificar que un circuito completo se conserve de forma precisa (con el apoyo de RigettiIonQ, yOQC) tal como se especifica o que solo se conserven determinadas partes del mismo (solo con el apoyo deRigetti). Al desarrollar algoritmos para la evaluación comparativa del hardware o los protocolos de mitigación de errores, debe tener la opción de especificar con precisión las compuertas y los diseños de circuitos que está ejecutando en el hardware. La compilación literal le permite controlar directamente el proceso de compilación al desactivar ciertos pasos de optimización, lo que garantiza que sus circuitos funcionen exactamente como se diseñaron.

Actualmente, la compilación literal es compatible con los dispositivos RigettiIonQ, y Oxford Quantum Circuits (OQC) y requiere el uso de puertas nativas. Al utilizar la compilación literal, se recomienda comprobar la topología del dispositivo para garantizar que las compuertas estén conectadas qubits y que el circuito utilice las compuertas nativas compatibles con el hardware. El siguiente ejemplo muestra cómo acceder mediante programación a la lista de puertas nativas compatibles con un dispositivo.

device.properties.paradigm.nativeGateSet

Para elloRigetti, el qubit recableado debe desactivarse configurándolo disableQubitRewiring=True para su uso con la compilación literal. Si disableQubitRewiring=False se establece cuando se utilizan recuadros literales en una compilación, el circuito cuántico no pasa la validación y no se ejecuta.

Si la compilación literal está habilitada para un circuito y se ejecuta en una QPU que no la admite, se genera un error que indica que una operación no compatible ha provocado el error de la tarea. A medida que más hardware cuántico admita de forma nativa las funciones del compilador, esta función se ampliará para incluir estos dispositivos. Los dispositivos que admiten la compilación literal la incluyen como operación compatible cuando se consulta con el siguiente código.

from braket.aws import AwsDevice from braket.device_schema.device_action_properties import DeviceActionType device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3") device.properties.action[DeviceActionType.OPENQASM].supportedPragmas

El uso de la compilación literal no conlleva ningún coste adicional. Se te seguirán cobrando las tareas cuánticas ejecutadas en dispositivos QPU de Braket, instancias de portátiles y simuladores bajo demanda en función de las tarifas actuales especificadas en la página de precios de Amazon Braket. Para obtener más información, consulte el cuaderno de ejemplo de compilación de Verbatim.

nota

Si utiliza OpenQASM para escribir los circuitos de los IonQ dispositivos OQC y desea mapear su circuito directamente a los cúbits físicos, debe utilizar el, #pragma braket verbatim ya que OpenQasm ignora por completo este disableQubitRewiring indicador.

Simulación de ruido

Para crear una instancia del simulador de ruido local, puede cambiar el backend de la siguiente manera.

device = LocalSimulator(backend="braket_dm")

Puedes construir circuitos ruidosos de dos maneras:

  1. Construya el circuito ruidoso de abajo hacia arriba.

  2. Tome un circuito existente y libre de ruido e inyecte ruido en todas partes.

El siguiente ejemplo muestra los enfoques que utilizan un circuito simple con ruido despolarizante y un canal Kraus personalizado.

# Bottom up approach # apply depolarizing noise to qubit 0 with probability of 0.1 circ = Circuit().x(0).x(1).depolarizing(0, probability=0.1) # create an arbitrary 2-qubit Kraus channel E0 = scipy.stats.unitary_group.rvs(4) * np.sqrt(0.8) E1 = scipy.stats.unitary_group.rvs(4) * np.sqrt(0.2) K = [E0, E1] # apply a two-qubit Kraus channel to qubits 0 and 2 circ = circ.kraus([0,2], K)
# Inject noise approach # define phase damping noise noise = Noise.PhaseDamping(gamma=0.1) # the noise channel is applied to all the X gates in the circuit circ = Circuit().x(0).y(1).cnot(0,2).x(1).z(2) circ_noise = circ.copy() circ_noise.apply_gate_noise(noise, target_gates = Gate.X)

La ejecución de un circuito es la misma experiencia de usuario que antes, como se muestra en los dos ejemplos siguientes.

Ejemplo 1

task = device.run(circ, s3_location)

Or (Disyunción)

Ejemplo 2

task = device.run(circ_noise, s3_location)

Para ver más ejemplos, consulte el ejemplo introductorio del simulador de ruido Braket