No use el método de intercambio, es muy ineficiente. Y la respuesta de la otra persona es específica para la puerta CNOT, y para ser sincero, complica las cosas en exceso.
Aquí hay un algoritmo muy simple que resuelve su problema para cada caso, no solo la puerta CNOT, para cualquier bit arbitrario.
El algoritmo:
let sys = matrix representing the current state of the system
let n = number of qubits being simulated
let lgm = logic gate matrix of size 2^n by 2^n
let f = our logic gate transformation function
for i = 0 to (2^n) - 1:
lgm[column = i] = f(i)
sys = sys × lgg
En las computadoras clásicas, hay algo conocido como el "decodificador". Digamos que solo tengo 3 cables, efectivamente, 3 bits. Pero quiero controlar 8 cables. ¿Se puede hacer eso? Sí, porque 3 bits tienen 8 posibilidades diferentes: 000, 001, 010, 011, 100, 101, 110, 111. Por lo tanto, podemos asignar cada posibilidad a uno de nuestros 8 cables de salida. Esto se llama "decodificación".
Si paso el número 101 y tenemos 3 bits, sabemos 101 = 5, por lo que estaré configurando el cable de salida 5 a un alto voltaje y los otros 7 cables de salida serán 0, lo que podemos representar así: decodificar (101) = [0, 0, 0, 0, 0, 1, 0, 0].
En este algoritmo, menciono la "función de transformación" llamada "f". Para las computadoras clásicas, la función de transformación solo toma un valor de entrada y devuelve la versión "decodificada" del valor de salida. Entonces, si tenemos 3 bits y la salida es 4, entonces devolveremos [0, 0, 0, 0, 1, 0, 0, 0]. Luego asignamos eso como la columna de nuestra matriz para ese valor.
Pensemos en la "decodificación" en términos de qubits. ¿Cómo podemos decodificar los qubits | 101>?
Sabemos que para nuestros vectores de probabilidad qubit, | 0> es [1, 0] y | 1> es [0, 1]. Entonces se pueden decodificar qubits lo que se llama el producto Kronecker.
Entonces, si convertimos cada bit al equivalente de vector de probabilidad y tomamos el producto Kronecker de todos ellos, obtenemos ...
|101> = |1> ⊗ |0> ⊗ |1> = [0, 1] ⊗ [1, 0] ⊗ [0, 1] = [0, 0, 0, 0, 0, 1, 0, 0]
Así es como nos gustaría decodificar qubits. Este algoritmo se puede aplicar a qubits de la misma manera usando esto.
Probemos este algoritmo en un problema más simple.
Supongamos que tenemos un sistema con solo 2 qubits. Si queremos aplicar la puerta Hadamard a solo 1 qubit, podemos generar una puerta lógica para ambos qubits que solo aplique la puerta Hadamard a un solo qubit. Supongamos que el qubit único al que queremos aplicarlo es nuestro qubit más significativo y el menos significativo no se verá afectado.
Queremos una función de transformación que para cada una de nuestras posibles entradas, produzca la salida correcta. Tenemos dos qubits, esto significa que hay cuatro salidas posibles.
f(|00>) = ?
f(|01>) = ?
f(|10>) = ?
f(|11>) = ?
Sabemos que el qubit menos significativo no se verá afectado, por lo que podemos completarlo.
f(|00>) = ? ⊗ |0>
f(|01>) = ? ⊗ |1>
f(|10>) = ? ⊗ |0>
f(|11>) = ? ⊗ |1>
También sabemos lo que el Hadamard le hace a un qubit, de modo que:
H(|0>) = 1/sqrt(2)|0> + 1/sqrt(2)|1>
H(|1>) = 1/sqrt(2)|0> - 1/sqrt(2)|1>
Entonces nuestra función de transformación es simplemente:
f(|00>) = (1/sqrt(2)|0> + 1/sqrt(2)|1>) ⊗ |0>
f(|01>) = (1/sqrt(2)|0> + 1/sqrt(2)|1>) ⊗ |1>
f(|10>) = (1/sqrt(2)|0> - 1/sqrt(2)|1>) ⊗ |0>
f(|11>) = (1/sqrt(2)|0> - 1/sqrt(2)|1>) ⊗ |1>
Expanda esto a nuestra forma de vector de probabilidad normalizada ...
f(|00>) = [ 1/sqrt(2), 1/sqrt(2) ] ⊗ [ 1, 0 ]
f(|01>) = [ 1/sqrt(2), 1/sqrt(2) ] ⊗ [ 0, 1 ]
f(|10>) = [ 1/sqrt(2), -1/sqrt(2) ] ⊗ [ 1, 0 ]
f(|11>) = [ 1/sqrt(2), -1/sqrt(2) ] ⊗ [ 0, 1 ]
Ahora vamos a resolver esto ...
f(|00>) = [ 1/sqrt(2), 0, 1/sqrt(2), 0 ]
f(|01>) = [ 0, 1/sqrt(2), 0, 1/sqrt(2) ]
f(|10>) = [ 1/sqrt(2), 0, -1/sqrt(2), 0 ]
f(|11>) = [ 0, 1/sqrt(2), 0, -1/sqrt(2) ]
Esa es nuestra función de transformación.
Nuestra matriz de puerta lógica, "lgm", tiene un tamaño de 2 ^ n por 2 ^ n donde n = número de qubits que se simulan, por lo que en este caso es 2 ^ 2 por 2 ^ 2 o 4x4. Nuestro algoritmo nos dice que para cada columna i, establezca la columna igual a f (i). Hemos definido nuestra función de transformación de probabilidad, por lo que podemos completar fácilmente estas columnas.
lgm =
|00> |01> |10> |11>
[ 1/sqrt(2), 0, 1/sqrt(2), 0 ]
[ 0, 1/sqrt(2), 0, 1/sqrt(2) ]
[ 1/sqrt(2), 0, -1/sqrt(2), 0 ]
[ 0, 1/sqrt(2), 0, -1/sqrt(2) ]
Ahora, el paso final en nuestro algoritmo es simplemente multiplicar por matriz nuestra matriz que representa todo el sistema cuántico, sys, por esta puerta lógica, lgm.
Y eso hace lo que queremos. Aplicará la puerta hadamard solo al qubit más grande y dejará solo el qubit menos significativo. Si no me crees, puedes probarlo tú mismo y ver que funciona.
La razón por la que esto es tan poderoso es porque se aplica a cualquier caso.
Probemos este algoritmo en su problema.
Imaginemos que tenemos un sistema de 3 qubits y queremos aplicar una puerta CNOT a qubits [0] y qubits [2]. Si busca la matriz CNOT en Wikipedia, esa matriz solo se aplica a un sistema de 2 qubits. Una solución ingenua sería agregarle matrices de identidad utilizando el producto Kronecker para que funcione en sistemas con tres qubits. Pero esto falla aquí: qubit [0] y qubit [2] no son adyacentes, por lo que simplemente agregar matrices de identidad no funcionará.
Nosotros podríamos intercambiar qubit [0] con qubit [1], aplique la puerta CNOT, luego intercambiar espalda. Pero eso es lento. En cambio, podríamos simplemente generar una puerta CNOT no adyacente para nuestro problema utilizando el algoritmo anterior.
Primero necesitamos crear una función de transformación para cada caso.
f(|000>) = |0> ⊗ |0> ⊗ |0>
f(|001>) = |0> ⊗ |0> ⊗ |1>
f(|010>) = |0> ⊗ |1> ⊗ |0>
f(|011>) = |0> ⊗ |1> ⊗ |1>
f(|100>) = |1> ⊗ |0> ⊗ |1>
f(|101>) = |1> ⊗ |0> ⊗ |0>
f(|110>) = |1> ⊗ |1> ⊗ |1>
f(|111>) = |1> ⊗ |1> ⊗ |0>
Si comprende la puerta CNOT, puede entender por qué esta es nuestra función. Piense en esto como una tabla de verdad. Dado que nuestro qubit de control es el qubit más significativo, qubit [2], solo cuando ese qubit es | 1> se negará el qubit menos significativo, qubit [0].
Expanda esto a nuestra forma de vector de probabilidad normalizada ...
f(|000>) = [ 1, 0 ] ⊗ [ 1, 0 ] ⊗ [ 1, 0 ]
f(|001>) = [ 1, 0 ] ⊗ [ 1, 0 ] ⊗ [ 0, 1 ]
f(|010>) = [ 1, 0 ] ⊗ [ 0, 1 ] ⊗ [ 1, 0 ]
f(|011>) = [ 1, 0 ] ⊗ [ 0, 1 ] ⊗ [ 0, 1 ]
f(|100>) = [ 0, 1 ] ⊗ [ 1, 0 ] ⊗ [ 0, 1 ]
f(|101>) = [ 0, 1 ] ⊗ [ 1, 0 ] ⊗ [ 1, 0 ]
f(|110>) = [ 0, 1 ] ⊗ [ 0, 1 ] ⊗ [ 0, 1 ]
f(|111>) = [ 0, 1 ] ⊗ [ 0, 1 ] ⊗ [ 1, 0 ]
Ahora vamos a resolver esto ...
f(|000>) = [ 1, 0, 0, 0, 0, 0, 0, 0 ]
f(|001>) = [ 0, 1, 0, 0, 0, 0, 0, 0 ]
f(|010>) = [ 0, 0, 1, 0, 0, 0, 0, 0 ]
f(|011>) = [ 0, 0, 0, 1, 0, 0, 0, 0 ]
f(|100>) = [ 0, 0, 0, 0, 0, 1, 0, 0 ]
f(|101>) = [ 0, 0, 0, 0, 1, 0, 0, 0 ]
f(|110>) = [ 0, 0, 0, 0, 0, 0, 0, 1 ]
f(|111>) = [ 0, 0, 0, 0, 0, 0, 1, 0 ]
Hagamos de estas las columnas de nuestra matriz lgm.
lgm =
[ 1, 0, 0, 0, 0, 0, 0, 0 ]
[ 0, 1, 0, 0, 0, 0, 0, 0 ]
[ 0, 0, 1, 0, 0, 0, 0, 0 ]
[ 0, 0, 0, 1, 0, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 1, 0, 0 ]
[ 0, 0, 0, 0, 1, 0, 0, 0 ]
[ 0, 0, 0, 0, 0, 0, 0, 1 ]
[ 0, 0, 0, 0, 0, 0, 1, 0 ]
Ahora, si la matriz multiplica nuestra matriz de todo el sistema, sys, por nuestra matriz de compuerta lógica, lgm, nuestro resultado será el efecto de aplicar la compuerta CNOT a qubit [2] y qubit [0] donde qubit [2] es el control qubit