#!/usr/bin/env python
# coding: utf-8

# # Bauer-Fike Eigenvalue Sensitivity Bound
# 
# Copyright (C) 2019 Andreas Kloeckner
# 
# <details>
# <summary>MIT License</summary>
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# </details>

# In[1]:


import numpy as np
import numpy.linalg as la


# In the Bauer-Fike eigenvalue sensitivity bound, an important observation is that, given a diagonalized matrix
# $$X^{- 1} A  X = D$$
# that is perturbed by an additive perturbation $E$
# $$X^{- 1} (A + E) X = D + F,$$
# and if we suppose that $\mu$ is an eigenvalue of $A+E$ (and $D+F$), we have
# $$\|(\mu I - D)^{- 1}\|^{- 1} = | \mu - \lambda _k |,$$
# where $\lambda_k$ is the eigenvalue of $A$ (diagonal entry of $D$) closest to $\mu$.
# 
# This notebook illustrates this latter fact. To that end, let the following be $D$:

# In[2]:


D = np.diag(np.arange(6))
D


# In[3]:


mu = 2.1


# In[4]:


mu * np.eye(6) - D


# In[5]:


la.inv(mu * np.eye(6) - D).round(3)


# In[6]:


la.norm(la.inv(mu * np.eye(6) - D), 2)


# For all $p$-norms, the norm of a diagonal matrix is the biggest (abs. value) diagonal entry, so we can also use, say, the $\infty$ norm:

# In[7]:


la.norm(la.inv(mu * np.eye(6) - D), np.inf)


# In[8]:


1/ la.norm(la.inv(mu * np.eye(6) - D), 2)


# Note that this matches the distance between $\mu$ and the closest entry of $D$.

# In[ ]:




