Source code for qiskit.finance.applications.ising.portfolio_diversification

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019, 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.

""" portfolio diversification """

import numpy as np
from qiskit.quantum_info import Pauli

from qiskit.aqua.operators import WeightedPauliOperator, StateFn


[docs]def get_operator(rho, n, q): """Converts an instance of portfolio optimization into a list of Paulis. Args: rho (numpy.ndarray) : an asset-to-asset similarity matrix, such as the covariance matrix. n (integer) : the number of assets. q (integer) : the number of clusters of assets to output. Returns: WeightedPauliOperator: operator for the Hamiltonian """ # pylint: disable=invalid-name # N = (n + 1) * n # number of qubits N = n**2 + n A = np.max(np.abs(rho)) * 1000 # A parameter of cost function # Determine the weights w instance_vec = rho.reshape(n ** 2) # quadratic term Q q0 = np.zeros([N, 1]) Q1 = np.zeros([N, N]) Q2 = np.zeros([N, N]) Q3 = np.zeros([N, N]) for x in range(n ** 2, n ** 2 + n): q0[x] = 1 Q0 = A * np.dot(q0, q0.T) for ii in range(0, n): v0 = np.zeros([N, 1]) for jj in range(n * ii, n * (ii + 1)): v0[jj] = 1 Q1 = Q1 + np.dot(v0, v0.T) Q1 = A * Q1 for jj in range(0, n): v0 = np.zeros([N, 1]) v0[n * jj + jj] = 1 v0[n ** 2 + jj] = -1 Q2 = Q2 + np.dot(v0, v0.T) Q2 = A * Q2 for ii in range(0, n): for jj in range(0, n): Q3[ii * n + jj, n ** 2 + jj] = -0.5 Q3[n ** 2 + jj, ii * n + jj] = -0.5 Q3 = A * Q3 Q = Q0 + Q1 + Q2 + Q3 # linear term c: c0 = np.zeros(N) c1 = np.zeros(N) c2 = np.zeros(N) c3 = np.zeros(N) for x in range(n ** 2): c0[x] = instance_vec[x] for x in range(n ** 2, n ** 2 + n): c1[x] = -2 * A * q for x in range(n ** 2): c2[x] = -2 * A for x in range(n ** 2): c3[x] = A g = c0 + c1 + c2 + c3 # constant term r c = A * (q ** 2 + n) # Defining the new matrices in the Z-basis Iv = np.ones(N) Qz = (Q / 4) gz = (-g / 2 - np.dot(Iv, Q / 4) - np.dot(Q / 4, Iv)) cz = (c + np.dot(g / 2, Iv) + np.dot(Iv, np.dot(Q / 4, Iv))) cz = cz + np.trace(Qz) Qz = Qz - np.diag(np.diag(Qz)) # Getting the Hamiltonian in the form of a list of Pauli terms pauli_list = [] for i in range(N): if gz[i] != 0: wp = np.zeros(N) vp = np.zeros(N) vp[i] = 1 pauli_list.append((gz[i], Pauli(vp, wp))) for i in range(N): for j in range(i): if Qz[i, j] != 0: wp = np.zeros(N) vp = np.zeros(N) vp[i] = 1 vp[j] = 1 pauli_list.append((2 * Qz[i, j], Pauli(vp, wp))) pauli_list.append((cz, Pauli(np.zeros(N), np.zeros(N)))) return WeightedPauliOperator(paulis=pauli_list)
[docs]def get_portfoliodiversification_solution(rho, n, q, result): # pylint: disable=invalid-name """ Tries to obtain a feasible solution (in vector form) of an instance of portfolio diversification from the results dictionary. Args: rho (numpy.ndarray) : an asset-to-asset similarity matrix, such as the covariance matrix. n (integer) : the number of assets. q (integer) : the number of clusters of assets to output. result (dictionary) : a dictionary obtained by QAOA.run or VQE.run containing key 'eigvecs'. Returns: numpy.ndarray: a vector describing the solution. """ # pylint: disable=invalid-name del rho, q # unused v = result['eigvecs'][0] if isinstance(v, StateFn): v = v.to_matrix() # N = (n + 1) * n # number of qubits N = n ** 2 + n index_value = [x for x in range(len(v)) if v[x] == max(v)][0] string_value = "{0:b}".format(index_value) while len(string_value) < N: string_value = '0' + string_value x_state = list() for elements in string_value: if elements == '0': x_state.append(0) else: x_state.append(1) x_state = np.flip(x_state, axis=0) return x_state
[docs]def get_portfoliodiversification_value(rho, n, q, x_state): # pylint: disable=invalid-name """ Evaluates an objective function of an instance of portfolio diversification and its solution (in vector form). Args: rho (numpy.ndarray) : an asset-to-asset similarity matrix, such as the covariance matrix. n (integer) : the number of assets. q (integer) : the number of clusters of assets to output. x_state (numpy.ndarray) : a vector describing the solution. Returns: float: cost of the solution. """ # pylint: disable=invalid-name # N = (n + 1) * n # number of qubits N = n ** 2 + n A = np.max(np.abs(rho)) * 1000 # A parameter of cost function # Determine the weights w instance_vec = rho.reshape(n ** 2) # quadratic term Q q0 = np.zeros([N, 1]) Q1 = np.zeros([N, N]) Q2 = np.zeros([N, N]) Q3 = np.zeros([N, N]) for x in range(n ** 2, n ** 2 + n): q0[x] = 1 Q0 = A * np.dot(q0, q0.T) for ii in range(0, n): v0 = np.zeros([N, 1]) for jj in range(n * ii, n * (ii + 1)): v0[jj] = 1 Q1 = Q1 + np.dot(v0, v0.T) Q1 = A * Q1 for jj in range(0, n): v0 = np.zeros([N, 1]) v0[n * jj + jj] = 1 v0[n ** 2 + jj] = -1 Q2 = Q2 + np.dot(v0, v0.T) Q2 = A * Q2 for ii in range(0, n): for jj in range(0, n): Q3[ii * n + jj, n ** 2 + jj] = -0.5 Q3[n ** 2 + jj, ii * n + jj] = -0.5 Q3 = A * Q3 Q = Q0 + Q1 + Q2 + Q3 # linear term c: c0 = np.zeros(N) c1 = np.zeros(N) c2 = np.zeros(N) c3 = np.zeros(N) for x in range(n ** 2): c0[x] = instance_vec[x] for x in range(n ** 2, n ** 2 + n): c1[x] = -2 * A * q for x in range(n ** 2): c2[x] = -2 * A for x in range(n ** 2): c3[x] = A g = c0 + c1 + c2 + c3 # constant term r c = A * (q ** 2 + n) # Evaluates the cost distance from a binary representation def fun(x): return np.dot(np.around(x), np.dot(Q, np.around(x))) + np.dot(g, np.around(x)) + c return fun(x_state)