|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "f6cb1fe6-ae30-4ceb-a7bf-605fad9540cf", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "<h1>Heisenberg antiferromagnet on the square lattice</h1>" |
| 9 | + ] |
| 10 | + }, |
| 11 | + { |
| 12 | + "cell_type": "markdown", |
| 13 | + "id": "030ee89c-ec88-4c0e-bb8b-09e30c8f2e18", |
| 14 | + "metadata": {}, |
| 15 | + "source": [ |
| 16 | + "<figure style=\"text-align:center\">\n", |
| 17 | + " <img src=\"https://varipeps.readthedocs.io/en/latest/_images/square_lattice.svg\"\n", |
| 18 | + " alt=\"Two dimensional square lattice with red links indicating horizontal and blue links indicating vertical interactions.\">\n", |
| 19 | + " <figcaption><em>Two dimensional square lattice</em></figcaption>\n", |
| 20 | + "</figure>" |
| 21 | + ] |
| 22 | + }, |
| 23 | + { |
| 24 | + "cell_type": "markdown", |
| 25 | + "id": "8e1498f8-fdc1-4545-a89a-6d602d6ae2ea", |
| 26 | + "metadata": {}, |
| 27 | + "source": [ |
| 28 | + "The Hamiltonian for the Heisenberg antiferromagnet with constant exchange interaction strength $J > 0$ is defined as:\n", |
| 29 | + "\n", |
| 30 | + "$$ H = J \\sum_{\\langle ij \\rangle} \\vec{S}_{i} \\vec{S}_{j} $$\n", |
| 31 | + "\n", |
| 32 | + "where $\\langle ij \\rangle$ denotes the sum over all nearest neighbors in the lattice.\n", |
| 33 | + "\n", |
| 34 | + "Our aim is now to find the ground state of the model using the variational iPEPS code of the variPEPS library." |
| 35 | + ] |
| 36 | + }, |
| 37 | + { |
| 38 | + "cell_type": "markdown", |
| 39 | + "id": "2c26bb16-3a92-414f-8a90-79f26d0cc010", |
| 40 | + "metadata": {}, |
| 41 | + "source": [ |
| 42 | + "<h2>Loading of relevant Python modules</h2>" |
| 43 | + ] |
| 44 | + }, |
| 45 | + { |
| 46 | + "cell_type": "code", |
| 47 | + "execution_count": 1, |
| 48 | + "id": "eed1c1da-97a2-4d46-a8d8-9c8e3d82ff20", |
| 49 | + "metadata": {}, |
| 50 | + "outputs": [], |
| 51 | + "source": [ |
| 52 | + "import varipeps\n", |
| 53 | + "import jax\n", |
| 54 | + "import jax.numpy as jnp" |
| 55 | + ] |
| 56 | + }, |
| 57 | + { |
| 58 | + "cell_type": "markdown", |
| 59 | + "id": "47850928-d204-4e6e-8c01-418c8277ce4c", |
| 60 | + "metadata": {}, |
| 61 | + "source": [ |
| 62 | + "First of all we have to load the relevant Python modules for our simulation. The [`varipeps`](https://varipeps.readthedocs.io/en/latest/api/index.html) module includes the full library to perform the variational optimization. Internally it is based on the [`jax`](https://docs.jax.dev/en/latest/) framework and its [`numpy`](https://numpy.org/doc/stable/reference/index.html)-like interface to execute the calculations. Since we will need arrays to define for example the Hamiltonian, we load this numpy interface as well." |
| 63 | + ] |
| 64 | + }, |
| 65 | + { |
| 66 | + "cell_type": "markdown", |
| 67 | + "id": "fc0c3c0b-f4f0-408b-9b62-105a8744451d", |
| 68 | + "metadata": {}, |
| 69 | + "source": [ |
| 70 | + "<h2>variPEPS config settings</h2>" |
| 71 | + ] |
| 72 | + }, |
| 73 | + { |
| 74 | + "cell_type": "code", |
| 75 | + "execution_count": 2, |
| 76 | + "id": "83ba46bc-51e9-41a2-a0b2-f0270960211d", |
| 77 | + "metadata": {}, |
| 78 | + "outputs": [], |
| 79 | + "source": [ |
| 80 | + "# Config Setting\n", |
| 81 | + "\n", |
| 82 | + "## Set maximal steps for the CTMRG routine\n", |
| 83 | + "varipeps.config.ctmrg_max_steps = 100\n", |
| 84 | + "## Set convergence threshold for the CTMRG routine\n", |
| 85 | + "varipeps.config.ctmrg_convergence_eps = 1e-7\n", |
| 86 | + "## Select the method used to calculate the (full) projectors in the CTMRG routine\n", |
| 87 | + "varipeps.config.ctmrg_full_projector_method = (\n", |
| 88 | + " varipeps.config.Projector_Method.FISHMAN\n", |
| 89 | + ")\n", |
| 90 | + "## Enable dynamic increase of CTMRG environment bond dimension\n", |
| 91 | + "varipeps.config.ctmrg_heuristic_increase_chi = True\n", |
| 92 | + "## Increase CTMRG enviroment bond dimension if truncation error exceeds this value\n", |
| 93 | + "varipeps.config.ctmrg_heuristic_increase_chi_threshold = 1e-4\n", |
| 94 | + "\n", |
| 95 | + "## Set maximal steps for the fix point routine in the gradient calculation\n", |
| 96 | + "varipeps.config.ad_custom_max_steps = 100\n", |
| 97 | + "## Set convergence threshold for the fix point routine in the gradient calculation\n", |
| 98 | + "varipeps.config.ad_custom_convergence_eps = 5e-8\n", |
| 99 | + "\n", |
| 100 | + "## Enable/Disable printing of the convergence of the single CTMRG/gradient fix point steps.\n", |
| 101 | + "## Useful to enable this during debugging, should be disabled for batch runs\n", |
| 102 | + "varipeps.config.ctmrg_print_steps = False\n", |
| 103 | + "varipeps.config.ad_custom_print_steps = False\n", |
| 104 | + "\n", |
| 105 | + "## Select the method used to calculate the descent direction during optimization\n", |
| 106 | + "varipeps.config.optimizer_method = varipeps.config.Optimizing_Methods.CG\n", |
| 107 | + "## Set maximal number of steps for the optimization routine\n", |
| 108 | + "varipeps.config.optimizer_max_steps = 2000" |
| 109 | + ] |
| 110 | + }, |
| 111 | + { |
| 112 | + "cell_type": "markdown", |
| 113 | + "id": "148b69f0-6b36-4528-889d-affce1ea0cf9", |
| 114 | + "metadata": {}, |
| 115 | + "source": [ |
| 116 | + "The [`varipeps`](https://varipeps.readthedocs.io/en/latest/api/index.html) library allows to configure a large number of numerical parameters to fine-tune the simulation. In this example we include several options commonly used in an optimization run. For a detailed description of the configurable options we refer to the API description of the config class: [`varipeps.config.VariPEPS_Config`](https://varipeps.readthedocs.io/en/latest/api/config.html#varipeps.config.VariPEPS_Config)." |
| 117 | + ] |
| 118 | + }, |
| 119 | + { |
| 120 | + "cell_type": "markdown", |
| 121 | + "id": "8ca36e8f-92e8-4bc2-8248-fd42e72fef91", |
| 122 | + "metadata": {}, |
| 123 | + "source": [ |
| 124 | + "<h2>Model parameters</h2>" |
| 125 | + ] |
| 126 | + }, |
| 127 | + { |
| 128 | + "cell_type": "code", |
| 129 | + "execution_count": 3, |
| 130 | + "id": "042b7ebd-63df-42e1-a507-e30e59f85996", |
| 131 | + "metadata": {}, |
| 132 | + "outputs": [], |
| 133 | + "source": [ |
| 134 | + "# Set constants for the simulation\n", |
| 135 | + "modelName = \"HeisenbergModel\"\n", |
| 136 | + "# Interaction strength\n", |
| 137 | + "J = 1\n", |
| 138 | + "# iPEPS bond dimension\n", |
| 139 | + "chiB = 2\n", |
| 140 | + "# Physical dimension\n", |
| 141 | + "p = 2\n", |
| 142 | + "# Maximal enviroment bond dimension\n", |
| 143 | + "maxChi = 36\n", |
| 144 | + "# Start value for enviroment bond dimension\n", |
| 145 | + "startChi = chiB**2 if chiB**2 < maxChi else maxChi" |
| 146 | + ] |
| 147 | + }, |
| 148 | + { |
| 149 | + "cell_type": "markdown", |
| 150 | + "id": "9f5c5931-2407-4d84-9df0-3afba2ad6120", |
| 151 | + "metadata": {}, |
| 152 | + "source": [ |
| 153 | + "In this block we define imporant parameters for the model we want to simulate, such as as the interaction strength, the physical dimension of our tensor network and the iPEPS bond dimension. In the last two lines the initial and the maximal enviroment bond dimension is defined. A feature of the variPEPS library is that it not only supports simulation at a fixed enviroment bond dimension, but also a heurisitic increase/decrease of the dimension up to a maximal value. The dynamic change is controlled by the truncation error in the CTMRG projector calculation (increase if the truncation errror becomes too large, decrease if it becomes insignificant). For example, in the config block above the parameter ``ctmrg_heuristic_increase_chi_threshold`` is set to the threshold at which to increase the refinement parameter. The maximal bond dimension ``maxChi`` ensures that the parameter does now grow unbounded, to the point where the memory and computational resources are exhausted." |
| 154 | + ] |
| 155 | + }, |
| 156 | + { |
| 157 | + "cell_type": "markdown", |
| 158 | + "id": "089d5b07-76bf-4062-a3e4-e5886b7e668d", |
| 159 | + "metadata": {}, |
| 160 | + "source": [ |
| 161 | + "<h2>Constructing the Hamiltonian</h2>" |
| 162 | + ] |
| 163 | + }, |
| 164 | + { |
| 165 | + "cell_type": "code", |
| 166 | + "execution_count": 4, |
| 167 | + "id": "2796f1f6-170b-4a43-a220-37a3f411b40a", |
| 168 | + "metadata": {}, |
| 169 | + "outputs": [], |
| 170 | + "source": [ |
| 171 | + "# define spin-1/2 matrices\n", |
| 172 | + "Id = jnp.eye(2)\n", |
| 173 | + "Sx = jnp.array([[0, 1], [1, 0]]) / 2\n", |
| 174 | + "Sy = jnp.array([[0, -1j], [1j, 0]]) / 2\n", |
| 175 | + "Sz = jnp.array([[1, 0], [0, -1]]) / 2\n", |
| 176 | + "\n", |
| 177 | + "# construct Hamiltonian terms\n", |
| 178 | + "hamiltonianGates = J * (jnp.kron(Sx, Sx) + jnp.kron(Sy, Sy) + jnp.kron(Sz, Sz))\n", |
| 179 | + "\n", |
| 180 | + "# create function to compute expectation values for the square Heisenberg AFM\n", |
| 181 | + "exp_func = varipeps.expectation.Two_Sites_Expectation_Value(\n", |
| 182 | + " horizontal_gates=(hamiltonianGates,),\n", |
| 183 | + " vertical_gates=(hamiltonianGates,),\n", |
| 184 | + ")" |
| 185 | + ] |
| 186 | + }, |
| 187 | + { |
| 188 | + "cell_type": "markdown", |
| 189 | + "id": "60042a7e-1217-46d0-a78f-3a6c83cf2134", |
| 190 | + "metadata": {}, |
| 191 | + "source": [ |
| 192 | + "Here the Hamiltonian is constructed for our model. The Heisenberg AFM on the square lattice can be described by the sum of the spin-spin interactions on the horizontal and vertical bonds. Since we assume a constant interaction strength for all bonds in our example, the expectation value can be calculated by the same two-site interaction gate applied in all nearest neighbor directions. The expectation function ``exp_func`` is later used in the optimization to calculate the energy expectation value, which in turn is used as cost function to obtain the ground state." |
| 193 | + ] |
| 194 | + }, |
| 195 | + { |
| 196 | + "cell_type": "markdown", |
| 197 | + "id": "d0654d74-97f1-475b-8f55-50b6fbfff94c", |
| 198 | + "metadata": {}, |
| 199 | + "source": [ |
| 200 | + "<h2>Initial unit cell construction</h2>" |
| 201 | + ] |
| 202 | + }, |
| 203 | + { |
| 204 | + "cell_type": "code", |
| 205 | + "execution_count": 5, |
| 206 | + "id": "483a00e1-062c-4ea6-8f14-fc345aaa2014", |
| 207 | + "metadata": {}, |
| 208 | + "outputs": [], |
| 209 | + "source": [ |
| 210 | + "# Unit cell structure\n", |
| 211 | + "structure = [[0, 1], [1, 0]]" |
| 212 | + ] |
| 213 | + }, |
| 214 | + { |
| 215 | + "cell_type": "markdown", |
| 216 | + "id": "9aace0ba-1085-468c-8888-02d4237d771f", |
| 217 | + "metadata": {}, |
| 218 | + "source": [ |
| 219 | + "Here we define the unit cell structure which is used to simulate our model. In this example we assume a $\\scriptsize{\\begin{matrix}A&B\\\\B&A\\end{matrix}}$-structure, i.e. a two-site antiferromagnetic state." |
| 220 | + ] |
| 221 | + }, |
| 222 | + { |
| 223 | + "cell_type": "code", |
| 224 | + "execution_count": 6, |
| 225 | + "id": "04f0cf82-ed0a-45eb-bad1-4044626e13d5", |
| 226 | + "metadata": {}, |
| 227 | + "outputs": [], |
| 228 | + "source": [ |
| 229 | + "# Create random initialization for the iPEPS unit cell\n", |
| 230 | + "unitcell = varipeps.peps.PEPS_Unit_Cell.random(\n", |
| 231 | + " structure, # Unit cell structure\n", |
| 232 | + " p, # Physical dimension\n", |
| 233 | + " chiB, # iPEPS bond dimension\n", |
| 234 | + " startChi, # Start value for enviroment bond dimension\n", |
| 235 | + " float, # Data type for the tensors: `float` (real) or `complex` tensors\n", |
| 236 | + " max_chi=maxChi, # Maximal enviroment bond dimension\n", |
| 237 | + ")" |
| 238 | + ] |
| 239 | + }, |
| 240 | + { |
| 241 | + "cell_type": "markdown", |
| 242 | + "id": "24fdebb9-62ff-4750-8663-1b4ac44f2ec5", |
| 243 | + "metadata": {}, |
| 244 | + "source": [ |
| 245 | + "Using the unit cell structure and the model parameter defined above, we can generate an initial unit cell. Here we initialize the iPEPS tensors with random numbers. Other ways to initialize the tensors are provided, for example loading results from a simple update calculation." |
| 246 | + ] |
| 247 | + }, |
| 248 | + { |
| 249 | + "cell_type": "markdown", |
| 250 | + "id": "7e0ee381-0a00-49a6-9735-c8ae02cf1a87", |
| 251 | + "metadata": {}, |
| 252 | + "source": [ |
| 253 | + "<h2>Run the optimization</h2>" |
| 254 | + ] |
| 255 | + }, |
| 256 | + { |
| 257 | + "cell_type": "code", |
| 258 | + "execution_count": null, |
| 259 | + "id": "f3e40cd4-6584-4f0b-aaf7-5268164cb041", |
| 260 | + "metadata": {}, |
| 261 | + "outputs": [], |
| 262 | + "source": [ |
| 263 | + "# Run optimization\n", |
| 264 | + "result = varipeps.optimization.optimize_peps_network(\n", |
| 265 | + " unitcell,\n", |
| 266 | + " exp_func,\n", |
| 267 | + " autosave_filename=f\"data/autosave_square_chiB_{chiB:d}.hdf5\",\n", |
| 268 | + ")" |
| 269 | + ] |
| 270 | + }, |
| 271 | + { |
| 272 | + "cell_type": "markdown", |
| 273 | + "id": "c66e58f4-8710-447c-956b-dc014c4638cf", |
| 274 | + "metadata": {}, |
| 275 | + "source": [ |
| 276 | + "This function call executes the main function of the library, the variational energy optimization to obtain a good ground state candidate. The function offers several options to customize the optimization for different iPEPS ansätze, such as the spiral iPEPS approach. In our example, we only need to provide the initial unit cell, the function for calculating the energy expectation value, and a file path for autosaving the optimization process, enabling the restoration of interrupted simulations." |
| 277 | + ] |
| 278 | + }, |
| 279 | + { |
| 280 | + "cell_type": "markdown", |
| 281 | + "id": "441ca3ab-fcaf-412b-8fff-2d1a9a8736ab", |
| 282 | + "metadata": {}, |
| 283 | + "source": [ |
| 284 | + "<h2>Evaluate the results</h2>" |
| 285 | + ] |
| 286 | + }, |
| 287 | + { |
| 288 | + "cell_type": "markdown", |
| 289 | + "id": "69ec6e81-8cf0-4abb-af9b-79789bc53a1e", |
| 290 | + "metadata": {}, |
| 291 | + "source": [ |
| 292 | + "In this section we show some exemplary evaluation of the result of the optimization." |
| 293 | + ] |
| 294 | + }, |
| 295 | + { |
| 296 | + "cell_type": "code", |
| 297 | + "execution_count": null, |
| 298 | + "id": "dc2a1460-976c-4a4c-a099-07d46f5ae361", |
| 299 | + "metadata": {}, |
| 300 | + "outputs": [], |
| 301 | + "source": [ |
| 302 | + "# Calculate magnetic expectation values\n", |
| 303 | + "Mag_Gates = [Sx, Sy, Sz]\n", |
| 304 | + "\n", |
| 305 | + "\n", |
| 306 | + "def calc_magnetic(unitcell):\n", |
| 307 | + " mag_result = []\n", |
| 308 | + " for ti, t in enumerate(unitcell.get_unique_tensors()):\n", |
| 309 | + " r = varipeps.expectation.one_site.calc_one_site_multi_gates(\n", |
| 310 | + " t.tensor, t, Mag_Gates\n", |
| 311 | + " )\n", |
| 312 | + " mag_result += r\n", |
| 313 | + " return mag_result\n", |
| 314 | + "\n", |
| 315 | + "\n", |
| 316 | + "magnetic_exp_values = calc_magnetic(result.unitcell)" |
| 317 | + ] |
| 318 | + }, |
| 319 | + { |
| 320 | + "cell_type": "markdown", |
| 321 | + "id": "c0b049d1-4507-442e-95f8-dda31ea0e66d", |
| 322 | + "metadata": {}, |
| 323 | + "source": [ |
| 324 | + "We assume for our example that we are interested in the single-site spin expectation values. These could be used to analyse the $z$-magnetization or the staggered magnetization of our model at/near the ground state." |
| 325 | + ] |
| 326 | + }, |
| 327 | + { |
| 328 | + "cell_type": "code", |
| 329 | + "execution_count": null, |
| 330 | + "id": "52e354b8-06f9-4685-aee4-c908b50886e8", |
| 331 | + "metadata": {}, |
| 332 | + "outputs": [], |
| 333 | + "source": [ |
| 334 | + "# Define some auxiliary data which should be stored along the final iPEPS unit cell\n", |
| 335 | + "auxiliary_data = {\n", |
| 336 | + " \"best_energy\": result.fun,\n", |
| 337 | + " \"best_run\": result.best_run,\n", |
| 338 | + " \"magnetic_exp_values\": magnetic_exp_values,\n", |
| 339 | + "}\n", |
| 340 | + "for k in sorted(result.max_trunc_error_list.keys()):\n", |
| 341 | + " auxiliary_data[f\"max_trunc_error_list_{k:d}\"] = result.max_trunc_error_list[k]\n", |
| 342 | + " auxiliary_data[f\"step_energies_{k:d}\"] = result.step_energies[k]\n", |
| 343 | + " auxiliary_data[f\"step_chi_{k:d}\"] = result.step_chi[k]\n", |
| 344 | + " auxiliary_data[f\"step_conv_{k:d}\"] = result.step_conv[k]\n", |
| 345 | + " auxiliary_data[f\"step_runtime_{k:d}\"] = result.step_runtime[k]\n", |
| 346 | + "\n", |
| 347 | + "# save full iPEPS state\n", |
| 348 | + "result.unitcell.save_to_file(\n", |
| 349 | + " f\"data/heisenberg_square_J_{J:d}_chiB_{chiB:d}_chiMax_{chiM:d}.hdf5\",\n", |
| 350 | + " auxiliary_data=auxiliary_data,\n", |
| 351 | + ")" |
| 352 | + ] |
| 353 | + }, |
| 354 | + { |
| 355 | + "cell_type": "markdown", |
| 356 | + "id": "eadb6c10-34be-4ace-b130-51cac295e871", |
| 357 | + "metadata": {}, |
| 358 | + "source": [ |
| 359 | + "Finally, we want to save the unit cell with the optimized tensors to a file for further analysis. The library allows to store the data directly into a HDF5 file along with user-supplied auxiliary data. Here, for example, we not only want to store the plain tensors but also the calculated energy, meta information from the optimization run (e.g. energy per step or the runtime per step) and the calculated magnetic expectation values. At a later examination of the results, these data can be easily loaded along with the tensors of the tensor network." |
| 360 | + ] |
| 361 | + } |
| 362 | + ], |
| 363 | + "metadata": { |
| 364 | + "kernelspec": { |
| 365 | + "display_name": "Python 3 (ipykernel)", |
| 366 | + "language": "python", |
| 367 | + "name": "python3" |
| 368 | + }, |
| 369 | + "language_info": { |
| 370 | + "codemirror_mode": { |
| 371 | + "name": "ipython", |
| 372 | + "version": 3 |
| 373 | + }, |
| 374 | + "file_extension": ".py", |
| 375 | + "mimetype": "text/x-python", |
| 376 | + "name": "python", |
| 377 | + "nbconvert_exporter": "python", |
| 378 | + "pygments_lexer": "ipython3", |
| 379 | + "version": "3.13.11" |
| 380 | + } |
| 381 | + }, |
| 382 | + "nbformat": 4, |
| 383 | + "nbformat_minor": 5 |
| 384 | +} |
0 commit comments