Construir circuitos en el SDK - Amazon Braket

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.

Construir circuitos en el SDK

En esta sección se proporcionan ejemplos de 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 asignar manualmente qubits, indique al compilador que ejecute sus circuitos exactamente como se ha definido y cree circuitos ruidosos con un simulador de ruido.

También puedes trabajar al nivel del pulso en Braket para varias compuertas, con algunas. 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, puede 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 (denominadoq0, 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, 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

En el siguiente ejemplo se 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 compuertas.

['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 lugar 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 al qubits definidas por el parámetro. 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/Aria-1") # 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 Aria-1 device: ['x', 'y', 'z', 'rx', 'ry', 'rz', 'h', 'cnot', 's', 'si', 't', 'ti', 'v', 'vi', 'xx', 'yy', 'zz', 'swap']

Es posible que las puertas compatibles deban compilarse en puertas nativas antes de que puedan ejecutarse en hardware cuántico. Al enviar 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 los dos qubit fidelidad de puerta 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/Ankaa-3") #specify the qubits a=10 b=11 edge_properties_entry = device.properties.standardized.twoQubitProperties['10-11'].twoQubitGateFidelity gate_name = edge_properties_entry[0].gateName fidelity = edge_properties_entry[0].fidelity print(f"Fidelity of the {gate_name} gate between qubits {a} and {b}: {fidelity}")

Medición parcial

Siguiendo los ejemplos anteriores, hemos medido todos los cúbits del circuito cuántico. Sin embargo, es posible medir qubits individuales o un subconjunto de qubits.

Ejemplo: mida un subconjunto de qubits

En este ejemplo, demostramos una medición parcial añadiendo una measure instrucción con los cúbits objetivo al final del circuito.

# Use the local state vector simulator device = LocalSimulator() # Define an example bell circuit and measure qubit 0 circuit = Circuit().h(0).cnot(0, 1).measure(0) # Run the circuit task = device.run(circuit, shots=10) # Get the results result = task.result() # Print the circuit and measured qubits print(circuit) print() print("Measured qubits: ", result.measured_qubits)

Manual qubit asignación

Cuando ejecutas un circuito cuántico en ordenadores cuánticos desde Rigetti, si lo desea, puede utilizar el manual qubit asignación para controlar qué qubits se 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 para que pueda seleccionar el mejor qubits para tu experimento.

Manual qubit la asignación le permite ejecutar circuitos con mayor precisión e investigar de forma individual qubit propiedades. Los investigadores y los usuarios avanzados optimizan el diseño de sus circuitos en función de los últimos datos de calibración del dispositivo y pueden obtener resultados más precisos.

El siguiente ejemplo muestra cómo asignar qubits de 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.

Recopilación literal

Cuando ejecuta un circuito cuántico en ordenadores cuánticos basados en puertas, puede indicar al compilador que ejecute sus circuitos exactamente como se ha definido sin ninguna modificación. Mediante la compilación literal, puede especificar que un circuito completo se conserve exactamente como se ha especificado o que solo se conserven partes específicas del mismo (con el apoyo de Rigetti únicamente). 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 exactamente 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 el Rigetti, IonQ, y IQM dispositivos y requiere el uso de puertas nativas. Al utilizar la compilación literal, se recomienda comprobar la topología del dispositivo para asegurarse de que las puertas estén conectadas qubits y que el circuito utilice las puertas 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

En Rigetti, qubit El recableado debe desactivarse configurándolo disableQubitRewiring=True para su uso con la compilación literal. Si disableQubitRewiring=False se establece cuando se utilizan cuadros 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/Ankaa-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 sus circuitos para el IonQ y desea mapear su circuito directamente a los qubits físicos, debe usar el, #pragma braket verbatim ya que OpenQASM ignora por completo el 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)

O

Ejemplo 2

task = device.run(circ_noise, s3_location)

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