¡Aprenda los fundamentos de la computación cuántica con! AWS Inscríbase en el plan de aprendizaje digital 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.
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.
En esta sección:
Puertas y circuitos
Las puertas y circuitos cuánticos se definen en la braket.circuits
Circuit()
Ejemplo: definir un circuito
El ejemplo comienza con la definición de un circuito de muestra de cuatro qubits (denominado q0
q1
q2
, 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. Instruction
los 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
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
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
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:
-
Construya el circuito ruidoso de abajo hacia arriba.
-
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