Solving Simon's problem with a quantum computer
In this section, we aim to solve the Simon's problem with a quantum computer. The Simon's problem states that:
There is a function implemented by an oracle with the property:
where is either or a fixed unknown bit string. Find the unknown bitstring .
In this section, we show how to use QURI Parts to implement the algorithm that solves Simon's problem.
Oracle function and circuit
Suppose the function input is a bit string of length , the oracle is a quantum circuit with qubits. In this set up, the oracle is implmented with a unitary matrix that satisfies the condition:
where in the left hand side of the equation, represents the second half of the qubits and represents the first half of the qubits. The function here is given by:
where is the unknown bit string to be solved for by the algorithm. With the above equations, we can implement the oracle as a circuit containing a unitary gate acting on all qubits.
import numpy as np
from quri_parts.core.utils.binary_field import BinaryArray, BinaryMatrix
from quri_parts.circuit import QuantumCircuit
from functools import partial
from typing import Callable
from typing_extensions import TypeAlias
OracleFunction: TypeAlias = Callable[[int], int]
def oracle_function(x: int, s: int) -> int:
return min(x^s, x)
def get_simon_oracle(s: int, bit_length: int) -> tuple[QuantumCircuit, OracleFunction]:
n_qubits = 2 * bit_length
U = np.zeros((2**n_qubits, 2**n_qubits))
for i in range(2**bit_length):
for j in range(2**bit_length):
# U|j>|i> = |j + f(i)>|i>
# <j + f(i)| <i|U|j> |i> = 1
oracle_output = ((j^oracle_function(i, s)) << bit_length) + i
oracle_input = (j << bit_length) + i
U[oracle_output, oracle_input] = 1
circuit = QuantumCircuit(n_qubits)
circuit.add_UnitaryMatrix_gate(range(n_qubits), U)
return circuit, partial(oracle_function, s=s)
Now, let's examine if our oracle correctly implements the function
Here we assume , the bit string's length is 4 and check if .
import pandas as pd
import numpy as np
from quri_parts.qulacs.simulator import evaluate_state_to_vector
from quri_parts.core.state import ComputationalBasisState
n_bit_len = 4
s = 0b0011
oracle, oracle_func = get_simon_oracle(s, n_bit_len)
recorder = {}
# Iterate over U|0000>|i>.
for i in range(2**n_bit_len):
out_state = evaluate_state_to_vector(
ComputationalBasisState(2*n_bit_len, bits=i).with_gates_applied(oracle)
).vector
second_register_out = np.where(out_state == 1)[0][0] >> n_bit_len
expected = oracle_func(i)
recorder[i] = {"y_oracle": second_register_out, "y_expected": expected}
print(pd.DataFrame(recorder).T.reset_index().rename(columns={"index": "x"}).set_index("x").T.to_markdown())
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
y_oracle | 0 | 1 | 1 | 0 | 4 | 5 | 5 | 4 | 8 | 9 | 9 | 8 | 12 | 13 | 13 | 12 |
y_expected | 0 | 1 | 1 | 0 | 4 | 5 | 5 | 4 | 8 | 9 | 9 | 8 | 12 | 13 | 13 | 12 |
With the table above, we have confirmed that the oracle is correctly implemented.
The algorithm for solving Simon's problem
The algorithm for solving Simon's problem consists of 2 parts. One quantum and the other classical. Here, we list out the explicit algorithm.
- (Quantum) Execute the quantum circuit multiple times to collect a set of equations