Construir circuits
Versões dos pacotes
O código desta página foi desenvolvido usando os seguintes requisitos. Recomendamos usar essas versões ou mais recentes.
qiskit[all]~=2.3.0
Esta página examina mais de perto a classe QuantumCircuit do SDK Qiskit, incluindo alguns métodos mais avançados que você pode usar para criar circuits quânticos.
O que é um Circuit quântico?
Um Circuit quântico simples é uma coleção de Qubits e uma lista de instruções que atuam sobre esses Qubits. Para demonstrar, a célula a seguir cria um novo Circuit com dois novos Qubits e, em seguida, exibe o atributo qubits do Circuit, que é uma lista de Qubits em ordem do bit menos significativo ao bit mais significativo .
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
Múltiplos objetos QuantumRegister e ClassicalRegister podem ser combinados para criar um Circuit. Todo QuantumRegister e ClassicalRegister também pode ter um nome.
from qiskit.circuit import QuantumRegister, ClassicalRegister
qr1 = QuantumRegister(2, "qreg1") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
Você pode encontrar o índice e o registrador de um Qubit usando o método find_bit do Circuit e seus atributos.
desired_qubit = qr2[0] # Qubit 0 of register 'qreg2'
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
Adicionar uma instrução ao Circuit acrescenta a instrução ao atributo data do Circuit. A saída da célula a seguir mostra que data é uma lista de objetos CircuitInstruction, cada um dos quais possui um atributo operation e um atributo qubits.
qc.x(0) # Add X-gate to qubit 0
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
A maneira mais fácil de visualizar essas informações é por meio do método draw, que retorna uma visualização de um Circuit. Veja Visualizar circuits para diferentes formas de exibir circuits quânticos.
qc.draw("mpl")
Os objetos de instrução de Circuit podem conter circuits de "definição" que descrevem a instrução em termos de instruções mais fundamentais. Por exemplo, o X-gate é definido como um caso específico do U3-gate, um Gate de Qubit único mais geral.
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")
Instruções e circuits são semelhantes no sentido de que ambos descrevem operações sobre bits e Qubits, mas têm propósitos diferentes:
- As instruções são tratadas como fixas, e seus métodos geralmente retornam novas instruções (sem modificar o objeto original).
- Os circuits são projetados para serem construídos ao longo de muitas linhas de código, e os métodos de
QuantumCircuitfrequentemente modificam o objeto existente.
O que é a profundidade de um Circuit?
A depth() de um Circuit quântico é uma medida do número de "camadas" de Gates quânticos, executados em paralelo, necessárias para completar o cálculo definido pelo Circuit. Como os Gates quânticos levam tempo para serem implementados, a profundidade de um Circuit corresponde aproximadamente ao tempo que o computador quântico leva para executar o Circuit. Portanto, a profundidade de um Circuit é uma quantidade importante usada para medir se um Circuit quântico pode ser executado em um dispositivo.
O restante desta página ilustra como manipular circuits quânticos.
Construir circuits
Métodos como QuantumCircuit.h e QuantumCircuit.cx adicionam instruções específicas aos circuits. Para adicionar instruções a um Circuit de forma mais geral, use o método append. Esse método recebe uma instrução e uma lista de Qubits aos quais aplicar a instrução. Veja a documentação da API da Circuit Library para uma lista de instruções suportadas.
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")
Para combinar dois circuits, use o método compose. Esse método aceita outro QuantumCircuit e uma lista opcional de mapeamentos de Qubits.
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")
Você também pode querer compilar circuits em instruções para manter seus circuits organizados. É possível converter um Circuit em uma instrução usando o método to_instruction, e então acrescentar essa instrução a outro Circuit como faria com qualquer outra instrução. O Circuit desenhado na célula a seguir é funcionalmente equivalente ao Circuit desenhado na célula anterior.
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
Se o seu Circuit for unitário, você pode convertê-lo em um Gate usando o método to_gate. Os objetos Gate são tipos específicos de instruções que possuem alguns recursos extras, como o método control, que adiciona um controle quântico.
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
Para ver o que está acontecendo, você pode usar o método decompose para expandir cada instrução em sua definição.
O método decompose retorna um novo Circuit e não modifica o Circuit sobre o qual atua.
qc_a.decompose().draw("mpl")
Medir Qubits
As medições são usadas para amostrar os estados de Qubits individuais e transferir os resultados para um registrador clássico. Note que, se você estiver submetendo circuits a um primitivo Sampler, as medições são obrigatórias. Porém, circuits submetidos a um primitivo Estimator não devem conter medições.
Os Qubits podem ser medidos usando três métodos: measure, measure_all e measure_active. Para aprender a visualizar resultados de medições, veja a página Visualizar resultados.
-
QuantumCircuit.measure: mede cada Qubit do primeiro argumento no bit clássico fornecido como segundo argumento. Esse método permite controle total sobre onde o resultado da medição é armazenado. -
QuantumCircuit.measure_all: não recebe argumento e pode ser usado para circuits quânticos sem bits clássicos pré-definidos. Cria fios clássicos e armazena os resultados das medições em ordem. Por exemplo, a medição do Qubit é armazenada no cbit ). Também adiciona uma barreira antes da medição. -
QuantumCircuit.measure_active: semelhante ameasure_all, mas mede apenas os Qubits que possuem operações.
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)
Circuits parametrizados
Muitos algoritmos quânticos de curto prazo envolvem a execução de muitas variações de um Circuit quântico. Como construir e otimizar circuits grandes pode ser computacionalmente caro, o Qiskit suporta circuits parametrizados. Esses circuits possuem parâmetros indefinidos, e seus valores não precisam ser definidos até pouco antes da execução do Circuit. Isso permite que você mova a construção e otimização do Circuit para fora do laço principal do programa. A célula a seguir cria e exibe um Circuit parametrizado.
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")
A célula a seguir cria muitas variações desse Circuit e exibe uma das variações.
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")
Você pode encontrar uma lista dos parâmetros indefinidos de um Circuit em seu atributo parameters.
qc.parameters
ParameterView([Parameter(angle)])
Alterar o nome de um parâmetro
Por padrão, os nomes dos parâmetros de um Circuit parametrizado são prefixados por x — por exemplo, x[0]. Você pode alterar os nomes após eles serem definidos, conforme mostrado no exemplo a seguir.
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)
# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)
# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)
Próximos passos
- Para aprender sobre algoritmos quânticos de curto prazo, faça o curso Variational algorithm design.
- Veja um exemplo de circuits sendo usados no tutorial Algoritmo de Grover.
- Trabalhe com circuits simples usando o IBM Quantum Composer.