Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Saiba como enviar um circuito quântico do Qiskit com o QDK (Azure Quantum Development Kit). Você pode enviar circuitos do Qiskit para o Azure Quantum usando o QDK (Azure Quantum Development Kit) e o Jupyter Notebook no Visual Studio Code (VS Code). Você também pode testar seus circuitos usando o simulador esparso local. O QDK dá suporte às versões 1 e 2 do Qiskit.
Para mais informações, consulte Circuitos quânticos.
Pré-requisitos
Para obter detalhes da instalação, consulte Configurar a extensão do QDK.
Um espaço de trabalho do Azure Quantum em sua assinatura do Azure. Para criar um espaço de trabalho, consulte Criar um espaço de trabalho no Azure Quantum.
Um Python ambiente com Python e Pip instalado.
VS Code com o Kit de Desenvolvimento do Azure Quantum, o , e as Python instaladas.
A biblioteca
qdkPython com os extrasazureeqiskit, e o pacoteipykernel.python -m pip install --upgrade "qdk[azure,qiskit]" ipykernel
Criar um novo Jupyter Notebook
- No VS Code, abra o menu Exibir e escolha Paleta de Comandos.
- Insira e selecione Criar: Novo Jupyter Notebook.
- O VS Code detecta e exibe a versão do Python e do ambiente virtual Python que foram selecionados para o notebook. Se você tiver vários Python ambientes, talvez seja necessário selecionar um kernel usando o seletor de kernel no canto superior direito. Se nenhum ambiente foi detectado, consulte Jupyter Notebooks no VS Code para obter informações de configuração.
Carregar as importações necessárias
Na primeira célula do seu notebook, execute o seguinte código para carregar as importações necessárias:
from qdk.azure import Workspace
from qdk.azure.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
Conectar ao serviço do Azure Quantum
Para se conectar ao serviço do Azure Quantum, você precisa da ID do recurso e da localização do workspace do Azure Quantum.
- Faça logon em sua conta https://portal.azure.comdo Azure.
- Selecione seu workspace do Azure Quantum e vá para Visão geral.
- Copie os parâmetros ID e Local do Recurso.
Adicione uma nova célula em seu notebook e use as informações da sua conta para criar Workspace e AzureQuantumProvider objetos para se conectar ao workspace do Azure Quantum.
workspace = Workspace(
resource_id = "", # Add the resourceID of your workspace
location = "" # Add the location of your workspace (for example "westus")
)
provider = AzureQuantumProvider(workspace)
Listar todos os back-ends
Agora você pode imprimir todos os back-ends de computação quântica que estão disponíveis em seu workspace:
print("This workspace's targets:")
for backend in provider.backends():
print("- " + backend.name)
This workspace's targets:
- ionq.simulator
- ionq.qpu.aria-1
- ionq.qpu.forte-1
- ionq.qpu.forte-enterprise-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-2sc
- quantinuum.sim.h2-1e
- quantinuum.sim.h2-2e
- quantinuum.qpu.h2-1
- quantinuum.qpu.h2-2
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
- rigetti.qpu.cepheus-1-36q
Executar um circuito simples
Em uma nova célula, crie um circuito de Qiskit simples.
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])
# Print out the circuit
circuit.draw()
┌───┐ ┌─┐
q_0: ┤ H ├──■───────┤M├──────
└───┘┌─┴─┐ └╥┘┌─┐
q_1: ─────┤ X ├──■───╫─┤M├───
└───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
└───┘ ║ ║ └╥┘
c: 3/════════════════╩══╩══╩═
0 1 2
Selecione um target para executar seu programa
Executar no simulador do IonQ
Antes de executar o circuito em hardware real, teste o circuito no simulador. Use get_backend para criar um Backend objeto para se conectar ao back-end do IonQ Simulator:
simulator_backend = provider.get_backend("ionq.simulator")
Os back-ends IonQ dão suporte a portões de um conjunto de portões definido, que são compilados para serem executados de modo ideal no hardware. Se o seu circuito contiver portas que não estão nesta lista, você precisará transpilar para o suportado gateset usando a transpile função fornecida pelo Qiskit:
from qiskit import transpile
circuit = transpile(circuit, simulator_backend)
A função transpile retorna um novo objeto de circuito em que as portas são decompostas em portas com suporte no back-end especificado.
Agora você pode executar o programa por meio do serviço do Azure Quantum e obter o resultado. A célula a seguir envia um trabalho que executa o circuito com 100 disparos:
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000
Para aguardar até que o trabalho seja concluído e retornar os resultados, execute:
result = job.result()
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)
Como o resultado é um tipo de objeto específico para o pacote Qiskit, use result.get_counts e plot_histogram para visualizar os resultados. Para representar todos os rótulos de bitstring possíveis, adicione os rótulos a counts.
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}
Você também pode usar a get_memory função para exibir dados de captura individuais do trabalho:
result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']
Observação
No IonQ targets, se você enviar um trabalho com um número ímpar de tiros, o número de tiros será arredondado para baixo até o número par mais próximo. Por exemplo, se você especificar 9 capturas, os resultados exibirão dados para 8 capturas.
Estimar o custo do trabalho
Antes de executar um trabalho na QPU, estime quanto ele custa para ser executado.
Para obter os detalhes de preços mais atuais, consulte Preços do IonQ ou localize seu workspace e veja as opções de preços na guia Provedor do seu workspace por meio de: aka.ms/aq/myworkspaces.
Executar na QPU do IonQ
Para se conectar a um hardware real (uma Unidade de Processador Quântico (QPU)), basta fornecer o nome do target"ionq.qpu.aria-1" método get_backend :
qpu_backend = provider.get_backend("ionq.qpu.aria-1")
Envie o circuito para ser executado no Azure Quantum, obtenha os resultados e execute plot_histogram para plotar os resultados.
Observação
O tempo necessário para executar um circuito na QPU pode variar dependendo dos tempos de fila atuais.
# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)
# Get the job results (this method waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='ionq.qpu.aria-1', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}
Importante
Você não pode enviar vários circuitos em um único trabalho. Como solução alternativa, você pode chamar o método backend.run para enviar cada circuito de forma assíncrona e obter os resultados de cada tarefa. Por exemplo:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())
Pré-requisitos
Para obter detalhes da instalação, consulte Configurar a extensão do QDK.
Um Python ambiente com Python e Pip instalado.
O pacote
qdkPython com os extrasqiskitejupyter.python pip install "qdk[qiskit,jupyter]"
Execute um circuito básico
No VS Code, abra um novo Python arquivo para criar e executar um circuito básico com o simulador esparso interno do módulo qsharp.
# load the required imports
from qdk import qsharp
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# run the circuit using the built-in sparse simulator
backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()
print(counts)
Para executar o programa, selecione o ícone Executar no canto superior direito e selecione Executar Python arquivo. A saída é exibida em uma nova janela de terminal.
┌─────────────────────────┐┌─┐
q_0: ─■───────────┤0 ├┤M├───
│P(0.79983) │ (XX-YY)(1.9337,1.7385) │└╥┘┌─┐
q_1: ─■───────────┤1 ├─╫─┤M├
└─────────────────────────┘ ║ └╥┘
c: 2/═════════════════════════════════════════╩══╩═
0 1
{'11': 680, '00': 344}
Gerar QIR para o circuito
Nesse mesmo circuito, você pode gerar QIR usado para execução em hardware quântico.
Observação
Para gerar QIR, todos os registros devem ser medidos. Se houver registros não utilizados, um erro será gerado. Além disso, você recebe um erro ao tentar gerar QIR com um Unrestrictedtarget perfil. O perfil Unrestricted só é válido para simulação. Você deve usar TargetProfile.Base, TargetProfile.Adaptive_RIou TargetProfile.Adaptive_RIF. Você pode sobrescrever a target_profile na chamada de backend.qir(...) para alternar perfis.
Importar
QSharpErroreTargetProfilefrom qdk.qsharp import QSharpError, TargetProfilePara gerar QIR, modifique a saída:
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
Seu código agora deve ter esta aparência:
# load the required imports
from qdk import qsharp
from qsharp import QSharpError, TargetProfile
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# generate QIR for the circuit
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
A saída do código deve ter esta aparência:
┌────────────┐ ┌─┐
q_0: ┤ Rx(2.7195) ├─■───────────┤M├───
└──┬─────┬───┘ │U1(5.5924) └╥┘┌─┐
q_1: ───┤ Tdg ├─────■────────────╫─┤M├
└─────┘ ║ └╥┘
c: 2/════════════════════════════╩══╩═
0 1
%Result = type opaque
%Qubit = type opaque
define void @ENTRYPOINT__main() #0 {
block_0:
call void @__quantum__qis__rx__body(double 2.7194945105768586, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__t__adj(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double -2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
call void @__quantum__rt__array_record_output(i64 2, i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
ret void
}
declare void @__quantum__qis__rx__body(double, %Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__t__adj(%Qubit*)
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
declare void @__quantum__rt__array_record_output(i64, i8*)
declare void @__quantum__rt__result_record_output(%Result*, i8*)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
Nem todos os programas podem ser executados em todo o hardware. Aqui, se você tentar usar target o Base perfil, receberá erros detalhados sobre quais partes do programa não têm suporte.
try:
backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
print(e)