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 inoltre istruzioni su come effettuare l'allocazione manuale qubits, ordina al compilatore di eseguire i circuiti esattamente come definiti e crea circuiti rumorosi con un simulatore di rumore.
In Braket puoi anche lavorare a livello di pulsazioni per vari cancelli, tra cui alcuni. QPUs Per ulteriori informazioni, consulta Pulse Control su Amazon Braket.
In questa sezione:
Cancelli e circuiti
Le porte e i circuiti quantistici sono definiti nella braket.circuits
Circuit()
Esempio: definire un circuito
L'esempio inizia definendo un circuito campione di quattro qubits (etichettatoq0
, q1
q2
, eq3
) costituito da porte Hadamard standard a qubit singolo 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-C--- | q1 : -H-|-C- | | 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)
Nota che non my_circuit
è modificato, quindi puoi usarlo per creare istanze 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 tutte le porte disponibili in Amazon Staffa.
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', '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']
Ognuna di queste porte può essere aggiunta a un circuito chiamando il metodo per quel tipo di circuito. Ad esempio, dovresti chiamarecirc.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 illustrato nel codice sorgente seguente) o porte a più qubit applicate a qubits definito dal parametro. 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. Instruction
gli 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]) new_instr = instr.copy(target_mapping={0: 5})
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 the Aria-1 device: ['x', 'y', 'z', 'rx', 'ry', 'rz', 'h', 'cnot', 's', 'si', 't', 'ti', 'v', 'vi', 'xx', 'yy', 'zz', 'swap']
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 le due qubit fedeltà tra due porte 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}")
Misurazione parziale
Seguendo gli esempi precedenti, abbiamo misurato tutti i qubit del circuito quantistico. Tuttavia, è possibile misurare singoli qubit o un sottoinsieme di qubit.
Esempio: misura un sottoinsieme di qubit
In questo esempio, dimostriamo una misurazione parziale aggiungendo un'measure
istruzione con i qubit target alla fine 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)
Manuale qubit assegnazione
Quando si esegue un circuito quantistico su computer quantistici da Rigetti, puoi opzionalmente usare il manuale qubit allocazione per controllare quali qubits vengono utilizzati per il tuo algoritmo. La console Amazon Braket
Manuale qubit l'allocazione consente di far funzionare i circuiti con maggiore precisione e di analizzarne i singoli elementi qubit proprietà. Ricercatori e 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 allocare qubits esplicitamente.
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)
Per ulteriori informazioni, consulta gli esempi di Amazon Braket su GitHub, o più specificamente, su
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 (supportato da Rigetti solo). 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 vi dà il controllo diretto sul processo di compilazione disattivando alcune fasi di ottimizzazione, garantendo così che i circuiti funzionino esattamente come previsto.
La compilazione Verbatim è attualmente supportata su Rigetti, IonQe IQM dispositivi e richiede l'uso di porte native. Quando si utilizza la compilazione letterale, è consigliabile controllare la topologia del dispositivo per assicurarsi che le porte vengano richiamate e collegate qubits 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
In Rigetti, qubit il ricablaggio deve essere disattivato impostando 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.
Nota
Se si utilizza OpenQASM per scrivere i circuiti per IonQ dispositivo e desideri mappare il tuo circuito direttamente sui qubit fisici, devi usare il flag #pragma braket verbatim
poiché il disableQubitRewiring
flag viene completamente ignorato da OpenQASM.
Simulazione del rumore
Per creare un'istanza del simulatore di rumore locale è possibile modificare il backend come segue.
device = LocalSimulator(backend="braket_dm")
È possibile creare circuiti rumorosi in due modi:
-
Costruisci il circuito rumoroso dal basso verso l'alto.
-
Prendi un circuito esistente e privo di rumore e inietta rumore dappertutto.
L'esempio seguente mostra gli approcci che utilizzano un circuito semplice con rumore depolarizzante e un canale Kraus personalizzato.
# 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 gestione di un circuito è la stessa esperienza utente di prima, come illustrato nei due esempi seguenti.
Esempio 1
task = device.run(circ, s3_location)
Or
Esempio 2
task = device.run(circ_noise, s3_location)
Per altri esempi, vedi l'esempio introduttivo del simulatore di rumore Braket