Pular para o conteúdo principal

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 q0q_0 ao bit mais significativo qnq_n.

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

Output of the previous code cell

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

Output of the previous code cell

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 QuantumCircuit frequentemente 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")

Output of the previous code cell

Para combinar dois circuits, use o método compose. Esse método aceita outro QuantumCircuit e uma lista opcional de mapeamentos de Qubits.

nota

O método compose retorna um novo Circuit e não modifica nenhum dos circuits sobre os quais atua. Para modificar o Circuit no qual você está chamando o método compose, use o argumento inplace=True.

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

Output of the previous code cell

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

Output of the previous code cell

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

Output of the previous code cell

Para ver o que está acontecendo, você pode usar o método decompose para expandir cada instrução em sua definição.

nota

O método decompose retorna um novo Circuit e não modifica o Circuit sobre o qual atua.

qc_a.decompose().draw("mpl")

Output of the previous code cell

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.

  1. 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.

  2. 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 qiq_i é armazenada no cbit measimeas_i). Também adiciona uma barreira antes da medição.

  3. QuantumCircuit.measure_active : semelhante a measure_all, mas mede apenas os Qubits que possuem operações.

qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)

Output of the previous code cell

qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)

Output of the previous code cell

qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)

Output of the previous code cell

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

Output of the previous code cell

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

Output of the previous code cell

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)
Esqueceu o nome do método? Tente perguntar ao Qiskit Code Assistant.

Próximos passos

Recomendações