Costruzione di circuiti nell'SDK - Amazon Braket

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Costruzione di circuiti nell'SDK

Questa sezione fornisce esempi di definizione di un circuito, visualizzazione delle porte disponibili, estensione di un circuito e visualizzazione delle porte supportate da ciascun dispositivo. Contiene anche istruzioni su come allocare manualmentequbits, indicare al compilatore di eseguire i circuiti esattamente come definito e creare circuiti rumorosi con un simulatore di rumore.

In Braket puoi anche lavorare a livello di impulsi per vari cancelli, con determinati tipi di porte. QPUs Per ulteriori informazioni, consulta Pulse Control su Amazon Braket.

Cancelli e circuiti

Le porte e i circuiti quantistici sono definiti nella braket.circuitsclasse dell'SDK Amazon Braket Python. Dall'SDK, puoi creare un'istanza di un nuovo oggetto di circuito chiamando. Circuit()

Esempio: definire un circuito

L'esempio inizia definendo un circuito campione di quattro qubits (etichettatiq0, q1q2, eq3) costituiti da porte Hadamard standard a singolo qubit e porte CNOT a due qubit. È possibile visualizzare questo circuito chiamando la funzione come illustrato nell'esempio seguente. 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 │

Esempio: definire un circuito parametrizzato

In questo esempio, definiamo un circuito con porte che dipendono da parametri liberi. Possiamo specificare i valori di questi parametri per creare un nuovo circuito o, quando inviamo il circuito, per eseguirlo come attività quantistica su determinati dispositivi.

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)

È possibile creare un nuovo circuito non parametrizzato a partire da un circuito parametrizzato fornendo un singolo circuito float (che è il valore che assumeranno tutti i parametri liberi) o argomenti di parole chiave che specificano il valore di ciascun parametro al circuito come segue.

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

Nota che non my_circuit è modificato, quindi puoi usarlo per creare istanziazioni di molti nuovi circuiti con valori di parametro fissi.

Esempio: modifica delle porte in un circuito

L'esempio seguente definisce un circuito con porte che utilizzano modificatori di controllo e potenza. È possibile utilizzare queste modifiche per creare nuove porte, come la porta controllata. Ry

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)

I modificatori di porta sono supportati solo sul simulatore locale.

Esempio: visualizza tutte le porte disponibili

L'esempio seguente mostra come visualizzare tutti i gate disponibili in 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)

L'output di questo codice elenca tutte le porte.

['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']

Ognuna di queste porte può essere aggiunta a un circuito chiamando il metodo per quel tipo di circuito. Ad esempio, chiamatecirc.h(0), per aggiungere una porta Hadamard alla prima. qubit

Nota

Le porte vengono aggiunte al loro posto e l'esempio che segue aggiunge tutte le porte elencate nell'esempio precedente allo stesso 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)

Oltre al set di porte predefinito, è possibile applicare al circuito anche porte unitarie autodefinite. Queste possono essere porte a qubit singolo (come mostrato nel codice sorgente seguente) o porte a più qubit applicate al valore definito dal parametro. 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])

Esempio: estendere i circuiti esistenti

È possibile estendere i circuiti esistenti aggiungendo istruzioni. An Instruction è una direttiva quantistica che descrive il compito quantistico da eseguire su un dispositivo quantistico. Instructiongli operatori includono solo oggetti di tipo. Gate

# 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})

Esempio: visualizza le porte supportate da ogni dispositivo

I simulatori supportano tutte le porte dell'SDK Braket, ma i dispositivi QPU supportano un sottoinsieme più piccolo. Puoi trovare le porte supportate di un dispositivo nelle proprietà del dispositivo. Di seguito viene mostrato un esempio 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']

Potrebbe essere necessario compilare le porte supportate in porte native prima di poter essere eseguite su hardware quantistico. Quando invii un circuito, Amazon Braket esegue questa compilazione automaticamente.

Esempio: recupera a livello di codice la fedeltà delle porte native supportate da un dispositivo

È possibile visualizzare le informazioni sulla fedeltà nella pagina Dispositivi della console Braket. A volte è utile accedere alle stesse informazioni a livello di programmazione. Il codice seguente mostra come estrarre la fedeltà a due qubit gate tra due gate di 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}")

Set di programmi

I set di programmi eseguono in modo efficiente più circuiti quantistici in un'unica attività quantistica. In quell'unica attività, puoi inviare fino a 100 circuiti quantistici o un singolo circuito parametrico con un massimo di 100 set di parametri diversi. Questa operazione riduce al minimo il tempo tra le successive esecuzioni dei circuiti e riduce il sovraccarico di elaborazione delle attività quantistiche. Attualmente, i set di programmi sono supportati su Amazon Braket Local Simulator IQM e Rigetti su dispositivi.

Definizione di un ProgramSet

Il primo esempio di codice seguente mostra come costruire un ProgramSet utilizzando sia circuiti parametrizzati che circuiti senza parametri.

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, ])

Questo set di programmi contiene quattro programmi unici:circ1,, e. circ2 circ3 circuit_binding Il circuit_binding programma viene eseguito con cinque diverse associazioni di parametri, creando cinque eseguibili. Gli altri tre programmi senza parametri creano ciascuno un file eseguibile. Il risultato è un totale di otto eseguibili, come illustrato nell'immagine seguente.

ProgramSet struttura con quattro circuiti, dove c4 utilizza CircuitBinding per elaborare cinque set di input.

Il secondo esempio di codice seguente mostra come utilizzare il product() metodo per collegare lo stesso set di osservabili a ciascun eseguibile del set di programmi.

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 )

Per i programmi senza parametri, ogni osservabile viene misurato per ogni circuito. Per i programmi parametrici, ogni osservabile viene misurato per ogni set di input, come mostrato nell'immagine seguente.

ProgramSet.product che mostra l'esecuzione parallela di tre circuiti, con c3 utilizzato CircuitBinding per elaborare cinque set di input con cinque osservabili ciascuno.

Il terzo esempio di codice seguente mostra come utilizzare il zip() metodo per accoppiare singoli osservabili con set di parametri specifici in. ProgramSet

program_set_3 = ProgramSet.zip( circuits=circuit_binding, observables=observables + [Y(0) @ Y(1)] )
ProgramSet.zip con CircuitBinding dimostrazione di cinque esecuzioni parallele utilizzando un circuito condiviso con osservabile individuale per set di input.

InveceCircuitBinding(), puoi comprimere direttamente un elenco di osservabili con un elenco di circuiti e set di input.

program_set_4 = ProgramSet.zip( circuits=[circ1, circ2, circ3], input_sets=[{}, {}, {}], observables=observables[:3] )
ProgramSet.zip che mostra l'esecuzione parallela di sette circuiti con il corrispondente set di input individuale e i singoli osservabili.

Per ulteriori informazioni ed esempi sui set di programmi, consultate il notebook Program Set in Github. amazon-braket-examples

Ispeziona ed esegui un programma impostato su un dispositivo

Il numero di file eseguibili di un set di programmi è uguale al numero di circuiti univoci legati a parametri. Calcola il numero totale di eseguibili e scatti del circuito utilizzando il seguente esempio di codice.

# 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 i set di programmi, si paga una tariffa singola per operazione e una tariffa per ripresa in base al numero totale di scatti su tutti i circuiti di un set di programmi.

Per eseguire il set di programmi, utilizzate il seguente esempio di codice.

# Run the program set task = device.run( program_set_1, shots=total_num_shots, )

Quando si utilizzano Rigetti dispositivi, il set di programmi può rimanere nello RUNNING stato mentre le attività sono parzialmente terminate e parzialmente in coda. Per risultati più rapidi, valuta la possibilità di inviare il programma impostato come Hybrid Job.

Analisi dei risultati

Esegui il codice seguente per analizzare e misurare i risultati degli eseguibili in a. ProgramSet

# 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)

Misurazione parziale

Invece di misurare tutti i qubit in un circuito quantistico, utilizzate la misurazione parziale per misurare singoli qubit o un sottoinsieme di qubit.

Esempio: misura un sottoinsieme di qubit

Il seguente esempio di codice dimostra la misurazione parziale misurando solo il qubit 0 in un circuito a stato 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)

Allocazione manuale qubit

Quando esegui un circuito quantistico su computer quantistici daRigetti, puoi opzionalmente utilizzare l'qubitallocazione manuale per controllare quali qubits vengono utilizzati per il tuo algoritmo. Amazon Braket Console e Amazon Braket SDK ti aiutano a ispezionare i dati di calibrazione più recenti del dispositivo QPU (Quantum Processing Unit) selezionato, in modo da poter scegliere il migliore per il tuo esperimento. qubits

L'qubitallocazione manuale consente di far funzionare i circuiti con maggiore precisione e di esaminare le singole proprietà. qubit I ricercatori e gli utenti esperti ottimizzano la progettazione dei circuiti sulla base dei più recenti dati di calibrazione dei dispositivi e possono ottenere risultati più accurati.

L'esempio seguente mostra come qubits allocare in modo esplicito.

# 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)

Per ulteriori informazioni, consulta gli esempi di Amazon Braket su GitHub, o più specificamente, su questo notebook: Allocazione di qubit su dispositivi QPU.

Compilazione Verbatim

Quando si esegue un circuito quantistico su computer quantistici basati su gate, è possibile indirizzare il compilatore a eseguire i circuiti esattamente come definito senza alcuna modifica. Utilizzando la compilazione letterale, è possibile specificare che un intero circuito venga preservato esattamente come specificato o che vengano conservate solo parti specifiche di esso (supportata solo da). Rigetti Quando si sviluppano algoritmi per il benchmarking dell'hardware o i protocolli di mitigazione degli errori, è necessario avere la possibilità di specificare esattamente le porte e i layout dei circuiti in esecuzione sull'hardware. La compilazione Verbatim offre il controllo diretto sul processo di compilazione disattivando alcune fasi di ottimizzazione, garantendo così che i circuiti funzionino esattamente come previsto.

La compilazione Verbatim è supportata sui IQM dispositivi RigettiIonQ, e richiede l'uso di gate nativi. Quando si utilizza la compilazione verbatim, è consigliabile controllare la topologia del dispositivo per assicurarsi che le porte vengano richiamate qubits connesse e che il circuito utilizzi le porte native supportate dall'hardware. L'esempio seguente mostra come accedere a livello di codice all'elenco delle porte native supportate da un dispositivo.

device.properties.paradigm.nativeGateSet

InfattiRigetti, il qubit ricablaggio deve essere disattivato impostandolo disableQubitRewiring=True per l'uso con la compilazione letterale. Se disableQubitRewiring=False è impostato quando si usano le caselle letterali in una compilazione, il circuito quantistico fallisce la convalida e non viene eseguito.

Se la compilazione verbatim è abilitata per un circuito ed è eseguita su una QPU che non la supporta, viene generato un errore che indica che un'operazione non supportata ha causato il fallimento dell'operazione. Poiché sempre più hardware quantistico supporta nativamente le funzioni del compilatore, questa funzionalità verrà ampliata per includere questi dispositivi. I dispositivi che supportano la compilazione letterale la includono come operazione supportata quando viene richiesta con il codice seguente.

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

Non sono previsti costi aggiuntivi associati all'utilizzo della compilazione letterale. Continueranno a essere addebitati i costi per le attività quantistiche eseguite su dispositivi Braket QPU, istanze notebook e simulatori on-demand in base alle tariffe correnti, come specificato nella pagina dei prezzi di Amazon Braket. Per ulteriori informazioni, consulta il taccuino di esempio della compilazione Verbatim.

Nota

Se si utilizza OpenQASM per scrivere i circuiti del IonQ dispositivo e si desidera mappare il circuito direttamente sui qubit fisici, è necessario utilizzare il flag #pragma braket verbatim poiché il flag viene completamente ignorato da OpenQASM. disableQubitRewiring

Simulazione del rumore

Per creare un'istanza del simulatore di rumore locale è possibile modificare il backend come segue.

# Import the device module from braket.aws import AwsDevice device = LocalSimulator(backend="braket_dm")

È possibile creare circuiti rumorosi in due modi:

  1. Costruisci il circuito rumoroso dal basso verso l'alto.

  2. Prendi un circuito esistente e privo di rumore e inietta rumore dappertutto.

L'esempio seguente mostra gli approcci che utilizzano un circuito di base con rumore depolarizzante e un canale Kraus personalizzato.

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)

L'utilizzo di un circuito è la stessa esperienza utente di prima, come illustrato nei due esempi seguenti.

Esempio 1

task = device.run(circ, shots=100)

Or

Esempio 2

task = device.run(circ_noise, shots=100)

Per altri esempi, vedi l'esempio introduttivo del simulatore di rumore Braket