diff --git a/doc/source/code-examples/applications-by-algorithm.rst b/doc/source/code-examples/applications-by-algorithm.rst index 4dfb64a6a2..1f69431d96 100644 --- a/doc/source/code-examples/applications-by-algorithm.rst +++ b/doc/source/code-examples/applications-by-algorithm.rst @@ -80,7 +80,6 @@ Diagonalization Algorithms tutorials/dbi/dbi_cost_functions.ipynb tutorials/dbi/dbi_gradient_descent_strategies.ipynb - tutorials/dbi/dbi_group_commutator_tests.ipynb tutorials/dbi/dbi_scheduling.ipynb tutorials/dbi/dbi_strategies_compare.ipynb tutorials/dbi/dbi_strategy_Ising_model.ipynb diff --git a/examples/dbi/dbi_group_commutator_tests.ipynb b/examples/dbi/dbi_group_commutator_tests.ipynb deleted file mode 100644 index 3d1d615626..0000000000 --- a/examples/dbi/dbi_group_commutator_tests.ipynb +++ /dev/null @@ -1,122 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from copy import deepcopy\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from qibo import hamiltonians, set_backend\n", - "from qibo.models.dbi.double_bracket import DoubleBracketGeneratorType, DoubleBracketScheduling, DoubleBracketIteration, DoubleBracketCostFunction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Hamiltonian\n", - "set_backend(\"numpy\")\n", - "\n", - "# hamiltonian parameters\n", - "nqubits = 5\n", - "h = 3.0\n", - "\n", - "# define the hamiltonian\n", - "H_TFIM = hamiltonians.TFIM(nqubits=nqubits, h=h)\n", - "\n", - "# define the least-squares cost function\n", - "cost = DoubleBracketCostFunction.least_squares\n", - "# initialize class\n", - "dbi = DoubleBracketIteration(deepcopy(H_TFIM),mode=DoubleBracketGeneratorType.group_commutator,cost=cost)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d = np.diag(np.linspace(1,2**nqubits,2**nqubits))\n", - "s_space = np.linspace(1e-5, 0.3, 500)\n", - "r = np.array([1,2,4,8])\n", - "off_diagonal_norm_diff = np.empty((500,len(r)+1))\n", - "\n", - "for s in range(len(s_space)):\n", - " for i in range(len(r)):\n", - " dbi_eval = deepcopy(dbi)\n", - " dbi_eval.mode = DoubleBracketGeneratorType.group_commutator\n", - " for j in range(r[i]):\n", - " dbi_eval(np.sqrt(s_space[s]/r[i]),d=d)\n", - " off_diagonal_norm_diff[s,i+1] = dbi_eval.off_diagonal_norm\n", - " dbi_eval = deepcopy(dbi)\n", - " dbi_eval.mode = DoubleBracketGeneratorType.single_commutator\n", - " dbi_eval(s_space[s],d=d)\n", - " off_diagonal_norm_diff[s,0] = dbi_eval.off_diagonal_norm\n", - "\n", - "\n", - "\n", - "plt.figure()\n", - "plt.plot(s_space, off_diagonal_norm_diff[:,0],label=r'$e^{sW}$')\n", - "for i in range(len(r)):\n", - " plt.plot(s_space, off_diagonal_norm_diff[:,i+1],label=r'$V_{GC}, r = $' + str(r[i]))\n", - "plt.xlabel('s')\n", - "plt.ylabel('off-diagonal norm')\n", - "plt.legend()\n", - "\n", - "plt.figure()\n", - "for i in range(len(r)):\n", - " plt.plot(s_space, off_diagonal_norm_diff[:,i+1]-off_diagonal_norm_diff[:,0],label=r'$V_{GC}, r = $' + str(r[i]))\n", - "plt.xlabel('s')\n", - "plt.ylabel('Difference of the off diagonal norm between $V_{GC}$ and $e^{sW}$')\n", - "plt.legend()\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "d = np.diag(np.linspace(1,2**nqubits,2**nqubits))\n", - "flows = 30\n", - "r = np.array([1,2,4,8])\n", - "off_diagonal_norm_diff = np.empty((1+flows,len(r)+1))\n", - "s = np.empty(flows)\n", - "dbi_eval = deepcopy(dbi)\n", - "off_diagonal_norm_diff[0,:] = dbi_eval.off_diagonal_norm\n", - "for i in range(flows):\n", - " dbi_eval.mode = DoubleBracketGeneratorType.single_commutator\n", - " s[i] = dbi_eval.choose_step(scheduling=DoubleBracketScheduling.polynomial_approximation,d=d, n=3)\n", - " dbi_eval(s[i],d=d)\n", - " off_diagonal_norm_diff[i+1,0] = dbi_eval.off_diagonal_norm\n", - "\n", - "for j in range(len(r)):\n", - " dbi_eval = deepcopy(dbi)\n", - " dbi_eval.mode = DoubleBracketGeneratorType.group_commutator\n", - " for i in range(flows):\n", - " for k in range(r[j]):\n", - " dbi_eval(np.sqrt(s[i]/r[j]),d=d)\n", - " off_diagonal_norm_diff[i+1,j+1] = dbi_eval.off_diagonal_norm\n", - "\n", - "plt.figure()\n", - "plt.plot(off_diagonal_norm_diff[:,0],label=r'$e^{sW}$')\n", - "for i in range(len(r)):\n", - " plt.plot(off_diagonal_norm_diff[:,i+1],label=r'$V_{GC}, r = $' + str(r[i]))\n", - "plt.xlabel('flow iterarion')\n", - "plt.ylabel('off-diagonal norm')\n", - "plt.legend()" - ] - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/src/qibo/models/dbi/double_bracket.py b/src/qibo/models/dbi/double_bracket.py index f68526226e..4e1150df6f 100644 --- a/src/qibo/models/dbi/double_bracket.py +++ b/src/qibo/models/dbi/double_bracket.py @@ -23,7 +23,12 @@ class DoubleBracketGeneratorType(Enum): """Use single commutator.""" group_commutator = auto() """Use group commutator approximation""" - # TODO: add double commutator (does it converge?) + group_commutator_third_order = auto() + """Implements: $e^{\frac{\\sqrt{5}-1}{2}isH}e^{\frac{\\sqrt{5}-1}{2}isD}e^{-isH}e^{isD}e^{\frac{3-\\sqrt{5}}{2}isH}e^{isD} + \approx e^{-s^2[H,D]} + O(s^4)$ + which is equation (8) in https://arxiv.org/abs/2111.12177] + s must be taken as $\\sqrt{s}$ to approximate the flow using the commutator + """ class DoubleBracketCostFunction(str, Enum): @@ -125,6 +130,17 @@ def __call__( @ self.h.exp(step) @ self.backend.calculate_matrix_exp(step, d) ) + elif mode is DoubleBracketGeneratorType.group_commutator_third_order: + if d is None: + d = self.diagonal_h_matrix + operator = ( + self.h.exp(-step * (np.sqrt(5) - 1) / 2) + @ self.backend.calculate_matrix_exp(-step * (np.sqrt(5) - 1) / 2, d) + @ self.h.exp(step) + @ self.backend.calculate_matrix_exp(step * (np.sqrt(5) + 1) / 2, d) + @ self.h.exp(-step * (3 - np.sqrt(5)) / 2) + @ self.backend.calculate_matrix_exp(-step, d) + ) operator_dagger = self.backend.cast( np.array(np.matrix(self.backend.to_numpy(operator)).getH()) ) diff --git a/tests/test_models_dbi.py b/tests/test_models_dbi.py index c20465e5a9..3ce40e6559 100644 --- a/tests/test_models_dbi.py +++ b/tests/test_models_dbi.py @@ -58,6 +58,25 @@ def test_double_bracket_iteration_group_commutator(backend, nqubits): assert initial_off_diagonal_norm > dbi.off_diagonal_norm +@pytest.mark.parametrize("nqubits", [1, 2]) +def test_double_bracket_iteration_group_commutator_3rd_order(backend, nqubits): + """Check 3rd order group commutator mode.""" + h0 = random_hermitian(2**nqubits, backend=backend, seed=seed) + d = backend.cast(np.diag(np.diag(backend.to_numpy(h0)))) + dbi = DoubleBracketIteration( + Hamiltonian(nqubits, h0, backend=backend), + mode=DoubleBracketGeneratorType.group_commutator_third_order, + ) + initial_off_diagonal_norm = dbi.off_diagonal_norm + + # test first iteration with default d + dbi(mode=DoubleBracketGeneratorType.group_commutator_third_order, step=0.01) + for _ in range(NSTEPS): + dbi(step=0.01, d=d) + + assert initial_off_diagonal_norm > dbi.off_diagonal_norm + + @pytest.mark.parametrize("nqubits", [1, 2]) def test_double_bracket_iteration_single_commutator(backend, nqubits): """Check single commutator mode."""