Construa circuitos no SDK - Amazon Braket

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Construa circuitos no SDK

Esta seção fornece exemplos de definição de um circuito, visualização das portas disponíveis, extensão de um circuito e visualização das portas suportadas por cada dispositivo. Ele também contém instruções sobre como alocar manualmentequbits, instruir o compilador a executar seus circuitos exatamente conforme definido e criar circuitos ruidosos com um simulador de ruído.

Você também pode trabalhar no nível de pulso no Braket para várias portas com determinadas QPUs. Para obter mais informações, consulte Pulse Control no Amazon Braket.

Portões e circuitos

As portas e circuitos quânticos são definidos na braket.circuitsclasse do SDK Amazon Braket Python. No SDK, você pode instanciar um novo objeto de circuito chamando. Circuit()

Exemplo: definir um circuito

O exemplo começa definindo um circuito de amostra de quatro qubits (rotuladoq0,, q1q2, eq3) consistindo em portas Hadamard padrão de um qubit e portas CNOT de dois qubits. Você pode visualizar esse circuito chamando a print função conforme mostra o exemplo a seguir.

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

Exemplo: definir um circuito parametrizado

Neste exemplo, definimos um circuito com portas que dependem de parâmetros livres. Podemos especificar os valores desses parâmetros para criar um novo circuito ou, ao enviar o circuito, para ser executado como uma tarefa quântica em 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)

Você pode criar um novo circuito não parametrizado a partir de um parametrizado fornecendo um único float (que é o valor que todos os parâmetros livres terão) ou argumentos de palavra-chave especificando o valor de cada parâmetro para o circuito da seguinte forma.

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

Observe que my_circuit não foi modificado, então você pode usá-lo para instanciar muitos novos circuitos com valores de parâmetros fixos.

Exemplo: Modificar portas em um circuito

O exemplo a seguir define um circuito com portas que usam modificadores de controle e potência. Você pode usar essas modificações para criar novos portões, como o Ry portão controlado.

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)

Os modificadores de porta são suportados somente no simulador local.

Exemplo: Veja todos os portões disponíveis

O exemplo a seguir mostra como ver todas as portas disponíveis no 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)

A saída desse código lista todas as portas.

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

Qualquer uma dessas portas pode ser anexada a um circuito chamando o método para esse tipo de circuito. Por exemplo, você circ.h(0) ligaria para adicionar um portão Hadamard ao primeiro. qubit

nota

As portas são anexadas no local, e o exemplo a seguir adiciona todas as portas listadas no exemplo anterior ao mesmo 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)

Além do conjunto de portas predefinido, você também pode aplicar portas unitárias autodefinidas ao circuito. Elas podem ser portas de um único qubit (conforme mostrado no código-fonte a seguir) ou portas de vários qubits aplicadas ao qubits definido pelo parâmetro. targets

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

Exemplo: Estenda os circuitos existentes

Você pode estender os circuitos existentes adicionando instruções. An Instruction é uma diretiva quântica que descreve a tarefa quântica a ser executada em um dispositivo quântico. Instructionos operadores incluem Gate somente objetos do 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]) new_instr = instr.copy(target_mapping={0: 5})

Exemplo: veja os portões que cada dispositivo suporta

Os simuladores oferecem suporte a todas as portas no SDK do Braket, mas os dispositivos QPU oferecem suporte a um subconjunto menor. Você pode encontrar as portas suportadas de um dispositivo nas propriedades do dispositivo. O seguinte mostra um exemplo com um dispositivo IonQ:

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

As portas suportadas podem precisar ser compiladas em portas nativas antes de poderem ser executadas em hardware quântico. Quando você envia um circuito, o Amazon Braket executa essa compilação automaticamente.

Exemplo: recupere programaticamente a fidelidade das portas nativas suportadas por um dispositivo

Você pode ver as informações de fidelidade na página Dispositivos do console Braket. Às vezes, é útil acessar as mesmas informações programaticamente. O código a seguir mostra como extrair a fidelidade de duas qubit portas entre duas portas de uma QPU.

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

Medição parcial

Seguindo os exemplos anteriores, medimos todos os qubits no circuito quântico. No entanto, é possível medir qubits individuais ou um subconjunto de qubits.

Exemplo: medir um subconjunto de qubits

Neste exemplo, demonstramos uma medição parcial adicionando uma measure instrução com os qubits de destino ao final do 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)

qubitAlocação manual

Ao executar um circuito quântico em computadores quânticos a partir deRigetti, você pode, opcionalmente, usar a qubit alocação manual para controlar quais qubits são usados em seu algoritmo. O Amazon Braket Console e o Amazon Braket SDK ajudam você a inspecionar os dados de calibração mais recentes do dispositivo de unidade de processamento quântico (QPU) selecionado, para que você possa selecionar o melhor para seu experimento. qubits

A qubit alocação manual permite que você execute circuitos com maior precisão e investigue qubit propriedades individuais. Pesquisadores e usuários avançados otimizam o projeto do circuito com base nos dados mais recentes de calibração do dispositivo e podem obter resultados mais precisos.

O exemplo a seguir demonstra como alocar explicitamentequbits.

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)

Para obter mais informações, consulte os exemplos do Amazon Braket GitHub em, ou mais especificamente, neste notebook: Alocação de qubits em dispositivos QPU.

nota

O OQC compilador não oferece suporte à configuraçãodisable_qubit_rewiring=True. Definir esse sinalizador como True gera o seguinte erro: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.

Compilação literal

Quando você executa um circuito quântico em computadores quânticos a partir de RigettiIonQ,, ou Oxford Quantum Circuits (OQC), você pode direcionar o compilador para executar seus circuitos exatamente como definido, sem nenhuma modificação. Usando a compilação literal, você pode especificar que um circuito inteiro seja preservado com precisão (suportado porRigetti,IonQ, eOQC) conforme especificado ou que somente partes específicas dele sejam preservadas (suportadas somente porRigetti). Ao desenvolver algoritmos para benchmarking de hardware ou protocolos de mitigação de erros, você precisa ter a opção de especificar exatamente os layouts de portas e circuitos que você está executando no hardware. A compilação integral oferece controle direto sobre o processo de compilação, desativando determinadas etapas de otimização, garantindo assim que seus circuitos funcionem exatamente como projetado.

Atualmente, a compilação literal é suportada em dispositivos RigettiIonQ, e Oxford Quantum Circuits (OQC) e requer o uso de portas nativas. Ao usar a compilação literal, é aconselhável verificar a topologia do dispositivo para garantir que as portas sejam chamadas conectadas qubits e que o circuito use as portas nativas suportadas no hardware. O exemplo a seguir mostra como acessar programaticamente a lista de portas nativas suportadas por um dispositivo.

device.properties.paradigm.nativeGateSet

PoisRigetti, a qubit reconexão deve ser desativada configurando disableQubitRewiring=True para uso com compilação literal. Se disableQubitRewiring=False for definido ao usar caixas textuais em uma compilação, o circuito quântico falha na validação e não será executado.

Se a compilação literal estiver habilitada para um circuito e executada em uma QPU que não a suporta, um erro é gerado indicando que uma operação não suportada causou a falha da tarefa. À medida que mais hardware quântico oferece suporte nativo às funções do compilador, esse recurso será expandido para incluir esses dispositivos. Os dispositivos que oferecem suporte à compilação literal a incluem como uma operação compatível quando consultados com o código a seguir.

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

Não há custo adicional associado ao uso da compilação literal. Você continua sendo cobrado por tarefas quânticas executadas em dispositivos Braket QPU, instâncias de notebook e simuladores sob demanda com base nas taxas atuais, conforme especificado na página de preços do Amazon Braket. Para obter mais informações, consulte o caderno de exemplo de compilação Verbatim.

nota

Se você estiver usando o OpenQASM para escrever seus circuitos para os IonQ dispositivos OQC e quiser mapear seu circuito diretamente para os qubits físicos, precisará usar o, #pragma braket verbatim pois o disableQubitRewiring sinalizador é completamente ignorado pelo OpenQASM.

Simulação de ruído

Para instanciar o simulador de ruído local, você pode alterar o back-end da seguinte maneira.

device = LocalSimulator(backend="braket_dm")

Você pode criar circuitos ruidosos de duas maneiras:

  1. Construa o circuito ruidoso de baixo para cima.

  2. Pegue um circuito existente e livre de ruído e injete ruído por toda parte.

O exemplo a seguir mostra as abordagens usando um circuito simples com ruído despolarizador e um canal Kraus personalizado.

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

Executar um circuito é a mesma experiência de usuário de antes, conforme mostrado nos dois exemplos a seguir.

Exemplo 1

task = device.run(circ, s3_location)

Ou

Exemplo 2

task = device.run(circ_noise, s3_location)

Para obter mais exemplos, consulte o exemplo introdutório do simulador de ruído Braket