The Main Component Problem

In this example we demonstrate solving the Main Component Problem (MCP). This is a subroutine of our decoding algorithm but is quite interesting on its own. The problem reads as follows:

\[\underset{\phi_i \in \mathbb{C}^2}{\arg \max }\left[\otimes_i\left\langle\phi_i\right|\right] \rho\left[\otimes_i\left|\phi_i\right\rangle\right],\]

which essentially means finding a basis state which contributes most to a given pure state.

[1]:
import numpy as np

from tqdm import tqdm
from mdopt.optimiser.dephasing_dmrg import DephasingDMRG as deph_dmrg
from mdopt.optimiser.dmrg import DMRG as dmrg
from mdopt.optimiser.dephasing_dmrg import EffectiveDensityOperator
from mdopt.mps.utils import (
    create_state_vector,
    create_simple_product_state,
    create_custom_product_state,
    mps_from_dense,
    inner_product,
)

This example also serves as a sanity check for the dephasing DMRG optimiser. Here, we solve the problem using exact diagonalisation, DMRG and dephasing DMRG. Next, we compare the solutions which should be exactly the same.

Let’s first create random pure state.

[2]:
num_sites = 10
psi = create_state_vector(num_sites)

Let us now bump up the main component (which we choose randomly) amplitude and renormalise the state.

[3]:
index_to_bump = np.random.randint(0, 2**num_sites)
psi[index_to_bump] = 10
psi /= np.linalg.norm(psi)

Now, we create an exact Matrix Product State (MPS) version of the state and its Matrix Product Density Operator (MPDO).

[4]:
mps = mps_from_dense(psi)
mpdo = mps.density_mpo()

Then, we find the main component (a computational basis state having the largest overlap) of the density matrix in the dense form.

[5]:
overlaps_exact = []
for i in tqdm(range(2**num_sites)):
    state_string = np.binary_repr(i, width=num_sites)
    overlaps_exact.append(
        np.absolute(create_custom_product_state(state_string).dense() @ psi) ** 2
    )

main_component_exact = np.argmax(overlaps_exact)
100%|██████████| 1024/1024 [00:00<00:00, 5645.63it/s]

Now, let’s find the main component of the MPDO using our vanilla 2-site DMRG optimiser.

[6]:
mps_start = create_simple_product_state(num_sites, which="+")
engine = dmrg(mps_start, mpdo, mode="LA")
engine.run()
max_excited_mps_from_dmrg = engine.mps

overlaps_dmrg = []
for i in range(2**num_sites):
    state_string = np.binary_repr(i, width=num_sites)
    overlaps_dmrg.append(
        np.absolute(
            inner_product(
                max_excited_mps_from_dmrg,
                create_custom_product_state(state_string),
            )
        )
        ** 2
    )
main_component_dmrg = np.argmax(overlaps_dmrg)
100%|██████████| 1/1 [00:00<00:00,  1.13it/s]

Then, we do the same with our built-in Dephasing DMRG.

[7]:
mps_start = create_simple_product_state(num_sites, which="+")
dephasing_engine = deph_dmrg(
    mps_start,
    mps,
    mode="LA",
)
dephasing_engine.run()
main_component_mps = dephasing_engine.mps

overlaps_dephased = []
for i in range(2**num_sites):
    state_string = np.binary_repr(i, width=num_sites)
    overlaps_dephased.append(
        np.absolute(
            inner_product(
                main_component_mps,
                create_custom_product_state(state_string),
            )
        )
        ** 2
    )
main_component_dephased = np.argmax(overlaps_dephased)
100%|██████████| 1/1 [00:00<00:00, 16.07it/s]

Some sanity checks: check that the answer from the Dephasing DMRG is a product state.

[8]:
mps_product_answer = dephasing_engine.mps
assert mps_product_answer.bond_dimensions == [
    1 for _ in range(mps_product_answer.num_bonds)
]

Some sanity checks: check that all the three answers are the same.

[9]:
assert np.logical_and(
    main_component_exact == main_component_dmrg,
    main_component_exact == main_component_dephased,
)