# Change of base & Transformation (Reflecting Bear)
## Background
Panda Bear is confused. He is trying to work out how things should look when reflected in a mirror, but is getting the wrong results.
As is the way with bears, his coordinate system is not orthonormal: so what he thinks is the direction perpendicular to the mirror isn't actually the direction the mirror reflects in.
Help Bear write a code that will do his matrix calculations properly! 

## Instructions
In this assignment you will write a Python function that will produce a transformation matrix for reflecting vectors in an arbitrarily angled mirror.

Building on the last assingment, where you wrote a code to construct an orthonormal basis that spans a set of input vectors, here you will take a matrix which takes simple form in that basis, and transform it into our starting basis.
Recall the from the last video,

 \\( T = E T_E E^{-1} \\)

You will write a function that will construct this matrix.
This assessment is not conceptually complicated, but will build and test your ability to express mathematical ideas in code.
As such, your final code submission will be relatively short, but you will receive less structure on how to write it.

### Matrices in Python
For this exercise, we shall make use of the @ operator again.
Recall from the last exercise, we used this operator to take the dot product of vectors.
In general the operator will combine vectors and/or matrices in the expected linear algebra way,
i.e. it will be either the vector dot product, matrix multiplication, or matrix operation on a vector, depending on it's input.
For example to calculate the following expressions,

 \\( a = \mathbf{s}\cdot\mathbf{t} \\)

 \\( \mathbf{s} = A\mathbf{t} \\)

 \\( M = A B \\),

One would use the code,
```python
a = s @ t
s = A @ t
M = A @ B
```
(This is in contrast to the \\(*\\) operator, which performs element-wise multiplication, or multiplication by a scalar.)

You may need to use some of the following functions:
```python
inv(A)
transpose(A)
gsBasis(A)
```
These, respectively, take the inverse of a matrix, give the transpose of a matrix, and produce a matrix of orthonormal column vectors given a general matrix of column vectors - i.e. perform the Gram-Schmidt process.
This exercise will require you to combine some of these functions.

### How to submit
Edit the code in the cell below to complete the assignment.
Once you are finished and happy with it, press the *Submit Assignment* button at the top of this notebook.

Please don't change any of the function names, as these will be checked by the grading script.


```python
# !find ~ | grep -i bearNecessities
# from bearNecessities import *
```


```python
%matplotlib inline

import numpy as np
import numpy as np
import numpy.linalg as la
from numpy.linalg import norm, inv
from numpy import transpose
import matplotlib.pyplot as plt
```


```python
def build_reflection_matrix(bearBasis) : 
    
    # The parameter bearBasis is a 2×2 matrix that is passed to the function.
    
    # Use the gsBasis function on bearBasis to get the mirror's orthonormal basis.
    E = gsBasis(bearBasis)
    
    # Transormation matrix that perform's the mirror's reflection in the mirror's basis.
    TE = np.array([[1, 0],
                   [0, -1]])
    # Combine the matrices E and TE to produce your transformation matrix.
    T = E @ TE @ E.T
    return T

```


```python
def gsBasis(A):
    """Gram-Schmidt for n vectors"""
    
    # Work with a copy - vectors are mutable
    B = np.array(A, dtype=np.float_)
    verySmallNumber
    # Loop over all vectors
    for i in range(B.shape[1]):
        # Loop over all previous vectors, j, to subtract.
        for j in range(i):
            # Subtract the overlap with previous vectors
            # you'll need the current vector B[:, i] and a previous vector B[:, j]
            B[:, i] -= (B[:, i] @ B[:, j] * B[:, j])
            
        # Normalise - norm(indepent)=1, norm(dependent)=0
        if la.norm(B[:, i]) > verySmallNumber:
            B[:, i] = B[:, i] / la.norm(B[:, i])
        else :
            B[:, i] = np.zeros_like(B[:, i])

    return B

def dimensions(A):
    """Gram-schmidt process to calculate the dimension spanned by a list of vectors.
    Independent vectors are normalised to one and dependent vectors to zero
    Thus the sum of all the norms will be the dimension"""
    return np.sum(la.norm(gsBasis(A), axis=0))
```


```python
def gram_schmidt_columns(X):
    Q, R = np.linalg.qr(X)
    return Q
```


```python

```

## Test your code before submission
To test the code you've written above, run the cell (select the cell above, then press the play button [ ▶| ] or press shift-enter).
You can then use the code below to test out your function.
You don't need to submit this cell; you can edit and run it as much as you like.

The code below will show a picture of Panda Bear.
If you have correctly implemented the function above, you will also see Bear's reflection in his mirror.


```python
# This is the matrix of Bear's basis vectors. 

# bearBasis = np.array(
#     [[1,   -1],
#      [1.5, 2]])
# # This line uses your code to build a transformation matrix for us to use.
# T = build_reflection_matrix(bearBasis)

# # Bear is drawn as a set of polygons, the vertices of which are placed as a matrix list of column vectors.
# # We have three of these non-square matrix lists: bear_white_fur, bear_black_fur, and bear_face.
# # We'll make new lists of vertices by applying the T matrix you've calculated.
# reflected_bear_white_fur = T @ bear_white_fur
# reflected_bear_black_fur = T @ bear_black_fur
# reflected_bear_face = T @ bear_face

# # This next line runs a code to set up the graphics environment.
# ax = draw_mirror(bearBasis)

# # We'll first plot Bear, his white fur, his black fur, and his face.
# ax.fill(bear_white_fur[0], bear_white_fur[1], color=bear_white, zorder=1)
# ax.fill(bear_black_fur[0], bear_black_fur[1], color=bear_black, zorder=2)
# ax.plot(bear_face[0], bear_face[1], color=bear_white, zorder=3)

# # Next we'll plot Bear's reflection.
# ax.fill(reflected_bear_white_fur[0], reflected_bear_white_fur[1], color=bear_white, zorder=1)
# ax.fill(reflected_bear_black_fur[0], reflected_bear_black_fur[1], color=bear_black, zorder=2)
# ax.plot(reflected_bear_face[0], reflected_bear_face[1], color=bear_white, zorder=3);
```

<h1>Linear algebra change of basis explained using Python</h1>


<div id="outline-container-orgceaba37" class="outline-2">
<h2 id="orgceaba37">Motivation</h2>
<div class="outline-text-2" id="text-orgceaba37">
<p>
I'm always forgetting about the intuition behind the change of basis in linear algebra.
There is a very nice video explaining it on Youtube, but I want the explanation in text format so I can easily refer too when in doubt.
</p>
</div>
</div>
<div id="outline-container-orgdf5ac15" class="outline-2">
<h2 id="orgdf5ac15">Change of basis</h2>
<div class="outline-text-2" id="text-orgdf5ac15">
<p>
Let's say we have two sets of basis vector \(\color{blue}{\boldsymbol{b_{i}}}\) and \(\color{red}{\boldsymbol{\beta_{i}}}\).
The set \(\color{blue}{\boldsymbol{b_{i}}}\) defines the original system, the one we start with, and the set \(\color{red}{\boldsymbol{\beta_{i}}}\) the transformed system.
The \(\color{blue}{blue}\) color will be used for original coordinate system and \(\color{red}{red}\) for the transformed.
The notation with \([]\) will need a subscript to denote which coordinate system it is referring to.
In the 2-d space, the basis vectors of the original system can be written as,
</p>

\begin{equation}
\label{eq:1}
\color{blue}{\boldsymbol{b_{1}} =
\begin{bmatrix}
b_{1x} \\ b_{1y}
\end{bmatrix}}_{\color{blue}{b}} \qquad 
\color{blue}{\boldsymbol{b_{2}} =
\begin{bmatrix}
b_{2x} \\ b_{2y}
\end{bmatrix}}_{\color{blue}{b}}
\end{equation}

<p>
generally, those will be the classic unit vectors \([1, 0]\) and \([0, 1]\).
The basis vector of the transformed space using the coordinate system of the original space are
</p>

\begin{equation}
\label{eq:2}
\color{blue}{\boldsymbol{\beta_{1}} =
\begin{bmatrix}
\beta_{1x} \\ \beta_{1y}
\end{bmatrix}}_{\color{blue}{b}} = \color{blue}{\beta_{1x}} \color{blue}{\boldsymbol{b_1}} + \color{blue}{\beta_{1y}} \color{blue}{\boldsymbol{b_2}} \qquad 
\color{blue}{\boldsymbol{\beta_{2}} =
\begin{bmatrix}
\beta_{2x} \\ \beta_{2y}
\end{bmatrix}}_{\color{blue}{b}} = \color{blue}{\beta_{2x}} \color{blue}{\boldsymbol{b_1}} +  \color{blue}{\beta_{2y}} \color{blue}{\boldsymbol{b_2}}
\end{equation}

<p>
Given that we know the transformation on the basis vector of the original system we can find \(\color{blue}{\beta_{1x}, \beta_{1y}, \beta_{2x}, \beta_{2y}}\).
</p>

<p>
Now, for any vector \(\boldsymbol{v}\) written in the transformed system,
</p>

\begin{equation}
\label{eq:20}
\color{red}{\boldsymbol{v}_{\beta}} = \color{red}{v_{1}} \boldsymbol{\color{red}{\beta_{1}}} + \color{red}{v_{2}} \boldsymbol{\color{red}{\beta_{2}}} =
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}}
\end{equation}

<p>
we can transform it by using \(\color{blue}{\beta}_{i}\) (the basis vector in the original system), expressed in the previous equation,
</p>

\begin{equation}
\label{eq:3}
\color{blue}{\boldsymbol{v}_{b}} = 
\color{red}{v_{1}} \boldsymbol{\color{blue}{\beta_{1}}} +
\color{red}{v_{2}} \boldsymbol{\color{blue}{\beta_{2}}}
\end{equation}

<p>
Using the above equation we can define matrix multiplication by,
</p>

\begin{equation}
\label{eq:5}
\color{blue}{\boldsymbol{v}_{{b}}} =
\begin{bmatrix}
\boldsymbol{\color{blue}{\beta_{1}}} & \boldsymbol{\color{blue}{\beta_{2}}}
\end{bmatrix}
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}}
= 
\begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}} = 
\begin{bmatrix}
\color{red}{v_{1}} \color{blue}{\beta_{1x}} +\color{red}{v_{2}} \color{blue}{\beta_{2x}} \\
\color{red}{v_{1}} \color{blue}{\beta_{1y}} + \color{red}{v_{2}} \color{blue}{\beta_{2y}}
\end{bmatrix}_{\color{blue}{b}}
\end{equation}

<p>
the matrix product will result in a vector in the original system.
The matrix has two columns which are the vectors with the transformed system using the original coordinates.
Therefore, the above equation is a <b>transformation</b> from the transformed system to the original system and the transformation matrix \(\boldsymbol{Q}\), is given by,
</p>

\begin{equation}
\label{eq:6}
\boldsymbol{Q} = \begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}
\end{equation}

<p>
If we have the vector in the original coordinate and want it in the transformed system, we have to invert the transformation matrix.
</p>

\begin{equation}
\label{eq:7}
\color{red}{\boldsymbol{v}_{{\beta}}}
=
\begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}^{-1}
\begin{bmatrix}
\color{blue}{v_{1}} \\ \color{blue}{v_{2}}
\end{bmatrix}_{\color{blue}{b}}
\end{equation}

<h2 id="org3bcefcd">Example</h2>
<div class="outline-text-2" id="text-org3bcefcd">
<p>
Assuming that $b_{i}$ is the Cartesian system and the new basis is given by, 
</p>

\begin{equation}
\label{eq:9}
\beta_{1} =
\begin{bmatrix}
2 \\ 3
\end{bmatrix} \qquad
\beta_2= 
\begin{bmatrix}
-1 \\ 1
\end{bmatrix}
\end{equation}

<p>
Those vectors in the Cartesian coordinate system are drawn with
</p>


```python
import sympy as sp
from sympy import Matrix as spm
sp.init_printing(use_unicode=True)

# Cartesian base
# b1, b2 = np.array([1, 0]), np.array([0, 1])
B = np.eye(2)
b1, b2 = B[:,0], B[:,1]
print('Cartesian base: ')
spm(B)

# New base
β1, β2 = np.array([2, 3]), np.array([-1, 1])

# Transform matrix
Q = np.array([β1, β2]).T
print('Transformed to original system with: ')
spm(Q)

# Vector in original base [b1, b2]
v = np.array([2, -4])
spm(v)

# Vector in the new coordinate system [β1, β2]
v_β = np.linalg.solve(Q, v)
print('The vector in the new coordinates: ')
spm(v_β)

# Change base; Q_inv @ v
spm(np.linalg.inv(Q) @ v)

# Change base and back; Q_inv @ v @ Q.T
spm(np.linalg.inv(Q) @ v @ Q.T)

# Transformation Matrix in new base (reflect mirror 90º)
TE = np.array([[1, 0], [0, -1]])

# Change base, transform and back to cartesian; Q_inv @ v @ TE @ Q.T
spm(np.linalg.inv(Q) @ v @ TE @ Q.T)
```


```python
def ax_annot(b, col, ax, alpha=1):
    """Helper to draw arrow on plot"""
    return ax.annotate(s=b, xy=(0,0), xytext=b*1.15, horizontalalignment='center', verticalalignment='center')  #arrowprops=dict(arrowstyle='<-', ec=col, fc=col, lw=1.2, alpha=alpha)
```


```python
def ax_arrow(b, col, ax, alpha=1):
    """Helper to draw arrow on plot"""
    ax_annot(b, col, ax, alpha=1)
    return ax.arrow(0, 0, b[0], b[1], fc=col, ec=col, head_width=0.2, head_length=.2, alpha=alpha)
```


```python
figsize = [7, 7]

fig, ax = plt.subplots()

ax_arrow(b1, 'b', ax)
ax_arrow(b2, 'b', ax)
ax_arrow(β1, 'r', ax)
ax_arrow(β2, 'r', ax)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```

#### Cartesian Base vectors __[b1, b2]__ for $\boldsymbol{v}=[2, -4]$


```python
fig, ax = plt.subplots()

ax_arrow(v, 'g', ax)
ax_arrow(v[0]*b1, 'b', ax)
ax_arrow(v[1]*b2, 'b', ax)

ax_arrow(b1, 'b', ax, .2)
ax_arrow(b2, 'b', ax, .2)
ax_arrow(β1, 'r', ax, .2)
ax_arrow(β2, 'r', ax, .2)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```

#### New base vectors [$\boldsymbol{\beta_{1}}$, $\boldsymbol{\beta_{2}}$]  for $\boldsymbol{v}=[2, -4]$


```python
fig, ax = plt.subplots()

ax_arrow(v, 'g', ax)
ax_arrow(v_β[0]*β1, 'b', ax)
ax_arrow(v_β[1]*β2, 'b', ax)

ax_arrow(b1, 'b', ax, .2)
ax_arrow(b2, 'b', ax, .2)
ax_arrow(β1, 'r', ax, .2)
ax_arrow(β2, 'r', ax, .2)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```


```python

```


```python

```


```python

```

64b081a14186daebc6cac86638aa40de5d82918d
ipynb
Jupyter Notebook
_math/Imperial College London - Math for ML/linalg_transform_base_mpl_annotate_ReflectingBear.ipynb
aixpact/data-science
f04a54595fbc2d797918d450b979fd4c2eabac15
MIT
2020-07-22T23:12:39.000Z
2020-07-25T02:30:48.000Z
_math/Imperial College London - Math for ML/linalg_transform_base_mpl_annotate_ReflectingBear.ipynb
aixpact/data-science
f04a54595fbc2d797918d450b979fd4c2eabac15
MIT
_math/Imperial College London - Math for ML/linalg_transform_base_mpl_annotate_ReflectingBear.ipynb
aixpact/data-science
f04a54595fbc2d797918d450b979fd4c2eabac15
MIT
Qwen/Qwen-72B
1. YES
2. YES