Konstruieren Sie Schaltkreise im 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.

Konstruieren Sie Schaltkreise im 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, zur Anweisung an den Compilerqubits, Ihre Schaltungen exakt wie definiert auszuführen, und zur Erstellung von verrauschten Schaltungen mit einem Geräuschsimulator.

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

Tore und Stromkreise

Quantengatter und Schaltkreise sind in der braket.circuitsKlasse des Amazon Braket Python SDK definiert. Im SDK können Sie ein neues Circuit-Objekt instanziieren, indem Sie es aufrufen. Circuit()

Beispiel: Definieren Sie einen Schaltkreis

Das Beispiel beginnt mit der Definition eines Beispielschaltkreises mit vier qubits (mit,, und beschriftetq3) q0 q1q2, der aus standardmäßigen Single-Qubit-Hadamard-Gattern und Zwei-Qubit-CNOT-Gattern besteht. Sie können diesen Schaltkreis visualisieren, indem Sie die Funktion aufrufen, wie das folgende Beispiel zeigt. 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 |

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, sie als Quantenaufgabe auf bestimmten Geräten laufen zu lassen.

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 auf dem lokalen Simulator unterstützt.

Beispiel: Alle verfügbaren Gates anzeigen

Das folgende Beispiel zeigt, wie Sie sich alle verfügbaren Gates in Amazon Braket ansehen können.

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 beispielsweise 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 durch den Parameter definierten Gates angewendet werden. 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])

Beispiel: Erweitern Sie bestehende Schaltungen

Sie können bestehende Schaltungen 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 Braket-SDK, aber QPU-Geräte unterstützen eine kleinere Teilmenge. Sie finden die unterstützten Gates eines Geräts 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/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']

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

Beispiel: Rufen Sie programmgesteuert die Genauigkeit systemeigener 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 qubit Zwei-Gate-Treue zwischen zwei Gates einer QPU extrahiert wird.

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

Teilweise Messung

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)

Manuelle Zuordnung qubit

Wenn Sie einen Quantenschaltkreis auf Quantencomputern von aus ausführenRigetti, können Sie optional die manuelle qubit Zuordnung verwenden, um zu steuern, welche für Ihren Algorithmus verwendet qubits werden. Die Amazon Braket-Konsole und das Amazon Braket-SDK helfen Ihnen dabei, die neuesten Kalibrierungsdaten Ihres ausgewählten QPU-Geräts (Quantum Processing Unit) zu überprüfen, sodass Sie das Beste qubits für Ihr Experiment auswählen können.

Durch die manuelle qubit Zuordnung können Sie Schaltungen mit höherer Genauigkeit ausführen und einzelne Eigenschaften untersuchen. qubit 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 eine qubits explizite Zuordnung vorgenommen wird.

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 QPU-Geräten.

Anmerkung

Der OQC Compiler unterstützt keine Einstellungen. disable_qubit_rewiring=True Wenn Sie dieses Flag auf setzenTrue, wird der folgende Fehler angezeigt: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.

Wörtliche Kompilierung

Wenn Sie einen Quantenschaltkreis auf Quantencomputern vonRigetti,, IonQ oder Oxford Quantum Circuits (OQC) aus 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 angegeben beibehalten wird (unterstützt von RigettiIonQ, undOQC) oder dass nur bestimmte Teile davon erhalten bleiben (nur unterstützt vonRigetti). 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 Geräten RigettiIonQ, und Oxford Quantum Circuits (OQC) unterstützt und erfordert die Verwendung systemeigener Gatter. Bei der verbatim-Kompilierung empfiehlt es sich, die Topologie des Geräts zu überprüfen, um sicherzustellen, dass die Gates aufgerufen qubits und verbunden sind und dass die Schaltung die systemeigenen Gatter 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

Denn die Rigetti qubit 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 sie auf einer QPU ausgeführt wird, 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/Aspen-M-3") device.properties.action[DeviceActionType.OPENQASM].supportedPragmas

Mit der verbatim-Kompilierung sind keine zusätzlichen Kosten verbunden. Ihnen werden weiterhin Quantenaufgaben, die auf Braket QPU-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 zur Verbatim-Kompilierung.

Anmerkung

Wenn Sie OpenQASM verwenden, um Ihre Schaltungen für die OQC IonQ AND-Geräte zu schreiben, und Sie Ihre Schaltung direkt den physikalischen Qubits zuordnen möchten, müssen Sie das verwenden, #pragma braket verbatim da das disableQubitRewiring Flag von OpenQASM vollständig ignoriert wird.

Geräuschsimulation

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