Example 1
Let's consider a simple example with a 2×2 square matrix.
$$ A = \begin{pmatrix} 2 & 1\\ 1 & 5 \end{pmatrix}
$$
The eigenvalues and eigenvectors can be easily obtained. The analytical solutions for the eigenvalues are as follows.
$$ A  \lambda I = 0 $$
$$\Leftrightarrow
\lambda^2 +3 \lambda 11 = 0 $$
$$\Leftrightarrow\
\lambda = \frac{1}{2} (3 \pm \sqrt{53} )
$$
If we approximate $ \sqrt{53}$ to be slightly larger than 7, then we can estimate the smaller eigenvalue to be around 5.let's calculate the exact value in Python:
import numpy as np
matrix = np.array([[2, 1],
[1, 5]]
)
# Calculate eigenvalues and eigenvectors.
eigenvalues, eigenvectors = np.linalg.eig(matrix)
# display result
print("Matrix:")
print(matrix)
print("\nEigenvalues: ", eigenvalues)
print("\nEigenvectors: \n", eigenvectors)
The output is as follows.
Matrix:
[[ 2 1]
[1 5]]
Eigenvalues: [ 2.14005494 5.14005494]
Eigenvectors:
[[ 0.99033427 0.13870121]
[0.13870121 0.99033427]]
Therefore, the minimum eigenvalue is 5.140, which is consistent with the analytical solution mentioned above.
Solving with VQE
Let's see how we can solve this eigenvalue problem using the VQE（Variational Quantum Eigensolver） method, which is a quantum computing algorithm designed to find the eigenvalues (minimum energy) of problems in fields such as chemistry and physics. VQE operates on quantum devices and is expected to work on noisy intermediatescale quantum (NISQ) devices, making it one of the practical applications of quantum computing.
VQE is based on the variational method and operates with the following basic steps:

Ansatz Selection: Choose an appropriate variational form (ansatz) for the problem. The ansatz is constructed by adjusting parameters within a quantum circuit, aiming to find the optimal shape for the given problem.

Expectation Value Evaluation: After adjusting the parameters with the ansatz, calculate the expectation value. This provides the energy of the state represented by the ansatz.

Classical Optimization: Update the parameters of the ansatz to minimize the calculated expectation value. This is typically done using classical optimization algorithms.

Convergence Check: Repeat steps 23 until the algorithm converges or reaches the desired accuracy.
Quantum Computing with Qiskit
Now, let's use Qiskit to perform quantum computing for the given matrix. First, make sure to install the required packages as follows:
pip install qiskitalgorithms
pip install qiskitaer
pip install pylatexenc
On top of this, let's start by calling the necessary libraries.
from qiskit import Aer
from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import COBYLA
from qiskit.circuit.library import RealAmplitudes
from qiskit.opflow import MatrixOp
import numpy as np
Here, VQE serves as the solver for solving the eigenvalue problem. COBYLA is the chosen optimizer, but we won't delve deeper into it in this article. MatrixOp is a module that complexifies the given matrix and generates the Hamiltonian.
# definet the matrix
matrix = np.array([[2, 1],
[1, 5]]
)
# create MatrixOp object
hamiltonian = MatrixOp(matrix)
print(hamiltonian)
Then, you get following.
Operator([[ 2.+0.j, 1.+0.j],
[1.+0.j, 5.+0.j]],
input_dims=(2,), output_dims=(2,))
You can confirm that the real matrix has been complexified. However, since the complex components are zero, there is practically no change. The goal is to solve the eigenvalue problem of the original matrix by solving the eigenvalue problem of this Hamiltonian with VQE.
The following code constructs a quantum circuit for VQE. One advantage of the VQE module is that you don't have to design the quantum circuit details yourself, but a drawback is that you may not understand what it is doing. It is important to study the surrounding areas well, especially when trying to understand its meaning or troubleshooting if convergence is not achieved.
# Constructing a quantum circuit for VQE
num_qubits = len(matrix)
ansatz = RealAmplitudes(num_qubits, reps=1)
optimizer = COBYLA(rhobeg=0.5, tol=0.0001)
from qiskit.utils import QuantumInstance
seed = 170
backend = Aer.get_backend('qasm_simulator')
qi = QuantumInstance(backend=backend, seed_simulator=seed, seed_transpiler=seed)
vqe_algorithm = VQE(ansatz=ansatz, optimizer=optimizer, quantum_instance=qi)
Here, the optimization logic uses COBYLA (Constrained Optimization BY Linear Approximations). COBYLA is a numerical optimization algorithm for solving constrained optimization problems. It approximates the constraints and, at each iteration, minimizes the objective function under linear constraints. The choice of optimizer significantly affects the convergence to the solution, so it is advisable to try several methods.
Additionally, the backend simulator used is 'qasm_simulator.' This simulator provides classical simulation and simulates the ideal behavior of a quantum circuit without considering quantum gate errors and noise. This simulator is used for fundamental understanding of quantum algorithms and initial verification. Therefore, it is important to note that actual quantum devices may not produce such ideal results.
The following code solves the eigenvalue problem and displays the results. In this case, 500 convergence experiments were performed, and the resulting eigenvalue was stored in EVa.
# Solving the eigenvalue problem
EVa = []
for i in range(500):
result = vqe_algorithm.compute_minimum_eigenvalue(hamiltonian)
eigenvalue = result.eigenvalue.real
eigenvector = result.eigenstate
EVa.append(eigenvalue)
# show the results
print("Matrix:")
print(matrix)
print("\nEigenvalue:")
print(eigenvalue)
print("\nEigenvector:")
print(eigenvector)
The following is the result. However, it represents the outcome of the 500th trial.
Matrix:
[[ 2 1]
[1 5]]
Eigenvalue:
5.140046712248724
Eigenvector:
{'0': 0.13975424859373686, '1': 0.9901862198596787}
The ideal minimum eigenvalue is 5.14005494, and the computed result from the quantum circuit is 5.14004671. This indicates that the result was obtained with a considerably high level of accuracy.
Next, let's visualize the obtained results.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.hist(EVa, bins=50, histtype='barstacked', ec='black')
plt.xlabel("eigenvalue")
plt.ylabel("number")
plt.show()
print("Max:", np.array(EVa).max())
print("Min:", np.array(EVa).min())
The visualization of the results obtained from the above code is as follows. Although most of the trial results are concentrated around 5.14, occasional outliers are observed. Overall, it can be confirmed that the convergence is achieved with good accuracy.
Advanced Issues
About Advanced Issues
The above results are displaying very good and understandable outcomes. However, depending on various conditions, convergence may not be easily achieved. Therefore, using the above code without careful consideration might not yield the expected results. In such cases, it is necessary to approach the problem thoughtfully or seek assistance from experts, as tackling advanced issues can be challenging.
Appendix
The following code summarizes the results obtained so far.
from qiskit import Aer
from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import COBYLA
from qiskit.circuit.library import RealAmplitudes
from qiskit.opflow import MatrixOp
import numpy as np
# difine the matrix
matrix = np.array([[2, 1],
[1, 5]]
)
# create MatrixOp object
hamiltonian = MatrixOp(matrix)
# construct quantum circuit for VQE
num_qubits = len(matrix)
ansatz = RealAmplitudes(num_qubits, reps=1)
optimizer = COBYLA(rhobeg=0.5, tol=0.0001)
from qiskit.utils import QuantumInstance
seed = 170
backend = Aer.get_backend('qasm_simulator')
qi = QuantumInstance(backend=backend, seed_simulator=seed, seed_transpiler=seed)
vqe_algorithm = VQE(ansatz=ansatz, optimizer=optimizer, quantum_instance=qi)
# solve eigenvalue problem
EVa = []
for i in range(500):
result = vqe_algorithm.compute_minimum_eigenvalue(hamiltonian)
eigenvalue = result.eigenvalue.real
eigenvector = result.eigenstate
EVa.append(eigenvalue)
# show the results
print("Matrix:")
print(matrix)
print("\nEigenvalue:")
print(eigenvalue)
print("\nEigenvector:")
print(eigenvector)