├── .gitignore
├── LICENSE
├── README.md
├── lemma2.png
└── notebooks
└── comparison.ipynb
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.ipynb_checkpoints
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Ritchie Ng
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # New Eigenvectors from Eigenvalues Calculation
2 | This repository implements this [paper](https://arxiv.org/pdf/1908.03795.pdf) that allows us to calculate eigenvectors from eigenvalues elegantly through PyTorch that allows your code to run on your CPU, GPU, or TPU.
3 |
4 | Easily run it on your browser through Google Colab or copy the function locally.
5 |
6 | ## Run Notebook on Google Colab
7 | [](https://colab.research.google.com/github/ritchieng/eigenvectors-from-eigenvalues/blob/master/notebooks/comparison.ipynb)
8 |
9 | ## Core Equation: Lemma 2
10 |
11 | **Lemma 2.** The norm squared of the elements of the eigenvectors are related to the eigenvalues and the submatrix eigenvalues.
12 |
13 |
14 |
15 |
16 |
17 | ```
18 | Mathjax of Lemma 2
19 |
20 | $$| v_{i, j} | ^ 2 \prod_{k=1; k \neq i}^{n} (\lambda_i (A) - \lambda_k (A)) = \prod_{k=1}^{n - 1} (\lambda_i (A) - \lambda_k (M_j))$$
21 | ```
22 |
23 |
24 | ## Authors and Abstract
25 | Peter B. Denton, Stephen J. Parke, Terance Tao, and Xining Zhang
26 | ```
27 | We present a new method of succinctly determining eigenvectors
28 | from eigenvalues. Specifically, we relate the norm squared of the elements of
29 | eigenvectors to the eigenvalues and the submatrix eigenvalues.
30 | ```
31 |
32 | ## Dependencies
33 | - PyTorch 1.9.1 (can be most versions of PyTorch as I used very core basic PyTorch functions)
34 | - Python 3.8 (doesn't matter much as I use basic operations)
35 |
36 | ## Code Repository Citation
37 | - If you would like to give some credit to this code implementation, these are the relevant links.
38 | - [](https://zenodo.org/badge/latestdoi/221868248)
39 | - [Eigenvectors from Eigenvalues CPU and GPU Implementation](https://www.researchgate.net/publication/337322294_Eigenvectors_from_Eigenvalues_CPU_and_GPU_Implementation)
40 |
41 | ## License
42 | MIT
43 |
--------------------------------------------------------------------------------
/lemma2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ritchieng/eigenvectors-from-eigenvalues/ba25a311efff03050630b962e0f81e6ef362b78b/lemma2.png
--------------------------------------------------------------------------------
/notebooks/comparison.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 6,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "1.9.0.post2\n",
13 | "3.8.8 (default, Apr 13 2021, 19:58:26) \n",
14 | "[GCC 7.3.0]\n"
15 | ]
16 | }
17 | ],
18 | "source": [
19 | "import torch\n",
20 | "print(torch.__version__)\n",
21 | "import sys\n",
22 | "print(sys.version)"
23 | ]
24 | },
25 | {
26 | "cell_type": "code",
27 | "execution_count": 7,
28 | "metadata": {
29 | "tags": []
30 | },
31 | "outputs": [],
32 | "source": [
33 | "def subidx(n:int, remove:int) -> list:\n",
34 | " out = list(range(n))\n",
35 | " out.remove(remove)\n",
36 | " return out\n",
37 | "\n",
38 | "def submatrix(A:torch.tensor, j:int) -> torch.tensor:\n",
39 | " n = A.shape[0]\n",
40 | " s = subidx(n, j)\n",
41 | " o = A[s, :]\n",
42 | " o = o[:, s]\n",
43 | " return o\n",
44 | "\n",
45 | "def get_eigenvector_val_old(hermitian_matrix, i, j, disable_complex=False):\n",
46 | " # Old way\n",
47 | " lam, v = torch.linalg.eig(hermitian_matrix)\n",
48 | " if disable_complex:\n",
49 | " old_eigenvector_ij = torch.abs(v[j,i]**2)\n",
50 | " else:\n",
51 | " old_eigenvector_ij = v[j,i]**2\n",
52 | " \n",
53 | " return old_eigenvector_ij\n",
54 | "\n",
55 | "def get_eigenvector_val(hermitian_matrix, i, j, disable_complex=False):\n",
56 | " # Only need to calculate eigenvalues\n",
57 | " lam = torch.linalg.eigvals(hermitian_matrix)\n",
58 | " \n",
59 | " n = len(lam)\n",
60 | " M = submatrix(hermitian_matrix, j)\n",
61 | " # Only need to calculate eigenvalues\n",
62 | " lam_submatrix = torch.linalg.eigvals(M)\n",
63 | "\n",
64 | " # Left side of equation 2\n",
65 | " left = torch.prod(torch.tensor([lam[i] - lam[k] for k in range(n) if k!=i]))\n",
66 | " # Right side of equation 2\n",
67 | " right = torch.prod(torch.tensor([lam[i] - lam_submatrix[k] for k in range(n-1)]))\n",
68 | " # Right divided by left\n",
69 | " eigenvector_ij = right / left\n",
70 | " \n",
71 | " if disable_complex:\n",
72 | " eigenvector_ij = torch.abs(eigenvector_ij)\n",
73 | " \n",
74 | " return eigenvector_ij"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": 5,
80 | "metadata": {},
81 | "outputs": [
82 | {
83 | "name": "stdout",
84 | "output_type": "stream",
85 | "text": [
86 | "Old Method Eigenvector ij: (0.02086203929382368-0j)\n",
87 | "--------------------------------------------------\n",
88 | "New Method Eigenvector ij: (0.020862039293826073+0j)\n"
89 | ]
90 | }
91 | ],
92 | "source": [
93 | "'''\n",
94 | "Run with Complex Numbers\n",
95 | "'''\n",
96 | "# Random square matrix\n",
97 | "rand_square_matrix = torch.rand(50, 50, dtype=float)\n",
98 | "\n",
99 | "# Hermitian matrix\n",
100 | "hermitian_matrix = rand_square_matrix * rand_square_matrix.T\n",
101 | "\n",
102 | "# Old \n",
103 | "old_eigenvector_ij = get_eigenvector_val_old(hermitian_matrix, i=0, j=0)\n",
104 | "\n",
105 | "# New\n",
106 | "new_eigenvector_ij = get_eigenvector_val(hermitian_matrix, i=0, j=0)\n",
107 | "\n",
108 | "print(f'Old Method Eigenvector ij: {old_eigenvector_ij}')\n",
109 | "print('-'*50)\n",
110 | "print(f'New Method Eigenvector ij: {new_eigenvector_ij}')"
111 | ]
112 | },
113 | {
114 | "cell_type": "code",
115 | "execution_count": 8,
116 | "metadata": {},
117 | "outputs": [
118 | {
119 | "name": "stdout",
120 | "output_type": "stream",
121 | "text": [
122 | "Old Method Eigenvector ij: 0.0225447410369363\n",
123 | "--------------------------------------------------\n",
124 | "New Method Eigenvector ij: 0.02254474103693581\n"
125 | ]
126 | }
127 | ],
128 | "source": [
129 | "'''\n",
130 | "Run with Complex Numbers Disabled\n",
131 | "'''\n",
132 | "# Random square matrix\n",
133 | "rand_square_matrix = torch.rand(50, 50, dtype=float)\n",
134 | "\n",
135 | "# Hermitian matrix\n",
136 | "hermitian_matrix = rand_square_matrix * rand_square_matrix.T\n",
137 | "\n",
138 | "# Old \n",
139 | "old_eigenvector_ij = get_eigenvector_val_old(hermitian_matrix, i=0, j=0, disable_complex=True)\n",
140 | "\n",
141 | "# New\n",
142 | "new_eigenvector_ij = get_eigenvector_val(hermitian_matrix, i=0, j=0, disable_complex=True)\n",
143 | "\n",
144 | "print(f'Old Method Eigenvector ij: {old_eigenvector_ij}')\n",
145 | "print('-'*50)\n",
146 | "print(f'New Method Eigenvector ij: {new_eigenvector_ij}')"
147 | ]
148 | }
149 | ],
150 | "metadata": {
151 | "kernelspec": {
152 | "display_name": "Python 3",
153 | "language": "python",
154 | "name": "python3"
155 | },
156 | "language_info": {
157 | "codemirror_mode": {
158 | "name": "ipython",
159 | "version": 3
160 | },
161 | "file_extension": ".py",
162 | "mimetype": "text/x-python",
163 | "name": "python",
164 | "nbconvert_exporter": "python",
165 | "pygments_lexer": "ipython3",
166 | "version": "3.8.8"
167 | }
168 | },
169 | "nbformat": 4,
170 | "nbformat_minor": 4
171 | }
172 |
--------------------------------------------------------------------------------