이 중 첫 번째와 마지막 함수는 상수 함수이고, 가운데 두 함수는 균형 함수입니다. 균형 함수란 입력 전체에 걸쳐 두 가지 가능한 출력값이 동일한 횟수만큼 나타나는 함수를 뜻합니다.
도이치 문제는 입력 함수가 상수 함수와 균형 함수 중 어느 범주에 속하는지를 판별하는 문제입니다.
Deutsch's problem
입력: 함수 f:{0,1}→{0,1}
출력: f 가 상수 함수이면 0, 균형 함수이면 1
도이치 문제의 입력 함수 f 를 문자열에 대한 임의 접근을 표현하는 것으로 본다면, 우리는 2비트 문자열 f(0)f(1) 을 다루고 있는 셈입니다.
functionf1f2f3f4string00011011
이러한 관점에서 보면, 도이치 문제는 두 비트의 패리티(동등하게는 배타적 논리합, XOR)를 계산하는 문제입니다.
이 문제를 올바르게 해결하는 모든 고전 질의 알고리즘은 f(0) 과 f(1) 두 비트를 모두 질의해야 합니다.
예컨대 f(1)=1 이라는 사실을 알게 되었다고 해도, 정답은 f(0)=1 인지 f(0)=0 인지에 따라 각각 0 이 될 수도 있고 1 이 될 수도 있습니다.
다른 경우들도 마찬가지입니다. 두 비트 중 하나만 알아서는 그 패리티에 대해 아무런 정보도 얻을 수 없습니다.
따라서 이전 절에서 설명한 불리언 Circuit은 이 문제를 해결하는 데 필요한 질의 횟수 측면에서 우리가 할 수 있는 최선입니다.
도이치 알고리즘은 단 한 번의 질의로 도이치 문제를 해결하며, 이로써 고전적 계산에 대한 양자 계산의 정량적 우위를 보여줍니다.
두 번이 아닌 한 번의 질의라는 다소 소박한 우위일 수 있지만, 어딘가에서는 시작해야 합니다.
과학적 진보는 때때로 겉보기에 보잘것없는 기원에서 비롯됩니다.
도이치 알고리즘을 분석하기 위해, 위 Circuit의 동작을 따라가면서 다음 그림이 가리키는 시점마다 Qubit의 상태를 파악해 보겠습니다.
초기 상태는 ∣1⟩∣0⟩ 이며, Circuit 왼쪽에 있는 두 개의 Hadamard 연산은 이 상태를 다음과 같이 변환합니다.
∣π1⟩=∣−⟩∣+⟩=21(∣0⟩−∣1⟩)∣0⟩+21(∣0⟩−∣1⟩)∣1⟩.
(항상 그렇듯, 여기서는 위쪽 Qubit을 오른쪽에, 아래쪽 Qubit을 왼쪽에 배치하는 Qiskit의 Qubit 순서 규약을 따르고 있습니다.) 이 곱 상태를 부분적으로만 분배한 채로(Qubit 1의 상태는 공 통 인수로 밖에 빼둔 상태) 표기하는 것이 다소 직관적이지 않게 느껴질 수 있지만, 이렇게 하면 이후의 식을 더 간결하게 나타낼 수 있습니다.
다음으로 Uf Gate가 수행됩니다.
Uf Gate의 정의에 따라, 위쪽/오른쪽 Qubit의 고전적 상태에 대한 함수 f 의 값이 아래쪽/왼쪽 Qubit에 XOR되며, 이에 따라 ∣π1⟩ 은 다음 상태로 변환됩니다.
흥미로운 일이 일어났습니다!
Uf Gate는 표준 기저 상태에 작용할 때 위쪽/오른쪽 Qubit은 그대로 두고 함수 값을 아래쪽/왼쪽 Qubit에 XOR하지만, 여기서는 위쪽/오른쪽 Qubit의 상태가 (일반적으로) 변하는 반면 아래쪽/왼쪽 Qubit의 상태는 그대로 유지됨을 볼 수 있습니다. 구 체적으로는 Uf Gate가 수행되기 전과 후 모두 ∣−⟩ 상태를 유지합니다.
이 현상은 *위상 킥백(phase kickback)*이라고 알려져 있으며, 곧 이에 대해 더 자세히 다루겠습니다.
마지막으로 (−1)f(0) 인수를 합 바깥으로 빼내는 단순화를 한 번 더 거치면, 상태 ∣π2⟩ 에 대한 다음 표현을 얻습니다.
여기서 −1 의 지수에 f(1)−f(0) 이 아니라 f(0)⊕f(1) 이 등장한다는 점에 주목해 주세요. 순수하게 대수적인 관점에서 보면 전자가 더 자연스러워 보일 수 있지만, 어느 쪽으로 계산해도 결과는 같습니다.
그 이유는 임의의 정수 k 에 대해 (−1)k 의 값은 k 가 짝수인지 홀수인지에만 의존하기 때문입니다.
이제 Qiskit에서 도이치 알고리즘을 어떻게 구현할 수 있는지 살펴보겠습니다. 버전 확인부터 시작한 뒤, 이 구현에만 필요한 임포트를 수행하겠습니다.
이후에 이어지는 다른 알고리즘의 구현에서는 모듈성을 더 높이기 위해 필요한 임포트를 각각 별도로 수행하겠습니다.
# Added by doQumentation — required packages for this notebook !pip install -q qiskit qiskit-aer
from qiskit import __version__ print(__version__)
2.1.1
from qiskit import QuantumCircuit from qiskit_aer import AerSimulator
먼저, 앞서 설명한 1비트에서 1비트로 가는 네 가지 함수 f1,f2,f3,f4 중 하나에 대한 질의 Gate를 구현하는 양자 Circuit을 정의하겠 습니다. 이미 언급했듯이, 질의 Gate의 구현은 사실 도이치 알고리즘 자체의 일부가 아닙니다.
여기서는 질의 Gate의 Circuit 구현 형태로 입력을 준비하는 한 가지 방법을 보여줄 뿐입니다.
defdeutsch_function(case:int): # This function generates a quantum circuit for one of the 4 functions # from one bit to one bit ifcasenotin[1,2,3,4]: raise ValueError("`case` must be 1, 2, 3, or 4.") f = QuantumCircuit(2) ifcasein[2,3]: f.cx(0,1) ifcasein[3,4]: f.x(1) return f
draw 메서드를 사용하면 각 Circuit이 어떻게 생겼는지 볼 수 있습니다. 다음은 함수 f3 에 대한 Circuit입니다.
display(deutsch_function(3).draw(output="mpl"))
다음으로 도이치 알고리즘의 실제 양자 Circuit을 만들되, 질의 Gate는 인자로 전달되는 양자 Circuit 구현으로 대체하겠습니다. 잠시 후 앞서 정의한 deutsch_function 함수가 정의하는 네 가지 Circuit 중 하나를 여기에 연결할 것입니다.
질의 Gate 구현과 Circuit의 나머지 부분을 시각적으로 구분하기 위해 배리어가 포함되어 있습니다.
defcompile_circuit(function: QuantumCircuit): # Compiles a circuit for use in Deutsch's algorithm. n = function.num_qubits -1 qc = QuantumCircuit(n +1, n) qc.x(n) qc.h(range(n +1)) qc.barrier() qc.compose(function, inplace=True) qc.barrier() qc.h(range(n)) qc.measure(range(n),range(n)) return qc
마찬가지로 draw 메서드를 사용하면 Circuit이 어떻게 생겼는지 확인할 수 있습니다.
마지막으로, 앞서 정의한 Circuit을 한 번 실행하고 적절한 결과인 "constant" 또는 "balanced"를 출력하는 함수를 만들겠습니다.
defdeutsch_algorithm(function: QuantumCircuit): # Determine if a one-bit function is constant or balanced. qc = compile_circuit(function) result = AerSimulator().run(qc, shots=1, memory=True).result() measurements = result.get_memory() if measurements[0]=="0": return"constant" return"balanced"
이제 위에서 정의한 네 가지 함수 중 어느 것에 대해서든 도이치 알고리즘을 실행할 수 있습니다.
f = deutsch_function(3) display(deutsch_algorithm(f))