Aufbau von Schaltungen in der SDK - Amazon Braket

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Aufbau von Schaltungen in der SDK

Dieser Abschnitt enthält Beispiele für das Definieren eines Schaltkreises, das Anzeigen verfügbarer Gates, das Erweitern eines Schaltkreises und das Anzeigen von Gates, die jedes Gerät unterstützt. Er enthält auch Anweisungen zur manuellen Zuweisung qubits, weisen Sie den Compiler an, Ihre Schaltungen genau wie definiert auszuführen, und erstellen Sie mit einem Geräuschsimulator verrauschte Schaltungen.

Mit bestimmten Werten können Sie in Braket auch auf Pulsebene für verschiedene Gatter arbeiten. QPUs Weitere Informationen finden Sie unter Pulse Control auf Amazon Braket.

Tore und Stromkreise

Quantengatter und Schaltkreise werden in der braket.circuitsKlasse Amazon Braket Python SDK definiert. Von der SDK aus können Sie ein neues Schaltungsobjekt instanziieren, indem Sie es aufrufen. Circuit()

Beispiel: Definieren Sie einen Schaltkreis

Das Beispiel beginnt mit der Definition eines Beispielkreislaufs aus vier qubits (beschriftet mitq0, q1q2, undq3) bestehend aus Standard-Hadamard-Gates mit einem Qubit und Gates mit zwei Qubits. CNOT Sie können diesen Schaltkreis visualisieren, indem Sie die Funktion aufrufen, wie das folgende Beispiel zeigtprint.

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

Beispiel: Definieren Sie einen parametrisierten Schaltkreis

In diesem Beispiel definieren wir einen Schaltkreis mit Gattern, die von freien Parametern abhängen. Wir können die Werte dieser Parameter angeben, um eine neue Schaltung zu erstellen oder, wenn wir die Schaltung einreichen, um sie als Quantenaufgabe auf bestimmten Geräten auszuführen.

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)

Sie können aus einem parametrisierten Schaltkreis einen neuen, nicht parametrisierten Schaltkreis erstellen, indem Sie entweder einzelne Argumente float (das ist der Wert, den alle freien Parameter annehmen) oder Schlüsselwortargumente angeben, die den Wert jedes Parameters für den Schaltkreis wie folgt angeben.

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

Beachten Sie, dass er unverändert my_circuit ist, sodass Sie ihn verwenden können, um viele neue Schaltungen mit festen Parameterwerten zu instanziieren.

Beispiel: Ändern Sie Gates in einem Schaltkreis

Das folgende Beispiel definiert einen Schaltkreis mit Gattern, die Steuerungs- und Leistungsmodifikatoren verwenden. Sie können diese Änderungen verwenden, um neue Tore zu erstellen, z. B. das gesteuerte Ry Tor.

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)

Tormodifikatoren werden nur im lokalen Simulator unterstützt.

Beispiel: Alle verfügbaren Gates anzeigen

Das folgende Beispiel zeigt, wie Sie sich alle verfügbaren Gates in ansehen Amazon Klammer.

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)

Die Ausgabe dieses Codes listet alle Gates auf.

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

Jedes dieser Gatter kann an einen Schaltkreis angehängt werden, indem die Methode für diesen Schaltungstyp aufgerufen wird. Sie würden zum Beispiel aufrufencirc.h(0), um dem ersten ein Hadamard-Gate hinzuzufügen qubit.

Anmerkung

Gatter werden an der richtigen Stelle angefügt, und im folgenden Beispiel werden alle im vorherigen Beispiel aufgelisteten Gatter zu demselben Schaltkreis hinzugefügt.

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)

Neben dem vordefinierten Gattersatz können Sie dem Schaltkreis auch selbstdefinierte einheitliche Gatter zuweisen. Dabei kann es sich um Single-Qubit-Gates (wie im folgenden Quellcode gezeigt) oder um Multi-Qubit-Gates handeln, die auf die qubits durch den Parameter definiert. targets

import numpy as np # apply a general unitary my_unitary = np.array([[0, 1],[1, 0]]) circ.unitary(matrix=my_unitary, targets=[0])

Beispiel: Erweitern Sie bestehende Schaltungen

Sie können bestehende Schaltkreise erweitern, indem Sie Anweisungen hinzufügen. An Instruction ist eine Quantenrichtlinie, die die Quantenaufgabe beschreibt, die auf einem Quantengerät ausgeführt werden muss. InstructionOperatoren schließen Gate nur Objekte des Typs ein.

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

Beispiel: Sehen Sie sich die Gates an, die jedes Gerät unterstützt

Simulatoren unterstützen alle Gates im BraketSDK, QPU Geräte unterstützen jedoch eine kleinere Teilmenge. Die unterstützten Gates eines Geräts finden Sie in den Geräteeigenschaften. Das Folgende zeigt ein Beispiel mit einem IonQ-Gerät:

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

Unterstützte Gates müssen möglicherweise zu nativen Gates kompiliert werden, bevor sie auf Quantenhardware laufen können. Wenn Sie eine Schaltung einreichen, Amazon Braket führt diese Kompilierung automatisch durch.

Beispiel: Rufen Sie programmgesteuert die Genauigkeit von systemeigenen Gates ab, die von einem Gerät unterstützt werden

Sie können die Genauigkeitsinformationen auf der Geräteseite der Braket-Konsole einsehen. Manchmal ist es hilfreich, programmgesteuert auf dieselben Informationen zuzugreifen. Der folgende Code zeigt, wie die beiden extrahiert werden qubit Gate-Treue zwischen zwei Gates von QPU a.

# import the device module from braket.aws import AwsDevice device = AwsDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2") #specify the qubits a=10 b=11 print(f"Fidelity of the ISWAP gate between qubits {a} and {b}: ", device.properties.provider.specs["2Q"][f"{a}-{b}"]["fISWAP"])

Teilmessung

In Anlehnung an die vorherigen Beispiele haben wir alle Qubits im Quantenkreis gemessen. Es ist jedoch möglich, einzelne Qubits oder eine Teilmenge von Qubits zu messen.

Beispiel: Messen Sie eine Teilmenge von Qubits

In diesem Beispiel demonstrieren wir eine Teilmessung, indem wir am Ende der measure Schaltung eine Anweisung mit den Ziel-Qubits hinzufügen.

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

Manuell qubit Zuweisung

Wenn Sie eine Quantenschaltung auf Quantencomputern von ausführen Rigetti, können Sie optional manuell verwenden qubit Zuordnung zur Steuerung welcher qubits werden für Ihren Algorithmus verwendet. Die Amazon Braket-Konsole und die Amazon Braket-Konsole SDK helfen Ihnen dabei, die neuesten Kalibrierungsdaten Ihres ausgewählten Geräts mit Quantenverarbeitungseinheit (QPU) zu überprüfen, sodass Sie das beste auswählen können qubits für Ihr Experiment.

Manuell qubit Die Zuordnung ermöglicht es Ihnen, Schaltungen mit größerer Genauigkeit auszuführen und einzelne zu untersuchen qubit Eigenschaften. Forscher und fortgeschrittene Anwender optimieren ihr Schaltungsdesign auf der Grundlage der neuesten Gerätekalibrierungsdaten und können genauere Ergebnisse erzielen.

Das folgende Beispiel zeigt, wie die Zuordnung erfolgt qubits explizit.

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)

Weitere Informationen finden Sie in den Amazon Braket-Beispielen auf GitHub oder genauer gesagt in diesem Notizbuch: Zuweisen von Qubits auf Geräten. QPU

Wörtliche Zusammenstellung

Wenn Sie eine Quantenschaltung auf Gate-basierten Quantencomputern ausführen, können Sie den Compiler anweisen, Ihre Schaltungen ohne Änderungen exakt so auszuführen, wie sie definiert sind. Mithilfe der wörtlichen Kompilierung können Sie entweder festlegen, dass ein ganzer Schaltkreis exakt wie spezifiziert erhalten bleibt oder dass nur bestimmte Teile davon erhalten bleiben (unterstützt von Rigetti nur). Bei der Entwicklung von Algorithmen für Hardware-Benchmarking- oder Fehlerminimierungsprotokolle müssen Sie die Möglichkeit haben, die Gates und Schaltungslayouts, die Sie auf der Hardware ausführen, genau zu spezifizieren. Die wörtliche Kompilierung gibt Ihnen direkte Kontrolle über den Kompilierungsprozess, indem Sie bestimmte Optimierungsschritte ausschalten und so sicherstellen, dass Ihre Schaltungen genau so laufen, wie sie entworfen wurden.

Die verbatim-Kompilierung wird derzeit auf dem unterstützt Rigetti, IonQ, und IQM Geräte und erfordert die Verwendung nativer Gates. Bei der wörtlichen Kompilierung ist es ratsam, die Topologie des Geräts zu überprüfen, um sicherzustellen, dass die Gates aufgerufen und verbunden sind qubits und dass die Schaltung die systemeigenen Gates verwendet, die von der Hardware unterstützt werden. Das folgende Beispiel zeigt, wie Sie programmgesteuert auf die Liste der systemeigenen Gates zugreifen können, die von einem Gerät unterstützt werden.

device.properties.paradigm.nativeGateSet

Wählen Sie in der &Snowconsole; Ihren Auftrag aus der Tabelle. Rigetti, qubit Die Neuverkabelung muss durch die Einstellung disableQubitRewiring=True für die Verwendung mit wörtlicher Kompilierung ausgeschaltet werden. Wenn diese disableQubitRewiring=False Option gesetzt ist, wenn in einer Kompilierung wörtliche Boxen verwendet werden, schlägt der Quantenschaltkreis bei der Validierung fehl und kann nicht ausgeführt werden.

Wenn die wörtliche Kompilierung für eine Schaltung aktiviert ist und auf einer ausgeführt wirdQPU, die sie nicht unterstützt, wird ein Fehler generiert, der darauf hinweist, dass ein nicht unterstützter Vorgang zum Fehlschlagen der Aufgabe geführt hat. Da immer mehr Quantenhardware Compilerfunktionen nativ unterstützt, wird diese Funktion um diese Geräte erweitert. Geräte, die die wörtliche Kompilierung unterstützen, schließen sie als unterstützten Vorgang ein, wenn sie mit dem folgenden Code abgefragt werden.

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-2") device.properties.action[DeviceActionType.OPENQASM].supportedPragmas

Mit der verbatim-Kompilierung sind keine zusätzlichen Kosten verbunden. Ihnen werden weiterhin Quantenaufgaben, die auf QPU Braket-Geräten, Notebook-Instances und On-Demand-Simulatoren ausgeführt werden, auf der Grundlage der aktuellen Tarife berechnet, die auf der Seite mit den Amazon Braket-Preisen angegeben sind. Weitere Informationen finden Sie im Beispiel-Notizbuch für die Verbatim-Kompilierung.

Anmerkung

Wenn Sie Open verwenden, QASM um Ihre Schaltungen für das zu schreiben IonQ Gerät, und Sie möchten Ihre Schaltung direkt den physikalischen Qubits zuordnen, müssen Sie das verwenden, #pragma braket verbatim da das disableQubitRewiring Flag von Open QASM komplett ignoriert wird.

Simulation von Geräuschen

Um den lokalen Geräuschsimulator zu instanziieren, können Sie das Backend wie folgt ändern.

device = LocalSimulator(backend="braket_dm")

Sie können geräuschbehaftete Schaltungen auf zwei Arten aufbauen:

  1. Baue den lauten Stromkreis von unten nach oben auf.

  2. Nehmen Sie einen vorhandenen, rauschfreien Stromkreis und fügen Sie überall Rauschen ein.

Das folgende Beispiel zeigt die Ansätze, bei denen eine einfache Schaltung mit depolarisierendem Rauschen und ein benutzerdefinierter Kraus-Kanal verwendet werden.

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

Das Ausführen einer Schaltung bietet dieselbe Benutzererfahrung wie zuvor, wie in den folgenden beiden Beispielen gezeigt.

Beispiel 1

task = device.run(circ, s3_location)

Oder

Beispiel 2

task = device.run(circ_noise, s3_location)

Weitere Beispiele finden Sie im einführenden Beispiel für einen Geräuschsimulator in Braket