Não use o método de troca, é muito ineficiente. E a resposta da outra pessoa é específica para o portal CNOT e, para ser franco, complica demais as coisas.
Aqui está um algoritmo muito simples que resolve seu problema em todos os casos, não apenas no portal CNOT, para quaisquer bits arbitrários.
O 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
Nos computadores clássicos, existe algo conhecido como "decodificador". Digamos que eu tenho apenas 3 fios, efetivamente, 3 bits. Mas eu quero controlar 8 fios. Isso pode ser feito? Sim, porque 3 bits tem 8 possibilidades diferentes: 000, 001, 010, 011, 100, 101, 110, 111. Portanto, podemos atribuir cada possibilidade a um dos nossos 8 fios de saída. Isso é chamado de "decodificação".
Se eu passar o número 101 e tivermos 3 bits, sabemos 101 = 5, então configurarei o fio de saída 5 para uma alta tensão e os outros 7 fios de saída serão 0, que podemos representar assim: decode (101) = [0, 0, 0, 0, 0, 1, 0, 0].
Neste algoritmo, menciono a "função de transformação" chamada "f". Para computadores clássicos, a função de transformação está apenas recebendo um valor de entrada e retornando a versão "decodificada" do valor de saída. Portanto, se tivermos 3 bits e a saída for 4, retornaremos [0, 0, 0, 0, 1, 0, 0, 0]. Em seguida, atribuímos isso como a coluna da nossa matriz a esse valor.
Vamos pensar em "decodificação" em termos de qubits. Como podemos decodificar os qubits | 101>?
Sabemos que para nossos vetores de probabilidade de qubit, | 0> é [1, 0] e | 1> é [0, 1]. A decodificação de qubits pode ser feita como o produto Kronecker.
Portanto, se convertermos cada bit no equivalente de vetor de probabilidade e pegarmos o produto Kronecker de todos eles, obteremos ...
|101> = |1> ⊗ |0> ⊗ |1> = [0, 1] ⊗ [1, 0] ⊗ [0, 1] = [0, 0, 0, 0, 0, 1, 0, 0]
É assim que queremos decodificar qubits. Este algoritmo pode ser aplicado a qubits da mesma forma usando isso.
Vamos tentar este algoritmo em um problema mais simples.
Vamos supor que temos um sistema com apenas 2 qubits. Se queremos aplicar o portão Hadamard a apenas 1 qubit, podemos gerar um portão lógico para ambos os qubits que aplique apenas o portão Hadamard a um único qubit. Vamos supor que o qubit único ao qual queremos aplicá-lo seja o qubit mais significativo e o menos significativo não será afetado.
Queremos uma função de transformação que, para cada uma de nossas entradas possíveis, produza a saída correta. Temos dois qubits, isso significa que existem quatro saídas possíveis.
f(|00>) = ?
f(|01>) = ?
f(|10>) = ?
f(|11>) = ?
Sabemos que o qubit menos significativo não será afetado, para que possamos preenchê-lo.
f(|00>) = ? ⊗ |0>
f(|01>) = ? ⊗ |1>
f(|10>) = ? ⊗ |0>
f(|11>) = ? ⊗ |1>
Também sabemos o que o Hadamard faz com um qubit, de modo que:
H(|0>) = 1/sqrt(2)|0> + 1/sqrt(2)|1>
H(|1>) = 1/sqrt(2)|0> - 1/sqrt(2)|1>
Portanto, nossa função de transformação é simplesmente:
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 isso para nosso formulário de vetor de probabilidade normalizado ...
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 ]
Agora vamos resolver isso ...
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) ]
Essa é a nossa função de transformação.
Nossa matriz de portas lógicas, "lgm", é do tamanho 2 ^ n por 2 ^ n onde n = número de qubits sendo simulados; portanto, neste caso, é 2 ^ 2 por 2 ^ 2 ou 4x4. Nosso algoritmo nos diz que, para cada coluna i, defina a coluna igual a f (i). Definimos nossa função de transformação de probabilidade, para que possamos preencher facilmente essas colunas.
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) ]
Agora, o passo final em nosso algoritmo é simplesmente multiplicar nossa matriz, representando todo o sistema quântico, sys, por esse portão lógico, lgm.
E isso faz o que queremos. Ele aplicará o portão hadamard apenas ao qubit mais alto e deixará o qubit menos significativo em paz. Se você não acredita em mim, pode tentar e ver se funciona.
A razão disso ser tão poderoso é porque se aplica a qualquer caso.
Vamos tentar este algoritmo no seu problema.
Imagine que temos um sistema de 3 qubit e queremos aplicar uma porta CNOT para qubit [0] e qubit [2]. Se você procurar a matriz CNOT na Wikipedia, essa matriz se aplica apenas a um sistema de 2 qubit. Uma solução ingênua seria anexar matrizes de identidade a ela usando o produto Kronecker para fazê-lo funcionar em sistemas com três qubits. Mas isso falha aqui: qubit [0] e qubit [2] não são adjacentes; portanto, simplesmente anexar matrizes de identidade não funcionará.
Nós poderia trocar qubit [0] com o qubit [1], aplicar o portão CNOT, então trocá-los de volta. Mas isso é lento. Em vez disso, poderíamos simplesmente gerar uma porta CNOT não adjacente para o nosso problema usando o algoritmo acima.
Primeiro, precisamos criar uma função de transformação 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>
Se você entende o portal CNOT, pode entender por que essa é a nossa função. Pense nisso como uma tabela da verdade. Como nosso qubit de controle é o qubit mais significativo, qubit [2], somente quando esse qubit for | 1> o qubit menos significativo, qubit [0], será negado.
Expanda isso para nosso formulário de vetor de probabilidade normalizado ...
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 ]
Agora vamos resolver isso ...
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 ]
Vamos fazer dessas as colunas da nossa 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 ]
Agora, se a matriz multiplicar toda a matriz do sistema, sys, pela matriz da porta lógica, lgm, nosso resultado será o efeito de aplicar a porta CNOT ao qubit [2] e qubit [0] onde qubit [2] é o controle qubit.