Repository: alugowski/matrepr (language: python)

Issue:
Add PyTorch support
https://pytorch.org/docs/stable/sparse.html


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 248a171..1c518e9 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ MatRepr formats matrices to HTML, string, and LaTeX, with Jupyter integration.
 * **NumPy** - `ndarray`
 * **[Python-graphblas](https://github.com/python-graphblas/python-graphblas)** - `gb.Matrix` and `gb.Vector` [(demo)](doc/demo-python-graphblas.ipynb)
 * **[PyData/Sparse](https://sparse.pydata.org/)** - `COO`, `DOK`, `GCXS` [(demo)](doc/demo-pydata-sparse.ipynb)
+* **[PyTorch](https://pytorch.org/docs/stable/sparse.html)** - `torch.Tensor` [(demo)](doc/demo-pytorch.ipynb)
 * `list`, `tuple`, including multi-dimensional and ragged
 
 Features:
diff --git a/doc/demo-pytorch.ipynb b/doc/demo-pytorch.ipynb
new file mode 100644
index 0000000..7c6182d
--- /dev/null
+++ b/doc/demo-pytorch.ipynb
@@ -0,0 +1,2049 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "source": [
+    "# MatRepr PyTorch\n",
+    "\n",
+    "Neatly format `torch.tensor`.\n",
+    "\n",
+    "1D dense and sparse tensors are formatted as row vectors.\n",
+    "\n",
+    "2D dense and sparse tensors are formatted as matrices.\n",
+    "\n",
+    "3D+ sparse tensors are formatted as a list of index/value tuples, including hybrid tensors. Dense 3D+ tensors rendered with native PyTorch formatter.\n",
+    "\n",
+    "There are many possible `torch.tensor` layouts, not all combinations are supported by MatRepr. Those will fall back to the native `__str__()` formatter. For example: scalars, 3D+ dense tensors, CSR/CSC with batch dimensions, etc."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.264291Z",
+     "start_time": "2023-09-06T22:42:26.475224Z"
+    },
+    "jupyter": {
+     "source_hidden": true
+    }
+   },
+   "outputs": [],
+   "source": [
+    "import torch\n",
+    "\n",
+    "import numpy\n",
+    "numpy.random.seed(1234)\n",
+    "\n",
+    "# so matrepr can be imported from the source tree.\n",
+    "import sys\n",
+    "sys.path.insert(0, '..')\n",
+    "\n",
+    "from matrepr import mdisplay, mprint\n",
+    "\n",
+    "# filter beta state warning\n",
+    "import warnings\n",
+    "warnings.filterwarnings(\"ignore\", message=\"Sparse CSR tensor support is in beta state\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.272286Z",
+     "start_time": "2023-09-06T22:42:27.265702Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [],
+   "source": [
+    "scalar = torch.tensor(5)\n",
+    "\n",
+    "dense1D = torch.rand(5000)\n",
+    "\n",
+    "rand2D = torch.rand(128, 64)\n",
+    "rand2D[rand2D < 0.6] = 0\n",
+    "rand2D_CSR = rand2D.to_sparse_csr()\n",
+    "\n",
+    "small3D = torch.tensor([[[1., 0], [2., 3.]], [[4., 0], [5., 6.]]])\n",
+    "coo3D = small3D.to_sparse_coo()\n",
+    "coo3D_hybrid = small3D.to_sparse(2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.285386Z",
+     "start_time": "2023-09-06T22:42:27.276238Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor([0.9123, 0.2138, 0.1577,  ..., 0.2302, 0.3208, 0.6786])"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dense1D"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor(crow_indices=tensor([   0,   25,   53,   77,  101,  127,  149,  172,\n",
+       "                             203,  229,  258,  280,  307,  328,  354,  385,\n",
+       "                             412,  450,  474,  493,  524,  551,  581,  608,\n",
+       "                             630,  659,  690,  719,  748,  775,  795,  817,\n",
+       "                             844,  862,  884,  910,  934,  962,  996, 1024,\n",
+       "                            1048, 1081, 1105, 1134, 1161, 1192, 1230, 1253,\n",
+       "                            1277, 1298, 1332, 1357, 1392, 1423, 1445, 1476,\n",
+       "                            1511, 1533, 1552, 1576, 1605, 1629, 1652, 1676,\n",
+       "                            1708, 1730, 1758, 1783, 1804, 1821, 1847, 1878,\n",
+       "                            1903, 1932, 1959, 1985, 2018, 2039, 2063, 2086,\n",
+       "                            2113, 2134, 2157, 2173, 2199, 2218, 2241, 2269,\n",
+       "                            2300, 2321, 2342, 2368, 2389, 2418, 2436, 2464,\n",
+       "                            2493, 2519, 2542, 2568, 2588, 2612, 2642, 2668,\n",
+       "                            2692, 2717, 2739, 2759, 2791, 2813, 2837, 2858,\n",
+       "                            2877, 2902, 2932, 2955, 2981, 3003, 3025, 3051,\n",
+       "                            3078, 3103, 3135, 3160, 3184, 3212, 3236, 3263,\n",
+       "                            3286]),\n",
+       "       col_indices=tensor([ 1,  3,  5,  ..., 54, 55, 60]),\n",
+       "       values=tensor([0.6698, 0.6196, 0.7489,  ..., 0.6112, 0.7558, 0.6966]),\n",
+       "       size=(128, 64), nnz=3286, layout=torch.sparse_csr)"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rand2D_CSR"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor(indices=tensor([[0, 0, 0, 1, 1, 1],\n",
+       "                       [0, 1, 1, 0, 1, 1],\n",
+       "                       [0, 0, 1, 0, 0, 1]]),\n",
+       "       values=tensor([1., 2., 3., 4., 5., 6.]),\n",
+       "       size=(2, 2, 2), nnz=6, layout=torch.sparse_coo)"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "coo3D"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor(indices=tensor([[0, 0, 1, 1],\n",
+       "                       [0, 1, 0, 1]]),\n",
+       "       values=tensor([[1., 0.],\n",
+       "                      [2., 3.],\n",
+       "                      [4., 0.],\n",
+       "                      [5., 6.]]),\n",
+       "       size=(2, 2, 2), nnz=4, layout=torch.sparse_coo)"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "coo3D_hybrid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor(5)"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "scalar"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:34:13.317717Z",
+     "start_time": "2023-09-06T22:34:13.315433Z"
+    }
+   },
+   "source": [
+    "## MatRepr default\n",
+    "\n",
+    "Load the MatRepr Jupyter extension with `%load_ext matrepr` to render tensors with MatRepr by default.\n",
+    "\n",
+    "A single-use alternative is to use `matrepr.mdisplay()`. For console use `matrepr.mprint()`. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.287428Z",
+     "start_time": "2023-09-06T22:42:27.285068Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [],
+   "source": [
+    "%load_ext matrepr"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.342346Z",
+     "start_time": "2023-09-06T22:42:27.287671Z"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprmatrix\">\n",
+       "<caption>length=5000, &#x27;torch.float32&#x27; elements, torch.strided</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th style=\"text-align: center;\">0</th>\n",
+       "        <th style=\"text-align: center;\">1</th>\n",
+       "        <th style=\"text-align: center;\">2</th>\n",
+       "        <th style=\"text-align: center;\">3</th>\n",
+       "        <th style=\"text-align: center;\">4</th>\n",
+       "        <th style=\"text-align: center;\">5</th>\n",
+       "        <th style=\"text-align: center;\">6</th>\n",
+       "        <th style=\"text-align: center;\"></th>\n",
+       "        <th style=\"text-align: center;\">4993</th>\n",
+       "        <th style=\"text-align: center;\">4994</th>\n",
+       "        <th style=\"text-align: center;\">4995</th>\n",
+       "        <th style=\"text-align: center;\">4996</th>\n",
+       "        <th style=\"text-align: center;\">4997</th>\n",
+       "        <th style=\"text-align: center;\">4998</th>\n",
+       "        <th style=\"text-align: center;\">4999</th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <td style=\"text-align: center;\">0.9123</td>\n",
+       "        <td style=\"text-align: center;\">0.2138</td>\n",
+       "        <td style=\"text-align: center;\">0.1577</td>\n",
+       "        <td style=\"text-align: center;\">0.4017</td>\n",
+       "        <td style=\"text-align: center;\">0.927</td>\n",
+       "        <td style=\"text-align: center;\">0.1635</td>\n",
+       "        <td style=\"text-align: center;\">0.6582</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.774</td>\n",
+       "        <td style=\"text-align: center;\">0.2935</td>\n",
+       "        <td style=\"text-align: center;\">0.5912</td>\n",
+       "        <td style=\"text-align: center;\">0.8633</td>\n",
+       "        <td style=\"text-align: center;\">0.2302</td>\n",
+       "        <td style=\"text-align: center;\">0.3208</td>\n",
+       "        <td style=\"text-align: center;\">0.6786</td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "tensor([0.9123, 0.2138, 0.1577,  ..., 0.2302, 0.3208, 0.6786])"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dense1D"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.342786Z",
+     "start_time": "2023-09-06T22:42:27.297844Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprmatrix\">\n",
+       "<caption>128×64, 3286 &#x27;torch.float32&#x27; elements, torch.sparse_csr</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <th style=\"text-align: center;\">0</th>\n",
+       "        <th style=\"text-align: center;\">1</th>\n",
+       "        <th style=\"text-align: center;\">2</th>\n",
+       "        <th style=\"text-align: center;\">3</th>\n",
+       "        <th style=\"text-align: center;\">4</th>\n",
+       "        <th style=\"text-align: center;\">5</th>\n",
+       "        <th style=\"text-align: center;\">6</th>\n",
+       "        <th style=\"text-align: center;\"></th>\n",
+       "        <th style=\"text-align: center;\">57</th>\n",
+       "        <th style=\"text-align: center;\">58</th>\n",
+       "        <th style=\"text-align: center;\">59</th>\n",
+       "        <th style=\"text-align: center;\">60</th>\n",
+       "        <th style=\"text-align: center;\">61</th>\n",
+       "        <th style=\"text-align: center;\">62</th>\n",
+       "        <th style=\"text-align: center;\">63</th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <th>0</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6698</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6196</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7489</td>\n",
+       "        <td style=\"text-align: center;\">0.8952</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6021</td>\n",
+       "        <td style=\"text-align: center;\">0.6449</td>\n",
+       "        <td style=\"text-align: center;\">0.8717</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9785</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>1</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9144</td>\n",
+       "        <td style=\"text-align: center;\">0.7465</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8148</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9172</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8863</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>2</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8973</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9478</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>3</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9928</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.9838</td>\n",
+       "        <td style=\"text-align: center;\">0.6982</td>\n",
+       "        <td style=\"text-align: center;\">0.7416</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9504</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>4</th>\n",
+       "        <td style=\"text-align: center;\">0.9618</td>\n",
+       "        <td style=\"text-align: center;\">0.6501</td>\n",
+       "        <td style=\"text-align: center;\">0.9263</td>\n",
+       "        <td style=\"text-align: center;\">0.844</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8712</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8267</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&dtdot;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>123</th>\n",
+       "        <td style=\"text-align: center;\">0.6765</td>\n",
+       "        <td style=\"text-align: center;\">0.9631</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9067</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.767</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.7601</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.97</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9297</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>124</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8878</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8579</td>\n",
+       "        <td style=\"text-align: center;\">0.7423</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6537</td>\n",
+       "        <td style=\"text-align: center;\">0.9821</td>\n",
+       "        <td style=\"text-align: center;\">0.6675</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>125</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.967</td>\n",
+       "        <td style=\"text-align: center;\">0.7392</td>\n",
+       "        <td style=\"text-align: center;\">0.8582</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6025</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>126</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6808</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>127</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8987</td>\n",
+       "        <td style=\"text-align: center;\">0.9682</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6966</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "tensor(crow_indices=tensor([   0,   25,   53,   77,  101,  127,  149,  172,\n",
+       "                             203,  229,  258,  280,  307,  328,  354,  385,\n",
+       "                             412,  450,  474,  493,  524,  551,  581,  608,\n",
+       "                             630,  659,  690,  719,  748,  775,  795,  817,\n",
+       "                             844,  862,  884,  910,  934,  962,  996, 1024,\n",
+       "                            1048, 1081, 1105, 1134, 1161, 1192, 1230, 1253,\n",
+       "                            1277, 1298, 1332, 1357, 1392, 1423, 1445, 1476,\n",
+       "                            1511, 1533, 1552, 1576, 1605, 1629, 1652, 1676,\n",
+       "                            1708, 1730, 1758, 1783, 1804, 1821, 1847, 1878,\n",
+       "                            1903, 1932, 1959, 1985, 2018, 2039, 2063, 2086,\n",
+       "                            2113, 2134, 2157, 2173, 2199, 2218, 2241, 2269,\n",
+       "                            2300, 2321, 2342, 2368, 2389, 2418, 2436, 2464,\n",
+       "                            2493, 2519, 2542, 2568, 2588, 2612, 2642, 2668,\n",
+       "                            2692, 2717, 2739, 2759, 2791, 2813, 2837, 2858,\n",
+       "                            2877, 2902, 2932, 2955, 2981, 3003, 3025, 3051,\n",
+       "                            3078, 3103, 3135, 3160, 3184, 3212, 3236, 3263,\n",
+       "                            3286]),\n",
+       "       col_indices=tensor([ 1,  3,  5,  ..., 54, 55, 60]),\n",
+       "       values=tensor([0.6698, 0.6196, 0.7489,  ..., 0.6112, 0.7558, 0.6966]),\n",
+       "       size=(128, 64), nnz=3286, layout=torch.sparse_csr)"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rand2D_CSR"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.343107Z",
+     "start_time": "2023-09-06T22:42:27.304142Z"
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprtensor\">\n",
+       "<caption>shape=(2,2,2), 6 &#x27;torch.float32&#x27; elements, torch.sparse_coo</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <th style=\"text-align: right;\">0</th>\n",
+       "        <th style=\"text-align: right;\">1</th>\n",
+       "        <th style=\"text-align: right;\">2</th>\n",
+       "        <th style=\"text-align: center;\">val</th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <th>0</th>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">1</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>1</th>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">2</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>2</th>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: center;\">3</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>3</th>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">4</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>4</th>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">5</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>5</th>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: center;\">6</td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "tensor(indices=tensor([[0, 0, 0, 1, 1, 1],\n",
+       "                       [0, 1, 1, 0, 1, 1],\n",
+       "                       [0, 0, 1, 0, 0, 1]]),\n",
+       "       values=tensor([1., 2., 3., 4., 5., 6.]),\n",
+       "       size=(2, 2, 2), nnz=6, layout=torch.sparse_coo)"
+      ]
+     },
+     "execution_count": 11,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "coo3D"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.343359Z",
+     "start_time": "2023-09-06T22:42:27.315621Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprtensor\">\n",
+       "<caption>shape=(2,2,2), 4 &#x27;torch.float32&#x27; elements, torch.sparse_coo</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <th style=\"text-align: right;\">0</th>\n",
+       "        <th style=\"text-align: right;\">1</th>\n",
+       "        <th style=\"text-align: center;\">val</th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <th>0</th>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">\n",
+       "            <table class=\"matreprmatrix\" style=\"margin: 0 auto;\">\n",
+       "                <tbody>\n",
+       "                <tr>\n",
+       "                    <td style=\"text-align: center;\">1</td>\n",
+       "                    <td style=\"text-align: center;\">0</td>\n",
+       "                </tr>\n",
+       "                </tbody>\n",
+       "            </table></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>1</th>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: center;\">\n",
+       "            <table class=\"matreprmatrix\" style=\"margin: 0 auto;\">\n",
+       "                <tbody>\n",
+       "                <tr>\n",
+       "                    <td style=\"text-align: center;\">2</td>\n",
+       "                    <td style=\"text-align: center;\">3</td>\n",
+       "                </tr>\n",
+       "                </tbody>\n",
+       "            </table></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>2</th>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">0</td>\n",
+       "        <td style=\"text-align: center;\">\n",
+       "            <table class=\"matreprmatrix\" style=\"margin: 0 auto;\">\n",
+       "                <tbody>\n",
+       "                <tr>\n",
+       "                    <td style=\"text-align: center;\">4</td>\n",
+       "                    <td style=\"text-align: center;\">0</td>\n",
+       "                </tr>\n",
+       "                </tbody>\n",
+       "            </table></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>3</th>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: right;\">1</td>\n",
+       "        <td style=\"text-align: center;\">\n",
+       "            <table class=\"matreprmatrix\" style=\"margin: 0 auto;\">\n",
+       "                <tbody>\n",
+       "                <tr>\n",
+       "                    <td style=\"text-align: center;\">5</td>\n",
+       "                    <td style=\"text-align: center;\">6</td>\n",
+       "                </tr>\n",
+       "                </tbody>\n",
+       "            </table></td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "tensor(indices=tensor([[0, 0, 1, 1],\n",
+       "                       [0, 1, 0, 1]]),\n",
+       "       values=tensor([[1., 0.],\n",
+       "                      [2., 3.],\n",
+       "                      [4., 0.],\n",
+       "                      [5., 6.]]),\n",
+       "       size=(2, 2, 2), nnz=4, layout=torch.sparse_coo)"
+      ]
+     },
+     "execution_count": 12,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "coo3D_hybrid"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "tensor(5)"
+      ]
+     },
+     "execution_count": 13,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "scalar"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Labels\n",
+    "\n",
+    "Specify title, row and/or column labels to help the reader quickly understand what they are looking at."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "tensor = torch.rand(64, 32)\n",
+    "tensor[tensor < 0.3] = 0\n",
+    "tensor = tensor.to_sparse()\n",
+    "\n",
+    "obs_labels = [f\"observation {i}\" for i in range(tensor.shape[0])]  # list of labels\n",
+    "feature_labels = {i: f\"feature {i+1}\" for i in range(tensor.shape[1])}  # map index to label works too"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprmatrix\">\n",
+       "<caption>Random Dataset</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <th style=\"text-align: center;\">feature 1</th>\n",
+       "        <th style=\"text-align: center;\">feature 2</th>\n",
+       "        <th style=\"text-align: center;\">feature 3</th>\n",
+       "        <th style=\"text-align: center;\">feature 4</th>\n",
+       "        <th style=\"text-align: center;\">feature 5</th>\n",
+       "        <th style=\"text-align: center;\"></th>\n",
+       "        <th style=\"text-align: center;\">feature 28</th>\n",
+       "        <th style=\"text-align: center;\">feature 29</th>\n",
+       "        <th style=\"text-align: center;\">feature 30</th>\n",
+       "        <th style=\"text-align: center;\">feature 31</th>\n",
+       "        <th style=\"text-align: center;\">feature 32</th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <th>observation 0</th>\n",
+       "        <td style=\"text-align: center;\">0.3472</td>\n",
+       "        <td style=\"text-align: center;\">0.4712</td>\n",
+       "        <td style=\"text-align: center;\">0.4631</td>\n",
+       "        <td style=\"text-align: center;\">0.4087</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9262</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.433</td>\n",
+       "        <td style=\"text-align: center;\">0.8568</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 1</th>\n",
+       "        <td style=\"text-align: center;\">0.7922</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7093</td>\n",
+       "        <td style=\"text-align: center;\">0.4448</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.9246</td>\n",
+       "        <td style=\"text-align: center;\">0.9083</td>\n",
+       "        <td style=\"text-align: center;\">0.8335</td>\n",
+       "        <td style=\"text-align: center;\">0.815</td>\n",
+       "        <td style=\"text-align: center;\">0.6405</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 2</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.5853</td>\n",
+       "        <td style=\"text-align: center;\">0.9673</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.5242</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.952</td>\n",
+       "        <td style=\"text-align: center;\">0.8521</td>\n",
+       "        <td style=\"text-align: center;\">0.8307</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.3719</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 3</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9561</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9454</td>\n",
+       "        <td style=\"text-align: center;\">0.3552</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6674</td>\n",
+       "        <td style=\"text-align: center;\">0.9862</td>\n",
+       "        <td style=\"text-align: center;\">0.5422</td>\n",
+       "        <td style=\"text-align: center;\">0.3391</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 4</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9543</td>\n",
+       "        <td style=\"text-align: center;\">0.6766</td>\n",
+       "        <td style=\"text-align: center;\">0.5506</td>\n",
+       "        <td style=\"text-align: center;\">0.5841</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.5843</td>\n",
+       "        <td style=\"text-align: center;\">0.8764</td>\n",
+       "        <td style=\"text-align: center;\">0.6554</td>\n",
+       "        <td style=\"text-align: center;\">0.8808</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&dtdot;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 59</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.5496</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7716</td>\n",
+       "        <td style=\"text-align: center;\">0.9963</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.8506</td>\n",
+       "        <td style=\"text-align: center;\">0.7186</td>\n",
+       "        <td style=\"text-align: center;\">0.6416</td>\n",
+       "        <td style=\"text-align: center;\">0.8713</td>\n",
+       "        <td style=\"text-align: center;\">0.525</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 60</th>\n",
+       "        <td style=\"text-align: center;\">0.9826</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6648</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.6753</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9586</td>\n",
+       "        <td style=\"text-align: center;\">0.5967</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 61</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.3046</td>\n",
+       "        <td style=\"text-align: center;\">0.8861</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.4987</td>\n",
+       "        <td style=\"text-align: center;\">0.6156</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6486</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 62</th>\n",
+       "        <td style=\"text-align: center;\">0.7702</td>\n",
+       "        <td style=\"text-align: center;\">0.5917</td>\n",
+       "        <td style=\"text-align: center;\">0.9953</td>\n",
+       "        <td style=\"text-align: center;\">0.7114</td>\n",
+       "        <td style=\"text-align: center;\">0.8805</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\">0.9866</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.3391</td>\n",
+       "        <td style=\"text-align: center;\">0.4349</td>\n",
+       "        <td style=\"text-align: center;\">0.4785</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>observation 63</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9826</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7169</td>\n",
+       "        <td style=\"text-align: center;\">0.926</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7886</td>\n",
+       "        <td style=\"text-align: center;\">0.7501</td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "mdisplay(tensor, row_labels=obs_labels, col_labels=feature_labels, title=\"Random Dataset\", max_cols=11)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:34:13.356497Z",
+     "start_time": "2023-09-06T22:34:13.338373Z"
+    }
+   },
+   "source": [
+    "## LaTeX"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.343599Z",
+     "start_time": "2023-09-06T22:42:27.334295Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/latex": [
+       "$\\begin{bmatrix}\n",
+       "     & 0.6698 &  & 0.6196 &  & 0.7489 & 0.8952 & \\dots &  & 0.6021 & 0.6449 & 0.8717 &  &  & 0.9785 \\\\\n",
+       "     & 0.9144 & 0.7465 &  & 0.8148 &  & 0.9172 & \\dots &  &  &  &  & 0.8863 &  &  \\\\\n",
+       "     &  &  &  &  & 0.8973 &  & \\dots &  &  &  &  &  &  & 0.9478 \\\\\n",
+       "     & 0.9928 &  &  &  &  &  & \\dots & 0.9838 & 0.6982 & 0.7416 &  &  &  & 0.9504 \\\\\n",
+       "    0.9618 & 0.6501 & 0.9263 & 0.844 &  &  & 0.8712 & \\dots &  &  & 0.8267 &  &  &  &  \\\\\n",
+       "    \\vdots & \\vdots & \\vdots & \\vdots & \\vdots & \\vdots & \\vdots & \\ddots & \\vdots & \\vdots & \\vdots & \\vdots & \\vdots & \\vdots & \\vdots \\\\\n",
+       "    0.6765 & 0.9631 &  & 0.9067 &  &  & 0.767 & \\dots & 0.7601 &  & 0.97 &  & 0.9297 &  &  \\\\\n",
+       "     & 0.8878 &  &  &  & 0.8579 & 0.7423 & \\dots &  & 0.6537 & 0.9821 & 0.6675 &  &  &  \\\\\n",
+       "     &  &  &  &  &  &  & \\dots & 0.967 & 0.7392 & 0.8582 &  & 0.6025 &  &  \\\\\n",
+       "     &  &  &  &  & 0.6808 &  & \\dots &  &  &  &  &  &  &  \\\\\n",
+       "     &  &  &  & 0.8987 & 0.9682 &  & \\dots &  &  &  & 0.6966 &  &  & \n",
+       "\\end{bmatrix}$"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Latex object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "mdisplay(rand2D_CSR, \"latex\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:34:13.360119Z",
+     "start_time": "2023-09-06T22:34:13.354250Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "source": [
+    "## String"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.344022Z",
+     "start_time": "2023-09-06T22:42:27.334892Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "<128×64, 3286 'torch.float32' elements, torch.sparse_csr>\n",
+      "        0       1       2       3            60      61     62     63\n",
+      "    ┌                                                                   ┐\n",
+      "  0 │         0.6698                  ...  0.8717                0.9785 │\n",
+      "  1 │         0.9144  0.7465          ...          0.8863               │\n",
+      "  2 │                         0.979   ...                        0.9478 │\n",
+      "  3 │         0.9928          0.744   ...                        0.9504 │\n",
+      "  4 │ 0.9618  0.6501  0.9263          ...                               │\n",
+      "    │   :       :       :       :     ...    :       :      :      :    │\n",
+      "123 │ 0.6765  0.9631                  ...          0.9297               │\n",
+      "124 │         0.8878                  ...  0.6675                       │\n",
+      "125 │                         0.9118  ...          0.6025               │\n",
+      "126 │                                 ...                               │\n",
+      "127 │                                 ...  0.6966                       │\n",
+      "    └                                                                   ┘\n"
+     ]
+    }
+   ],
+   "source": [
+    "mprint(rand2D_CSR)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:34:13.387721Z",
+     "start_time": "2023-09-06T22:34:13.384682Z"
+    }
+   },
+   "source": [
+    "## More compact size"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.350769Z",
+     "start_time": "2023-09-06T22:42:27.345724Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [],
+   "source": [
+    "import matrepr\n",
+    "matrepr.params.max_rows = 10\n",
+    "matrepr.params.max_cols = 7\n",
+    "matrepr.params.num_after_dots = 0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.354578Z",
+     "start_time": "2023-09-06T22:42:27.347832Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    table.matreprmatrix caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix  {\n",
+       "        border-collapse: collapse;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprmatrix > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:first-of-type {\n",
+       "        border-left: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::before {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody tr td:empty::after {\n",
+       "        content: \"\\00a0\\00a0\\00a0\";\n",
+       "        visibility: hidden;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:first-of-type::before {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: 0;\n",
+       "        right: auto;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:first-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-top: solid 2px;\n",
+       "    }\n",
+       "    table.matreprmatrix > tbody > tr:last-child > td:last-of-type::after {\n",
+       "        content: \"\";\n",
+       "        width: 4px;\n",
+       "        position: absolute;\n",
+       "        top: 0;\n",
+       "        bottom: 0;\n",
+       "        visibility: visible;\n",
+       "        left: auto;\n",
+       "        right: 0;\n",
+       "        border-bottom: solid 2px;\n",
+       "    }\n",
+       "    table.matreprtensor caption {\n",
+       "        white-space: pre;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > thead  {\n",
+       "        border: 0px;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "    table.matreprtensor > thead tr th {\n",
+       "        font-size: smaller;\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr td {\n",
+       "        vertical-align: middle;\n",
+       "        text-align: center;\n",
+       "        position: relative;\n",
+       "    }\n",
+       "    table.matreprtensor > tbody tr th:last-of-type {\n",
+       "        border-right: solid 2px;\n",
+       "    }\n",
+       "</style>\n",
+       "<table class=\"matreprmatrix\">\n",
+       "<caption>128×64, 3286 &#x27;torch.float32&#x27; elements, torch.sparse_csr</caption>\n",
+       "    <thead>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <th style=\"text-align: center;\">0</th>\n",
+       "        <th style=\"text-align: center;\">1</th>\n",
+       "        <th style=\"text-align: center;\">2</th>\n",
+       "        <th style=\"text-align: center;\">3</th>\n",
+       "        <th style=\"text-align: center;\">4</th>\n",
+       "        <th style=\"text-align: center;\">5</th>\n",
+       "        <th style=\"text-align: center;\"></th>\n",
+       "    </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "    <tr>\n",
+       "        <th>0</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6698</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.6196</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7489</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>1</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9144</td>\n",
+       "        <td style=\"text-align: center;\">0.7465</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8148</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>2</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8973</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>3</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9928</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>4</th>\n",
+       "        <td style=\"text-align: center;\">0.9618</td>\n",
+       "        <td style=\"text-align: center;\">0.6501</td>\n",
+       "        <td style=\"text-align: center;\">0.9263</td>\n",
+       "        <td style=\"text-align: center;\">0.844</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>5</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7552</td>\n",
+       "        <td style=\"text-align: center;\">0.7358</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.8429</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>6</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9857</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>7</th>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.7053</td>\n",
+       "        <td style=\"text-align: center;\">0.6431</td>\n",
+       "        <td style=\"text-align: center;\">0.9769</td>\n",
+       "        <td style=\"text-align: center;\">0.6682</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th>8</th>\n",
+       "        <td style=\"text-align: center;\">0.9278</td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\"></td>\n",
+       "        <td style=\"text-align: center;\">0.9216</td>\n",
+       "        <td style=\"text-align: center;\">0.9487</td>\n",
+       "        <td style=\"text-align: center;\">&ctdot;</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "        <th></th>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&vellip;</td>\n",
+       "        <td style=\"text-align: center;\">&dtdot;</td>\n",
+       "    </tr>\n",
+       "    </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "tensor(crow_indices=tensor([   0,   25,   53,   77,  101,  127,  149,  172,\n",
+       "                             203,  229,  258,  280,  307,  328,  354,  385,\n",
+       "                             412,  450,  474,  493,  524,  551,  581,  608,\n",
+       "                             630,  659,  690,  719,  748,  775,  795,  817,\n",
+       "                             844,  862,  884,  910,  934,  962,  996, 1024,\n",
+       "                            1048, 1081, 1105, 1134, 1161, 1192, 1230, 1253,\n",
+       "                            1277, 1298, 1332, 1357, 1392, 1423, 1445, 1476,\n",
+       "                            1511, 1533, 1552, 1576, 1605, 1629, 1652, 1676,\n",
+       "                            1708, 1730, 1758, 1783, 1804, 1821, 1847, 1878,\n",
+       "                            1903, 1932, 1959, 1985, 2018, 2039, 2063, 2086,\n",
+       "                            2113, 2134, 2157, 2173, 2199, 2218, 2241, 2269,\n",
+       "                            2300, 2321, 2342, 2368, 2389, 2418, 2436, 2464,\n",
+       "                            2493, 2519, 2542, 2568, 2588, 2612, 2642, 2668,\n",
+       "                            2692, 2717, 2739, 2759, 2791, 2813, 2837, 2858,\n",
+       "                            2877, 2902, 2932, 2955, 2981, 3003, 3025, 3051,\n",
+       "                            3078, 3103, 3135, 3160, 3184, 3212, 3236, 3263,\n",
+       "                            3286]),\n",
+       "       col_indices=tensor([ 1,  3,  5,  ..., 54, 55, 60]),\n",
+       "       values=tensor([0.6698, 0.6196, 0.7489,  ..., 0.6112, 0.7558, 0.6966]),\n",
+       "       size=(128, 64), nnz=3286, layout=torch.sparse_csr)"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rand2D_CSR"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "ExecuteTime": {
+     "end_time": "2023-09-06T22:42:27.378472Z",
+     "start_time": "2023-09-06T22:42:27.354045Z"
+    },
+    "collapsed": false,
+    "jupyter": {
+     "outputs_hidden": false
+    }
+   },
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "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.11.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/matrepr/__init__.py b/matrepr/__init__.py
index c200da0..ab3a0a9 100644
--- a/matrepr/__init__.py
+++ b/matrepr/__init__.py
@@ -7,9 +7,9 @@
 from shutil import get_terminal_size
 from typing import Any, Type, Callable, Dict, List, Union, Mapping, Optional
 
-from .adapters import Driver, MatrixAdapter
+from .adapters import Driver, MatrixAdapter, FallbackToNative
 from .html_formatter import HTMLTableFormatter, NotebookHTMLFormatter
-from .latex_formatter import LatexFormatter, python_scientific_to_latex_times10
+from .latex_formatter import LatexFormatter, python_scientific_to_latex_times10, tex_escape
 from matrepr.html import load_ipython_extension, unload_ipython_extension
 
 
@@ -194,6 +194,9 @@ def _register_bundled():
     from .adapters.numpy_driver import NumpyDriver
     register_driver(NumpyDriver)
 
+    from .adapters.torch_driver import PyTorchDriver
+    register_driver(PyTorchDriver)
+
     from .adapters.list_like import ListDriver
     register_driver(ListDriver)
 
@@ -226,7 +229,7 @@ def _get_adapter(mat: Any, options: Optional[MatReprParams], unsupported_raise=T
     return adapter
 
 
-def to_html(mat: Any, notebook=False, **kwargs) -> str:
+def to_html(mat: Any, notebook=False, fallback_to_None=False, **kwargs) -> str:
     """
     Render a matrix to HTML.
 
@@ -237,17 +240,26 @@ def to_html(mat: Any, notebook=False, **kwargs) -> str:
     :return: A string containing an HTML representation of `mat`.
     """
     options = params.get(**kwargs)
-    adapter = _get_adapter(mat, options)
 
-    if notebook:
-        formatter = NotebookHTMLFormatter(**options.to_kwargs())
-    else:
-        formatter = HTMLTableFormatter(**options.to_kwargs())
+    try:
+        adapter = _get_adapter(mat, options)
 
-    return str(formatter.format(adapter))
+        if notebook:
+            formatter = NotebookHTMLFormatter(**options.to_kwargs())
+        else:
+            formatter = HTMLTableFormatter(**options.to_kwargs())
+
+        return str(formatter.format(adapter))
+    except FallbackToNative:
+        if hasattr(mat, "_repr_html_"):
+            return getattr(mat, "_repr_html_")()
+        elif fallback_to_None:
+            return None
+        else:
+            return f"<pre>{str(mat)}</pre>"
 
 
-def to_latex(mat: Any, **kwargs):
+def to_latex(mat: Any, fallback_to_None=False, **kwargs):
     """
     Render a matrix to LaTeX.
 
@@ -257,11 +269,18 @@ def to_latex(mat: Any, **kwargs):
     :return: A string containing a LaTeX representation of `mat`.
     """
     options = params.get(**kwargs)
-    adapter = _get_adapter(mat, options)
-
-    formatter = LatexFormatter(**options.to_kwargs())
 
-    return str(formatter.format(adapter))
+    try:
+        adapter = _get_adapter(mat, options)
+        formatter = LatexFormatter(**options.to_kwargs())
+        return str(formatter.format(adapter))
+    except FallbackToNative:
+        if hasattr(mat, "_repr_latex_"):
+            return getattr(mat, "_repr_latex_")()
+        elif fallback_to_None:
+            return None
+        else:
+            return r"\texttt{" + tex_escape(str(mat)) + r"}"
 
 
 def to_str(mat: Any, **kwargs) -> str:
@@ -276,20 +295,22 @@ def to_str(mat: Any, **kwargs) -> str:
     """
     options = params.get(**kwargs)
 
-    ret = []
-
-    if options.title:
-        if options.title is True:
-            adapter = _get_adapter(mat, None)
-            title = f"<{adapter.describe()}>"
-        else:
-            title = options.title
-        ret.append(title)
-
-    from .string_formatter import to_tabulate
-    ret.append(to_tabulate(mat, **kwargs))
-
-    return "\n".join(ret)
+    try:
+        ret = []
+
+        if options.title:
+            if options.title is True:
+                adapter = _get_adapter(mat, None)
+                title = f"<{adapter.describe()}>"
+            else:
+                title = options.title
+            ret.append(title)
+
+        from .string_formatter import to_tabulate
+        ret.append(to_tabulate(mat, **kwargs))
+        return "\n".join(ret)
+    except FallbackToNative:
+        return str(mat)
 
 
 def mprint(mat: Any, **kwargs):
diff --git a/matrepr/adapters/__init__.py b/matrepr/adapters/__init__.py
index 868a824..e13176b 100644
--- a/matrepr/adapters/__init__.py
+++ b/matrepr/adapters/__init__.py
@@ -22,6 +22,8 @@ def describe(shape: tuple = None, nnz: int = None, nz_type=None, layout: str = N
     if nnz is not None:
         dtype_str = f" '{str(nz_type)}'" if nz_type else ""
         parts.append(f"{nnz}{dtype_str} elements")
+    elif nz_type is not None:
+        parts.append(f"'{nz_type}' elements")
 
     if layout is not None:
         parts.append(str(layout))
@@ -42,6 +44,10 @@ def __init__(self, iterable):
         super().__init__(iterable)
 
 
+class FallbackToNative(Exception):
+    """Thrown if the native repr method should be used."""
+
+
 class MatrixAdapter(ABC):
     def __init__(self):
         self.row_labels: Union[Mapping[int, Any], bool] = True
@@ -434,9 +440,9 @@ def to_trunc(mat: MatrixAdapter, max_rows, max_cols, num_after_dots) -> Truncate
     if len(shape) == 1:
         # vector
         nrows = 1
-        ncols = mat.get_shape()[0]
+        ncols = shape[0]
     elif len(shape) == 2:
-        nrows, ncols = mat.get_shape()
+        nrows, ncols = shape
         max_rows = min(max_rows, nrows)
         max_cols = min(max_cols, ncols)
     else:
@@ -515,6 +521,8 @@ def to_trunc(mat: MatrixAdapter, max_rows, max_cols, num_after_dots) -> Truncate
                 continue
 
             for col_range in [(0, pre_dot_end), (post_dot_start, ncols)]:
+                if col_range[0] == col_range[1]:
+                    continue
                 for col_idx, value in mat.get_row(row_idx, col_range=col_range):
                     trunc.set(row_idx, col_idx, value)
         return trunc
@@ -536,6 +544,8 @@ def to_trunc(mat: MatrixAdapter, max_rows, max_cols, num_after_dots) -> Truncate
                 continue
 
             for row_range in [(0, pre_dot_end), (post_dot_start, nrows)]:
+                if row_range[0] == row_range[1]:
+                    continue
                 for row_idx, value in mat.get_col(col_idx, row_range=row_range):
                     trunc.set(row_idx, col_idx, value)
         return trunc
diff --git a/matrepr/adapters/torch_driver.py b/matrepr/adapters/torch_driver.py
new file mode 100644
index 0000000..453b047
--- /dev/null
+++ b/matrepr/adapters/torch_driver.py
@@ -0,0 +1,64 @@
+# Copyright (C) 2023 Adam Lugowski.
+# Use of this source code is governed by the BSD 2-clause license found in the LICENSE.txt file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+from typing import Any, Iterable, Tuple
+
+from . import Driver
+
+
+class PyTorchDriver(Driver):
+    @staticmethod
+    def get_supported_types() -> Iterable[Tuple[str, bool]]:
+        return [
+            ("torch.Tensor", True),
+        ]
+
+    @staticmethod
+    def adapt(tensor: Any):
+        import torch
+        from . import FallbackToNative
+        from .torch_impl import PyTorch1DTensorAdapter, PyTorchFallbackAdapter
+        from .torch_impl import PyTorch2DTensorDenseAdapter, PyTorch2DTensorCooAdapter
+        from .torch_impl import PyTorch2DTensorCSRAdapter, PyTorch2DTensorCSCAdapter
+        from .torch_impl import PyTorchNDTensorCooAdapter
+
+        sparse_layouts = [
+            torch.sparse_coo,
+            torch.sparse_csr,
+            torch.sparse_csc,
+            torch.sparse_bsr,
+            torch.sparse_bsc,
+        ]
+
+        # test layouts because it's possible to have is_sparse == False and is_sparse_csr == True
+        is_sparse = tensor.is_sparse or tensor.layout in sparse_layouts
+        ndims = len(tensor.shape)
+
+        batchsize = tensor.shape[:-tensor.sparse_dim() - tensor.dense_dim()]
+        if len(batchsize) != 0:
+            # batches not supported yet
+            return PyTorchFallbackAdapter(tensor)
+
+        try:
+            if ndims == 0:
+                # single value
+                return PyTorchFallbackAdapter(tensor)
+            elif ndims == 1:
+                return PyTorch1DTensorAdapter(tensor)
+            elif tensor.layout == torch.sparse_csr:
+                return PyTorch2DTensorCSRAdapter(tensor)
+            elif tensor.layout == torch.sparse_csc:
+                return PyTorch2DTensorCSCAdapter(tensor)
+            elif ndims == 2:
+                if is_sparse:
+                    return PyTorch2DTensorCooAdapter(tensor)
+                else:
+                    return PyTorch2DTensorDenseAdapter(tensor)
+            else:  # ndims > 2
+                if is_sparse:
+                    return PyTorchNDTensorCooAdapter(tensor)
+        except FallbackToNative:
+            pass
+
+        return PyTorchFallbackAdapter(tensor)
diff --git a/matrepr/adapters/torch_impl.py b/matrepr/adapters/torch_impl.py
new file mode 100644
index 0000000..2ce2f9b
--- /dev/null
+++ b/matrepr/adapters/torch_impl.py
@@ -0,0 +1,186 @@
+# Copyright (C) 2023 Adam Lugowski.
+# Use of this source code is governed by the BSD 2-clause license found in the LICENSE.txt file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+from typing import Any, Iterable, Tuple
+
+import torch
+
+from . import describe, FallbackToNative, MatrixAdapterRow, MatrixAdapterCol, MatrixAdapterCoo, TensorAdapterCooRow
+
+
+class PyTorchBase:
+    def __init__(self, tensor: torch.Tensor):
+        self.tensor: torch.Tensor = tensor
+
+    def get_shape(self) -> tuple:
+        return tuple(self.tensor.shape)
+
+    def describe(self) -> str:
+        parts = []
+
+        try:
+            get_nnz = getattr(self.tensor, "_nnz", None)
+            nnz = get_nnz() if get_nnz else None
+        except NotImplementedError:
+            nnz = None
+
+        return describe(shape=tuple(self.tensor.shape),
+                        nnz=nnz, nz_type=self.tensor.dtype,
+                        layout=self.tensor.layout,
+                        notes=", ".join(parts))
+
+
+class PyTorchFallbackAdapter(PyTorchBase, MatrixAdapterRow):
+    def __init__(self, tensor):
+        MatrixAdapterRow.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+
+    def get_shape(self) -> tuple:
+        return (1, )
+
+    def get_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        raise FallbackToNative
+
+
+class PyTorch1DTensorAdapter(PyTorchBase, MatrixAdapterRow):
+    def __init__(self, tensor: torch.Tensor):
+        assert len(tensor.shape) <= 1
+        MatrixAdapterRow.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+        self.row_labels = False
+        self.coo: torch.Tensor = tensor.to_sparse_coo() if tensor.is_sparse else None
+
+    def get_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        assert row_idx == 0
+
+        if not self.tensor.is_sparse:
+            # dense
+            return enumerate([v.item() for v in self.tensor[slice(*col_range)]], start=col_range[0])
+
+        indices = self.coo.indices()
+        values = self.coo.values()
+        mask = (col_range[0] <= indices) & (indices < col_range[1])
+        return [(i.item(), v.item()) for i, v in zip(indices[mask], values[mask.reshape(len(values),)])]
+
+
+class PyTorch2DTensorDenseAdapter(PyTorchBase, MatrixAdapterRow):
+    def __init__(self, tensor: torch.Tensor):
+        assert len(tensor.shape) == 2 and not tensor.is_sparse
+        MatrixAdapterRow.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+
+    def get_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        return enumerate([v.item() for v in self.tensor[row_idx, slice(*col_range)]], start=col_range[0])
+
+
+class PyTorch2DTensorCSRAdapter(PyTorchBase, MatrixAdapterRow):
+    def __init__(self, tensor: torch.Tensor):
+        assert tensor.layout == torch.sparse_csr
+        batchsize = tensor.shape[:-tensor.sparse_dim() - tensor.dense_dim()]
+        if len(batchsize) > 0:
+            # batches not supported yet
+            # see also https://github.com/pytorch/pytorch/issues/107478
+            raise FallbackToNative
+        assert len(tensor.shape) == 2
+
+        MatrixAdapterRow.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+        self.indptr = tensor.crow_indices()
+        self.indices = tensor.col_indices()
+        self.values = tensor.values()
+
+    def get_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        return [
+            (self.indices[i].item(), self.values[i].item())
+            for i in range(self.indptr[row_idx], self.indptr[row_idx + 1])
+            if col_range[0] <= self.indices[i] < col_range[1]
+        ]
+
+
+class PyTorch2DTensorCSCAdapter(PyTorchBase, MatrixAdapterCol):
+    def __init__(self, tensor: torch.Tensor):
+        assert tensor.layout == torch.sparse_csc
+        batchsize = tensor.shape[:-tensor.sparse_dim() - tensor.dense_dim()]
+        if len(batchsize) > 0:
+            # batches not supported yet
+            raise FallbackToNative
+        assert len(tensor.shape) == 2
+
+        MatrixAdapterCol.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+        self.indptr = tensor.ccol_indices()
+        self.indices = tensor.row_indices()
+        self.values = tensor.values()
+
+    def get_col(self, col_idx: int, row_range: Tuple[int, int]) -> Iterable[Tuple[int, Any]]:
+        return [
+            (self.indices[i].item(), self.values[i].item())
+            for i in range(self.indptr[col_idx], self.indptr[col_idx + 1])
+            if row_range[0] <= self.indices[i] < row_range[1]
+        ]
+
+
+class PyTorch2DTensorCooAdapter(PyTorchBase, MatrixAdapterCoo):
+    def __init__(self, tensor: torch.Tensor):
+        assert len(tensor.shape) == 2
+        MatrixAdapterCoo.__init__(self)
+        PyTorchBase.__init__(self, tensor)
+        self.coo: torch.Tensor = tensor.to_sparse_coo()
+        self.coo = self.coo.coalesce()
+
+    def get_coo(self, row_range: Tuple[int, int], col_range: Tuple[int, int]) -> Iterable[Tuple[int, int, Any]]:
+        rows, cols = self.coo.indices()
+        values = self.coo.values()
+        row_mask = (row_range[0] <= rows) & (rows < row_range[1])
+        col_mask = (col_range[0] <= cols) & (cols < col_range[1])
+        mask = row_mask & col_mask
+        return [(r.item(), c.item(), v.item())
+                for r, c, v in zip(rows[mask], cols[mask], values[mask])]
+
+
+class PyTorchNDTensorDenseAdapter(PyTorchBase, TensorAdapterCooRow):
+    def __init__(self, tensor):
+        PyTorchBase.__init__(self, tensor)
+        TensorAdapterCooRow.__init__(self)
+        self.nnz = sum(tuple(tensor.shape))
+        self.ndim = len(tensor.shape)
+
+    def get_shape(self) -> tuple:
+        return self.nnz, self.ndim+1
+
+    def get_dense_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        ret = self.coo.coords[:, row_idx]
+        ret = list(ret) + [self.coo.data[row_idx]]
+        return ret[slice(*col_range)]
+
+
+class PyTorchNDTensorCooAdapter(PyTorchBase, TensorAdapterCooRow):
+    def __init__(self, tensor):
+        self.ndim = len(tensor.shape)
+        self.nsparsedim = tensor.sparse_dim()
+        try:
+            # noinspection PyProtectedMember
+            self.nnz = tensor._nnz()
+        except (NotImplementedError, AttributeError):
+            raise FallbackToNative
+
+        PyTorchBase.__init__(self, tensor)
+        TensorAdapterCooRow.__init__(self)
+        self.coo = tensor.to_sparse_coo()
+
+    def get_shape(self) -> tuple:
+        return self.nnz, self.nsparsedim+1
+
+    def get_dense_row(self, row_idx: int, col_range: Tuple[int, int]) -> Iterable[Any]:
+        indices = self.coo.indices()
+        end = min(col_range[1], self.nsparsedim)
+        ret = [indices[i][row_idx].item() for i in range(col_range[0], end)]
+
+        if col_range[1] == self.nsparsedim + 1:
+            value = self.coo.values()[row_idx]
+            if self.ndim == self.nsparsedim:
+                value = value.item()
+            ret.append(value)
+
+        return ret
diff --git a/matrepr/html.py b/matrepr/html.py
index 3820192..4c40c60 100644
--- a/matrepr/html.py
+++ b/matrepr/html.py
@@ -12,7 +12,7 @@
 
 def _repr_html_(mat):
     from . import to_html
-    return to_html(mat, notebook=True)
+    return to_html(mat, notebook=True, fallback_to_None=True)
 
 
 def load_ipython_extension(ipython):
diff --git a/matrepr/html_formatter.py b/matrepr/html_formatter.py
index a9d66a4..44b577c 100644
--- a/matrepr/html_formatter.py
+++ b/matrepr/html_formatter.py
@@ -225,6 +225,7 @@ def _write_style(self, matrix_class: str, tensor_class: str):
 
             # tensor styles
             (tensor + "caption", {"white-space": "pre", "text-align": "center"}),  # title
+            (tenhead, {"border": "0px"}),
             (tenbody + "tr th", {**index_attributes, "text-align": "right"}),  # row indices
             (tenhead + "tr th", {**index_attributes, "text-align": "center"}),  # column indices
             (tenbody + "tr td", {"vertical-align": "middle", "text-align": self.cell_align, "position": "relative"}),
diff --git a/matrepr/latex.py b/matrepr/latex.py
index f9ba305..7c4bd8f 100644
--- a/matrepr/latex.py
+++ b/matrepr/latex.py
@@ -12,7 +12,7 @@
 
 
 def _repr_latex_(mat):
-    return to_latex(mat)
+    return to_latex(mat, fallback_to_None=True)
 
 
 def load_ipython_extension(ipython):
diff --git a/matrepr/latex_formatter.py b/matrepr/latex_formatter.py
index d44df3c..81292c7 100644
--- a/matrepr/latex_formatter.py
+++ b/matrepr/latex_formatter.py
@@ -73,7 +73,7 @@ def pprint(self, obj, is_index=False):
                 obj = self.fill_value
 
         if is_index and isinstance(obj, int):
-            return int(obj)
+            return str(obj)
 
         if isinstance(obj, (int, float)):
             return self.floatfmt(obj)
diff --git a/pyproject.toml b/pyproject.toml
index 3323d1d..df4808d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,6 +22,7 @@ classifiers = [
 
 keywords = [
     "matrix",
+    "tensor",
     "sparse",
     "html",
     "latex",
@@ -39,4 +40,4 @@ repository = "https://github.com/alugowski/matrepr"
 
 [project.optional-dependencies]
 test = ["pytest", "html5lib", "scipy"]
-supported = ["scipy", "numpy", "python-graphblas", "sparse"]
+supported = ["scipy", "numpy", "python-graphblas", "sparse", "torch"]


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 9b35138..6a7d9a2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -35,16 +35,13 @@ jobs:
       if: ${{ !contains(matrix.python-version, 'pypy') }}  # no scipy wheels for pypy
       run: pytest
 
-    - name: Install python-graphblas
+    - name: Install other supported packages
       if: ${{ !contains(matrix.python-version, 'pypy') && matrix.python-version != '3.7' }}  # no wheels for pypy and old python
       run: |
         pip install suitesparse-graphblas==7.4.4.1a1
         pip install python-graphblas
-
-    - name: Install pydata sparse
-      if: ${{ !contains(matrix.python-version, 'pypy') && matrix.python-version != '3.7' }}  # no wheels for pypy and old python
-      run: |
         pip install sparse
+        pip install torch
 
     - name: Python Test without Jupyter
       if: ${{ !contains(matrix.python-version, 'pypy') }}  # no scipy wheels for pypy
diff --git a/tests/test_torch.py b/tests/test_torch.py
new file mode 100644
index 0000000..e381112
--- /dev/null
+++ b/tests/test_torch.py
@@ -0,0 +1,107 @@
+# Copyright (C) 2023 Adam Lugowski.
+# Use of this source code is governed by the BSD 2-clause license found in the LICENSE.txt file.
+# SPDX-License-Identifier: BSD-2-Clause
+
+import unittest
+
+import numpy as np
+
+try:
+    import torch
+except ImportError:
+    torch = None
+
+from matrepr import to_html, to_latex, to_str
+
+np.random.seed(123)
+
+
+def generate_fixed_value(m, n):
+    row_factor = 10**(1+len(str(n)))
+    data = []
+    for r in range(m):
+        data.append([1] * n)
+        for c in range(n):
+            data[r][c] = (r+1)*row_factor + c
+
+    return torch.tensor(data, dtype=torch.int64), data
+
+
+@unittest.skipIf(torch is None, "PyTorch not installed")
+class PyTorchTests(unittest.TestCase):
+    def setUp(self):
+        rand2d = torch.rand(50, 30)
+        self.rand2d = rand2d[rand2d < 0.6] = 0
+
+        rand3d = torch.rand(50, 30, 10)
+        self.rand3d = rand3d[rand3d < 0.6] = 0
+
+        self.tensors = [
+            (True, torch.tensor(5)),
+            (False, torch.tensor([])),
+            (False, torch.tensor([1, 2, 3, 4])),
+            (False, torch.tensor([[1, 2], [1003, 1004]])),
+            (False, torch.tensor([[1, 2], [1003, 1004]]).to_sparse_coo()),
+            (False, torch.tensor([[1, 2], [1003, 1004]]).to_sparse_csr()),
+            (False, rand2d),
+            (False, rand2d.to_sparse_coo()),
+            (True, rand3d),
+            (False, rand3d.to_sparse_coo()),
+            (True, torch.tensor([[[0., 0], [1., 2.]], [[0., 0], [3., 4.]]]).to_sparse(2)),
+        ]
+
+    def test_no_crash(self):
+        for fallback_ok, tensor in self.tensors:
+            res = to_str(tensor, title=True)
+            self.assertGreater(len(res), 5)
+
+            res = to_html(tensor, title=True)
+            self.assertGreater(len(res), 5)
+            if not fallback_ok:
+                self.assertNotIn("<pre>", res)
+
+            res = to_latex(tensor, title=True)
+            self.assertGreater(len(res), 5)
+
+    def test_2d_formats(self):
+        to_html_args = dict(notebook=False, max_rows=20, max_cols=20, title=False)
+
+        expected = [to_html(t.to_sparse_coo(), **to_html_args) for _, t in self.tensors]
+
+        for converter in ["to_sparse_coo", "to_sparse_csr", "to_sparse_csc", "to_sparse_bsr", "to_sparse_bsc"]:
+            for i, (flag, source_tensor) in enumerate(self.tensors):
+                if flag or len(source_tensor.shape) != 2:
+                    continue
+
+                if "_bs" in converter:
+                    if source_tensor.shape[0] > 10:
+                        # The block-compressed tensor formats may have explicit zeros that COO and CSC/CSR won't.
+                        # The smaller sample problems don't run into this, so skip the bigger ones.
+                        continue
+                    tensor = getattr(source_tensor, converter)(blocksize=2)
+                else:
+                    tensor = getattr(source_tensor, converter)()
+                res = to_html(tensor, **to_html_args)
+                self.assertEqual(expected[i], res)
+
+    def test_contents_2d(self):
+        source_tensor, data = generate_fixed_value(8, 8)
+        for converter in ["to_dense", "to_sparse_coo", "to_sparse_csr", "to_sparse_csc",
+                          "to_sparse_bsr", "to_sparse_bsc"]:
+            if "_bs" in converter:
+                tensor = getattr(source_tensor, converter)(blocksize=2)
+            else:
+                tensor = getattr(source_tensor, converter)()
+
+            res = to_html(tensor, notebook=False, max_rows=20, max_cols=20, title=True, indices=True)
+            for row in data:
+                for value in row:
+                    self.assertIn(f"<td>{value}</td>", res)
+
+            trunc = to_html(tensor, notebook=False, max_rows=5, max_cols=5, title=True, indices=True)
+            for value in (data[0][0], data[0][-1], data[-1][0], data[-1][-1]):
+                self.assertIn(f"<td>{value}</td>", trunc)
+
+
+if __name__ == '__main__':
+    unittest.main()