{ "cells": [ { "cell_type": "markdown", "id": "9355093a", "metadata": {}, "source": [ "# Hamiltonian Adaptive Ternary Tree\n", "\n", "HATT is an algorithm for the construction of Ternary-Tree encodings which are optimised for the Hamiltonian of interest.\n", "\n", "This notebook shows how to reproduce the results of: \n", "Y. Liu et al., \"HATT: Hamiltonian Adaptive Ternary Tree for Optimizing Fermion-to-Qubit Mapping,\" 2025 IEEE International Symposium on High Performance Computer Architecture (HPCA), Las Vegas, NV, USA, 2025, pp. 143-157, doi: 10.1109/HPCA61900.2025.00022." ] }, { "cell_type": "markdown", "id": "0353ac6f", "metadata": {}, "source": [ "# Preprocess Hamiltonian\n", "\n", "The first thing we need to do for HATT is to process our fermionic operator into a majorana operator.\n", "\n", "There's a function to do this in `ferrmion.utils` if you need it, and the details aren't so important. We'll start with the small example given in the original paper.\n", "\n", "$$H_F = a^{\\dagger}_0a_0 + 2 a^{\\dagger}_1 a^{\\dagger}_2 a_1 a_2$$" ] }, { "cell_type": "code", "execution_count": 1, "id": "a4d182fd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 1): 0.5j, (4, 5): -0.5j, (2, 3): -0.5j, (2, 3, 4, 5): (0.5+0j)}" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from ferrmion.core import fermionic_to_sparse_majorana\n", "import numpy as np\n", "\n", "n_modes = 3\n", "ones = np.zeros((n_modes, n_modes))\n", "twos = np.zeros((n_modes, n_modes, n_modes, n_modes))\n", "\n", "ones[0, 0] = 1\n", "twos[1, 2, 1, 2] = 2\n", "\n", "majorana_ham = fermionic_to_sparse_majorana(signatures=[\"+-\",\"++--\"], coeffs=[ones,twos],constant_energy=0)\n", "majorana_ham" ] }, { "cell_type": "markdown", "id": "5770ed18", "metadata": {}, "source": [ "By rerodering the modes using $\\{\\gamma_i,\\gamma_j\\}=2\\delta_{i,j}$ you can simplify this down to the following:" ] }, { "cell_type": "code", "execution_count": 2, "id": "73219c58", "metadata": {}, "outputs": [], "source": [ "majorana_ham = {(0, 1): 0.5j, (2, 3): -0.5j, (4, 5): -0.5j, (2, 3, 4, 5): 0.5}\n", "n_modes = 3" ] }, { "cell_type": "markdown", "id": "5d1c81ac", "metadata": {}, "source": [ "# Algorithm 3\n", "\n", "There are three algorithms presented, each iteratively adding some improvements. We'll jump straight to algorithm 3, which caches some information about the tree as we build it." ] }, { "cell_type": "code", "execution_count": 3, "id": "94340021", "metadata": {}, "outputs": [], "source": [ "from itertools import permutations\n", "from typing import Iterable\n", "from ferrmion.encode import TernaryTree\n", "from ferrmion.encode.ternary_tree_node import TTNode\n", "\n", "\n", "def _qubit_term_weight(term: Iterable, comb: tuple[int, int, int]) -> int:\n", " \"\"\"Find the single-qubit Pauli-weight of majorana terms.\n", "\n", " If any pauli term is found an even number f times, we obtain I, weight = 0.\n", " If we find all three pauli terms, return I (with an imaginary ccoefficient), weight = 0\n", " If we find either one pauli or two then the weight = 1.\n", "\n", " Args:\n", " term (Iterable): Indices of term in our majorana-hamiltonian.\n", " comb (tuple[int, int, int]): Combination of indices to weigh (x,y,z).\n", "\n", " Returns:\n", " int: Weight of the term.\n", " \"\"\"\n", " term_array = np.array([t for t in term])\n", " odd_parity_paulis = np.array(\n", " [np.count_nonzero(np.array(term_array - index)) % 2 for index in comb]\n", " )\n", " print(f\"{term_array=}\")\n", " print(f\"{comb=}\")\n", " print([np.array(term_array - index) for index in comb])\n", " non_commuting = np.sum(odd_parity_paulis) % 3\n", " weight = int(non_commuting != 0)\n", " print(f\"{weight=}\")\n", " return weight\n", "\n", "\n", "def _reduce_hamiltonian(\n", " majorana_ham: dict[tuple[int, ...], float],\n", " parent_index: int,\n", " selection: tuple[int, int, int],\n", ") -> dict[tuple[int, ...], float]:\n", " \"\"\"Simplify the Hamiltonian.\n", "\n", " As we increase the qubit number, we iteratively remove majoranas\n", " which act trivially on the remaining qubits.\n", " We replace them with the index of their parent string\n", " as going forward they are identical to the parent string.\n", "\n", " Args:\n", " majorana_ham (dict[tuple[int,...],float]): Current Hamiltonian.\n", " parent_index (int): Qubit index of the parent node.\n", " selection (tuple[int, int, int]): Indices of the majoranas to be replaced.\n", "\n", " Returns:\n", " dict[tuple[int,...],float]: Reduced Hamiltonian.\n", " \"\"\"\n", " new_ham = {}\n", " for term, coeff in majorana_ham.items():\n", " new_term = [i if i not in selection else parent_index for i in term]\n", " if len(set(new_term)) != 1:\n", " new_ham[tuple(new_term)] = coeff\n", " return new_ham" ] }, { "cell_type": "markdown", "id": "3d223df4", "metadata": {}, "source": [ "We'll first set up for iteratively building the tree. \n", "\n", "We need:\n", "- a set of leaves and nodes\n", "- a way to keep track of which ones have been used already \n", "- maps from each node to its furthest child and parent which can be found by taking only z branches" ] }, { "cell_type": "code", "execution_count": 4, "id": "2896bbdd", "metadata": {}, "outputs": [], "source": [ "# We need 2*M +1 leaves and M nodes.\n", "nodes = {i: None for i in range(2 * n_modes + 1)}\n", "for i in range(n_modes):\n", " nodes[2 * n_modes + 1 + i] = TTNode(qubit_label=i)\n", "\n", "# Start with all the leaves unassigned\n", "unassigned = {*range(2 * n_modes + 1)}\n", "\n", "# We create two maps, of z_ancestors and z_descendants\n", "ancestor_map = {i: i for i in nodes}\n", "descendant_map = {i: i for i in nodes}\n", "\n", "# We can also total up the pauli-weight as we go to save effort later\n", "total_weight = 0" ] }, { "cell_type": "markdown", "id": "e4afbe4f", "metadata": {}, "source": [ "The next step is to iteratively update the tree, using a greedy method to explicitly check which combination of possible child nodes gives us the smallest Pauli-weight." ] }, { "cell_type": "code", "execution_count": 5, "id": "2d108eb9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "term_array=array([0, 1])\n", "comb=[0, 1, 2]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 2]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[0, 1, 2]\n", "[array([4, 5]), array([3, 4]), array([2, 3])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 2]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([0, 1, 2, 3])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "NEW MIN weight=np.int64(3)\n", "NEW COMB comb=[0, 1, 2]\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 3]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 3]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[0, 1, 3]\n", "[array([4, 5]), array([3, 4]), array([1, 2])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 3]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-1, 0, 1, 2])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 4]\n", "[array([0, 1]), array([-1, 0]), array([-4, -3])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 4]\n", "[array([2, 3]), array([1, 2]), array([-2, -1])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 4]\n", "[array([4, 5]), array([3, 4]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 4]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-2, -1, 0, 1])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 5]\n", "[array([0, 1]), array([-1, 0]), array([-5, -4])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 5]\n", "[array([2, 3]), array([1, 2]), array([-3, -2])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 5]\n", "[array([4, 5]), array([3, 4]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 5]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-3, -2, -1, 0])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 6]\n", "[array([0, 1]), array([-1, 0]), array([-6, -5])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 6]\n", "[array([2, 3]), array([1, 2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 6]\n", "[array([4, 5]), array([3, 4]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 6]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-4, -3, -2, -1])]\n", "weight=0\n", "This weight weight=np.int64(1)\n", "\n", "NEW MIN weight=np.int64(1)\n", "NEW COMB comb=[0, 1, 6]\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 2]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 2]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[0, 1, 2]\n", "[array([4, 5]), array([3, 4]), array([2, 3])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 2]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([0, 1, 2, 3])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 3]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 3]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[0, 1, 3]\n", "[array([4, 5]), array([3, 4]), array([1, 2])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 3]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-1, 0, 1, 2])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 4]\n", "[array([0, 1]), array([-1, 0]), array([-4, -3])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 4]\n", "[array([2, 3]), array([1, 2]), array([-2, -1])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 4]\n", "[array([4, 5]), array([3, 4]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 4]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-2, -1, 0, 1])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 5]\n", "[array([0, 1]), array([-1, 0]), array([-5, -4])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 5]\n", "[array([2, 3]), array([1, 2]), array([-3, -2])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 5]\n", "[array([4, 5]), array([3, 4]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 5]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-3, -2, -1, 0])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[0, 1, 6]\n", "[array([0, 1]), array([-1, 0]), array([-6, -5])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[0, 1, 6]\n", "[array([2, 3]), array([1, 2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[0, 1, 6]\n", "[array([4, 5]), array([3, 4]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[0, 1, 6]\n", "[array([2, 3, 4, 5]), array([1, 2, 3, 4]), array([-4, -3, -2, -1])]\n", "weight=0\n", "This weight weight=np.int64(1)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 0]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[2, 3, 0]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 0]\n", "[array([2, 3]), array([1, 2]), array([4, 5])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 0]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([2, 3, 4, 5])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 1]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[2, 3, 1]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 1]\n", "[array([2, 3]), array([1, 2]), array([3, 4])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 1]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([1, 2, 3, 4])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 4]\n", "[array([-2, -1]), array([-3, -2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 4]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 4]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 4]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-2, -1, 0, 1])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 5]\n", "[array([-2, -1]), array([-3, -2]), array([-5, -4])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 5]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 5]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 5]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-3, -2, -1, 0])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 6]\n", "[array([-2, -1]), array([-3, -2]), array([-6, -5])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 6]\n", "[array([0, 1]), array([-1, 0]), array([-4, -3])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 6]\n", "[array([2, 3]), array([1, 2]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 6]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-4, -3, -2, -1])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 0]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[2, 3, 0]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 0]\n", "[array([2, 3]), array([1, 2]), array([4, 5])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 0]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([2, 3, 4, 5])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 1]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[2, 3, 1]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 1]\n", "[array([2, 3]), array([1, 2]), array([3, 4])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 1]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([1, 2, 3, 4])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 4]\n", "[array([-2, -1]), array([-3, -2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 4]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 4]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 4]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-2, -1, 0, 1])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 5]\n", "[array([-2, -1]), array([-3, -2]), array([-5, -4])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 5]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 5]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 5]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-3, -2, -1, 0])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[2, 3, 6]\n", "[array([-2, -1]), array([-3, -2]), array([-6, -5])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[2, 3, 6]\n", "[array([0, 1]), array([-1, 0]), array([-4, -3])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 6]\n", "[array([2, 3]), array([1, 2]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 6]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-4, -3, -2, -1])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 0]\n", "[array([-4, -3]), array([-5, -4]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[4, 5, 0]\n", "[array([-2, -1]), array([-3, -2]), array([2, 3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 0]\n", "[array([0, 1]), array([-1, 0]), array([4, 5])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 0]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([2, 3, 4, 5])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 1]\n", "[array([-4, -3]), array([-5, -4]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[4, 5, 1]\n", "[array([-2, -1]), array([-3, -2]), array([1, 2])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 1]\n", "[array([0, 1]), array([-1, 0]), array([3, 4])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 1]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([1, 2, 3, 4])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 2]\n", "[array([-4, -3]), array([-5, -4]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 2]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 2]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 2]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([0, 1, 2, 3])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 3]\n", "[array([-4, -3]), array([-5, -4]), array([-3, -2])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 3]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 3]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 3]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-1, 0, 1, 2])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 6]\n", "[array([-4, -3]), array([-5, -4]), array([-6, -5])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 6]\n", "[array([-2, -1]), array([-3, -2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 6]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 6]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-4, -3, -2, -1])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 0]\n", "[array([-4, -3]), array([-5, -4]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[4, 5, 0]\n", "[array([-2, -1]), array([-3, -2]), array([2, 3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 0]\n", "[array([0, 1]), array([-1, 0]), array([4, 5])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 0]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([2, 3, 4, 5])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 1]\n", "[array([-4, -3]), array([-5, -4]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3])\n", "comb=[4, 5, 1]\n", "[array([-2, -1]), array([-3, -2]), array([1, 2])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 1]\n", "[array([0, 1]), array([-1, 0]), array([3, 4])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 1]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([1, 2, 3, 4])]\n", "weight=1\n", "This weight weight=np.int64(3)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 2]\n", "[array([-4, -3]), array([-5, -4]), array([-2, -1])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 2]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 2]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 2]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([0, 1, 2, 3])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 3]\n", "[array([-4, -3]), array([-5, -4]), array([-3, -2])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 3]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 3]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 3]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-1, 0, 1, 2])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([0, 1])\n", "comb=[4, 5, 6]\n", "[array([-4, -3]), array([-5, -4]), array([-6, -5])]\n", "weight=0\n", "term_array=array([2, 3])\n", "comb=[4, 5, 6]\n", "[array([-2, -1]), array([-3, -2]), array([-4, -3])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 6]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 6]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-4, -3, -2, -1])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "comb=(6, 5)\n", "total_weight=np.int64(1)\n", "Ham majorana_ham={(0, 1): 0.5j, (2, 3): (-0-0.5j), (4, 5): (-0-0.5j), (2, 3, 4, 5): 0.5}\n", "Reduced Ham majorana_ham={(2, 3): (-0-0.5j), (4, 5): (-0-0.5j), (2, 3, 4, 5): 0.5}\n", "term_array=array([2, 3])\n", "comb=[2, 3, 4]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 4]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 4]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-2, -1, 0, 1])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "NEW MIN weight=np.int64(2)\n", "NEW COMB comb=[2, 3, 4]\n", "\n", "term_array=array([2, 3])\n", "comb=[2, 3, 5]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 5]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 5]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-3, -2, -1, 0])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[2, 3, 7]\n", "[array([0, 1]), array([-1, 0]), array([-5, -4])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 7]\n", "[array([2, 3]), array([1, 2]), array([-3, -2])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 7]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-5, -4, -3, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[2, 3, 4]\n", "[array([0, 1]), array([-1, 0]), array([-2, -1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 4]\n", "[array([2, 3]), array([1, 2]), array([0, 1])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 4]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-2, -1, 0, 1])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[2, 3, 5]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 5]\n", "[array([2, 3]), array([1, 2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 5]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-3, -2, -1, 0])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[2, 3, 7]\n", "[array([0, 1]), array([-1, 0]), array([-5, -4])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[2, 3, 7]\n", "[array([2, 3]), array([1, 2]), array([-3, -2])]\n", "weight=0\n", "term_array=array([2, 3, 4, 5])\n", "comb=[2, 3, 7]\n", "[array([0, 1, 2, 3]), array([-1, 0, 1, 2]), array([-5, -4, -3, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 2]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 2]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 2]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([0, 1, 2, 3])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 3]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 3]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 3]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-1, 0, 1, 2])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 7]\n", "[array([-2, -1]), array([-3, -2]), array([-5, -4])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 7]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 7]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-5, -4, -3, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 2]\n", "[array([-2, -1]), array([-3, -2]), array([0, 1])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 2]\n", "[array([0, 1]), array([-1, 0]), array([2, 3])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 2]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([0, 1, 2, 3])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 3]\n", "[array([-2, -1]), array([-3, -2]), array([-1, 0])]\n", "weight=1\n", "term_array=array([4, 5])\n", "comb=[4, 5, 3]\n", "[array([0, 1]), array([-1, 0]), array([1, 2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 3]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-1, 0, 1, 2])]\n", "weight=0\n", "This weight weight=np.int64(2)\n", "\n", "term_array=array([2, 3])\n", "comb=[4, 5, 7]\n", "[array([-2, -1]), array([-3, -2]), array([-5, -4])]\n", "weight=0\n", "term_array=array([4, 5])\n", "comb=[4, 5, 7]\n", "[array([0, 1]), array([-1, 0]), array([-3, -2])]\n", "weight=1\n", "term_array=array([2, 3, 4, 5])\n", "comb=[4, 5, 7]\n", "[array([-2, -1, 0, 1]), array([-3, -2, -1, 0]), array([-5, -4, -3, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "comb=(7, 5)\n", "total_weight=np.int64(3)\n", "Ham majorana_ham={(2, 3): (-0-0.5j), (4, 5): (-0-0.5j), (2, 3, 4, 5): 0.5}\n", "Reduced Ham majorana_ham={(8, 5): (-0-0.5j), (8, 8, 8, 5): 0.5}\n", "term_array=array([8, 5])\n", "comb=[8, 5, 7]\n", "[array([ 0, -3]), array([3, 0]), array([ 1, -2])]\n", "weight=1\n", "term_array=array([8, 8, 8, 5])\n", "comb=[8, 5, 7]\n", "[array([ 0, 0, 0, -3]), array([3, 3, 3, 0]), array([ 1, 1, 1, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "NEW MIN weight=np.int64(2)\n", "NEW COMB comb=[8, 5, 7]\n", "\n", "term_array=array([8, 5])\n", "comb=[8, 5, 7]\n", "[array([ 0, -3]), array([3, 0]), array([ 1, -2])]\n", "weight=1\n", "term_array=array([8, 8, 8, 5])\n", "comb=[8, 5, 7]\n", "[array([ 0, 0, 0, -3]), array([3, 3, 3, 0]), array([ 1, 1, 1, -2])]\n", "weight=1\n", "This weight weight=np.int64(2)\n", "\n", "comb=[8, 5, 7]\n", "total_weight=np.int64(5)\n", "Ham majorana_ham={(8, 5): (-0-0.5j), (8, 8, 8, 5): 0.5}\n", "Reduced Ham majorana_ham={}\n", "{9} 5\n" ] } ], "source": [ "for i in range(n_modes):\n", " parent_index = 2 * n_modes + 1 + i\n", " parent = nodes[parent_index]\n", "\n", " min = np.inf\n", " selection = None\n", " for comb in permutations(unassigned, 2):\n", " small_y = None\n", " small_x = None\n", " x_index, z_index = comb\n", " small_x = descendant_map[x_index]\n", "\n", " # discard this combination\n", " if small_x == 2 * n_modes:\n", " continue\n", "\n", " if small_x % 2 == 0:\n", " small_y = small_x + 1\n", " else:\n", " small_y = small_x - 1\n", " # We can't use this index for y a\n", " # it has been used in the combination already\n", " # so we'd be replacing our x or z!\n", " if small_y in comb:\n", " # print(comb, small_y)\n", " # print(\"small y in comb\")\n", " continue\n", "\n", " y_index = ancestor_map[small_y]\n", "\n", " if y_index in comb:\n", " # print(comb, y_index)\n", " # print(\"y index in comb\")\n", " continue\n", "\n", " if small_x % 2 == 0:\n", " comb = np.array([x_index, y_index, z_index], dtype=np.uint)\n", " else:\n", " comb = np.array([y_index, x_index, z_index], dtype=np.uint)\n", " comb = [int(i) for i in comb]\n", " weight = np.sum(\n", " [_qubit_term_weight(term, comb) for term in majorana_ham.keys()]\n", " )\n", " print(f\"This weight {weight=}\\n\")\n", " if weight < min:\n", " print(f\"NEW MIN {weight=}\")\n", " print(f\"NEW COMB {comb=}\\n\")\n", " min = weight\n", " selection = comb\n", "\n", " total_weight += min\n", " print(f\"{comb=}\")\n", " print(f\"{total_weight=}\")\n", " # Now find the Y pair of the x-node\n", " for i, char in zip(selection, [\"x\", \"y\", \"z\"]):\n", " if i in unassigned:\n", " unassigned.remove(i)\n", "\n", " if isinstance(nodes.get(i, None), TTNode):\n", " parent.add_child(which_child=char, child_node=nodes.get(i))\n", " else:\n", " parent.leaf_majorana_indices[char] = i\n", "\n", " z_index = selection[2]\n", " z_desc = descendant_map[z_index]\n", " descendant_map[parent_index] = z_desc\n", " ancestor_map[z_index] = parent_index\n", " ancestor_map[z_desc] = parent_index\n", "\n", " unassigned.add(parent_index)\n", "\n", " # See the docstring for this function above\n", " print(f\"Ham {majorana_ham=}\")\n", " majorana_ham = _reduce_hamiltonian(majorana_ham, parent_index, selection)\n", " print(f\"Reduced Ham {majorana_ham=}\")\n", "if len(unassigned) != 1:\n", " raise ValueError(\"Not all nodes assigned by HATT.\")\n", "print(unassigned, total_weight)\n", "root = nodes[unassigned.pop()]" ] }, { "cell_type": "markdown", "id": "dc99b09c", "metadata": {}, "source": [ "Finally, we can build the tree from our root node, which must be the only node without a parent." ] }, { "cell_type": "code", "execution_count": 6, "id": "d379765d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'x': {'x': 2, 'y': 3, 'z': 4}, 'y': 5, 'z': {'x': 0, 'y': 1, 'z': 6}}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree = TernaryTree(n_modes=n_modes, root_node=root)\n", "tree.enumeration_scheme = tree.default_enumeration_scheme()\n", "tree.pauli_weight = total_weight\n", "tree.as_dict()" ] }, { "cell_type": "markdown", "id": "36edc52f", "metadata": {}, "source": [ "# Inbuilt function\n", "\n", "`ferrmion` has an inbuilt function which works in just the same way." ] }, { "cell_type": "code", "execution_count": 7, "id": "81c97959", "metadata": {}, "outputs": [], "source": [ "import json\n", "from ferrmion.encode import TernaryTree, MaxNTO\n", "from pathlib import Path\n", "from ferrmion.hamiltonians import molecular_hamiltonian\n", "\n", "folder = Path.cwd().joinpath(Path(\"../../../python/tests/\"))\n", "with open(folder.joinpath(\"./data/h2o_sto-3g.json\"), \"rb\") as file:\n", " data = json.load(file)\n", "ones = np.array(data[\"ones\"])\n", "twos = np.array(data[\"twos\"])\n", "\n", "fham = molecular_hamiltonian(ones, twos, 0.0)\n", "mham = fermionic_to_sparse_majorana(signatures=[\"+-\",\"++--\"], coeffs=[ones,twos],constant_energy=0)" ] }, { "cell_type": "code", "execution_count": 8, "id": "11e09872", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4668\n" ] }, { "data": { "image/png": "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NiRBjSRV/fDDD7N+Jvs4duwY/Pz8VEApZOK1aRELZZNVjrIz04IFCxAXF6duUkdvv/12NWldeiLzUqlSJezZs0cNqa9fvx4hISEYPHiwWjBFRGSErCvunr7P1hhQ2pD0kI0ePRorV65UQ42mHjNZbEK2Vbp0afXpskyZMupnyV/5119/YcCAAWruJeVNAkPpaZTh7JdeeinfvJ+mQNPX11cF6//88w/uvPNOjBs3jm8tEbks6eiRm3zQbtKkCV544QVnF8kwGFDa2AMPPID27dur5OVCenguX76stlzcunWrrQ/ndky9vjJP8Pr161lJa1evXo3evXvj6tWrKtikW5MPPHlNE5D32LTYacaMGSoZf7Vq1bB06VIVVBIRuYpdu3ap3M8//vij2qHu2rVrWee9uXPn4u2338aFCxecXUxDcO8lsjb0yy+/qMoqaV1kqFAy9MucNblP5qzJEO0777yjgk0qPtOJ4NSpU2penwTsMody2bJlCA8PxzfffMO31wbvsSyIeu6559TcS9nRqH///nkGnomJiQgKCuL8VSLSJTmHyY5sMj1KrseSw/e2225DvXr1cO+996oFilOmTOGGIzbARTk2moshq2elF0eGFKWyyo4vTZs2VVsKClkEERgYaIvDuTVTktrp06erXYeeeOIJTJ48GfPnz0ePHj3U3D8msrXO8uXL1clVAkuZbykn3vyS8stcTAnqmWSdiPRI5opLNpDPP/8cXbp0UXPC5QNzdHS0mjYlCxflcRn1ulX2CyoYA0obOXLkCEJDQ7MuvHIhliHCn3/+Oes5XIlcfObvnbzHffr0wYYNGzBw4EA1sVpWLJP15OQqqYLkhCv197777su391H+Jz/99FNWiqLdu3erYL5mzZrqA5YpyKxevTr/NUTkNKbRFhk9zDlXXEa7ZC45z1PWY0BpB7IIR9KztGnTBhMmTGCeRBu+r9Lwpff3vffeUycAWb1sOhHkDDpl3qo83533Bi8qOcGuW7dO7a0uJ2CZwlG/fn0VuMuCM39//3xfyyTrRKRX5cqVU9POhg4dmrVQVq4P7OixHQaUdjRt2jR89913ai9myeVHxScrt5966il069ZNLcCRYe4RI0aooYq8TgjSUyaLSWTFPfcGL77jx4+r+cC///473nzzzQIDSnslWScistYHH3ygOiIOHDjAvb3thAGlHckE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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from ferrmion.visualise import draw_tt\n", "from ferrmion.optimize.hatt import hamiltonian_adaptive_ternary_tree\n", "\n", "hatt = hamiltonian_adaptive_ternary_tree(fham, fham.n_modes)\n", "print(hatt.pauli_weight)\n", "hatt.as_dict()\n", "\n", "draw_tt(hatt, enumeration_scheme=hatt.default_enumeration_scheme())" ] }, { "cell_type": "code", "execution_count": 9, "id": "6558036f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(13, (5, 6, 12)),\n", " (5, (34, 35, 18)),\n", " (6, (26, 27, 19)),\n", " (12, (11, 39, 2)),\n", " (11, (10, 8, 38)),\n", " (2, (14, 15, 1)),\n", " (10, (3, 9, 7)),\n", " (8, (22, 23, 37)),\n", " (1, (32, 33, 0)),\n", " (3, (16, 17, 24)),\n", " (9, (40, 41, 4)),\n", " (7, (20, 21, 36)),\n", " (0, (30, 31, None)),\n", " (4, (28, 29, 25))]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hatt.flatpack()" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.1" } }, "nbformat": 4, "nbformat_minor": 5 }