기존의 비트
반도체를 이용한 0과 1의 2가지 전기적 신호로 모든것을 표현한다.
큐비트
양자역학적 관점에서 0과 1, 0과 1도 아닌 중첩 상태를 이용한다.
우리가 사용하는 기본적인 컴퓨터는 비트를 사용한다.
몇 개의 비트로 구현 가능한 기본적인 프로그램들은, 회로도(circuit diagram)으로 나타낼 수 있다.
// 반가산기

위는 반가산기의 회로도이다.
좌측은 입력, 우측은 출력을 나타내며, 중심은 회로도를 구성하는 '게이트(gates)'들을 나타낸다.
양자 컴퓨터도 기본적 개념은 이와 동일하다.
허나, 입력, 출력 및 연산에 사용되는 심볼(위 회로도의 게이트)을 표현하는 규칙이 다르다.
양자 컴퓨터에서 NOT 연산은 NOT 게이트에 의해 수행된다.
Qiskit에서 x 연산자를 통해 NOT 연산을 수행할 수 있다.
양자 컴퓨터에서 XOR 연산은 controlled-NOT(CNOT) 게이트에 의해 수행된다.
Qiskit에서 cx 연산자를 통해 이를 수행할 수 있다.
이는 한 쌍의 큐비트에 적용된다.
하나는 제어 큐비트(control qubit), 다른 하나는 타겟 큐비트(target qubit)이 역할을 수행한다.
CNOT의 효과는 다음과 같이 설명할 수 있다.
(위의 두 예시는 동일한 의미)

첨에 0으로 초기화되니까?
둘다 1일때 NOT연산을 수행해 줘야 한다.
이래야 해당 경우에만 요구되는 값인 1을 가지게 된다.
이를 위해서는 CNOT과 같지만, 두 개의 큐비트에서 제어되는 새로운 게이트가 필요하다.
이는 두 제어 큐비트의 상태가 모두 1일 경우에만 NOT연산을 수행할 것이다.
이러한 역할을 수행하는 게이트를 Toffoli 게이트라고 한다.
(Boolean 논리 게이트에서 AND 연산과 동일한 역할 수행)
디지털 컴퓨터들과 해당 컴퓨터들에서 작동하는 모든 소프트웨어에서 사용되는 모든 복잡한 변수, 객체, 데이터 구조체들은 기본적으로 모두 비트의 더미이다.
양자 컴퓨팅에서는 이들을 고전 변수라 부른다.
또한, 고전 변수들을 사용하여 작동하는 컴퓨터들을 고전 컴퓨터라 부른다.
양자 컴퓨터에서는 비트의 양자 변형인 큐비트를 기본 변수로 사용한다.
큐비트는 일반적인 비트와 동일한 제약 사항이 존재한다.
1. 단일 이진 정보만 저장할 수 있다.
2. 0과 1의 출력을 제공한다.
그러나, 큐비트는 양자 역학으로만 설명할 수 있는 방식들로 조작할 수 있다.
이것은 우리에게 새로운 게이트를 제공하여, 알고리즘을 설계하는 새로운 방법을 찾을 수 있게 한다.
이러한 새로운 게이트들의 완전한 이해를 위해서는, 큐비트의 상태를 기록하는 법을 이해한다.

현재 자동차의 위치는 변수 x를 사용하여 다음과 같이 나타낼 수 있다.

또는, 상태 벡터라고 불리는 숫자(변수)들의 모음으로 나타낼 수 있다.
상태 벡터의 각 요소들은 특정 위치에서 자동차를 찾을 확률을 포함한다.

상태 벡터 표기법은 다음과 같다.

위치에 국한되지 않고, 자동차가 가질 수 있는 모든 가능한 속도와 색상의 상태 벡터를 유지할 수 있다.
위의 예시와 같은 고전 시스템에서, 하나의 수를 저장하기 위해 거대한 벡터를 유지해야 하므로, 이는 비효율적이다.
그러나, 상태 벡터는 양자 컴퓨터를 포함한 양자 시스템을 추적하는 매우 좋은 방법이다.
고전 비트들은, 계산 도중 언제나 0 또는 1의 완전히 잘 정의된(well-defined) 상태를 갖는다.
고전 비트는 0과 1의 상태 이외에는 어떠한 값도 가지지 않으며, 가질 수 없다.
허나 이러한 제한은 양자 비트에서 해제된다.
큐비트에서 0을 얻든 1을 얻든, 출력을 추출하기 위한 측정이 수행될 때에만 잘 정의된 상태를 가지면 된다.
이 점에서, 큐비트는 0과 1, 두 옵션 중 하나를 커밋해야 한다.
다른 모든 시점에서, 상태는 단순 이진 값으로 보이는 것 보다 더 복잡하다.
직교 벡터를 사용해서 2차원 상의 큐비트의 모든 상태를 표현할 수 있다.
|0> 과 |1>을 사용해서 할 수 있다.
이들은 선형적으로 독립이므로, 벡터의 덧셈과 스칼라의 곱셈으로 모든 2차원 평면상의 벡터를 표현할 수 있다.
따라서 이들을 basis라고 부른다.
이 케이스에서, 그들은 상호간에 직교이며, 정규화되었으므로, 우리는 이것들을 직교 기저(orthonormal basis)라고 한다.
|q0>는 큐비트의 상태벡터라고 하며, 해당 큐비트에 대한 모든 것을 알 수 있다.
큐비트의 상태 벡터는 |0>과 |1>의 선형 조합으로 설명된다.
양자 역학에서는 '중첩'이라는 단어를 사용하여 이러한 조합을 설명한다.
python에서 허수 부분은 j로 나타낸다. (일반적인 수학에서 i로 나타내는)

왜 ket 1에만 i가 붙엇냐?
파동함수이기 때문?
상태 |v>가 |x>일 확률을 찾기 위해서는,

<, | 기호는 <x|가 행 벡터이고, |, > 기호는 v가 열 벡터임을 의미한다.
양자 역학에서 열 벡터는 kets라고 부르며, 행 벡터는 bras라고 부른다.
이를 bra-ket 표기법이라고 통칭한다.
어떠한 ket |a>라도 상응하는 bra <a|가 있으며, 우리는 켤레 전치(conjugate transpose)를 사용하여 이들 간의 변환을 수행할 수 있다.
켤레 전치법에서, 행렬은 전치되고 요소들은 켤레 복소수이다.
* 연산자를 사용하여 나타낼 수 있다.
켤레 복소수는 실수 부분은 동일하고, 허수 부분은 값은 동일하나 부호가 반대이다.
ket(열 벡터)가 아래와 같을 때,

이는 다음과 같이 대응하는 bra(행 벡터)를 제공한다.

벡터를 곱하는 방법에는 여러 가지가 있으나, 우리는 내적(inner product)를 사용한다.
내적은 스칼라곱(dot product)의 일반화이다.
아래와 같은 bra와 ket이 있을 때 내적은 다음과 같다.

두 벡터의 내적은 항상 스칼라이다.
또한, 두 직교 벡터의 내적은 0이다.

벡터 |0>과 |1>은 정규화되어있다.(크기가 1)
따라서 다음이 성립한다.


위 방정식에서, |x>는 어떠한 큐비트 상태도 될 수 있다.
|x>일 확률을 찾기 위해서, |x>와 우리가 측정하는 상태(해당 경우에서는 |v>)를 내적하고, 크기를 제곱한다.
이전의 |q_0>의 |0> 측정 확률이 0.5임을 알고 있다.

동일하게 |1> 측정 확률도 확인할 수 있다.
해당 규칙은, 진폭이 확률과 관련되어 있음을 나타낸다.
확률의 합은 무조건 1이 되어야 하며, 상태 벡터가 적절하게 정규화되었는지 확인해야 한다.
특히, 상태 벡터의 크기는 1이어야한다.

따라서, 아래가 성립한다.

또한, 우리가 정규화되지 않은 벡터를 initialize()하려고 할 경우, 에러가 발생한다.
여기서 배운 측정 규칙은 확률 p(|x>)는 상태 |v>가 |x>로 측정될 확률임을 의미한다.
|x>는 |0> 또는 |1>이 아니다.
이러한 측정법은 매우 많은 측정법중의 하나이다.
어떠한 '상태의 직교 쌍'에 대해서도, 우리는 큐비트가 그 두 직교 상태 사이가 되도록 측정을 정의할 수 있다.
|1>의 상태를 측정하면 1의 결과가 나오는 것을 알고있다.
또한 다음과 같이 적을 수 있다.

이를 측정하기 위해, 우리는 다음과 같은 측정 규칙을 적용한다.

위에서, 요소 i가 복소수 크기를 측정하려고 할 때 사라지는 것을 알 수 있다.
이 효과는 상태 |x>를 측정할 때 완벽하게 독립적이다.
우리가 뭘 측정하는지를 고려하지 않고, 상태 i|1>의 확률은 |1>과 일치한다.
측정이 큐비트에서 정보를 추출할 수 있는 유일한 방법이므로, 이는 이러한 두 상태는 물리적으로 관련된 모든 면에서 두 상태가 동일하다는 것을 의미한다.
일반적으로, |r| = 1의 상태에 있는 모든 요소 r를 '전역 위상(global phase)'라고 지칭한다.
전역 위상만 다른 상태는 물리적으로 구별할 수 없다.

이는, 위상(phase)
이는 '관계 위상(relative phase)'으로 알려진 중첩 상태에서의 항 사이 의 위상차와 구별된다.
진폭에 특정 상태에서 큐비트를 찾을 확률에 대한 정보가 포함되어 있다는 것을 알고 있지만, 일단 큐비트를 측정하면, 큐비트의 상태가 무엇인지 확실하게 알 수 있다.

큐비트가 상태 |0>에서 찾아졌다면, 재측정 시, 상태 |0>에서 큐비트를 찾을 확률이 100퍼센트이다.
이것은 측정이 큐비트의 상태를 변경한다는 것을 의미한다.

이것을 큐비트의 상태 붕괴(collapsing)라고 하며, 현명하게 사용해야 한다.
예를 들어, 계산의 각 지점에서 큐비트의 값을 추적하기 위해 각 큐비트를 지속적으로 측정한다면, 큐비트는 항상 0 혹은 1의 잘 정의된 상태에 있을 것이다.
이는 고전적인 비트를 사용한 고전적인 계산과 다르지 않다.
진정한 양자 계산을 위해서는 큐비트가 더욱 복잡한 상태를 탐색할 수 있게 해야 한다.
따라서, 측정은 우리가 결과를 추출해야 하는 경우에만 사용한다.
이는 양자 회로의 끝에서 측정을 수행해야 함을 의미한다.
실제 양자 컴퓨터 사용 시, 우리는 우리의 큐비트의 상태를 파괴하기 전까지, 즉 계산 도중에는 알 수 없다.
큐비트 (|q>)의 일반적인 상태는 아래와 같다.

알파와 베타는 복소수임을 두 번째 줄에서 알 수 있다.
앞서 학습했듯이, 우리는 이러한 상태 중 일부를 구분할 수 없다.
첫째로, 전역 위상(global phase)을 측정할 수 없기 때문에, 상태 |0>와 |1> 간의 위상 차이만 측정할 수 있다.
알파와 베타로 복소수를 나타내는 대신, 실수에 국한시키고, 용어(term)를 추가함으로써 상대적 위상차를 알 수 있다.

e^iϕ = 1이다.
마지막으로, 큐비트 상태는 정규화되어야 하기 때문에

이다.
삼각법을 통해,

실수 알파와 베타를 하나의 기호로 나타내기 위한 세타

아래와 같이, 두 변수, 파이와 세타를 사용하여 어떠한 큐비트의 상태도 나타낼 수 있다.

일반적인 큐비트 상태를 플로팅한다.

우리는 일반적인 큐비트의 상태를 plot하고 싶다.

θ와 ϕ를 구면 좌표로 해석하면(큐비트의 상태의 크기가 1이므로, r = 1이다), 블로흐 구(Bloch sphere)로 어떠한 큐비트의 상태라도 나타낼 수 있다.
아래는 θ = π/2 and ϕ = 0인 큐비트 |+⟩를 나타낸 것이다.

블로흐 벡터와 큐비트의 상태 벡터를 혼동하면 안 된다.
상태 벡터는 큐비트가 될 수 있는 두 가지 상태에 대한 진폭을 나타낸다.
블로흐 벡터는 2D 복소수 상태 벡터를 3D 공간에 나타내기 위해 사용하는 시각화 툴이다.
X 게이트는 Pauli-X 행렬로 나타낼 수 있다.

X 게이트는 |0>과 |1>의 진폭을 교환한다.

# Let's do an X-gate on a |0> qubit
qc = QuantumCircuit(1)
qc.x(0)
qc.draw()
블로흐 구의 x축을 기준으로 π 라디안만큼 회전한 값이 된다.
X 게이트는 NOT 게이트라고도 부른다.
Y & Z 파울리 행렬들은 Y & Z 게이트로 동작한다.



P-gate는 매개변수화되어 있으며, 파이를 통해 무슨 작업을 수행할 지 결정할 수 있다.
P-gate는 Z축 방향으로 파이만큼의 회전을 수행한다.

파이는 실수이다.
Z-gate는 P-gate의 특별한 경우이다.
파이가 파이일 경우

I 게이트는 아무것도 하지 않는 게이트이다.
항등 행렬이다.
회로의 아무 곳에나 I 게이트를 적용해도 큐비트의 상태에 아무런 영향을 끼치지 않는다.
사용하는 이유는 다음과 같다.
계산에 사용된다.

실제 하드웨어를 고려할 때, '아무것도 하지 않음(do-nothing)', 'none'등을 지정하기 위해 사용한다.
S 게이트는, 'Ø = π/2'일 경우의 P 게이트이며, √Z-gate라고도 불린다.
블로흐 구를 1/4 회전시킨 것이다.
해당 챕터의 타 게이트들과 달리, S 게이트의 역(inverse)이 자기 자신이 아니다.
Inverse는 S†-gate(S-dagger, Sdg, √Z†-gate)이다.
S†-gate는 Ø = -π/2일 때의 P-gate이다.

√Z-gate라는 이름은, 두 개의 연속적인 S-gate가 Z-gate하나와 같은 역할을 하기 때문이다.

qc = QuantumCircuit(1)
qc.s(0) # Apply S-gate to qubit 0
qc.sdg(0) # Apply Sdg-gate to qubit 0
qc.draw()

T-gate는 매우 일반적으로 사용되는 게이트이다.(중요함)
'ϕ = π/4'일 때의 P-gate이다.

S-gate와 마찬가지로, T-gate는 ^4√Z-gate라고도 불린다.
qc = QuantumCircuit(1)
qc.t(0) # Apply T-gate to qubit 0
qc.tdg(0) # Apply Tdg-gate to qubit 0
qc.draw()
U-gate는 다음과 같이 매개변수화 된 게이트이다.

이 장의 모든 게이트들은 U(θ,ϕ,λ)의 형식으로 나타낼 수 있다.
그러나 복잡한 형식 때문에, 회로도에서 U 게이트를 통해 자주 나타내지는 않는다.

U 게이트로 나타낸 H, P 게이트이다.
# Let's have U-gate transform a |0> to |+> state
qc = QuantumCircuit(1)
qc.u(pi/2, 0, pi, 0)
qc.draw()
이로부터, 여기서 언급된 게이트들 이외에도, 무한한 수의 가능한 게이트들이 있다는 것을 알 수 있다.
또한, 표준으로 선택된 것을 제외하고는, Z-basis 역시 특별하지 않다는 것을 알 수 있다.
또한, Qiskit에서는 X에도 동등하게 S와 Sdg 게이트(SX-gate, SXdg-gate)를 제공한다.
이들은 X축으로 회전을 수행한다.
IBM 양자 하드웨어에서 실행하기 전에, 모든 단일-큐비트 작업들은 I, X, SX, Rz로 컴파일된다.
따라서, 이들을 물리 게이트(physical gates)라고 칭한다.
큐비트와 양자 게이트를 사용하면 디지털 및 아날로그 고전 알고리즘과 근본적으로 다른 새로운 알고리즘을 설계할 수 있다.
이를 통해, 고전 컴퓨터에서 다루기 힘든 문제에 대한 해결책을 찾으려 한다.
예를 들어,
함수 f(x)에 대해, f(x)를 최소로 하는 매개변수 x의 값을 찾고자 할 때나, f(x)가 주기 함수일 시 주기를 찾는 등에 사용할 수 있다.
디지털 컴퓨터의 알고리즘은 가능한 전역 속성에 대한 충분한 정보를 얻기 위해 다양한 입력에 의해 계산된다.
그러나, 양자 컴퓨터를 사용한다면 중첩 상태를 생성할 수 있으므로, 가능한 많은 입력을 동시에 적용할 수 있게된다.
이는 그러한 상태의 측정이 단순히 단일 결과를 제공하기 때문에 가능한 모든 출력에 접근할 수 있다는 것을 의미하지는 않는다.
그러나, 대신 우리가 필요로 하는 전역 속성(property)를 드러낼 양자 간섭 효과를 유도할 수 있다.
이러한 일반적 설명은 많은 양자 알고리즘을 통해 알 수 있다.
Grover의 알고리즘에 따르면, N개의 요소를 탐색하는 시간 복잡도는 O(N)에서 O(N^(1/2))로 감소한다.
인수분해 문제의 핵심인 주기함수를 분석하는 Shor의 알고리즘을 사용하면, 더 높은 속도 향상을 얻을 수 있다.
디지털 컴퓨터로 n자릿수를 인수분해하는 시간복잡도는 O(e^n^(1/3))이나, 양자 솔루션을 통해 시간복잡도를 O(n^3)으로 낮출 수 있다.
양자 알고리즘에 대한 또 다른 접근 방식은 양자 컴퓨터를 통해 양자 문제를 해결하는 것이다.
양자 상태를 표현하려면, 큐비트 수에 따라 기하급수적으로 확장되는 많은 양의 정보가 필요하다.
n개의 큐비트의 상태를 그저 적는 것은 디지털 컴퓨터에서 다루기 힘든 작업이다.
그러나, 양자 컴퓨터에서는 동일한 작업을 위해 그저 n개의 큐비트만이 필요하다.
양자 상태를 표현, 조작하는 이러한 자연적 능력을 통해 분자 및 기본 입자와 같은 양자 시스템을 연구하고 이해할 수 ㅇㅆ다.