MGM.04 SVD Analysis of 2D Matrices
TUTORIALS

Needs["LinearAlgebra`MatrixManipulation`"];
Needs["Graphics`Colors`"];
Off[General::"spell"];
Off[General::"spell1"];
Off[ParametricPlot3D::"ppcom"];
Off[ParametricPlot::"ppcom"];
Off[Plot::"plnr"];
SetOptions[Limit, Analytic -> True];
$Pre = Chop;

CMView = {2.7, 1.6, 1.2};

Vector Drawer

\(\(\( (*\ \(\(:\)\(Date : \ \ Copyright\ 2001\)\), \ 
      Math\ Everywhere, \ \(\(Inc\)\(.\)\)\ 
*) \)\(
\)\( (*
Original\ Conception\ to\ create\ a\ vector\ drawer\ is\ due\ to\ Bill\ Davis . 
Current\ code\ is\ by\ Bruce\ \(\(Carpenter\)\(.\)\)
*) \)\(
\)\( (*\ \ \(\(\(:\)\(Drawbacks : \ \ Since\ the\ vectors\ are\ drawn\ out\ of\)\)\ 

      \ \ \ \ \ context\), \ 
      the\ shapes\ of\ the\ arrowheads\ are\ only\ 
\ \ \ \ \ correct\ with\ AspectRatio\ set\ to\ \(\(Automatic\)\(.\)\)
*) \)\)\)

BeginPackage["Vector3D`","Graphics`Colors`"];

Axes3D::usage = "Axes3D[a, b] creates a Graphics3D object of cartesian axes with x, y, and z running from -a/3 to a, and with axes labels b units beyond the tips of the axes.  Axes3D[a] is Axes3D[a, a/8].";

Perpend::usage = "Perpend[a] returns a unit vector which is perpendicular to the vector a.";

Arrow::usage = "Arrow[a] produces a 2 or 3 dimensional vector from the origin to a. Arrow[a, Tail -> tail] gives a vector from tail to a.";
	
Vector::usage = "Vector[a, b] gives a 2D or 3D vector from a to b.";

ArrowHead::usage = "ArrowHead[a, vec] produces an arrowhead with its tip placed at the point a, pointing in the direction of the vector vec.";

Tail::usage = "Tail -> point puts the tail of the vector at point.";

Norm::usage = "Norm[vec] returns the Euclidean length of vec.";

Normalize::usage = "Normalize[vec] returns a unit vector in the direction of vec, provided vec is nonzero.";

Aperture::usage = "Aperture is the ratio of the radius of the base to the length of the head of a vector.";

TipSize::usage = "TipSize specifies an absolute size for the inner tip length of the head of a vector.";

TipRatio::usage = "TipRatio is the ratio of the inner length of the arrowhead to the length of the shaft of a vector.";

HeadRatio::usage = "HeadRatio is the ratio of the outer length of the arrowhead to the length of the shaft of a vector.";

HeadSize::usage = "HeadSize specifies an absolute size for the head of a vector.";

ScaleFactor::usage = "ScaleFactor specifies the amount to scale a vector in length and may be either a number or a pure function.";

ZeroVectorPointSize::usage = "ZeroVectorPointSize is the size of the point used to represent a zero vector.";

Options[Vector] = Options[Arrow] = Options[ArrowHead] =
{HeadRatio -> 0.18, TipRatio -> 0.14, Aperture -> 0.3, ScaleFactor -> 1, HeadType -> Polygon, ShaftQ -> True, EdgesQ -> True, VectorColor -> RGBColor[0,0,1], ShaftWidth -> 0.005, ZeroVectorPointSize -> 0.01};
		
Begin["`Private`"];

SetOptions[ParametricPlot,AspectRatio -> Automatic];
SetOptions[Plot,AspectRatio -> Automatic];
SetOptions[Graphics,AspectRatio -> Automatic];

Axes3D[u_,v_] := 
      Graphics3D[{
            {Blue,Line[{{-u/3,0,0},{u,0,0}}]},
                    Text["x",{u + v,0,0}],
            {Blue,Line[{{0,-u/3,0},{0,u,0}}]},
                    Text["y",{0, u + v,0}],
            {Blue,Line[{{0,0,-u/3},{0,0,u}}]},
                    Text["z",{0,0,u + v}]}]; 
Axes3D[u_] := Axes3D[u,u/8];
				
Norm[a_?VectorQ] := N[Sqrt[a.a]];

Normalize[a_?VectorQ] := If[a.a == 0, a, a/Norm[a]];

Perpend[a_?VectorQ] := Normalize[{a[[2]],-a[[1]]}]/;Length[a]==2;

Perpend[a_?VectorQ]:=
    Normalize[If[a[[1]]==0,{1,0,0},{a[[2]],-a[[1]],0}]]/;
      Length[a]==3;
      
Base3D = Table[{Cos[2 k Pi/8.], Sin[2 k Pi/8.]},{k,0,8}]; 

Vector[from_?VectorQ, to_?VectorQ, opts___] := Module[
   {sq, sw, ht, hs, hr, tr, ap, sf, vc, zvps, diff = to - from, tip},
   {sq, sw, ht, hs, hr, ts, tr, ap, sf, vc, zvps} = {ShaftQ, ShaftWidth, HeadType, HeadSize, HeadRatio, TipSize, TipRatio, Aperture, ScaleFactor, VectorColor, ZeroVectorPointSize} /. {opts} /. Options[Vector];
   If[from==to, Return[Graphics[{PointSize[zvps],vc,Point[from]}]]];
   diff = If[NumberQ[N[sf]], sf diff, sf[diff]];
   tip = from + diff;
   If[NumberQ[hs], hr = hs/Norm[diff]; tr = 0.75 hr];
   If[NumberQ[ts], tr = ts/Norm[diff]];
   Graphics[{If[sq,{vc,Thickness[sw],Line[{from,tip - tr diff}]},{}],
      With[{trans = ap hr Norm[diff] Perpend[diff]},
      {vc, Thickness[sw], ht[{tip,
                   (tip - hr diff + trans),
                   (tip - tr diff),
                   (tip - hr diff - trans),tip}]}]}]
] /; Length[from]==Length[to]==2

Vector[from_?VectorQ, to_?VectorQ, opts___] := Module[
   {sq, eq, sw, hs, hr, tr,ap, sf, vc, zvps, diff = to - from, tip},
   {sq, eq, sw, hs, hr, ap, sf, vc, zvps} = {ShaftQ, EdgesQ, ShaftWidth, HeadSize, HeadRatio, Aperture, ScaleFactor, VectorColor, ZeroVectorPointSize} /. {opts} /. Options[Vector];
   If[from==to, Return[Graphics3D[{PointSize[zvps],vc,Point[from]}]]];
   diff = If[NumberQ[N[sf]], sf diff, sf[diff]];
   tip = from + diff;
   If[NumberQ[hs], hr = hs/Norm[diff]];
   tr = hr/2;
   Graphics3D[{If[sq,{vc,Thickness[sw],Line[{from,tip-tr diff}]},{}], If[eq, {}, EdgeForm[]], {SurfaceColor[vc],
      With[{temp = Perpend[diff]},
      Polygon[Append[#,tip]]& /@ Partition[(tip - hr diff + #)&/@((ap hr Norm[diff] Base3D) . {temp,Normalize[Cross[temp,diff]]}),2,1]]}}]
] /; Length[from]==Length[to]==3


Arrow[a_, Tail->b_, opts___] := Vector[b,a+b,opts]

Arrow[a_, opts___] := Vector[Table[0,{Length[a]}],a,opts]

ArrowHead[a_, b_, opts___] := Vector[a-b,a,ShaftQ->False,opts];

End[];

EndPackage[];
Null

Graphics`Colors`GosiaGreen = 
        RGBColor[0,  0.392187,  0];

ThreeAxes[u,v]

ThreeAxes[u_, v_] := 
        Graphics3D[{{Blue, Line[{{-u, 0, 0}, {u, 0, 0}}]}, 
            Text["x", {u + v, 0, 0}], {Blue, 
              Line[{{0, -u, 0}, {0, u, 0}}]}, 
            Text["y", {0, u + v, 0}], {Blue, 
              Line[{{0, 0, 0}, {0, 0, u}}]}, 
            Text["z", {0, 0, u + v}]}];
ThreeAxes[u_] := ThreeAxes[u, (u/8)];
ThreeAxes::"usage" = "ThreeAxes[a,b] makes a standard cartesian \
axis graphics object with x, y, and z running from -a to a, and with axis \
labels b units beyond the tips of the axes.  ThreeAxes[a] is \
ThreeAxes[a,a/8].";

T.1) The issue of rank. When an SVD stretch factor is 0

T.1.a.i) Only one positive stretch factor

Here is the matrix
         A=(({{-0.7, 1.4}, {0.5, -1.0}})) 
and an SVD analysis of its stretch factors:

A=(({{-0.7, 1.4}, {0.5, -1.0}}));
MatrixForm[
      A]

stretches=SingularValues[A][[2]]

Mathematica reports only one stretch factor.
How do you interpret this?

When Mathematica reports just one stretch factor, Mathematica is telling you that there are really two stretch factors but one of them is 0. Mathematica does not bother to give you the 0 stretch factor. 
This signals that the given matrix A is not invertible.
Check:

Inverse[A]

This checks.

T.1.a.ii) Only one hangerframe vector, only one aligner frame vector, only one stretch factor

Stay with the same matrix 
          A=(({{-0.7, 1.4}, {0.5, -1.0}}))  
and look at the full SVD analysis of it:

A=(({{-0.7, 1.4}, {0.5, -1.0}}));
MatrixForm[
      A]

alignerframe=SingularValues[A][[3]]

stretches=SingularValues[A][[2]]

hangerframe=SingularValues[A][[1]]

Mathematica reports 
             only one alignerframe vector,
             only one stretch factor, and 
             only one hangerframe vector.
What information do you get from this?

Because A is not invertible,you know that the matrix A hangs all its hits on a line through {0,0}. 
This is the line through {0,0} defined by the lone vector in the hangerframe.

Clear[hangerframe];
hangerframe[1]=SingularValues[A][[1,1]]

See it happen by taking some random points and hitting A on them.

a = 2;
points = 
        Table[{Random[Real, {-a, a}], Random[Real, {-a, a}]}, {k, 1, 
            100}];
pointcolor[k_] = 
        RGBColor[0.5 (Sin[((2 π k)/Length)[points]] + 1), 
          0.5 (Cos[((2 π k)/Length)[points]] + 1), 
          0.3];
pointplot = 
        Table[Graphics[{PointSize[0.04], pointcolor[k], 
              Point[points[[k]]]}], {k, 
            1, Length[points]}];
hitpointplot = 
        Table[Graphics[{PointSize[0.04], pointcolor[k], 
              Point[A . 
                  points[[k]]]}], {k, 1, 
            Length[points]}];
actionarrows = 
        Table[Arrow[
            A . points[[k]] - 
              points[[k]], 
            Tail -> points[[k]], 
            VectorColor -> pointcolor[k]], {k, 1, 
            Length[points]}];
b = 3;
lineplot = 
        Graphics[{Thickness[0.01], 
            Line[{-b hangerframe[1], b hangerframe[1]}]}];
ranger = 1.8 a;
before = 
        Show[pointplot, lineplot, Axes -> True, 
          AxesLabel -> {"x", "x"}, 
          PlotRange -> {{-ranger, ranger}, {-ranger, ranger}}, 
          PlotLabel -> "Points before the hit with A"];
Show[before, actionarrows, 
        PlotRange -> {{-ranger, ranger}, {-ranger, ranger}}, 
        PlotLabel -> "Action arrows"];
after = 
        Show[hitpointplot, lineplot, Axes -> True, 
          AxesLabel -> {"u", "v"}, 
          PlotRange -> {{-ranger, ranger}, {-ranger, ranger}}, 
          PlotLabel -> "Same points after the hit with A"];

The plotted line is the line through {0,0} defined by the lone hangerframe vector:

hangerframe = SingularValues[
          A][[1]]

T.1.a.iii) Rank

Stay with the same matrix as in parts i) and ii).
Some folks say that this the rank of this matrix is 1.
The same folks say that the rank of any invertible 2D matrix  is 2.
What do they mean by this?

The rank of a matrix is the number of dimensions the matrix uses to hang its hits.

The matrix in parts i) and ii) hangs all its hits on a one dimensional straight line. That's why folks say the rank of this matrix is 1. 

On the other hand, invertible 2D matrices use all of 2D to hang their hits. That's why folks say that the rank of an invertible 2D matrix is 2.

T.1.a.iv) Hangers with just one column and aligners with just one row

Here's a new matrix
             A=(({{-0.6, 2.7}, {0.4, -1.8}})):
and a look at its SVD stretch factors:

A=(({{-0.6, 2.7}, {0.4, -1.8}}));
stretches=SingularValues[A][[2]]

This matrix is rank 1.
Here are the SVD aligner,  stretcher and  hanger for A:

hanger=Transpose[SingularValues[A][[1]]];
MatrixForm[
      hanger]

stretcher=DiagonalMatrix[SingularValues[A][[2]]];
MatrixForm[
      stretcher]

aligner=SingularValues[A][[3]];
MatrixForm[
      aligner]

Check:

MatrixForm[hanger.stretcher.aligner]
MatrixForm[
      A]

What happened here?

Mathematica took:

MatrixForm[hanger]

MatrixForm[stretcher]

MatrixForm[aligner]

and multiplied them out to duplicate A:

MatrixForm[hanger.stretcher.aligner]
MatrixForm[
      A]

You can do this by hand if you like.

hanger.stretcher.aligner 
                   = (({{-0.83205029433784361`}, {0.55470019622522928`}})).(3.32415402771893297`).(({{0.216930457818656119`, -0.976187060183952581`}}))
                   
                   = (({{-0.83205029433784361`}, {0.55470019622522928`}})).(3.32415 ×({{0.216930457818656119`,3.32415 ×, -0.976187060183952581`}})) 

                   = (({{a, b}, {c, d}}))
with 
        a = (-0.83205) (3.32415) (0.216930457818656119`)
        b = (-0.83205) (3.32415) (-0.976187)
        c  = (0.5547) (3.32415) (0.216930457818656119`) 
        d = (0.5547) (3.32415) (-0.976187).

T.2)  Det[A .B]   = Det[A] Det[B]
If A is a 2D diagonal matrix, then Det[A] = product of diagonal entries
Why Det[(A^(-1))]  =  (1/Det) [A]
 If A is a 2D hanger or aligner based on a right hand frame, then Det[A]  =  1.
 If A is a 2D hanger or aligner based on a left hand frame, then Det[A]  = —1.
 Why A and (A^t)  have the same stretch factors and why  Det[(A^t)] = Det[A]

T.2.a)    Det[A .B]  =  Det[A] Det[B]

Look at these calculations based on the formula

Det[(({{a, b}, {c, d}}))]  =   a d  - b c

involving cleared matrices:

Clear[a, b, c, d, r, s, t, u, w, x, y, z];
A = (({{a, b}, {c, d}}));
P= (({{r, s}, {t, u}}));
T=(({{w, x}, {y, z}}));

Expand[Det[A .P]] == Expand[Det[A] Det[P]]

Expand[Det[A .P.T]] == Expand[Det[A] Det[P] Det[T]]

What's the message?

Look again:

Expand[Det[A .P]] == Expand[Det[A] Det[P]]

This tells you that the determinant of the product of two matrices is the product of their determinants.
Now look at this one:

Expand[Det[A .P.T]] == Expand[Det[A] Det[P] Det[T]]

This tells you that the determinant of the product of three matrices is the product of their determinants.

The same story holds up for any number of matrices.

T.2.b) If A is diagonal matrix , then Det[A] = product of diagonal entries

Here's a random diagonal matrix

Clear[
        diagonalentry];
diagonalentry[1]  =  
        Random[Real, {-2, 2}];
diagonalentry[
          2]  =  Random[Real, {-2, 2}];
diagonalmatrix=(({{diagonalentry[1], 0}, {0, diagonalentry[2]}}));
MatrixForm[
      diagonalmatrix]

Det[diagonalmatrix] is:

Det[diagonalmatrix]

Compare:

diagonalentry[1] diagonalentry[2]

Explain why the same thing happens for any and all diagonal matrices.

The easiest way to see this is to use the formula

Det[(({{a, b}, {c, d}}))]  =   a d  - b c

from the Basics.
Applying this formula to

Det[diagonalmatrix ]  = Det[(({{diagonalentry[1], 0}, {0, diagonalentry[2]}}))]

gives 
           Det[diagonalmatrix ]  = diagonalentry[1] diagonalentry[2] - 0 0 = diagonalentry[1] diagonalentry[2].

T.2.c)  Why   Det[(A^(-1))] =  (1/Det) [A]

Look at these calculations of Det[(A^(-1))] and (1/Det)[A] for a random matrix A:

A = (({{Random[Real, {-3, 3}], Random[
                      Real, {-3, 3}]}, {Random[Real, {-3, 3}], Random[
                      Real, {-3, 3}]}}));
Det[Inverse[A]]

(1/(Det[A]))

Apparently,   Det[(A^(-1))] = (1/Det) [A].

Explain why this is guaranteed for any and all invertible 2D matrices A.

Identity =  (A^(-1)). A
So
        1  = Det[Identity] = Det[(A^(-1))] Det[A].
And so
        (1/Det) [A] = Det[(A^(-1))] .
That's all there is to it.

T.2.d.i) If A is a hanger or aligner based on a right hand frame, then Det[A] = 1

Here's a random right hand perpendicular frame:

s = Random[Real, {0, 2 π}];
Clear[perpframe];
{perpframe[1], 
          perpframe[2]} = {{Cos[s], Sin[s]}, {Cos[s + (π/2)], 
            Sin[s + (π/2)]}};
rightframeplot  = 
        Show[Table[
            Arrow[perpframe[k], Tail -> {0, 0}, 
              VectorColor -> Indigo, HeadSize -> 0.2], {k, 1, 2}], 
          Graphics[Text["perpframe[1]", 0.6 perpframe[1]]], 
          Graphics[Text["perpframe[2]", 0.6 perpframe[2]]], 
          Graphics[{GosiaGreen, Text["Right Hand", {0, 0.8}]}], 
          Axes -> True, AxesLabel -> {"x", "y"}, 
          PlotRange -> {{-1, 1}, {-1, 1}}];

The hanger matrix based on this perpendicular frame is

hanger  =  Transpose[{perpframe[1], perpframe[2]}];
MatrixForm[hanger]

Its determinant is:

Det[hanger]

The aligner matrix based on this perpendicular frame is

aligner  =  {perpframe[1], perpframe[2]};
MatrixForm[aligner]

Its determinant is:

Det[aligner]

Explain why the same thing happens for all aligners and hangers based on right hand perpendicular frames.

Hits with hangers or aligners don't change any area measurements so both their stretch factors are equal to 1.
         So |Det[aligner]| = |Det[hanger]|  =  1.

To see why Det[hanger] = 1, look at

Show[rightframeplot];

The first column of hanger is perpframe[1] and the second column of hanger is perpframe[2].

Because {perpframe[1],perpframe[2]} is a right hand frame, the columns of hanger are positively oriented. 
So Det[hanger] gets the plus sign. 
In other words Det[hanger] = 1 .

To see why Det[aligner] = 1, remember
                 aligner = (hanger^(-1)).
This gives Det[aligner] = (1/(Det [hanger] )) =  (1/1) = 1.

T.2.d.ii) If A is a hanger or aligner based on a left hand frame, then Det[A] = —1

Here's a random left hand perpendicular frame:

s = Random[Real, {0, 2 π}];
Clear[
        perpframe];
{perpframe[1], perpframe[2]}={{Cos[s], Sin[s]},-{Cos[s + (π/2)], 
                Sin[s + (π/2)]}};
leftframeplot  = 
        Show[Table[
            Arrow[perpframe[k], Tail -> {0, 0}, 
              VectorColor -> Indigo, HeadSize -> 0.2], {k, 1, 2}], 
          Graphics[Text["perpframe[1]", 0.6 perpframe[1]]], 
          Graphics[Text["perpframe[2]", 0.6 perpframe[2]]], 
          Graphics[{GosiaGreen, Text["Left Hand", {0, 0.8}]}], 
          Axes -> True, AxesLabel -> {"x", "y"}, 
          PlotRange -> {{-1, 1}, {-1, 1}}];

The hanger matrix based on this perpendicular frame is

hanger  =  Transpose[{perpframe[1], perpframe[2]}];
MatrixForm[hanger]

Its determinant is:

Det[hanger]

The aligner matrix based on this perpendicular frame is

aligner  =  {perpframe[1], perpframe[2]};
MatrixForm[aligner]

Its determinant is:

Det[aligner]

Explain why the same thing happens for all aligners and hangers based on left hand perpendicular frames.

Hits with hangers or aligners don't change any area measurements so both their stretch factors are equal to 1.
         So |Det[aligner]| = |Det[hanger]|  =  1.

To see why Det[hanger] = -1, look at

Show[leftframeplot];

The first column of hanger is perpframe[1] and the second column of hanger is perpframe[2].

Because {perpframe[1],perpframe[2]} is a left hand frame, the columns of hanger are negatively oriented. 

So Det[hanger] gets the minus sign. 
In other words Det[hanger] = -1 .

To see why Det[aligner] = -1, remember
                 aligner = (hanger^(-1)).
This gives Det[aligner] = (1/(Det [hanger] )) =  (1/(-1)) = -1.

T.2.e)   Why  A and   (A^t)  have the same stretch factors and why Det[(A^t)] = Det[A]

Look at these calculations of Det[A] and Det[(A^t)] for random 2D matrices A:

A = (({{Random[Real, {-5, 5}], Random[Real, {-5, 5}]}, {Random[Real, {-5, 5}], Random[Real, {-5, 5}]}}));
Det[A]
Det[
      Transpose[A]]

This is strong evidence that when you go with any 2D matrix A , then both A and (A^t) have the same determinant. 
Explain why this is guaranteed.

Go with any 2D matrix 
        A = hanger.stretcher.aligner.
This gives
        (A^t) = (aligner^t).stretcher.(hanger^t).

So 
         Det[A] = Det[hanger] Det[stretcher] Det[aligner] 
and
        Det[(A^t)] = Det[(aligner^t)] Det[stretcher] Det[(hanger^t)].
   
But  Det[(aligner^t)] = Det[aligner] and Det[hanger] = Det[(hanger^t)]

The upshot: Det[A] and  Det[(A^t)] are both the product of the same three numbers. 
This makes them equal.

T.3) Hits with 2D matrices with positive determinants preserve orientation. 
 Hits with 2D matrices with negative determinants reverse orientation

T.3.a.i) If A is a 2D matrix with a positive determinant, then hits with A preserve orientation

Here is a 3D matrix A with a positive determinant

A = (({{1.2, 0.5}, {-0.1, 1.6}}));
Det[A]

Here are random two vectors in 2D:

Clear[vector];
Clear[a];
a[i_]  :=  ((((-1))^Random)[Integer, {0, 1}]) 
              Random[Real, {0.5, 1.5}];

vector[1]  = {a[1], 
          a[2]};
vector[2]  =  {a[3], 
          a[4]};
ranger  =  
        1.5;
before =Show[\(Table[
\ \ \ \ \ Arrow[vector[k], Tail -> {0, 0}, 
                VectorColor -> Indigo], {k, 1, 2}]\), 
     Graphics[Text["vector[1]", 0.4 vector[1]]],
     Graphics[
              Text["vector[2]", 0.7 vector[2]]],
PlotLabel ->If[ Det[{vector[1], vector[2]}] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[{vector[1], vector[2]}] < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
      PlotRange -> {{-ranger, 
                  ranger}, {-ranger, ranger}},Axes -> True,AxesLabel -> {"x", "y"}];

Now look at A.vector[1] and A.vector[2]:

newranger  =  
        Max[SingularValues[A][[2]]] ranger;
after =Show[Table[
     Arrow[A.vector[k],Tail -> {0, 0},VectorColor -> Indigo],{k, 1, 2}], 
     Graphics[Text["\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\".\",\nFontColor->RGBColor[0, 0, 1]]\)vector[1]",0.4  A.vector[1]]],
     Graphics[Text["\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\".\",\nFontColor->RGBColor[0, 0, 1]]\)vector[2]",0.7 A.vector[2]]],
PlotLabel ->If[ Det[{A.vector[1],A.vector[
                              2]}]>0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[{A.vector[
                                  1],A.vector[
                                  2]}]<0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
  PlotRange -> {{-newranger, 
                  newranger}, {-newranger, newranger}},
Axes -> True,AxesLabel -> {"x", "y"}];

See them both.

Show[GraphicsArray[{before, after}]];

Notice that {A.vector[1],A.vector[2]} have the same orientation as {vector[1],vector[2]}.

Explain this: 
If A is a 2D matrix with a positive determinant ,then  hits with A preserve orientation in the sense that: 
 ▪ If {vector[1],vector[2]} are positively oriented, then so are  {A.vector[1],A,vector[2]}.
  ▪ If {vector[1],vector[2]} are negatively oriented, then so are  {A.vector[1],A,vector[2]}.

Go with a matrix A with Det[A] > 0.
Make a new matrix  
             B = (({{vector[1], vector[2]}, {↓, ↓}})).

The sign of Det[B] determines the orientation (positive or negative) of {vector[1],vector[2]}.

The product A.B  =  (({{A.vector[1], A.vector[2]}, {↓, ↓}})).
The sign of Det[A.B] determines the orientation (positive or negative) of {A.vector[1],A.vector[2]}.


But
      Det[A.B] =  Det[A] Det[B].
And because Det[A] > 0, you are guaranteed that Det[A.B] has the sign of Det[B].

The upshot:
 ▪ If {vector[1],vector[2]} are positively oriented, then so are  {A.vector[1],A,vector[2]}.
  ▪ If {vector[1],vector[2]} are negatively oriented, then so are {A.vector[1],A,vector[2]}.
  And you're out of here.

T.3.a.ii) If A is a 2D matrix with a negative determinant, then hits with A reverse orientation

Here is a 3D matrix A with a negative determinant

A = (({{0.4, 1.8}, {1.5, 0.3}}));
Det[A]

Here are random two vectors in 2D:

Clear[vector];
Clear[a];
a[i_]  :=  ((((-1))^Random)[Integer, {0, 1}]) 
              Random[Real, {0.5, 1.5}];

vector[1]  = {a[1], 
          a[2]};
vector[2]  =  {a[3], 
          a[4]};
ranger  =  
        1.5;
before =Show[\(Table[
\ \ \ \ \ Arrow[vector[k], Tail -> {0, 0}, 
                VectorColor -> Indigo], {k, 1, 2}]\), 
     Graphics[Text["vector[1]", 0.4 vector[1]]],
     Graphics[
              Text["vector[2]", 0.7 vector[2]]],
PlotLabel ->If[ Det[{vector[1], vector[2]}] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[{vector[1], vector[2]}] < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
      PlotRange -> {{-ranger, 
                  ranger}, {-ranger, ranger}},Axes -> True,AxesLabel -> {"x", "y"}];

Now look at A.vector[1] and A.vector[2]:

newranger  =  
        Max[SingularValues[A][[2]]] ranger;
after =Show[Table[
     Arrow[A.vector[k],Tail -> {0, 0},VectorColor -> Indigo],{k, 1, 2}], 
     Graphics[Text["\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\".\",\nFontColor->RGBColor[0, 0, 1]]\)vector[1]",0.4  A.vector[1]]],
     Graphics[Text["\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\".\",\nFontColor->RGBColor[0, 0, 1]]\)vector[2]",0.7 A.vector[2]]],
PlotLabel ->If[ Det[{A.vector[1],A.vector[
                              2]}]>0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[{A.vector[
                                  1],A.vector[
                                  2]}]<0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
  PlotRange -> {{-newranger, 
                  newranger}, {-newranger, newranger}},
Axes -> True,AxesLabel -> {"x", "y"}];

See them both.

Show[GraphicsArray[{before, after}]];

Notice that the orientation of {A.vector[1],A.vector[2]} is opposite to the orientation of {vector[1],vector[2]}.

Explain this: 
If A is a 2D matrix with a negative determinant ,then  hits with A reverse orientation in the sense that: 
 ▪ If {vector[1],vector[2]} are positively oriented, then {A.vector[1],A,vector[2]}  are negatively oriented.
  ▪ If {vector[1],vector[2]} are negatively oriented, then {A.vector[1],A,vector[2]}  are positively oriented.

Go with a matrix A with Det[A] < 0.
Make a new matrix  
             B = (({{vector[1], vector[2]}, {↓, ↓}})).

The sign of Det[B] determines the orientation (positive or negative) of {vector[1],vector[2]}.

The product A.B  =  (({{A.vector[1], A.vector[2]}, {↓, ↓}})).
The sign of Det[A.B] determines the orientation (positive or negative) of {A.vector[1],A.vector[2]}.


But
      Det[A.B] =  Det[A] Det[B].
And because Det[A] < 0, you are guaranteed that Det[A.B] has the sign opposite to the sign of  Det[B].

The upshot:
 ▪ If {vector[1],vector[2]} are positively oriented, then  {A.vector[1],A,vector[2]} are negatively oriented. 
  ▪ If {vector[1],vector[2]} are negatively oriented, then  {A.vector[1],A,vector[2]} are positively oriented. 
  And you're really out of here.

T.4) Revealing the cross product formula:
If X = {a, b, c} and  Y = {r, s, t}, then
         X × Y = {Det[(({{b, c}, {s, t}}))], –Det[(({{a, c}, {r, t}}))], Det[(({{a, b}, {r, s}}))]}.

T.4.a.i) The formula for the cross product of two 3D vectors

Look at this:

Clear[a, b, c, r, s, t];
X = {a, b, c} ;
Y ={r,s,t};
{Det[(({{b, c}, {s, t}}))],-Det[(({{a, c}, {r, t}}))],Det[(({{a, b}, {r, s}}))]}

Compare with Mathematica's calculation of X × Y :

Cross[X,Y]

What's the message?

The message is:
If X = {a, b, c} and  Y = {r, s, t}, then
         X × Y = {Det[(({{b, c}, {s, t}}))], –Det[(({{a, c}, {r, t}}))], Det[(({{a, b}, {r, s}}))]}:

Clear[a, b, c, r, s, t];
X = {a, b, c} ;
Y ={r,s,t};
Cross[X,Y] =={Det[(({{b, c}, {s, t}}))],-Det[(({{a, c}, {r, t}}))],Det[(({{a, b}, {r, s}}))]}

T.5) Using SVD matrix analysis to set the plot range

T.5.a.i) Using stretch factors to help set the plot range

Here's a curve:

Clear[x, y, t];
\(\({x[t_], y[t_]} = 2\ {Cos[t]\ Sin[t]\^5, Sin[t]\^3};\)
\)
{tlow, thigh} = {0, 2 π};
\(\(ranger = 2.7;\)
\)
Clear[hitplotter, hitpointplotter, pointcolor, actionarrows, 
        matrix2D];
pointcolor[t_] = 
        RGBColor[0.5 (Cos[t] + 1), 0.5 (Sin[t] + 1), 
          0];
\(\(jump = \(thigh - tlow\)\/16;\)
\)
\(\(hitplotter[matrix2D_] := 
        ParametricPlot[matrix2D . {x[t], y[t]}, {t, tlow, thigh}, 
          PlotStyle -> {{Thickness[0.01], NavyBlue}}, 
          PlotRange -> {{\(-ranger\), ranger}, {\(-ranger\), ranger}}, 
          AxesLabel -> {"x", "y"}, 
          DisplayFunction -> Identity];\)
\)
\(\(hitpointplotter[matrix2D_] := 
        Table[Graphics[{pointcolor[t], PointSize[0.035], 
              Point[matrix2D . {x[t], y[t]}]}], {t, tlow, thigh - jump, 
            jump}];\)
\)
before = 
        Show[hitplotter[IdentityMatrix[2]], 
          hitpointplotter[IdentityMatrix[2]], 
          PlotLabel -> "Before the hit with A", 
          DisplayFunction -> $DisplayFunction];

Here's a 2D matrix A and an attempt to plot what a hit with A does to this curve:

A=(({{1.8, 1.9}, {-0.9, 1.8}}));
MatrixForm[A]

after = 
        Show[hitplotter[A], hitpointplotter[A], 
          PlotLabel -> "After the hit with A", 
          DisplayFunction -> $DisplayFunction];

What went wrong?

Look at:

ranger

The plot range specification through
          PlotRange->{{-ranger,ranger},{-ranger,ranger}} 
did not accommodate the full curve in the second plot.

T.5.a.ii) Automatic setting of the PlotRange

Is there a way to set ranger in advance to avoid guessing?

Of course, if there were no way this question would not have been asked.
Here's how it goes:
First plot the original curve in true scale using 
           AspectRatio->  Automatic
           and PlotRange->All:

originalcurve = 
        ParametricPlot[{x[t], y[t]}, {t, tlow, thigh}, 
          PlotStyle -> {{Thickness[0.015], Blue}}, 
          AspectRatio -> Automatic, PlotRange -> All, 
          AxesLabel -> {"x", "y"}];

Now eyeball a circle centered on {0,0} that snugly surrounds the curve:

radius = 2.0;
Show[originalcurve, Graphics[Circle[{0, 0}, radius]], 
        PlotRange -> All];

Look at the stretch factors:

{xstretch, 
        ystretch} = SingularValues[
          A][[2]]

Redefine ranger:

ranger = Max[{1.0,Max[{xstretch, ystretch}]}] radius

Now run the plots:

\(\(before = 
        Show[hitplotter[IdentityMatrix[2]], 
          hitpointplotter[IdentityMatrix[2]], 
          PlotLabel -> "Before the hit with A", 
          DisplayFunction -> $DisplayFunction];\)
\)
after = 
        Show[hitplotter[A], hitpointplotter[A], 
          PlotLabel -> "After the hit with A", 
          DisplayFunction -> $DisplayFunction];

Now both plots are accommodated automatically and the same scale is used in both.

T.5.a.iii) The math behind the scene

What guarantees that setting
        ranger = radius Max[{xstretch,ystretch,1}]
will always work?

Once you identify the radius = r of a circle centered on {0,0} completely enclosing the curve, then you are sure that the hit with A stretches this circle and everything inside it by no more than a factor of
             Max[{xstretch,ystretch}].
So the plot of the hit curve must come out inside the circle of radius
            r Max[{xstretch,ystretch,1}].

T.6)  Hand Calculations:
 Mathematica Fat's tips on memorizing the formulas for the determinant and cross product and templates for hand calculation of solutions of linear systems (Cramer's rule), inverse matrices  and SVD

HC.a) Mathematica Fat's tips on memorizing the formula for the 2D determinant

The formula for the determinant is:
            Det[(({{a, b}, {c, d}}))]  =   a d  - b c
What are Mathematica Fats's tips for memorizing it?

Fats says the formula is
                        Det[(({{a, b}, {c, d}}))]  =   a d  - b c 
To memorize it, I draw this diagram:

(({{}}))

The way I think about it: 
It's just opposite from the way you want it to be. 
The arrow with the negative slope carries a plus sign. 
The arrow with the positive slope carries a minus sign.

HC.b) Mathematica Fat's tips on memorizing the formula for the cross product

The formula for the cross product is:
 If X = {a, b, c} and  Y = {r, s, t}, then
         X × Y = {Det[(({{b, c}, {s, t}}))], –Det[(({{a, c}, {r, t}}))], Det[(({{a, b}, {r, s}}))]}.
What are Mathematica Fats's tips for memorizing it?

Fats says:
Start with
 X = {a, b, c} and  Y = {r, s, t}, 
 and make this box;
                       ({{a, b, c}, {r, s, t}})

To get the first slot of   X × Y,  scratch out the first vertical column to get this box:
                       ({{■, b, c}, {■, s, t}})

This gives you a 2D matrix. 
The first slot of   X × Y  is Det[(({{b, c}, {s, t}}))].

To get the second slot of slot of   X × Y,  go back to
          X = {a, b, c} and  Y = {r, s, t}, 
and then go back to this box:
                        ({{a, b, c}, {r, s, t}})

Scratch out the second vertical column to get this box
                        ({{a, ■, c}, {r, ■, t}})

This gives you another 2D matrix. 
The second slot of   X × Y is   - Det[(({{a, c}, {r, t}}))].

To get the third  slot of slot of   X × Y, 
 go back to
          X = {a, b, c} and  Y = {r, s, t}, 
and then go back to this box
                         ({{a, b, c}, {r, s, t}})

Scratch out the third vertical column to get this box
                         ({{a, b, ■}, {r, s, ■}})

This gives you another 2D matrix. 
The third slot of   X × Y  is  Det[(({{a, b}, {r, s}}))].

There you go:
If X = {a, b, c} and  Y = {r, s, t}, then
         X × Y = {Det[(({{b, c}, {s, t}}))], –Det[(({{a, c}, {r, t}}))], Det[(({{a, b}, {r, s}}))]}:

HC.d) Cramer's rule formulas for solutions of linear systems

In your grandfather's day, Cramer's rule was a hot topic. If you want to talk with your grandfather about matrices, you might want to know about Cramer's rule.
Here it is:
If Det[(({{a, b}, {c, d}}))] is not 0, then the solutions {x,y} of
             (({{a, b}, {c, d}})).{x,y} = {u,v} 
are given by

x  =((Det[( ({{u, b}, {v, d  }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))    and    y  =((Det[( ({{a, u}, {c, v }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))

Check:

Clear[a, b, c, d, u, v];
linsystem  =(({{a, b}, {c, d}})).{x, y} == {u, v}

x=((Det[( ({{u, b}, {v, d  }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))

y=((Det[( ({{a, u}, {c, v }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))

Simplify[(({{a, b}, {c, d}})).{x, y} ]== {u, v}

It works any time the determinant of the coefficient matrix is not 0.
Explain where these formulas come from.

Answer:

Go with

(({{a, b}, {c, d}})).{x,y} = {u,v}

Clear[a, b, c, d, x, y, u, v];
(({{a, b}, {c, d}})).{x, y}=={u, v}

Put col[1] = {a,c} and col[2] = {b,d} and note that

(({{a, b}, {c, d}})).{x,y} = {u,v}

is the same as the vector equation: 
            x col[1] + y col[2] = {u,v}:

Clear[
        col];
col[1]  =  {a, c};
col[2]  =  {b, 
          d};
  x col[1] + y col[2] =={u, v}

Make vectors perpendicular to each column:
          perpcol[1] = {c,-a}
         perpcol[2]  = {d,-b}

Now remember  
                       x col[1] + y col[2] = {u,v}
Dot perpcol[2] on both sides  to get
             perpcol[2]. ( x col[1] + y] col[2]) = perpcol[2].{u,v}
This is the same as
              x  perpcol[2]. col[1] +y perpcol[2].col[2] = perpcol[2].{u,v}
      
Because perpcol[2] is perpendicular to col[2], this reduces to

             x  perpcol[2]. col[1]  + 0  = perpcol[2].{u,v}
      
So the solution for x is:
                    x=((perpcol[2].{u . v})/(perpcol[2].col[1]))
                    
Similarly the solution for y is
                     y=((perpcol[1].{u, v})/(perpcol[1].col[2])).

Try it running on cleared constants:

Clear[a, b, c, d, x, u, v];
(({{a, b}, {c, d}})).{x[1], x[2]}=={u, v}

Clear[
        col];
col[1]  =  {a, c};
col[2]  =  {b, 
          d};
 perpcol[1]  =  {c, -a};
 perpcol[2]  =  {d, -b};
x=((perpcol[2].{u, v})/(perpcol[2].col[1]))

This is the same as:

Cramerx=((Det[( ({{u, b}, {v, d  }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))

Similarly the solution for y is:

y=((perpcol[1].{u, v})/(perpcol[1].col[2]))

This is the same as:

Cramery=((Det[( ({{a, u}, {c, v }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))

HC.e) Hand calculation of inverse matrices

Explain this: If  Det[(({{a, b}, {c, d}}))] is not zero, then

(((({{a, b}, {c, d}})))^(-1))  =      (1/(Det[( ({{a, b}, {c, d  }})) ])) (({{d, -b}, {-c, a}}))

Answer:

According to Cramer's rule:
The solutions {x,y} of
             (({{a, b}, {c, d}})).{x,y} = {u,v} 
are given by

Clear[a, b, c, d, u, v]
{x, y}={((Det[( ({{u, b}, {v, d  }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))   ,((Det[( ({{a, u}, {c, v }})) ])/(Det[( ({{a, b}, {c, d  }})) ]))}

The matrix you hit on {u,v} to get {x,y} is the inverse of (({{a, b}, {c, d}})).
From the output above, you can see that that matrix is:

(((({{a, b}, {c, d}})))^(-1)) = (1/(a d  - b c))(({{d, -b}, {-c, a}}))
                      
                            =  (1/(Det[( ({{a, b}, {c, d  }})) ])) (({{d, -b}, {-c, a}}))

because  a d - b c = Det[( ({{a, b}, {c, d  }})) ].

HC.f) Hand calculation of SVD: Tedious but possible

Here is a 2D matrix:

A=(({{1.8, -2.1}, {1.3, 0.2}}));
MatrixForm[A]

Use hand-style calculations to duplicate this matrix by coming up by with an aligner frame, stretch factors and a hanger frame so that
     A = hanger.stretcher.aligner

First notice that no matter what x is,the vectors
     {x, 1 - x} and {x - 1 ,x} 
are perpendicular:

Clear[x];
Expand[{x, 1 - x} . {x - 1, x}]

Now find a solution x of
           (A . {x, 1 - x}) . (A . {x - 1, x}) = 0:

SVDeqn  =   Expand[(A . {x, 1 - x}) . (A . {x - 1, 
                  x})]  ==  0

This is an ordinary quadratic equation which is readily solved by the quadratic formula:

xsols  =  Solve[SVDeqn]

Go with one of the solutions:

goodx  =  x /. xsols[[1]]

Use this x and put
	\(alignerframe[
          1] = {goodx, 1 - goodx}\/\((\@\({goodx, 1 - goodx} . {goodx, 1 - goodx}\))\)\)
and
	\(alignerframe[
          2] = {goodx - 1, goodx}\/\((\@\({goodx - 1, goodx} . {goodx - 1, goodx}\))\)\):

Clear[alignerframe];
	alignerframe[1]  =  {goodx, 1 - goodx}/
            Sqrt[{goodx, 1 - goodx} . {goodx, 1 - goodx}];
	alignerframe[2]  =  {goodx  -  1, goodx}/
            Sqrt[{goodx  -  1, goodx} . {goodx  -  1, goodx}];
aligner  =  {alignerframe[1], alignerframe[2]};
MatrixForm[
      aligner]

The stretch factors are:
           \(\(\(xstretch\)\(=\)\(\(||\)\(A . 
            alignerframe[1]\)\(||\)\)\(
\)\(\ \)\)\) 
           =(Sqrt[(A . alignerframe[1]) . (A . 
                  alignerframe[1])])
and
            \(\(\(\ \)\(ystretch = \(\(\(||\)\(A . 
              alignerframe[
                2]\)\(||\)\)\ 
		\ 
\ \ \ \ \ \ \ \ \ \ \  = \@\(\((A . alignerframe[2])\) . \((A . alignerframe[2])\)\)\)\)\)\)
so your stretcher is:

xstretch  =  (Sqrt[(A . alignerframe[1]) . (A . alignerframe[1])]);
ystretch  =  (Sqrt[(A . alignerframe[2]) . (A . alignerframe[2])]);
stretcher = (({{xstretch, 0}, {0, ystretch}}));
MatrixForm[
      stretcher]

Your hangerframe is:
         hangerframe[1] = (1/xstretch) A . alignerframe[1]
         hangerframe[2] = (1/ystretch) A . alignerframe[2]

So your hanger is:

Clear[hangerframe];
	{hangerframe[1], 
            hangerframe[2]}  = {(1/xstretch) 
              A . alignerframe[1], (1/ystretch) 
              A . alignerframe[2]};
hanger  =  Transpose[{hangerframe[1], hangerframe[2]} ];
MatrixForm[hanger]

Try them out by comparing A with:

MatrixForm[hanger.stretcher.aligner]
MatrixForm[
      A]

It's within the reach of low-level but tedious hand algebra.