Portuguese
Idiomas
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Nota

Esta página foi gerada a partir do tutoriais/simuladores/7_metodo_matriz_de_estado_do_produto.ipynb.

Método de simulação de estado do produto matricial

Métodos de simulação

O AerSimulator possui vários métodos de simulação incluindo statevector, stabilizer, extended_stabilizer e matrix_product_state. Cada um destes determina a representação interna do circuito quântico e os algoritmos utilizados para processar as operações quânticas. Cada um tem vantagens e desvantagens, e escolher o melhor método é uma questão de estudo e investigação. Neste tutorial, nos concentraremos no método de simulação do estado do produto matricial.

Método de simulação de estado do produto matricial

Este método de simulação baseia-se no conceito de estados de produto de matriz. Esta estrutura foi inicialmente proposta no artigo Efficient classical simulation of slightly entangled quantum computations por Vidal em https://arxiv.org/abs/quant-ph/0301063. Há artigos adicionais que descrevem a estrutura em mais detalhes, por exemplo The density-matrix renormalization group in the age of matrix product states por Schollwoeck https://arxiv.org/abs/1008.3477.

Um estado quântico puro é geralmente descrito como um vetor de estado, pela expressão \(|\psi\rangle = \sum_{i_1=0}^1 {\ldots} \sum_{i_n=0}^1 c_{i_1 \ldots i_n} |i_i\rangle {\otimes} {\ldots} {\otimes} |i_n\rangle\).

A representação do vetor de estado implica em uma representação de tamanho exponencial, independentemente do circuito real. Toda porta quântica que opera nessa representação requer tempo e memória exponenciais.

A representação do estado de produto de matriz (MPS) oferece uma representação local, na forma: \(\Gamma^{[1]} \lambda^{[1]} \Gamma^{[2]} \lambda^{[2]}\ldots \Gamma^{[1]} \lambda^{[n-1]} \Gamma^{[n]}\), tal que todas as informações contidas nos \(c_{i_1 \ldots i_n}\), podem ser geradas fora da representação do MPS.

Cada \(\Gamma^{[i]}\) é um tensor de números complexos que representa o qubit \(i\). Cada \(\lambda^{[i]}\) é uma matriz de números reais que é usada para normalizar as amplitudes dos qubits \(i\) e \(i+1\). Portas de um único qubit operam apenas no tensor relevante.

Portas de dois qubits operam em qubits consecutivos \(i\) e \(i+1\). Isso envolve uma operação de contração tensorial sobre \(\lambda^{[i-1]}\), \(\Gamma^{[i-1]}\), \(\lambda^{[i]}\), \(\Gamma^{[i+1]}\) e \(\lambda^{[i+1]}\), que cria um tensor único. Aplicamos a porta a este tensor e, em seguida, decompomos ele para a estrutura original. Esta operação pode aumentar o tamanho dos respectivos tensores. Portas que envolvem dois qubits que não são consecutivos exigem uma série de portas de troca para aproximar os dois qubits um do outro e depois as trocas inversas.

No pior dos casos, os tensores podem crescer exponencialmente. No entanto, o tamanho da estrutura geral permanece ‘pequeno’ para circuitos que não possuem ‘muitas’ portas de dois qubits. Isso permite operações muito mais eficientes em circuitos com um entrelaçamento relativamente ‘baixo’. Caracterizar quando utilizar este método sobre outros métodos é um assunto de pesquisa atual.

Usando o método de simulação do estado de produto de matriz

O método de simulação da matriz estado produto é invocado no AerSimulator, configurando o método de simulação. Fora isso, todas as operações são controladas pelo própria AerSimulator, como no exemplo a seguir:

[1]:
import numpy as np

# Import Qiskit
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator

# Construct quantum circuit
circ = QuantumCircuit(2, 2)
circ.h(0)
circ.cx(0, 1)
circ.measure([0,1], [0,1])

# Select the AerSimulator from the Aer provider
simulator = AerSimulator(method='matrix_product_state')

# Run and get counts, using the matrix_product_state method
tcirc = transpile(circ, simulator)
result = simulator.run(tcirc).result()
counts = result.get_counts(0)
counts
[1]:
{'11': 515, '00': 509}

Para ver o vetor de estado interno do circuito, podemos usar a instrução save_statevector. Para retornar a estrutura MPS interna completa, também podemos usar a instrução save_matrix_product_state.

[2]:
circ = QuantumCircuit(2, 2)
circ.h(0)
circ.cx(0, 1)

# Define a snapshot that shows the current state vector
circ.save_statevector(label='my_sv')
circ.save_matrix_product_state(label='my_mps')
circ.measure([0,1], [0,1])

# Execute and get saved data
tcirc = transpile(circ, simulator)
result = simulator.run(tcirc).result()
data = result.data(0)

#print the result data
data
[2]:
{'counts': {'0x0': 494, '0x3': 530},
 'my_sv': array([0.70710678+0.j, 0.        +0.j, 0.        +0.j, 0.70710678+0.j]),
 'my_mps': ([(array([[1.-0.j, 0.-0.j]]), array([[0.-0.j, 1.-0.j]])),
   (array([[1.-0.j],
           [0.-0.j]]),
    array([[0.-0.j],
           [1.-0.j]]))],
  [array([0.70710678, 0.70710678])])}

Executar circuitos usando o método de simulação de estado de produto de matriz pode ser rápido em relação a outros métodos. No entanto, se nós geramos o vetor de estado durante a execução, então a conversão para vetor de estado é, claro, exponencial na memória e no tempo, e por isso não nos beneficiamos com a utilização deste método. Podemos nos beneficiar se fizermos apenas operações que não exijam imprimir o vetor de estado completo. Por exemplo, se executamos um circuito e depois tomamos a medição. O circuito abaixo tem 200 qubits. Criamos um estado EPR que envolve todos esses qubits. Embora este estado seja altamente emaranhado, é bem gerido pelo método do estado de produto de matriz, porque na realidade só existem dois estados.

Podemos lidar com mais qubits do que isso, mas a execução pode levar alguns minutos. Tente executar um circuito similar com 500 qubits! Ou talvez até 1000 (você pode tomar uma xícara de café enquanto espera).

[3]:
num_qubits = 50
circ = QuantumCircuit(num_qubits, num_qubits)

# Create EPR state
circ.h(0)
for i in range (0, num_qubits-1):
    circ.cx(i, i+1)

# Measure
circ.measure(range(num_qubits), range(num_qubits))

tcirc = transpile(circ, simulator)
result = simulator.run(tcirc).result()
print("Time taken: {} sec".format(result.time_taken))
result.get_counts()
Time taken: 0.31022214889526367 sec
[3]:
{'11111111111111111111111111111111111111111111111111': 548,
 '00000000000000000000000000000000000000000000000000': 476}
[4]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
Qiskit0.25.0
Terra0.17.0
Aer0.8.0
Ignis0.6.0
Aqua0.9.0
IBM Q Provider0.12.2
System information
Python3.8.8 | packaged by conda-forge | (default, Feb 20 2021, 16:22:27) [GCC 9.3.0]
OSLinux
CPUs8
Memory (Gb)31.38858413696289
Tue Apr 20 15:22:58 2021 UTC

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.

[ ]: