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')
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, , consiste no oráculo de fase, , na mudança de fase zero ou na reflexão zero, , e em uma preparação do estado de entrada :
Na pesquisa padrão de Grover, temos :
A operação 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 ) e, em seguida, todo o estado é refletido em torno da média (com ).
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); pode não ser uma camada de portas de Hadamard [3].
A ação do oráculo de fase é definida como
em que se 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 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 . Antes de o operador de Grover ser aplicado no algoritmo de Grover, os qubits são primeiro preparados com uma aplicação do operador (ou portas Hadamard na formulação padrão). Assim, sempre temos uma operação do tipo . Portanto, é possível mover a lógica de bitflip para 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 é geralmente definida como
em que é a identidade em qubits. Por padrão, essa classe implementa a versão negativa , 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")
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")
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")
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")
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)) # < 100Parâ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 .
- zero_reflection (QuantumCircuit |DensityMatrix |Operator | None) – A reflexão sobre o estado zero, .
- 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.