{ "cells": [ { "cell_type": "markdown", "id": "b910d945", "metadata": {}, "source": [ "# Trace Optimization\n", "\n", "Trace optimization with orthogonal constraints taken from: Effrosini Kokiopoulou, Jie Chen, and Yousef Saad. \"Trace optimization and eigenproblems in dimension reduction methods.\" Numerical Linear Algebra with Applications 18.3 (2011): 565-602." ] }, { "cell_type": "markdown", "id": "13b5ad66", "metadata": {}, "source": [ "## Problem Description\n", "Given a symmetric matrix $A$ of dimension $n\\times n$, and an arbitrary unitary matrix $V$ of dimension $n\\times d$. \n", "\n", "The trace of $V^TAV$ is maximized when $V$ is an orthogonal basis of the eigenspace associated with the (algebraically) largest eigenvalues.\n", "\n", "If eigenvalues are labeled decreasingly and $u_1,...,u_d$ are eigenvectors associated with the first $d$ eigenvalues $\\lambda_1,...,\\lambda_d$, and $U = [u_1,...,u_d]$ with $U^TU=I$, then,\n", "\n", "$$\\max_{V \\in R^{n\\times d}, V^TV=I} \\text{Tr}[V^TAV]=\\text{Tr}[U^TAU]=\\lambda_1+...+\\lambda_d$$\n" ] }, { "cell_type": "markdown", "id": "73483897", "metadata": {}, "source": [ "## Modules Importing\n", "Import all necessary modules and add PyGRANSO src folder to system path." ] }, { "cell_type": "code", "execution_count": 1, "id": "ae68ad56", "metadata": {}, "outputs": [], "source": [ "import time\n", "import torch\n", "import sys\n", "## Adding PyGRANSO directories. Should be modified by user\n", "sys.path.append('/home/buyun/Documents/GitHub/PyGRANSO')\n", "from pygranso.pygranso import pygranso\n", "from pygranso.pygransoStruct import pygransoStruct" ] }, { "cell_type": "markdown", "id": "d3713c13", "metadata": {}, "source": [ "## Data Initialization \n", "Specify torch device, and generate data\n", "\n", "Use GPU for this problem. If no cuda device available, please set *device = torch.device('cpu')*" ] }, { "cell_type": "code", "execution_count": 2, "id": "f80d015b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_894447/3523941836.py:11: UserWarning: Casting complex values to real discards the imaginary part (Triggered internally at /opt/conda/conda-bld/pytorch_1623448255797/work/aten/src/ATen/native/Copy.cpp:240.)\n", " L, U = L.to(dtype=torch.double), U.to(dtype=torch.double)\n" ] } ], "source": [ "device = torch.device('cuda')\n", "n = 5\n", "d = 1\n", "torch.manual_seed(0)\n", "# All the user-provided data (vector/matrix/tensor) must be in torch tensor format.\n", "# As PyTorch tensor is single precision by default, one must explicitly set `dtype=torch.double`.\n", "# Also, please make sure the device of provided torch tensor is the same as opts.torch_device.\n", "A = torch.randn(n,n).to(device=device, dtype=torch.double)\n", "A = (A + A.T)/2\n", "L, U = torch.linalg.eig(A)\n", "L, U = L.to(dtype=torch.double), U.to(dtype=torch.double) \n", "index = torch.argsort(L,descending=True)\n", "U = U[:,index[0:d]]" ] }, { "cell_type": "markdown", "id": "174aa2e7", "metadata": {}, "source": [ "## Function Set-Up\n", "\n", "Encode the optimization variables, and objective and constraint functions.\n", "\n", "Note: please strictly follow the format of comb_fn, which will be used in the PyGRANSO main algortihm." ] }, { "cell_type": "code", "execution_count": 3, "id": "76877185", "metadata": {}, "outputs": [], "source": [ "# variables and corresponding dimensions.\n", "var_in = {\"V\": [n,d]}\n", "\n", "def user_fn(X_struct,A,d):\n", " V = X_struct.V\n", "\n", " # objective function\n", " f = -torch.trace(V.T@A@V)\n", "\n", " # inequality constraint, matrix form\n", " ci = None\n", "\n", " # equality constraint\n", " ce = pygransoStruct()\n", " ce.c1 = V.T@V - torch.eye(d).to(device=device, dtype=torch.double)\n", "\n", " return [f,ci,ce]\n", "\n", "comb_fn = lambda X_struct : user_fn(X_struct,A,d)" ] }, { "cell_type": "markdown", "id": "2b21c2ec", "metadata": {}, "source": [ "## User Options\n", "Specify user-defined options for PyGRANSO" ] }, { "cell_type": "code", "execution_count": 4, "id": "54137e9f", "metadata": {}, "outputs": [], "source": [ "opts = pygransoStruct()\n", "opts.torch_device = device\n", "opts.print_frequency = 1\n", "# opts.opt_tol = 1e-7\n", "opts.maxit = 3000\n", "# opts.mu0 = 10\n", "# opts.steering_c_viol = 0.02" ] }, { "cell_type": "markdown", "id": "be9ba1d7", "metadata": {}, "source": [ "## Main Algorithm" ] }, { "cell_type": "code", "execution_count": 5, "id": "8ce3b204", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[33m╔═════ QP SOLVER NOTICE ════════════════════════════════════════════════════════════════════════╗\n", "\u001b[0m\u001b[33m║ PyGRANSO requires a quadratic program (QP) solver that has a quadprog-compatible interface, ║\n", "\u001b[0m\u001b[33m║ the default is osqp. Users may provide their own wrapper for the QP solver. ║\n", "\u001b[0m\u001b[33m║ To disable this notice, set opts.quadprog_info_msg = False ║\n", "\u001b[0m\u001b[33m╚═══════════════════════════════════════════════════════════════════════════════════════════════╝\n", "\u001b[0m═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n", "PyGRANSO: A PyTorch-enabled port of GRANSO with auto-differentiation ║ \n", "Version 1.2.0 ║ \n", "Licensed under the AGPLv3, Copyright (C) 2021-2022 Tim Mitchell and Buyun Liang ║ \n", "═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n", "Problem specifications: ║ \n", " # of variables : 5 ║ \n", " # of inequality constraints : 0 ║ \n", " # of equality constraints : 1 ║ \n", "═════╦═══════════════════════════╦════════════════╦═════════════════╦═══════════════════════╦════════════════════╣\n", " ║ <--- Penalty Function --> ║ ║ Total Violation ║ <--- Line Search ---> ║ <- Stationarity -> ║ \n", "Iter ║ Mu │ Value ║ Objective ║ Ineq │ Eq ║ SD │ Evals │ t ║ Grads │ Value ║ \n", "═════╬═══════════════════════════╬════════════════╬═════════════════╬═══════════════════════╬════════════════════╣\n", " 0 ║ 1.000000 │ 1.16724813601 ║ -2.14592113443 ║ - │ 3.313169 ║ - │ 1 │ 0.000000 ║ 1 │ 4.801284 ║ \n", " 1 ║ 1.000000 │ -4.18220640118 ║ -27.2345373313 ║ - │ 23.05233 ║ S │ 1 │ 1.000000 ║ 1 │ 19.60748 ║ \n", " 2 ║ 0.810000 │ -7.44513089341 ║ -25.7524524611 ║ - │ 13.41436 ║ S │ 1 │ 1.000000 ║ 1 │ 2.119321 ║ \n", " 3 ║ 0.478297 │ -3.36403570563 ║ -29.7615131867 ║ - │ 10.87080 ║ S │ 1 │ 1.000000 ║ 1 │ 0.807332 ║ \n", " 4 ║ 0.313811 │ 0.44260646755 ║ -29.8199400438 ║ - │ 9.800420 ║ S │ 1 │ 1.000000 ║ 1 │ 0.181373 ║ \n", " 5 ║ 0.313811 │ -0.05159283053 ║ -25.9178254403 ║ - │ 8.081695 ║ S │ 2 │ 2.000000 ║ 1 │ 0.266675 ║ \n", " 6 ║ 0.313811 │ -0.60015959521 ║ -19.8021105233 ║ - │ 5.613953 ║ S │ 2 │ 2.000000 ║ 1 │ 0.129813 ║ \n", " 7 ║ 0.313811 │ -0.74007491793 ║ -15.7240418418 ║ - │ 4.194296 ║ S │ 1 │ 1.000000 ║ 1 │ 0.073206 ║ \n", " 8 ║ 0.313811 │ -0.80534295483 ║ -10.5540665925 ║ - │ 2.506635 ║ S │ 3 │ 4.000000 ║ 1 │ 0.096243 ║ \n", " 9 ║ 0.313811 │ -0.90562463200 ║ -3.96127832617 ║ - │ 0.337466 ║ S │ 3 │ 1.500000 ║ 1 │ 0.109112 ║ \n", " 10 ║ 0.313811 │ -0.94306331782 ║ -3.09440966016 ║ - │ 0.027995 ║ S │ 1 │ 1.000000 ║ 1 │ 0.036484 ║ \n", " 11 ║ 0.313811 │ -0.95168907673 ║ -3.04557834593 ║ - │ 0.004046 ║ S │ 1 │ 1.000000 ║ 1 │ 0.016092 ║ \n", " 12 ║ 0.313811 │ -0.95404206443 ║ -3.04284283001 ║ - │ 8.34e-04 ║ S │ 1 │ 1.000000 ║ 1 │ 0.010167 ║ \n", " 13 ║ 0.313811 │ -0.95488755011 ║ -3.04425497591 ║ - │ 4.32e-04 ║ S │ 1 │ 1.000000 ║ 1 │ 0.003923 ║ \n", " 14 ║ 0.313811 │ -0.95497194333 ║ -3.04323398616 ║ - │ 2.71e-05 ║ S │ 1 │ 1.000000 ║ 1 │ 0.001371 ║ \n", " 15 ║ 0.313811 │ -0.95498874787 ║ -3.04321724294 ║ - │ 5.07e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 8.65e-04 ║ \n", " 16 ║ 0.313811 │ -0.95499959494 ║ -3.04325102043 ║ - │ 4.82e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 6.98e-04 ║ \n", " 17 ║ 0.313811 │ -0.95500308923 ║ -3.04325221318 ║ - │ 1.70e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 3.20e-04 ║ \n", " 18 ║ 0.313811 │ -0.95500354042 ║ -3.04324890133 ║ - │ 2.11e-07 ║ S │ 1 │ 1.000000 ║ 1 │ 8.22e-05 ║ \n", " 19 ║ 0.313811 │ -0.95500356428 ║ -3.04324833552 ║ - │ 9.93e-09 ║ S │ 1 │ 1.000000 ║ 2 │ 2.46e-05 ║ \n", "═════╬═══════════════════════════╬════════════════╬═════════════════╬═══════════════════════╬════════════════════╣\n", " ║ <--- Penalty Function --> ║ ║ Total Violation ║ <--- Line Search ---> ║ <- Stationarity -> ║ \n", "Iter ║ Mu │ Value ║ Objective ║ Ineq │ Eq ║ SD │ Evals │ t ║ Grads │ Value ║ \n", "═════╬═══════════════════════════╬════════════════╬═════════════════╬═══════════════════════╬════════════════════╣\n", " 20 ║ 0.313811 │ -0.95500356476 ║ -3.04324830572 ║ - │ 1.06e-10 ║ S │ 7 │ 1.031250 ║ 2 │ 7.11e-06 ║ \n", " 21 ║ 0.282430 │ -0.85950320836 ║ -3.04324830605 ║ - │ 1.11e-10 ║ S │ 1 │ 1.000000 ║ 3 │ 1.92e-06 ║ \n", " 22 ║ 0.282430 │ -0.85950320837 ║ -3.04324830571 ║ - │ 8.61e-12 ║ S │ 5 │ 1.125000 ║ 4 │ 2.38e-07 ║ \n", " 23 ║ 0.282430 │ -0.85950320837 ║ -3.04324830572 ║ - │ 8.20e-12 ║ S │ 3 │ 0.250000 ║ 5 │ 6.46e-07 ║ \n", " 24 ║ 0.282430 │ -0.85950320837 ║ -3.04324830570 ║ - │ 4.19e-13 ║ S │ 6 │ 1.062500 ║ 6 │ 7.63e-05 ║ \n", " 25 ║ 0.282430 │ -0.85950320837 ║ -3.04324830570 ║ - │ 6.05e-13 ║ S │ 11 │ 9.77e-04 ║ 7 │ 0.001019 ║ \n", " 26 ║ 0.282430 │ -0.85950320837 ║ -3.04324830570 ║ - │ 8.78e-13 ║ S │ 2 │ 0.500000 ║ 8 │ 1.00e-06 ║ \n", " 27 ║ 0.282430 │ -0.85950320845 ║ -3.04324830625 ║ - │ 7.90e-11 ║ \u001b[33mSI\u001b[0m │ 2 │ 0.500000 ║ 9 │ 2.12e-07 ║ \n", " 28 ║ 0.282430 │ -0.85950320845 ║ -3.04324830631 ║ - │ 9.62e-11 ║ S │ 3 │ 0.250000 ║ 10 │ 9.83e-07 ║ \n", " 29 ║ 0.282430 │ -0.85950320845 ║ -3.04324830634 ║ - │ 1.03e-10 ║ S │ 4 │ 0.125000 ║ 10 │ 5.25e-06 ║ \n", " 30 ║ 0.282430 │ -0.85950320845 ║ -3.04324830635 ║ - │ 1.07e-10 ║ S │ 5 │ 0.062500 ║ 10 │ 5.19e-06 ║ \n", " 31 ║ 0.282430 │ -0.85950320845 ║ -3.04324830635 ║ - │ 1.08e-10 ║ S │ 7 │ 0.015625 ║ 10 │ 5.37e-06 ║ \n", "═════╩═══════════════════════════╩════════════════╩═════════════════╩═══════════════════════╩════════════════════╣\n", "F = final iterate, B = Best (to tolerance), MF = Most Feasible ║ \n", "Optimization results: ║ \n", "═════╦═══════════════════════════╦════════════════╦═════════════════╦═══════════════════════╦════════════════════╣\n", " F ║ │ ║ -3.04324830635 ║ - │ 1.08e-10 ║ │ │ ║ │ ║ \n", " B ║ │ ║ -3.04324890133 ║ - │ 2.11e-07 ║ │ │ ║ │ ║ \n", " MF ║ │ ║ -3.04324830570 ║ - │ 8.44e-14 ║ │ │ ║ │ ║ \n", "═════╩═══════════════════════════╩════════════════╩═════════════════╩═══════════════════════╩════════════════════╣\n", "Iterations: 31 ║ \n", "Function evaluations: 105 ║ \n", "PyGRANSO termination code: 6 --- line search bracketed a minimizer but failed to satisfy Wolfe conditions at a ║ \n", "feasible point (to tolerances). This may be an indication that approximate stationarity has been attained. ║ \n", "═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝\n", "Total Wall Time: 1.0528507232666016s\n", "torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T) = 3.772472601724718e-06\n", "torch.trace(V.T@A@V) = 3.0432483063508395\n", "torch.trace(U.T@A@U) = 3.0432483060418907\n", "sum of first d eigvals = 3.04324830604189\n", "sorted eigs = tensor([ 3.0432, 0.8890, -0.4730, -0.9598, -1.8722], device='cuda:0',\n", " dtype=torch.float64)\n" ] } ], "source": [ "start = time.time()\n", "soln = pygranso(var_spec = var_in,combined_fn = comb_fn,user_opts = opts)\n", "end = time.time()\n", "print(\"Total Wall Time: {}s\".format(end - start))\n", "\n", "V = torch.reshape(soln.final.x,(n,d))\n", "\n", "rel_dist = torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T)\n", "print(\"torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T) = {}\".format(rel_dist))\n", "\n", "print(\"torch.trace(V.T@A@V) = {}\".format(torch.trace(V.T@A@V)))\n", "print(\"torch.trace(U.T@A@U) = {}\".format(torch.trace(U.T@A@U)))\n", "print(\"sum of first d eigvals = {}\".format(torch.sum(L[index[0:d]])))\n", "print(\"sorted eigs = {}\".format(L[index]))" ] }, { "cell_type": "markdown", "id": "f1c12544", "metadata": {}, "source": [ "## More Constraints\n", "**(Optional)** Exploring the pygranso performance on different number of constraints" ] }, { "cell_type": "code", "execution_count": 6, "id": "2945a9bb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "\u001b[33m╔═════ QP SOLVER NOTICE ════════════════════════════════════════════════════════════════════════╗\n", "\u001b[0m\u001b[33m║ PyGRANSO requires a quadratic program (QP) solver that has a quadprog-compatible interface, ║\n", "\u001b[0m\u001b[33m║ the default is osqp. Users may provide their own wrapper for the QP solver. ║\n", "\u001b[0m\u001b[33m║ To disable this notice, set opts.quadprog_info_msg = False ║\n", "\u001b[0m\u001b[33m╚═══════════════════════════════════════════════════════════════════════════════════════════════╝\n", "\u001b[0m═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗\n", "PyGRANSO: A PyTorch-enabled port of GRANSO with auto-differentiation ║ \n", "Version 1.2.0 ║ \n", "Licensed under the AGPLv3, Copyright (C) 2021-2022 Tim Mitchell and Buyun Liang ║ \n", "═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣\n", "Problem specifications: ║ \n", " # of variables : 10 ║ \n", " # of inequality constraints : 0 ║ \n", " # of equality constraints : 4 ║ \n", "═════╦═══════════════════════════╦════════════════╦═════════════════╦═══════════════════════╦════════════════════╣\n", " ║ <--- Penalty Function --> ║ ║ Total Violation ║ <--- Line Search ---> ║ <- Stationarity -> ║ \n", "Iter ║ Mu │ Value ║ Objective ║ Ineq │ Eq ║ SD │ Evals │ t ║ Grads │ Value ║ \n", "═════╬═══════════════════════════╬════════════════╬═════════════════╬═══════════════════════╬════════════════════╣\n", " 0 ║ 1.000000 │ 27.7034556094 ║ 0.81257641642 ║ - │ 8.581446 ║ - │ 1 │ 0.000000 ║ 1 │ 10.40129 ║ \n", " 10 ║ 0.282430 │ -0.18719099678 ║ -2.46656247013 ║ - │ 0.280276 ║ S │ 2 │ 2.000000 ║ 1 │ 0.486407 ║ \n", " 20 ║ 0.166772 │ -0.55397439861 ║ -3.46402291008 ║ - │ 0.021852 ║ S │ 1 │ 1.000000 ║ 1 │ 0.092432 ║ \n", " 30 ║ 0.088629 │ -0.34324393783 ║ -3.87472269962 ║ - │ 1.46e-04 ║ S │ 1 │ 1.000000 ║ 1 │ 0.002322 ║ \n", " 40 ║ 0.025032 │ -0.09733355831 ║ -3.88881298264 ║ - │ 7.01e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 0.002899 ║ \n", " 50 ║ 0.025032 │ -0.09765249793 ║ -3.90193007079 ║ - │ 1.09e-05 ║ S │ 1 │ 1.000000 ║ 1 │ 0.003514 ║ \n", " 60 ║ 0.025032 │ -0.09795121684 ║ -3.91354197166 ║ - │ 7.61e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 0.003132 ║ \n", " 70 ║ 0.025032 │ -0.09811594986 ║ -3.91992492755 ║ - │ 3.69e-06 ║ S │ 1 │ 1.000000 ║ 1 │ 0.002289 ║ \n", " 80 ║ 0.002465 │ -0.00966775963 ║ -3.92198806015 ║ - │ 5.13e-08 ║ S │ 3 │ 1.500000 ║ 2 │ 5.79e-04 ║ \n", " 90 ║ 5.64e-04 │ -0.00221178042 ║ -3.92221123547 ║ - │ 2.74e-08 ║ S │ 3 │ 1.500000 ║ 3 │ 4.65e-06 ║ \n", "═════╩═══════════════════════════╩════════════════╩═════════════════╩═══════════════════════╩════════════════════╣\n", "F = final iterate, B = Best (to tolerance), MF = Most Feasible ║ \n", "Optimization results: ║ \n", "═════╦═══════════════════════════╦════════════════╦═════════════════╦═══════════════════════╦════════════════════╣\n", " F ║ │ ║ -3.92221123547 ║ - │ 2.74e-08 ║ │ │ ║ │ ║ \n", " B ║ │ ║ -3.92221510373 ║ - │ 2.72e-08 ║ │ │ ║ │ ║ \n", " MF ║ │ ║ -3.92199228401 ║ - │ 1.84e-09 ║ │ │ ║ │ ║ \n", "═════╩═══════════════════════════╩════════════════╩═════════════════╩═══════════════════════╩════════════════════╣\n", "Iterations: 90 ║ \n", "Function evaluations: 122 ║ \n", "PyGRANSO termination code: 0 --- converged to stationarity and feasibility tolerances. ║ \n", "═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝\n", "Total Wall Time: 0.9984183311462402s\n", "torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T) = 0.062441956102622084\n", "torch.trace(V.T@A@V) = 3.922211235466178\n", "torch.trace(U.T@A@U) = 3.932280709191555\n", "sum of first d eigvals = 3.9322807091915544\n", "sorted eigs = tensor([ 3.0432, 0.8890, -0.4730, -0.9598, -1.8722], device='cuda:0',\n", " dtype=torch.float64)\n" ] } ], "source": [ "device = torch.device('cuda')\n", "n = 5\n", "d = 2\n", "torch.manual_seed(0)\n", "# All the user-provided data (vector/matrix/tensor) must be in torch tensor format.\n", "# As PyTorch tensor is single precision by default, one must explicitly set `dtype=torch.double`.\n", "# Also, please make sure the device of provided torch tensor is the same as opts.torch_device.\n", "A = torch.randn(n,n).to(device=device, dtype=torch.double)\n", "A = (A + A.T)/2\n", "L, U = torch.linalg.eig(A)\n", "L, U = L.to(dtype=torch.double), U.to(dtype=torch.double) \n", "index = torch.argsort(L,descending=True)\n", "U = U[:,index[0:d]]\n", "\n", "# variables and corresponding dimensions.\n", "var_in = {\"V\": [n,d]}\n", "\n", "def user_fn(X_struct,A,d):\n", " V = X_struct.V\n", "\n", " # objective function\n", " f = -torch.trace(V.T@A@V)\n", "\n", " # inequality constraint, matrix form\n", " ci = None\n", "\n", " # equality constraint\n", " ce = pygransoStruct()\n", " ce.c1 = V.T@V - torch.eye(d).to(device=device, dtype=torch.double)\n", "\n", " return [f,ci,ce]\n", "\n", "comb_fn = lambda X_struct : user_fn(X_struct,A,d)\n", "\n", "opts = pygransoStruct()\n", "opts.torch_device = device\n", "opts.print_frequency = 10\n", "opts.opt_tol = 5e-6\n", "opts.maxit = 1000\n", "# opts.mu0 = 10\n", "# opts.steering_c_viol = 0.02\n", "\n", "start = time.time()\n", "soln = pygranso(var_spec = var_in,combined_fn = comb_fn,user_opts = opts)\n", "end = time.time()\n", "print(\"Total Wall Time: {}s\".format(end - start))\n", "\n", "V = torch.reshape(soln.final.x,(n,d))\n", "\n", "rel_dist = torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T)\n", "print(\"torch.norm(V@V.T - U@U.T)/torch.norm(U@U.T) = {}\".format(rel_dist))\n", "\n", "print(\"torch.trace(V.T@A@V) = {}\".format(torch.trace(V.T@A@V)))\n", "print(\"torch.trace(U.T@A@U) = {}\".format(torch.trace(U.T@A@U)))\n", "print(\"sum of first d eigvals = {}\".format(torch.sum(L[index[0:d]])))\n", "print(\"sorted eigs = {}\".format(L[index]))" ] } ], "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.9.7" } }, "nbformat": 4, "nbformat_minor": 5 }