qiskit/test/python/quantum_info/states/test_utils.py

134 lines
6.4 KiB
Python

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2020.
#
# 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.
"""Tests utility functions for QuantumState classes."""
import unittest
import numpy as np
from qiskit.quantum_info.states import Statevector, DensityMatrix
from qiskit.quantum_info.states import partial_trace, shannon_entropy, schmidt_decomposition
from test import QiskitTestCase # pylint: disable=wrong-import-order
class TestStateUtils(QiskitTestCase):
"""Test utility functions for QuantumState classes."""
def test_statevector_partial_trace(self):
"""Test partial_trace function on statevectors"""
psi = Statevector.from_label("10+")
self.assertEqual(partial_trace(psi, [0, 1]), DensityMatrix.from_label("1"))
self.assertEqual(partial_trace(psi, [0, 2]), DensityMatrix.from_label("0"))
self.assertEqual(partial_trace(psi, [1, 2]), DensityMatrix.from_label("+"))
self.assertEqual(partial_trace(psi, [0]), DensityMatrix.from_label("10"))
self.assertEqual(partial_trace(psi, [1]), DensityMatrix.from_label("1+"))
self.assertEqual(partial_trace(psi, [2]), DensityMatrix.from_label("0+"))
self.assertEqual(partial_trace(psi, []), DensityMatrix(psi))
def test_density_matrix_partial_trace(self):
"""Test partial_trace function on density matrices"""
rho = DensityMatrix.from_label("10+")
self.assertEqual(partial_trace(rho, [0, 1]), DensityMatrix.from_label("1"))
self.assertEqual(partial_trace(rho, [0, 2]), DensityMatrix.from_label("0"))
self.assertEqual(partial_trace(rho, [1, 2]), DensityMatrix.from_label("+"))
self.assertEqual(partial_trace(rho, [0]), DensityMatrix.from_label("10"))
self.assertEqual(partial_trace(rho, [1]), DensityMatrix.from_label("1+"))
self.assertEqual(partial_trace(rho, [2]), DensityMatrix.from_label("0+"))
self.assertEqual(partial_trace(rho, []), rho)
def test_shannon_entropy(self):
"""Test shannon_entropy function"""
input_pvec = np.array([0.5, 0.3, 0.07, 0.1, 0.03])
# Base 2
self.assertAlmostEqual(1.7736043871504037, shannon_entropy(input_pvec))
# Base e
self.assertAlmostEqual(1.229368880382052, shannon_entropy(input_pvec, np.e))
# Base 10
self.assertAlmostEqual(0.533908120973504, shannon_entropy(input_pvec, 10))
def test_schmidt_decomposition_separable(self):
"""Test schmidt_decomposition for separable 2-level system without subsystem permutation"""
target = Statevector.from_label("l10")
schmidt_comps = schmidt_decomposition(target, [0])
# check decomposition elements
self.assertAlmostEqual(schmidt_comps[0][0], 1)
self.assertEqual(schmidt_comps[0][1], -1 * Statevector.from_label("l1"))
self.assertEqual(schmidt_comps[0][2], -1 * Statevector.from_label("0"))
# check that state can be properly reconstructed
state = Statevector(sum(suv[0] * np.kron(suv[1], suv[2]) for suv in schmidt_comps))
self.assertEqual(state, target)
def test_schmidt_decomposition_separable_with_permutation(self):
"""Test schmidt_decomposition for separable 2-level system with subsystem permutation"""
target = Statevector.from_label("0l1")
schmidt_comps = schmidt_decomposition(Statevector.from_label("l10"), [2, 1])
# check decomposition elements
self.assertAlmostEqual(schmidt_comps[0][0], 1)
self.assertEqual(schmidt_comps[0][1], Statevector.from_label("0"))
self.assertEqual(schmidt_comps[0][2], Statevector.from_label("l1"))
# check that state can be properly reconstructed
state = Statevector(sum(suv[0] * np.kron(suv[1], suv[2]) for suv in schmidt_comps))
self.assertEqual(state, target)
def test_schmidt_decomposition_entangled(self):
"""Test schmidt_decomposition for entangled 2-level system"""
target = np.sqrt(1 / 3) * Statevector.from_label("00") + np.sqrt(
2 / 3
) * Statevector.from_label("11")
schmidt_comps = schmidt_decomposition(target, [0])
# check decomposition elements
self.assertAlmostEqual(schmidt_comps[0][0], np.sqrt(2 / 3))
self.assertEqual(schmidt_comps[0][1], Statevector.from_label("1"))
self.assertEqual(schmidt_comps[0][2], Statevector.from_label("1"))
self.assertAlmostEqual(schmidt_comps[1][0], np.sqrt(1 / 3))
self.assertEqual(schmidt_comps[1][1], Statevector.from_label("0"))
self.assertEqual(schmidt_comps[1][2], Statevector.from_label("0"))
# check that state can be properly reconstructed
state = Statevector(sum(suv[0] * np.kron(suv[1], suv[2]) for suv in schmidt_comps))
self.assertEqual(state, target)
def test_schmidt_decomposition_3_level_system(self):
"""Test schmidt_decomposition for entangled 3-level system"""
target = Statevector(np.array([1, 0, 0, 0, 1, 0, 0, 0, 1]) * 1 / np.sqrt(3), dims=(3, 3))
schmidt_comps = schmidt_decomposition(target, [0])
# check decomposition elements
self.assertAlmostEqual(schmidt_comps[0][0], 1 / np.sqrt(3))
self.assertEqual(schmidt_comps[0][1], Statevector(np.array([1, 0, 0]), dims=3))
self.assertEqual(schmidt_comps[0][2], Statevector(np.array([1, 0, 0]), dims=3))
self.assertAlmostEqual(schmidt_comps[1][0], 1 / np.sqrt(3))
self.assertEqual(schmidt_comps[1][1], Statevector(np.array([0, 1, 0]), dims=3))
self.assertEqual(schmidt_comps[1][2], Statevector(np.array([0, 1, 0]), dims=3))
self.assertAlmostEqual(schmidt_comps[2][0], 1 / np.sqrt(3))
self.assertEqual(schmidt_comps[2][1], Statevector(np.array([0, 0, 1]), dims=3))
self.assertEqual(schmidt_comps[2][2], Statevector(np.array([0, 0, 1]), dims=3))
# check that state can be properly reconstructed
state = Statevector(
sum(suv[0] * np.kron(suv[1], suv[2]) for suv in schmidt_comps), dims=(3, 3)
)
self.assertEqual(state, target)
if __name__ == "__main__":
unittest.main()