Nota
Esta página foi gerada de tutorials/circuits_advanced/05_pulse_gates.ipynb.
Execute interativamente no IBM Quantum lab.
Portas de pulso¶
Most quantum algorithms can be described with circuit operations alone. When we need more control over the low-level implementation of our program, we can use pulse gates. Pulse gates remove the constraint of executing circuits with basis gates only, and also allow you to override the default implementation of any basis gate.
Portas de pulso permitem mapear uma porta de circuito lógico (por exemplo, X
) para um programa Qiskit Pulse chamado de Schedule
. Este mapeamento é referido como uma calibração. Uma calibração de alta fidelidade é uma que implementa fielmente a operação lógica da qual é mapeada (por exemplo, se a calibração do X
direciona \(|0\rangle\) to \(|1\rangle\), etc.).
Uma programação especifica a dinâmica de tempo exata dos sinais de entrada em todas as entradas canais para o dispositivo. Geralmente, há vários canais por qubit, como direção e medida. Essa interface é mais poderosa e requer uma compreensão mais profunda da física do dispositivo subjacente.
É importante notar que programas Pulse operam em qubits físicos. Um pulso de condução no qubit \(a\) não executará a mesma operação lógica no estado do qubit \(b\) - em outras palavras, calibrações de porta não podem ser trocadas entre os qubits. Isto contrasta com o nível de circuito, onde uma porta X
é definida independentemente do operando do qubit.
Esta página mostra como adicionar uma calibração ao seu circuito.
Nota: Para executar um programa com portas de pulso, o backend deve ser habilitado com o OpenPulse. Você pode verificar, via backend.configuration().open_pulse
, que é True
, quando o OpenPulse está habilitado. Se estiver habilitado e as portas de pulso não estiverem ativados, você pode, no seu circuito de entrada agendar.
Construindo o circuito¶
Vamos começar com um exemplo muito simples, um circuito do estado Bell.
[1]:
from qiskit import QuantumCircuit
circ = QuantumCircuit(2, 2)
circ.h(0)
circ.cx(0, 1)
circ.measure(0, 0)
circ.measure(1, 1)
circ.draw('mpl')
[1]:

Fazendo as suas calibrações¶
Agora que temos o nosso circuito, vamos definir uma calibração para a porta Hadamard no qubit 0.
Na prática a forma do pulso e seus parâmetros serão otimizados através de uma série de experimentos Rabi (veja o Qiskit Textbook para uma explicação). Para esta demonstração, nosso Hadamard será um pulso gaussiano. Vamos jogar nosso pulso no canal direção do qubit 0.
Não se preocupe muito com os detalhes de construção da própria calibração; você pode aprender tudo sobre isso na seguinte página: construindo agendamentos pulse.
[2]:
from qiskit import pulse
from qiskit.pulse.library import Gaussian
from qiskit.test.mock import FakeValencia
backend = FakeValencia()
with pulse.build(backend, name='hadamard') as h_q0:
pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(0))
Vamos fazer um novo agendamento para ver o que construímos.
[3]:
h_q0.draw()
[3]:

Vincule sua calibração ao seu circuito¶
Resta, apenas, completar o registro. O método de circuito add_calibration
precisa de informações sobre a porta e a referência ao cronograma para completar o mapeamento:
QuantumCircuit.add_calibration(gate, qubits, schedule, parameters)
A porta
pode ser um objeto circuit.Gate
ou o nome da porta. Geralmente, você precisará de um cronograma diferente para cada conjunto único de qubits
e parâmetros
. Uma vez que a porta Hadamard não tem nenhum parâmetro, não temos que fornecer nenhum.
[4]:
circ.add_calibration('h', [0], h_q0)
Por último, note que o transpilador respeitará suas calibrações. Use-o como você normalmente usaria (nosso exemplo é muito simples para que o transpilador o otimize, então a saída é a mesma).
[5]:
from qiskit import transpile
from qiskit.test.mock import FakeAlmaden
backend = FakeAlmaden()
circ = transpile(circ, backend)
print(backend.configuration().basis_gates)
circ.draw('mpl', idle_wires=False)
['id', 'u1', 'u2', 'u3', 'cx']
[5]:

Observe que h
não é uma porta base para o falso backend FakeAlmaden
. Uma vez que adicionamos uma calibração para ele, o transpiler tratará a nossa porta como uma porta base; mas apenas nas qubits para as quais foi definida. Uma Hadamard aplicada a um qubit diferente, seria destinado às portas base.
É isso!
Portas personalizadas¶
Mostraremos, brevemente, o mesmo processo para portas totalmente customizadas que não são padrões. Esta demonstração inclui uma porta com parâmetros.
[6]:
from qiskit import QuantumCircuit
from qiskit.circuit import Gate
circ = QuantumCircuit(1, 1)
custom_gate = Gate('my_custom_gate', 1, [3.14, 1])
# 3.14 is an arbitrary parameter for demonstration
circ.append(custom_gate, [0])
circ.measure(0, 0)
circ.draw('mpl')
[6]:

[7]:
with pulse.build(backend, name='custom') as my_schedule:
pulse.play(Gaussian(duration=64, amp=0.2, sigma=8), pulse.drive_channel(0))
circ.add_calibration('my_custom_gate', [0], my_schedule, [3.14, 1])
# Alternatively: circ.add_calibration(custom_gate, [0], my_schedule)
Se usarmos a variável de instância Gate
custom_gate
para adicionar a calibração, os parâmetros são derivados dessa instância. Lembre-se de que a ordem dos parâmetros é significativa.
[8]:
circ = transpile(circ, backend)
circ.draw('mpl', idle_wires=False)
[8]:

Normalmente, se tentássemos transpilar nosso circ
, teríamos um erro. Não haveria nenhuma definição funcional fornecida para "my_custom_gate"
, então o transpiler não poderia associar para o conjunto porta base do dispositivo de destino. Podemos mostrar isto tentando adicionar "my_custom_gate"
a outro qubit que não foi calibrado.
[9]:
circ = QuantumCircuit(2, 2)
circ.append(custom_gate, [1])
from qiskit import QiskitError
try:
circ = transpile(circ, backend)
except QiskitError as e:
print(e)
"Cannot unroll the circuit to the given basis, ['id', 'u1', 'u2', 'u3', 'cx']. Instruction my_custom_gate not found in equivalence library and no rule found to expand."
[10]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/Users/thomas/opt/anaconda3/envs/qiskit-3.8/lib/python3.8/site-packages/qiskit/aqua/operators/operator_globals.py:48: DeprecationWarning: `from_label` is deprecated and will be removed no earlier than 3 months after the release date. Use Pauli(label) instead.
X = make_immutable(PrimitiveOp(Pauli.from_label('X')))
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.23.6 |
Terra | 0.17.0 |
Aer | 0.7.5 |
Ignis | 0.5.2 |
Aqua | 0.8.2 |
IBM Q Provider | 0.11.1 |
System information | |
Python | 3.8.5 (default, Aug 5 2020, 03:39:04) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 32.0 |
Sat Feb 27 11:07:23 2021 AST |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.