Skip to main content
IBM Quantum Platform

qiskit.circuit.library.grover_operator

qiskit.circuit.library.grover_operator(oracle, state_preparation=None, zero_reflection=None, reflection_qubits=None, insert_barriers=False, name='Q')

GitHub

Construa o operador de Grover.

O algoritmo de busca de Grover [1, 2] consiste em aplicações repetidas do chamado operador de Grover usado para amplificar as amplitudes dos estados de saída desejados. Esse operador, Q\mathcal{Q}, consiste no oráculo de fase, Sf\mathcal{S}_f, na mudança de fase zero ou na reflexão zero, S0\mathcal{S}_0, e em uma preparação do estado de entrada A\mathcal{A} :

Q=AS0ASf\mathcal{Q} = \mathcal{A} \mathcal{S}_0 \mathcal{A}^\dagger \mathcal{S}_f

Na pesquisa padrão de Grover, temos A=Hn\mathcal{A} = H^{\otimes n} :

Q=HnS0HnSf=DSf\mathcal{Q} = H^{\otimes n} \mathcal{S}_0 H^{\otimes n} \mathcal{S}_f = D \mathcal{S_f}

A operação D=HnS0HnD = H^{\otimes n} \mathcal{S}_0 H^{\otimes n} também é chamada de operador de difusão. Nessa formulação, podemos ver que o operador de Grover consiste em duas etapas: primeiro, o oráculo de fase multiplica os estados bons por -1 (com Sf\mathcal{S}_f ) e, em seguida, todo o estado é refletido em torno da média (com DD ).

Essa classe permite definir uma preparação de estado diferente, como na amplificação de amplitude quântica (uma generalização do algoritmo de Grover); A\mathcal{A} pode não ser uma camada de portas de Hadamard [3].

A ação do oráculo de fase Sf\mathcal{S}_f é definida como

Sf:x(1)f(x)x\mathcal{S}_f: |x\rangle \mapsto (-1)^{f(x)}|x\rangle

em que f(x)=1f(x) = 1 se xx for um bom estado e 0 caso contrário. Para destacar o fato de que esse oráculo inverte a fase dos estados bons e não inverte o estado de um qubit resultante, chamamos o Sf\mathcal{S}_f de oráculo de fase.

Observe que você pode construir facilmente um oráculo de fase a partir de um oráculo de bitflip, colocando a porta X controlada no qubit de resultado por uma porta X e H. Por exemplo

Bitflip oracle     Phaseflip oracle
q_0: ──■──         q_0: ────────────■────────────
     ┌─┴─┐              ┌───┐┌───┐┌─┴─┐┌───┐┌───┐
out: ┤ X ├         out: ┤ X ├┤ H ├┤ X ├┤ H ├┤ X ├
     └───┘              └───┘└───┘└───┘└───┘└───┘

Há alguma flexibilidade na definição do oráculo e do operador A\mathcal{A}. Antes de o operador de Grover ser aplicado no algoritmo de Grover, os qubits são primeiro preparados com uma aplicação do operador A\mathcal{A} (ou portas Hadamard na formulação padrão). Assim, sempre temos uma operação do tipo ASfA\mathcal{A} \mathcal{S}_f \mathcal{A}^\dagger. Portanto, é possível mover a lógica de bitflip para A\mathcal{A} e deixar o oráculo apenas para fazer as mudanças de fase por meio de portas Z baseadas nos bitflips. Um possível caso de uso para isso são os oráculos que não descompactam os qubits de estado.

A reflexão zero S0\mathcal{S}_0 é geralmente definida como

S0=20n0nIn\mathcal{S}_0 = 2 |0\rangle^{\otimes n} \langle 0|^{\otimes n} - \mathbb{I}_n

em que In\mathbb{I}_n é a identidade em nn qubits. Por padrão, essa classe implementa a versão negativa 20n0nIn2 |0\rangle^{\otimes n} \langle 0|^{\otimes n} - \mathbb{I}_n, uma vez que ela pode ser implementada simplesmente com um Z multicontrolado imprensado por portas X no qubit de destino e a fase global introduzida não importa para o algoritmo de Grover.

Exemplos:

Podemos construir um operador de Grover apenas com o oráculo de fase:

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import grover_operator

oracle = QuantumCircuit(2)
oracle.z(0)  # good state = first qubit is |1>
grover_op = grover_operator(oracle, insert_barriers=True)
grover_op.draw("mpl")
Diagrama de circuito gerado pelo código anterior.

Também podemos modificar a preparação do estado:

oracle = QuantumCircuit(1)
oracle.z(0)  # the qubit state |1> is the good state
state_preparation = QuantumCircuit(1)
state_preparation.ry(0.2, 0)  # non-uniform state preparation
grover_op = grover_operator(oracle, state_preparation)
grover_op.draw("mpl")
Diagrama de circuito gerado pelo código anterior.

Além disso, também podemos marcar em quais qubits a reflexão zero deve atuar. Isso é útil no caso de alguns qubits serem usados apenas como espaço de rascunho, mas não deve afetar o oráculo:

oracle = QuantumCircuit(4)
oracle.z(3)
reflection_qubits = [0, 3]
state_preparation = QuantumCircuit(4)
state_preparation.cry(0.1, 0, 3)
state_preparation.ry(0.5, 3)
grover_op = grover_operator(oracle, state_preparation, reflection_qubits=reflection_qubits)
grover_op.draw("mpl")
Diagrama de circuito gerado pelo código anterior.

O oráculo e a reflexão zero também podem ser passados como qiskit.quantum_info objetos:

from qiskit.quantum_info import Statevector, DensityMatrix, Operator

mark_state = Statevector.from_label("011")
reflection = 2 * DensityMatrix.from_label("000") - Operator.from_label("III")
grover_op = grover_operator(oracle=mark_state, zero_reflection=reflection)
grover_op.draw("mpl")
Diagrama de circuito gerado pelo código anterior.

Para um grande número de qubits, a porta X multicontrolada usada para a reflexão zero pode ser sintetizada de diferentes maneiras. Dependendo do número de qubits disponíveis, o compilador escolherá uma implementação diferente:

from qiskit import transpile, Qubit
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import grover_operator

oracle = QuantumCircuit(10)
oracle.z(oracle.qubits)
grover_op = grover_operator(oracle)

# without extra qubit space, the MCX synthesis is expensive
basis_gates = ["u", "cx"]
tqc = transpile(grover_op, basis_gates=basis_gates)
is_2q = lambda inst: len(inst.qubits) == 2
print("2q depth w/o scratch qubits:", tqc.depth(filter_function=is_2q))  # > 350

# add extra bits that can be used as scratch space
grover_op.add_bits([Qubit() for _ in range(num_qubits)])
tqc = transpile(grover_op, basis_gates=basis_gates)
print("2q depth w/ scratch qubits:", tqc.depth(filter_function=is_2q)) # < 100

Parâmetros

  • oracle (QuantumCircuit |Statevector) – O oráculo de fase implementa uma reflexão sobre o estado ruim. Observe que esse não é um oráculo de bitflip; consulte a documentação para obter mais informações.
  • state_preparation (QuantumCircuit | None) – O operador prepara o estado bom e ruim. Para o algoritmo de Grover, essa é uma porta Hadamard de n-qubit e, para amplificação ou estimativa de amplitude, o operador A\mathcal{A}.
  • zero_reflection (QuantumCircuit |DensityMatrix |Operator | None) – A reflexão sobre o estado zero, S0\mathcal{S}_0.
  • reflection_qubits (list[int] | None) – Qubits nos quais a reflexão zero atua.
  • insert_barriers (bool) – Se devem ser inseridas barreiras entre as reflexões e A.
  • name (str) – O nome do circuito.

Referências

[1] L. K. Grover (1996), A fast quantum mechanical algorithm for database search, arXiv:quant-ph/9605043.

[2] I. Chuang e M. Nielsen, Quantum Computation and Quantum Information, Cambridge: Cambridge University Press, 2000. Capítulo 6.1.2.

[3] Brassard, G., Hoyer, P., Mosca, M., & Tapp, A. (2000). Amplificação e estimativa da amplitude quântica. arXiv:quant-ph/0005055.

Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.