O equivalente 'Hello World' no mundo D-Wave é o exemplo do tabuleiro de xadrez 2D. Neste exemplo, você recebe o seguinte gráfico quadrado com 4 nós:
Vamos definir que vértice σ i preto se σ i = - 1 e branco se σ i = + 1 . O objetivo é criar um padrão quadriculado com os quatro vértices no gráfico. Há várias maneiras de definir
h e J para alcançar este resultado. Primeiro de tudo, existem duas soluções possíveis para esse problema:σEuσEu= - 1σEu= + 1hJ
O recozedor quântico D-Wave minimiza o ising hamiltoniano que definimos e é importante entender o efeito das diferentes configurações do acoplador. Considere, por exemplo , o acoplador :J0 , 1
Se o definirmos como , o Hamiltoniano será minimizado se ambos os qubits tiverem o mesmo valor. Dizemos que acopladores negativos se correlacionam . Enquanto que se o definirmos como J 0 , 1 = + 1 , o Hamiltoniano será minimizado se os dois qubits tiverem valores opostos. Assim, acopladores positivos se correlacionam .J0 , 1= - 1J0 , 1= + 1
No exemplo do tabuleiro de damas, queremos anti-correlacionar cada par de qubits vizinhos, o que dá origem ao seguinte hamiltoniano:
H= σ0 0σ1+ σ0 0σ2+ σ1σ3+ σ2σ3
0 0σ0 0= - 1h0 0= 1
H= σ0 0+ σ0 0σ1+ σ0 0σ2+ σ1σ3+ σ2σ3
Então, vamos codificá-lo!
NOTA: VOCÊ PRECISA acessar o serviço em nuvem da D-Wave para que tudo funcione.
Primeiro, verifique se você tem o pacote Python dwave_sapi2
( https://cloud.dwavesys.com/qubist/downloads/ ) instalado. Tudo será Python 2.7, já que o D-Wave atualmente não suporta nenhuma versão superior do Python. Dito isto, vamos importar o essencial:
from dwave_sapi2.core import solve_ising
from dwave_sapi2.embedding import find_embedding, embed_problem, unembed_answer
from dwave_sapi2.util import get_hardware_adjacency
from dwave_sapi2.remote import RemoteConnection
Para conectar-se à API do D-Wave Solver, você precisará de um token de API válido para o solucionador SAPI, o URL da SAPI e decidir qual processador quântico deseja usar:
DWAVE_SAPI_URL = 'https://cloud.dwavesys.com/sapi'
DWAVE_TOKEN = [your D-Wave API token]
DWAVE_SOLVER = 'DW_2000Q_VFYC_1'
Eu recomendo usar a quimera virtual de rendimento total D-Wave 2000Q (VFYC), que é um chip totalmente funcional sem qubits mortos! Aqui está o layout do chip Chimera:
Neste ponto, estou dividindo o tutorial em duas partes distintas. Na primeira seção, estamos incorporando manualmente o problema no gráfico de hardware do Chimera e na segunda seção, estamos usando as heurísticas de incorporação da D-Wave para encontrar uma incorporação de hardware.
Incorporação manual
A célula unitária no canto superior esquerdo no layout do chip D-Wave 2000Q acima é assim:
0 010 → 01 → 42 → 73 → 3hJ
J = {(0,4): 1, (4,3): 1, (3,7): 1, (7,0): 1}
h = [-1,0,0,0,0,0,0,0,0]
h
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Agora, podemos definir o número de leituras e optar answer_mode
por ser "histograma", que já classifica os resultados pelo número de ocorrências para nós. Agora estamos prontos para resolver a instância de Ising com o recozedor quântico D-Wave:
params = {"answer_mode": 'histogram', "num_reads": 10000}
results = solve_ising(solver, h, J, **params)
print results
Você deve obter o seguinte resultado:
{
'timing': {
'total_real_time': 1655206,
'anneal_time_per_run': 20,
'post_processing_overhead_time': 13588,
'qpu_sampling_time': 1640000,
'readout_time_per_run': 123,
'qpu_delay_time_per_sample': 21,
'qpu_anneal_time_per_sample': 20,
'total_post_processing_time': 97081,
'qpu_programming_time': 8748,
'run_time_chip': 1640000,
'qpu_access_time': 1655206,
'qpu_readout_time_per_sample': 123
},
'energies': [-5.0],
'num_occurrences': [10000],
'solutions': [
[1, 3, 3, 1, -1, 3, 3, -1, {
lots of 3 's that I am omitting}]]}
energies
- 5,030 → 04 → 17 → 23 → 3[ 1 , - 1 , - 1 , 1 ]
Incorporação heurística
Jh
J = {(0,1): 1, (0,2): 1, (1,3): 1, (2,3): 1}
h = [-1,0,0,0]
Novamente estabelecemos a conexão remota e obtemos a instância do solucionador D-Wave 2000Q VFYC:
connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN)
solver = connection.get_solver(DWAVE_SOLVER)
Para encontrar uma incorporação do nosso problema, precisamos primeiro obter a matriz de adjacência do gráfico de hardware atual:
adjacency = get_hardware_adjacency(solver)
Agora vamos tentar encontrar uma incorporação do nosso problema:
embedding = find_embedding(J.keys(), adjacency)
Se você estiver lidando com grandes instâncias Ising, convém procurar por incorporações em vários encadeamentos (paralelizados por várias CPUs) e selecionar a incorporação com o menor comprimento de cadeia! Uma cadeia é quando vários qubits são forçados a agir como um único qubit para aumentar o grau de conectividade. No entanto, quanto maior a cadeia, maior a probabilidade de que ela se quebre. E correntes quebradas dão maus resultados!
Agora estamos prontos para incorporar nosso problema no gráfico:
[h, j0, jc, embeddings] = embed_problem(h, J, embedding, adjacency)
j0
jc
J
J = j0.copy()
J.update(jc)
Agora, estamos prontos para resolver o problema incorporado:
params = {"answer_mode": 'histogram', "num_reads": 10000}
raw_results = solve_ising(solver, h, J, **params)
print 'Lowest energy found: {}'.format(raw_results['energies'])
print 'Number of occurences: {}'.format(raw_results['num_occurrences'])
A raw_results
vontade não fará sentido para nós, a menos que resolvamos o problema. No caso, algumas cadeias quebraram, estamos corrigindo-as através de uma votação majoritária, conforme definido pelo argumento opcional broken_chains
:
unembedded_results = unembed_answer(raw_results['solutions'],
embedding, broken_chains='vote')
print 'Solution string: {}'.format(unembedded_results)
Se você executar isso, deverá obter o resultado correto em todas as leituras:
Lowest energy found: [-5.0]
Number of occurences: [10000]
Solution string: [[1, -1, -1, 1]]
Espero que isso tenha respondido à sua pergunta e eu recomendo verificar todos os parâmetros adicionais que você pode passar para a solve_ising
função para melhorar a qualidade de suas soluções, como num_spin_reversal_transforms
ou postprocess
.