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 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 algunas. 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 ├───●───────── └───┘ │ ┌───┐ │ q1 : ─┤ H ├───┼─────●─── └───┘ │ │ ┌───┐ ┌─┴─┐ │ 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 nuevo circuito 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) print(my_fixed_circuit)
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', 'GPhase', 'GPi', 'GPi2', 'H', 'I', 'ISwap', 'MS', 'PRx', 'PSwap', 'PhaseShift', 'PulseGate', 'Rx', 'Ry', 'Rz', 'S', 'Si', 'Swap', 'T', 'Ti', 'U', '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, llame 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, 6]) new_instr = instr.copy(target_mapping={0: 5, 1: 6})
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 Aria 1: ['x', 'y', 'z', 'h', 's', 'si', 't', 'ti', 'v', 'vi', 'rx', 'ry', 'rz', 'cnot', 'swap', 'xx', 'yy', 'zz']
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/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}")
Conjuntos de programas
Los conjuntos de programas ejecutan de manera eficiente múltiples circuitos cuánticos en una sola tarea cuántica. En esa tarea, puede enviar hasta 100 circuitos cuánticos o un solo circuito paramétrico con hasta 100 conjuntos de parámetros diferentes. Esta operación minimiza el tiempo entre las ejecuciones subsiguientes de los circuitos y reduce la sobrecarga de procesamiento de las tareas cuánticas. Actualmente, los conjuntos de programas son compatibles con Amazon Braket Local Simulator y en los dispositivos IQM andRigetti.
Definir un ProgramSet
El siguiente primer ejemplo de código muestra cómo construir un ProgramSet
utilizando circuitos parametrizados y circuitos sin parámetros.
from braket.aws import AwsDevice from braket.circuits import Circuit, FreeParameter from braket.program_sets.circuit_binding import CircuitBinding from braket.program_sets import ProgramSet # Initialize the quantum device device = AwsDevice("arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet") # Define circuits circ1 = Circuit().h(0).cnot(0, 1) circ2 = Circuit().rx(0, 0.785).ry(1, 0.393).cnot(1, 0) circ3 = Circuit().t(0).t(1).cz(0, 1).s(0).cz(1, 2).s(1).s(2) parameterize_circuit = Circuit().rx(0, FreeParameter("alpha")).cnot(0, 1).ry(1, FreeParameter("beta")) # Create circuit bindings with different parameters circuit_binding = CircuitBinding( circuit=parameterize_circuit, input_sets={ 'alpha': (0.10, 0.11, 0.22, 0.34, 0.45), 'beta': (1.01, 1.01, 1.03, 1.04, 1.04), }) # Creating the program set program_set_1 = ProgramSet([ circ1, circ2, circ3, circuit_binding, ])
Este conjunto de programas contiene cuatro programas únicos:circ1
,circ2
, circ3
y. circuit_binding
El circuit_binding
programa se ejecuta con cinco enlaces de parámetros diferentes, lo que crea cinco ejecutables. Los otros tres programas libres de parámetros crean un ejecutable cada uno. Esto da como resultado un total de ocho ejecutables, como se muestra en la siguiente imagen.

El siguiente segundo ejemplo de código muestra cómo utilizar el product()
método para adjuntar el mismo conjunto de observables a cada ejecutable del conjunto de programas.
from braket.circuits.observables import I, X, Y, Z observables = [Z(0) @ Z(1), X(0) @ X(1), Z(0) @ X(1), X(0) @ Z(1)] program_set_2 = ProgramSet.product( circuits=[circ1, circ2, circuit_binding], observables=observables )
En el caso de los programas sin parámetros, cada observable se mide para cada circuito. Para los programas paramétricos, cada observable se mide para cada conjunto de entrada, como se muestra en la siguiente imagen.

En el tercer ejemplo de código siguiente se muestra cómo utilizar el zip()
método para emparejar observables individuales con conjuntos de parámetros específicos de. ProgramSet
program_set_3 = ProgramSet.zip( circuits=circuit_binding, observables=observables + [Y(0) @ Y(1)] )

En lugar de hacerloCircuitBinding()
, puede comprimir directamente una lista de observables con una lista de circuitos y conjuntos de entradas.
program_set_4 = ProgramSet.zip( circuits=[circ1, circ2, circ3], input_sets=[{}, {}, {}], observables=observables[:3] )

Para obtener más información y ejemplos de conjuntos de programas, consulta el cuaderno de conjuntos de programas
Inspecciona y ejecuta un conjunto de programas en un dispositivo
El número de ejecutables de un conjunto de programas es igual al número de circuitos enlazados a parámetros únicos. Calcule el número total de ejecutables y tomas de circuitos mediante el siguiente ejemplo de código.
# Number of shots per executable shots = 10 num_executables = program_set_1.total_executables # Calculate total number of shots across all executables total_num_shots = shots*num_executables
nota
Con los conjuntos de programas, se paga una tarifa única por tarea y una tarifa por toma basada en el número total de tomas en todos los circuitos de un conjunto de programas.
Para ejecutar el conjunto de programas, usa el siguiente ejemplo de código.
# Run the program set task = device.run( program_set_1, shots=total_num_shots, )
Al utilizar Rigetti dispositivos, el conjunto de programas puede permanecer en ese RUNNING
estado mientras las tareas estén parcialmente terminadas y parcialmente en cola. Para obtener resultados más rápidos, considere enviar su conjunto de programas como Hybrid Job.
Analizar los resultados
Ejecute el siguiente código para analizar y medir los resultados de los ejecutables de unProgramSet
.
# Get the results from a program set result = task.result() # Get the first executbable first_program = result[0] first_executable = first_program[0] # Inspect the results of the first executable measurements_from_first_executable = first_executable.measurements print(measurements_from_first_executable)
Medición parcial
En lugar de medir todos los qubits de un circuito cuántico, utilice la medición parcial para medir qubits individuales o un subconjunto de qubits.
nota
Las funciones adicionales, como la medición del circuito medio y las operaciones de retroalimentación, están disponibles como capacidades experimentales. Consulte el acceso a circuitos dinámicos en los dispositivos IQM.
Ejemplo: mida un subconjunto de cúbits
El siguiente ejemplo de código muestra una medición parcial midiendo solo el cúbit 0 en un circuito de estado de Bell.
from braket.devices import LocalSimulator from braket.circuits import Circuit # 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)
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.
# Import the device module from braket.aws import AwsDevice device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-3") circ = Circuit().h(0).cnot(0, 7) # Indices of actual qubits in the QPU # Set up S3 bucket (where results are stored) my_bucket = "amazon-braket-s3-demo-bucket" # The name of the bucket my_prefix = "your-folder-name" # The name of the folder in the bucket s3_location = (my_bucket, my_prefix) 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
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 (solo compatible con). Rigetti 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 los circuitos que se ejecutan 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.
La compilación literal es compatible con los IQM dispositivos RigettiIonQ, 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 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
nota
Si utilizas OpenQASM para escribir los circuitos del IonQ dispositivo y deseas mapear tu circuito directamente a los cúbits físicos, debes 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.
# Import the device module from braket.aws import AwsDevice 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 básico con ruido despolarizante y un canal Kraus personalizado.
import scipy.stats import numpy as np # 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)
from braket.circuits import Noise # 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, shots=100)
O
Ejemplo 2
task = device.run(circ_noise, shots=100)
Para ver más ejemplos, consulte el ejemplo introductorio del simulador de ruido Braket