MGM.04 SVD Analysis of 2D Matrices
 BASICS

Needs["LinearAlgebra`MatrixManipulation`"];
Needs["Graphics`Colors`"];
Off[General::"spell"];
Off[General::"spell1"];
Off[ParametricPlot3D::"ppcom"];
Off[ParametricPlot::"ppcom"];
Off[Plot::"plnr"];
Off[Solve::"ifun"];
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].";

B.1)   SVD Matrix analysis:
Putting any 2D matrix A in the form A = hanger. stretcher. aligner

SVD analysis tells you that every matrix can be duplicated with matrix maker ingredients: aligner, stretcher and hanger. If you want to find out how to do this for any 2D matrix, jump in right now.

B.1.a.i) Taking a random matrix and duplicating it  with matrix maker ingredients: 
aligner, stretcher and hanger

Here's  a random 2D matrix

A=(({{Random[Real, {-2, 2}], Random[Real, {-2, 2}]}, {Random[Real, {-2, 2}], Random[Real, {-2, 2}]}}));
MatrixForm[
      A]

Duplicate this matrix by coming up by with an aligner frame, stretch factors and a hanger frame so that
     A =   hanger. stretcher.aligner.

First go with a cleared perpendicular frame:

Clear[perpframe, s];
\(	{perpframe[1], 
        perpframe[2]}\  = \ {{Cos[s], Sin[s]}, {Cos[s + π\/2], 
          Sin[s + π\/2]}}\)

Now go after an s that makes 
            A.perpframe[1] and A.perpframe[2] 
into perpendicular vectors

schoices = Solve[(A . perpframe[1]).(A . perpframe[2]) == 0,s]

Take any of these choices

s  =  s /. schoices[[2]]

Plug this s into the cleared perpendicular frame to get your alignerframe and aligner::

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

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

xstretch  =  
        Norm[A . alignerframe[1]];
ystretch  =  
        Norm[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]

Bingo!
Try it for more random 2D matrices A.

Clear[perpframe, s];
	{perpframe[1], 
            perpframe[2]}  =  {{Cos[s], Sin[s]}, {Cos[s + (π/2)], 
              Sin[s + (π/2)]}};
schoices = Solve[(A . perpframe[1]).(A . perpframe[2]) == 0,s];
s  =  s /. schoices[[2]];

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

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

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

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

B.1.a.ii) What is SVD analysis?

What is SVD analysis of a 2D matrix A?

You just did it. 
SVD analysis of a given matrix A is the act of duplicating A with matrix maker ingredients 
         A=hanger.stretcher.aligner.

B.1.a.iii) Why SVD analysis is always possible

What guarantees that SVD analysis works?

The discussion above hinges on going with
           perpframe[1] = {Cos[s], Sin[s]}
perpframe[2] = {Cos[s + (π/2)], Sin[s + (π/2)]}
and coming up with an s that makes 
           (A . perpframe[1]) . (A . perpframe[2]) = 0.
To see why this is possible for any 2D matrix A, go with a cleared matrix A:

Clear[a, b, c, d];
A = (({{a, b}, {c, d}}));
MatrixForm[
      A]

Go with a cleared candidate for your aligner frame:

Clear[perpframe, s];
\(	{perpframe[1], 
        perpframe[2]}\  = \ {{Cos[s], Sin[s]}, {Cos[s + π\/2], 
          Sin[s + π\/2]}}\)

The job is to explain why at least one solution s of
           (A . perpframe[1]) . (A . perpframe[2]) = 0 
is guaranteed.
To do this, look at:

(A . perpframe[1]).(A . perpframe[2])

This is the same as:

Expand[(A . perpframe[1]).(A . perpframe[2])]

Simplify[Expand[(A . perpframe[1]).(A . perpframe[2])]]

This signals that saying that
           (A . perpframe[1]) . (A . perpframe[2]) = 0 
 is the same as saying that
             2 (a b + c d) Cos[2 s]+(-(a^2) + (b^2) - (c^2) + (d^2)) Sin[2 s] = 0.
So saying that
           (A . perpframe[1]) . (A . perpframe[2]) = 0
is the same as saying that
           2 (a b + c d) Cos[2 s]=((a^2) - (b^2) + (c^2) - (d^2)) Sin[2 s] .
And this the same as saying that
           ((2 (a b  +  c d))/((a^2) -  (b^2) +  (c^2) -  
              (d^2)))=((Sin[2 s])/(  Cos[2 s] ))
And this the same as saying that
           ((2 (a b  +  c d))/((a^2) -  (b^2) +  (c^2) -  
              (d^2)))=Tan[2 s] .
 And because Tan[2 s] takes on all values from -∞  to  ∞, 
 your  s is guaranteed.

B.1.a.iv) More than one aligner frame

The discussion above tells you that it is always possible to come up with a right hand perpendicular frame that serves as the aligner frame for a given matrix.
Can you get more than one aligner frame for a given matrix?
Is it an issue?

The answer depends on how anal you want to be.

A=(({{Random[Real, {-2, 2}], Random[Real, {-2, 2}]}, {Random[Real, {-2, 2}], Random[Real, {-2, 2}]}}));
MatrixForm[
      A]

Clear[perpframe, s];
\(	{perpframe[1], 
        perpframe[2]}\  = \ {{Cos[s], Sin[s]}, {Cos[s + \ Pi/2], 
          Sin[s\  + \ Pi/2]}}\)

Now go after the s's that make
           (A . perpframe[1]) . (A . perpframe[2]) = 0:

schoices = Solve[(A . perpframe[1]) . (A . 
                perpframe[2])  ==  0, s]

This gives you four choices for s:

(Subscript[s, 1 ])= s/.schoices[[1]]

(Subscript[s, 2 ])= s/.schoices[[2]]

(Subscript[s, 3 ])= s/.schoices[[3]]

(Subscript[s, 4 ])= s/.schoices[[4]]

See four perpendicular frames all of which will work as aligner frame for this matrix:

{perpframe[1], perpframe[2]} /. s -> (Subscript[s, 1 ])

{perpframe[1], perpframe[2]} /. s -> (Subscript[s, 2 ])

{perpframe[1], perpframe[2]} /. s -> (Subscript[s, 3])

{perpframe[1], perpframe[2]} /. s -> (Subscript[s, 4])

Four right hand aligner frames - but they are just slightly repackaged versions of the first one.
Any of these will work very satisfactorily. And if you want to go with left hand aligner frames you can go with these:

{perpframe[1],-perpframe[2]}/.s -> (Subscript[s, 1 ])

{perpframe[1],-perpframe[2]}/.s -> (Subscript[s, 2 ])

{perpframe[1],-perpframe[2]}/.s -> (Subscript[s, 3])

{perpframe[1],-perpframe[2]}/.s -> (Subscript[s, 4])

Now you've got eight aligner frames.. 
But one is enough.

B.2)   Mathematica's SVD analysis instruction

B.2.a) Doing SVD analysis with a Mathematica instruction

Here's random 2D matrix A:

A=(({{Random[Real, {-2, 2}], Random[Real, {-2, 2}]}, {Random[Real, {-2, 2}], Random[Real, {-2, 2}]}}));
MatrixForm[
      A]

According to B.1) above,you can use SVD analysis to duplicate 
             A=hanger.stretcher.aligner 
this way:

Clear[perpframe, s];
	{perpframe[1], 
            perpframe[2]}  =  {{Cos[s], Sin[s]}, {Cos[s + (π/2)], 
              Sin[s + (π/2)]}};
schoices = Solve[(A . perpframe[1]).(A . perpframe[2]) == 0,s];
s  =  s /. schoices[[2]];

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

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

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

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

That's a lot of typing.
To eliminate the need for all this typing, Mathematica has an instruction that will help you do this SVD analysis quickly.
How do you use it?

To get an aligner matrix for A you do this:

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

To get the corresponding hanger matrix for A you do this:

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

To get the stretcher matrix for A, you do this:

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

Check it out:

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

Yep. It's as easy as 1-2-3.

If you want the individual vectors in the calculated aligner frame, do this:

Clear[alignerframe, k];
alignerframe[k_]:=SingularValues[A][[3,k]];
Table[
      alignerframe[k], {k, 1, 2}]

If you want xstretch and ystretch here they are:

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

If you want the individual vectors in the calculated hanger frame, do this:

Clear[hangerframe, k];
hangerframe[k_]:=SingularValues[A][[1,k]];
Table[
      hangerframe[k], {k, 1, 2}]

Check everything out:

MatrixForm[A]

MatrixForm[hanger.stretcher.aligner]

{A.alignerframe[1],xstretch hangerframe[1]}

{A.alignerframe[2],ystretch hangerframe[2]}

Everything checks.
Another way for the winning team of mathematics and Mathematica to serve you.

B.3)  Using SVD analysis and the fact that if 
             A =  hanger.(({{xstretch, 0}, {0, ystretch}})).aligner, 
             
then       (A^(-1)) = (aligner^t). (({{(1/xstretch), 0}, {0, (1/ystretch)}})). (hanger^t)   
to invert 2D matrices.
Using SVD analysis to recognize and deal with non-invertible matrices

B.3.a.i) Using SVD analysis to determine whether a matrix is invertible

Here's a random 2D matrix A:

A = (({{Random[Real, {-4, 4}], Random[Real, {-4, 4}]}, {Random[Real, {-4, 4}], Random[Real, {-4, 4}]}}));
MatrixForm[
      A]

Use SVD analysis to determine whether this matrix is invertible.

Check the SVD stretch factors:

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

Neither stretch factor is 0.
This tells you that is matrix is invertible.

B.3.a.ii) Using SVD analysis  and the fact that
  (A^(-1)) = (aligner^t). (({{(1/xstretch), 0}, {0, (1/ystretch)}})). (hanger^t)
  to construct the inverse

Stay with the same matrix A as in part i)
Here's Mathematica's calculation of (A^(-1)):

MatrixForm[Inverse[A]]

Use SVD analysis and matrix maker ingredients to explain where this calculation comes from.

Do SVD analysis of A by writing A in the form 
          A = hanger. stretcher. aligner:

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

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

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

Now remembering that  
->the hanger for (A^(-1)) is the transpose of the aligner for A
-> the stretch factors for (A^(-1)) are the inverses of the stretch factors for A 
->the aligner for (A^(-1)) is the transpose of the hanger for A,
you build
             (A^(-1)) = (aligner^t). (({{(1/xstretch), 0}, {0, (1/ystretch)}})). (hanger^t):

unstretcher=(({{(1/xstretch), 0}, {0, (1/ystretch)}}));
SVDinverse=Transpose[aligner].unstretcher.Transpose[hanger];
MatrixForm[
      SVDinverse]

Compare:

MatrixForm[Inverse[A]]

Not much to it when you understand what to do with the matrix maker ingredients.

B.3.a.iii) The moral

What's the moral?

You can use SVD analysis to build the inverse of any invertible matrix.

B.3.b.i) Using SVD analysis to recognize noninvertible matrices

Here's another sample 2D matrix A:

A=(({{1.2, -3.6}, {0.4, -1.2}}));
MatrixForm[
      A]

Here's Mathematica's attempt at a calculation of (A^(-1)):

MatrixForm[Inverse[A]]

Garbage.
Use SVD analysis to explain why that happened.

Look at the SVD stretch factors of A:

SingularValues[A][[2]]

Mathematica reports only one non-zero stretch factor.
This is Mathematica's way of telling you that one of the stretch factors is 0. 
And this tells you that A is not invertible.

B.3.b.ii) Using SVD analysis to determine the line on which a noninvertible matrix hangs all its hits

Stay with the same noninvertible matrix A as in part i).
Use SVD analysis to determine the line on which A hangs all its hits. Back up your answer with a convincing plot.

Look at:

alignerframe = SingularValues[A][[3]]

Mathematica delivers only the alignerframe vector whose corresponding stretch factor is not 0.
The matrix A hangs all its hits on the line with direction unit vector

linedirection =A .  alignerframe[[1]]/Norm[
            A .  alignerframe[[1]]]

This is the same as hangerframe[1].

SingularValues[A][[1]][[1]]

Watch it happen in this action movie:

Clear[hitpointplotter, pointcolor, actionarrows, matrix2D, r, x, y, 
        t];
ranger = 
        Max[Append[SingularValues[
                A][[2]], 
            1.5]];
\(\({x[t_], y[t_]} = {Cos[t], Sin[t]};\)
\)
pointcolor[t_] = 
        RGBColor[0.5 (Cos[t] + 1), 0.5 (Sin[t] + 1), 
          0];
{tlow, thigh}  =  { 0,  2 π};
\(\(tjump = \(thigh - tlow\)\/32;\)

\)
hitpointplotter[matrix2D_] := 
        Table[Graphics[{pointcolor[t], PointSize[0.03], 
              Point[matrix2D . {x[t], y[t]}]}], {t, tlow, thigh - tjump, 
            tjump}];
\(\(actionarrows[matrix2D_] := 
        Table[Arrow[matrix2D . {x[t], y[t]} - {x[t], y[t]}, 
            Tail -> {x[t], y[t]}, VectorColor -> pointcolor[t], 
            HeadSize -> 0.25], {t, tlow, thigh - tjump, 
            tjump}];\)
\)
\(\(before = 
        Show[hitpointplotter[IdentityMatrix[2]], 
          PlotLabel -> "Before", Axes -> True, 
          AxesLabel -> {"x", "y"}, 
          PlotRange -> {{\(-ranger\), ranger}, {\(-ranger\), ranger}}, 
          DisplayFunction -> $DisplayFunction];\)
\)
\(\(Show[before, actionarrows[A], PlotLabel -> "Action plot", 
        DisplayFunction -> $DisplayFunction];\)

\)
after = 
        Show[hitpointplotter[A], 
          Graphics[
            Line[{-2 ranger linedirection, 2 ranger linedirection}]], 
          PlotLabel -> "After", Axes -> True, 
          AxesLabel -> {"x", "y"}, 
          PlotRange -> {{-ranger, ranger}, {-ranger, ranger}}, 
          DisplayFunction -> $DisplayFunction];

That black line is the line through {0,0} whose direction is defined by:

hangerframe[1]

The noninvertible matrix A hangs all its hits in this line.

B.4)  Linear Algebra: If the coefficient matrix A is invertible ,  then given {u,v}  you can solve 
           A.{x,y} = {u,v} 
for {x,y} by putting
           {x,y} =  (A^(-1)).{u,v}.
If the coefficient matrix A is not invertible , saying you can solve 
           A.{x,y} = {u,v} 
for {x,y}  is the same as saying {u.v} is on the line through {0,0} running in the direction of hangerframe[1].

B.4.a) When the coefficient matrix A is invertible , you can solve 
           A.{x,y} = {u,v} 
for {x,y} by putting
           {x,y} =  (A^(-1)).{u,v}

Use what you know about matrices to try come up with the x and the y that solve the simultaneous linear equations:
      2.1 x - 1.7 y = 9.8
      1.8 x + 0.6 y = - 1.5.

Go with this matrix:

A=(({{2.1, -1.7}, {1.8, 0.6}}));
MatrixForm[
      A]

The linear system of equations is
       2.1 x - 1.7 y = 9.8
       1.8 x + 0.6 y = - 1.5.
This is the same as 
        A.{x,y} = {9.8 , -1.5}:

Clear[x, y];
A.{x, y}=={9.8,-1.5}

To come up with the x and the y that solve this system, just start with

A.{x,y} = {9.8 , -1.5}:

and hit both sides with (A^(-1)) to get

{x,y} = (A^(-1))A.{x,y} = (A^(-1)).{9.8.-1.5}:

{xsol, ysol}=Inverse[A] . {9.8, -1.5}

This is the solution.
Check:

A.{xsol, ysol}=={9.8, -1.5}

Got it.
This approach works anytime the coefficient matrix is invertible.

B.4.b.i) When the coefficient matrix A is not invertible , you can solve 
           A.{x,y} = {u,v} 
only if {u,v} is on the line through {0,0} in the direction of hangerframe [1]

Here's a matrix which is not invertible:

A=(({{0.6, -0.3}, {0.8, -0.4}}));
MatrixForm[
      A]

Inverse[A]

That's garbage.
In spite of this, the corresponding linear system, for given u and v,
        3.0 x - 1.5 y = u
        1.0 x - 0.5 y = v
might have many or no solutions for x and y, depending on where the point {u,v} is located.
How do you make this determination?

Begin your SVD analysis of A:

stretches=SingularValues[A][[2]]

Only one non-zero stretch factor. (As expected because A is not invertible.)
Let Mathematica give you the hangerframe vector corresponding to this lone stretch factor:

hangerframe[1] =SingularValues[A][[1]][[1]]

Hitting a point {x,y} with A will result in a point hung on the line through {0,0} determined by hangerframe[1]. 
What it happen in this action movie:

ranger

a Max[SingularValues[A][[2]]]

a = 2;
points = 
        Table[{Random[Real, {-a, a}], Random[Real, {-a, a}]}, {k, 1, 
            100}];

\(\(ranger = \ a\ Max[\(SingularValues[A]\)[\([2]\)]];\)
\)
\(\(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.03], pointcolor[k], 
              Point[points[[k]]]}], {k, 
            1, Length[points]}];\)
\)
\(\(hitpointplot = 
        Table[Graphics[{PointSize[0.03], 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[{LightSeaGreen, Thickness[0.01], 
            Line[{\(-b\)\ hangerframe[1], 
                b\ hangerframe[1]}]}];\)
\)
\(\(before = 
        Show[lineplot, pointplot, Axes -> True, 
          AxesLabel -> {"x", "y"}, 
          PlotRange -> {{\(-ranger\), ranger}, {\(-ranger\), ranger}}, 
          PlotLabel -> "Before"];\)
\)
\(\(Show[before, actionarrows, 
        PlotRange -> {{\(-ranger\), ranger}, {\(-ranger\), ranger}}, 
        PlotLabel -> "Action arrows"];\)
\)
after = 
        Show[lineplot, hitpointplot, Axes -> True, 
          AxesLabel -> {"u", "v"}, 
          PlotRange -> {{-ranger, ranger}, {-ranger, ranger}}, 
          PlotLabel -> "After"];

The plotted line is the line through {0,0} defined by hangerframe[1].
The upshot:
Given {u,v}, if you are going to have any chance of solving
          A.{x,y} = {u,v}
for {x,y}, then {u,v} MUST be on the line through {0,0} defined by
          hangerframe[1].
          
This is the same as saying that {u,v} is its own component in the direction of hangerframe[1].

And this is the same as saying

             {u,v} = ({u,v}.hangerframe[1]) hangerframe[1]

B.4.b.ii) Failure because  {u,v} is not on the line through {0,0} in the direction of hangerframe [1]

Stay with the same matrix A as in part i) above.
Go with 
            {u,v} = {1.00,1.45}
Does the linear system
           A.{x,y} = {u,v},
(which is the same as
             3.0 x - 1.5 y = u
             1.0 x - 0.5 y = v)
have a solution for x and y?

Remember that if you are going to have any chance of solving
          A.{x,y} = {u,v}
for {x,y}, then {u,v} MUST be on the line through {0,0} defined by
          hangerframe[1].
 
This is the same as saying
        {u,v} = ({u,v}.hangerframe[1]) hangerframe[1].
 Check this out:

{u, v}={1.00, 1.45}

({u, v}.hangerframe[1]) hangerframe[1]

Close, but no cigar. 
The linear system
         A.{x,y} = {1.00,1.45}
has NO solutions for x and y.

B.4.b.iii) Success because  {u,v} is  on the line through {0,0} in the direction of hangerframe [1]

Stay with the same matrix A as in part i) above.
Go with 
            {u,v} = {2.46, 3.28}
Does the linear system
           A.{x,y} = {u,v},
(which is the same as
             3.0 x - 1.5 y = u
             1.0 x - 0.5 y = v)
have a solution for x and y?

Check:

{u, v}={2.46, 3.28}

({u, v}.hangerframe[1]) hangerframe[1]

These agree.
This tells you that the system
         A.{x,y} = {u,v} = ({u,v}.hangerframe[1]) hangerframe[1]  
DOES have a solution {x,y}.

B.4.b.iv) Coming up with a solution {x,y} through the formula
                   {x, y} =((({u, v}.hangerframe[1] )alignerframe[1])/xstretch)

Stay with the same matrix A as in part i) above.
At this point you know that if  
            {u,v} = {2.46, 3.28},
the linear system
           A.{x,y} = {u,v}
does have a solution {x,y}.
Here's how you can get one .

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

Clear[alignerframe];
alignerframe[1]=SingularValues[A][[3]][[1]]

xstretch=SingularValues[A][[2]][[1]]

You build a solution {x,y} this way:

Xsol=((({u, v}.hangerframe[1] )alignerframe[1])/xstretch)

Try it out:

A . Xsol

{u, v}

Explain why that worked.

You know
         {u, v}=({u, v}.hangerframe[1] )hangerframe[1]. 
         
And you know
         A . alignerframe[1]=xstretch hangerframe[1].
         
This is the same as
         A.(((alignerframe[1])/xstretch))=hangerframe[1].
         
And this is the same as
A.(((({u, v}.hangerframe[1]) alignerframe[1])/xstretch))=({u,v}.hangerframe[1]) hangerframe[1]. 
                                
And this is the same as
        A.(((({u, v}.hangerframe[1]) alignerframe[1])/xstretch))={u, v}
because .
         {u, v} = ({u, v} . hangerframe[1] ) hangerframe[1].
The upshot:
When you hit A on
           ((({u, v} . hangerframe[1]) alignerframe[1])/xstretch),
you are guaranteed to get {u, v}.

That's where the formula:

Xsol=(({u, v} . hangerframe[1] alignerframe[1])/xstretch)

comes from.

B.4.b.v) Success comes in spades

Stay with the same matrix A as in part iii) above. And stay with the same {x,y} and {u,v} as in part iii) so that 
           A.{x,y} = {u,v}
Are there solutions other than the {x,y} you found in part iii)?
If so, indicate with a plot where they are.

You bet there are!

To see where they come from, remember that ystretch = 0. This tells you that hits with A collapse everything perpendicular to alignerframe[1] to {0,0}.
Look at:

alignerframe[1]

A vector perpendicular to alignerframe[1] is:

alignerframe[2] = {alignerframe[1][[2]],-alignerframe[1][[1]]}

Check:

A . alignerframe[2]

Consequently when you go with the Xsol you got in the last part and add to it any multiple of alignerframe[2], you get another solution:

Clear[t];
Chop[Expand[A . (Xsol + t alignerframe[2])]]

{u, v}

The upshot:
All the solutions of the linear system
           A.{x,y} = {u,v} 
are located on the line through {x,y} with direction vector alignerframe[2].
These are the points parameterized by:

Clear[solutionline, t];
solutionline[t_] = Xsol + t alignerframe[2]

Here's a look at part of this line:

basepoint = Xsol;
\(\(basepointplot = 
        Graphics[{Red, PointSize[0.05], Point[basepoint]}];\)

\)
\(\(solutionlineplot = 
        Graphics[{NavyBlue, Thickness[0.02], 
            Line[{solutionline[\(-1\)], solutionline[4]}]}];\)
\)
\(\(Xsollabel = Graphics[Text["Xsol", basepoint]];\)
\)
solutionlineplot = 
        Show[basepointplot, Xsollabel, solutionlineplot, Axes -> True, 
          PlotRange -> All, 
          AxesLabel -> {"x", "y"}];

See an action movie showing A hit all points on the line smack-dab onto {u,v}:

Clear[hitpointplotter, pointcolor, actionarrows, matrix2D, r, x, y, 
        t];
\(\({x[t_], y[t_]} = solutionline[t];\)
\)
pointcolor[t_] = 
        RGBColor[0.5 (Cos[t] + 1), 0.5 (Sin[t] + 1), 
          0];
{tlow, thigh}  =  { -1, 4};
\(\(tjump = \(thigh - tlow\)\/20;\)

\)
hitpointplotter[matrix2D_] := 
        Table[Graphics[{pointcolor[t], PointSize[0.03], 
              Point[matrix2D . {x[t], y[t]}]}], {t, tlow, thigh - tjump, 
            tjump}];
\(\(actionarrows[matrix2D_] := 
        Table[Arrow[matrix2D . {x[t], y[t]} - {x[t], y[t]}, 
            Tail -> {x[t], y[t]}, VectorColor -> pointcolor[t], 
            HeadSize -> 0.25], {t, tlow, thigh - tjump, 
            tjump}];\)
\)
\(\(before = 
        Show[solutionlineplot, hitpointplotter[IdentityMatrix[2]], 
          PlotLabel -> "Before", Axes -> True, 
          AxesLabel -> {"x", "y"}, 
          PlotRange -> {{2, 6}, {\(-3\), 3.5}}, 
          DisplayFunction -> $DisplayFunction];\)
\)
\(\(Show[before, actionarrows[A], PlotLabel -> "Action plot", 
        DisplayFunction -> $DisplayFunction];\)

\)
after = 
        Show[hitpointplotter[A], 
          PlotLabel -> "After the hit with A", Axes -> True, 
          AxesLabel -> {"x", "y"}, 
          PlotRange -> {{2, 6}, {-3, 3.5}}, 
          DisplayFunction -> $DisplayFunction];

Think of it: 
All points {x,y} on the plotted line are solutions of 
        A.{x,y} = {u,v}.
The moral:
If A is not invertible and 
          A.{x,y} = {u,v} 
has any one solution then it has bundles of solutions. 
It's enough to make you want to freak out.

B.5) Positive versus negative orientation of the columns of a 2D matrix.
If the columns of A are positively oriented, then Det[A] =  + xstretch ystretch.
If the columns of A are negatively oriented, then Det[A] =  — xstretch ystretch.
So you can use |Det[A]| = xstretch ystretch as the area conversion factor. 
If you interchange the vertical columns of a 2D matrix, you change the sign but not the absolute value of the determinant.
The short, sweet formula Det[(({{a, b}, {c, d}}))]  =   a d  - b c

B.5.a ) Positive versus negative orientation of the columns of a 2D matrix

Here is a 2D matrix A together with a plot of the vertical columns of A:
           col[1] = A.{1,0} and col[2] = A.{0,1}

Clear[columnplotter, matrix];
columnplotter[matrix_] := Show[Arrow[matrix.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.4],Arrow[matrix.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.5],Graphics[{Text["col[1]= A.{1,0}",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  matrix.{0, 1}]}],Axes -> True,AxesLabel -> {"x", "y"},PlotRange -> {{-1.5, 1.5}, {-1.5, 1.5}},PlotLabel ->If[ Det[A] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[A]  < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
DisplayFunction -> Identity];
A=(({{1.0, -1.2}, {1.0, 0.7}}));


Show[
        columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A =" MatrixForm[A]

Matrix folks say that the orientation of the columns of A is positive.
Now look at the columns of A = "" (({{-1.2, 1.0}, {0.7, 1.0}}))

A= (({{-1.2, 1.0}, {0.7, 1.0}}));
Show[columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A =" MatrixForm[A]

Look at the same thing for random matrices A:

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

A=(({{a[1, 1], a[1, 2]}, {a[2, 1], a[2, 2]}}));
Show[columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A = " MatrixForm[A]

Rerun many times and then say what positive and negative orientation means.

Take a look at this one:

A=(({{0.8, -1.1}, {1.2, -0.8}}));
Show[columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A = " MatrixForm[A]

This is positive orientation and the shorter angle from col[1] to col[2] is counterclockwise.

And take a look at this one:

A=(({{-1.3, 1.4}, {0.6, 1.2}}));
Show[columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A = " MatrixForm[A]

This is negative orientation and the shorter angle from col[1] to col[2] is clockwise.

That's all there is to it. 

The columns of a 2D matrix A are positively oriented if the shorter angle from col[1] to col[2] is counterclockwise. 
The columns of a 2D matrix A are negatively oriented if the shorter angle from col[1] to col[2] is clockwise.

Try it again for random matrices A:

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

A=(({{a[1, 1], a[1, 2]}, {a[2, 1], a[2, 2]}}));
Show[columnplotter[A], 
        DisplayFunction -> $DisplayFunction];
"A = " MatrixForm[A]

Rerun until the idea crystallizes.

B.5.b.i) Definition of determinant first part:
If the columns of A are positively oriented, then Det[A] =  + xstretch ystretch

Here's a 2D matrix A together with Mathematica's calculation of the determinant of A:

A=(({{ 2.2, 0.9}, {0.5, 1.7}}));
Det[
      A]

What does this calculation of Det[(({{ 2.2, 0.9}, {0.5, 1.7}}))] measure?

Go with the unit square with corners at {0,0},{1,0},{1,1} and {0,1}:

unitsquare =Show[Graphics[
              Line[{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}]],Arrow[{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],Axes -> True,AxesLabel -> {"x", "y"}];

Here's what you get when you hit everything with A=(({{ 2.2, 0.9}, {0.5, 1.7}})):

A=(({{ 2.2, 0.9}, {0.5, 1.7}}));
Clear[hitplotter, 
        matrix];
hitplotter[matrix_] :=Show[Graphics[Line[{matrix.{0, 0},matrix.{1, 0},matrix.{1, 1},matrix.{0, 1},matrix.{0, 0}}]],Arrow[matrix.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[matrix.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1]= A.{1,0}",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  matrix.{0, 1}]}],
PlotLabel ->If[ Det[matrix] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[matrix]  < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],Axes -> True,AxesLabel -> {"x", "y"}];
hitplotter[A];

That's the parallelogram defined by the columns of A.
As you can see the columns of A have positive orientation.

If any given 2D matrix A has positively oriented columns,
         Det[A] is defined to be the area measurement of the  parallelogram defined by the columns of A.
         
Because the area of the square measures out to 1 and you hit A on the square to get the parallelogram, 
Det[A] is given by:

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

Check:

Det[A]

On the money.

B.5.b.ii )  Definition of determinant second part:
If the columns of A are negatively oriented, then Det[A] = —xstretch ystretch

Here's another 2D matrix A together with Mathematica's calculation of the determinant of A:

A=(({{ 0.9, 2.2}, {1.7, 0.5}}));
Det[
      A]

What does this calculation of Det[(({{ 0.9, 2.2}, {1.7, 0.5}}))] measure?

Go with the unit square with corners at {0,0},{1,0},{1,1} and {0,1}:

Clear[hitplotter, matrix];
hitplotter[matrix_] :=Show[Graphics[Line[{matrix.{0, 0},matrix.{1, 0},matrix.{1, 1},matrix.{0, 1},matrix.{0, 0}}]],Arrow[matrix.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[matrix.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1]",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2]",0.5  matrix.{0, 1}]}],
PlotLabel ->If[ Det[matrix] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[matrix]  < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],Axes -> True,AxesLabel -> {"x", "y"}];
hitplotter[
        IdentityMatrix[2]];

Here's the parallelogram you get when you hit this square with  A=(({{ 0.9, 2.2}, {1.7, 0.5}})):

A=(({{ 0.9, 2.2}, {1.7, 0.5}}));
hitplotter[
        A];

That's the parallelogram defined by the columns of A.
As you can see, the columns of A have negative orientation.

If any given 2D matrix A has negatively oriented columns,
         -Det[A] is defined to be the area measurement of the  parallelogram defined by the columns of A.
         
Because the area of the square measures out to 1 and you hit A on the square to get the parallelogram, 
Det[A] is given by:

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

Check:

-Det[A]

Try some more for random matrices A:

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

A=(({{a[1, 1], a[1, 2]}, {a[2, 1], a[2, 2]}}));
Clear[hitplotter, 
        matrix];
hitplotter[matrix_] :=Show[Graphics[Line[{matrix.{0, 0},matrix.{1, 0},matrix.{1, 1},matrix.{0, 1},matrix.{0, 0}}]],Arrow[A.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[A.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1] = A.{1,0}",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  matrix.{0, 1}]}],
PlotLabel ->If[ Det[A] > 0,"\!\(\*
StyleBox[\"Pos\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation, so \!\(\*
StyleBox[\"Det\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"[\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"]\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\" \",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"=\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\" \",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"area\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\" \",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"enclosed\",\nFontColor->RGBColor[0, 0, 1]]\)",If[Det[A]  < 0,"\!\(\*
StyleBox[\"Neg\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation, so \!\(\*
StyleBox[\"Det\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"[\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"A\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"]\",\nFontColor->RGBColor[0, 0, 1]]\) = \!\(\*
StyleBox[\"-\",\nFontSize->16,\nFontColor->RGBColor[1, 0, 0]]\)\!\(\*
StyleBox[\"area\",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\" \",\nFontColor->RGBColor[0, 0, 1]]\)\!\(\*
StyleBox[\"enclosed\",\nFontColor->RGBColor[0, 0, 1]]\)","No Orientation"]],Axes -> True,AxesLabel -> {"x", "y"}];
hitplotter[A];

Rerun until you feel good.

B.5.b.iii)  Using the determinant to measure area

Here's a random 2D matrix A together with the ellipse you get when you hit the unit circle with A:

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

A=(({{a[1, 1], a[1, 2]}, {a[2, 1], a[2, 2]}}));
ellipseplot  =  
        ParametricPlot[A . {Cos[t], Sin[t]}, {t, 0, 2 Pi}, 
          PlotStyle -> {{GosiaGreen, Thickness[0.01]}}, 
          DisplayFunction -> Identity];
Clear[columnplotter, matrix];

columnplotter[matrix_] := Show[Arrow[matrix.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.4],Arrow[matrix.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.5],Graphics[{Text["col[1]= A.{1,0}",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  matrix.{0, 1}]}],Axes -> True,AxesLabel -> {"x", "y"},PlotRange -> {{-2, 2}, {-2, 2}},PlotLabel ->If[ Det[A] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[A]  < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],
DisplayFunction -> Identity];



Show[columnplotter[A], ellipseplot, 
        DisplayFunction -> $DisplayFunction];
"A =" MatrixForm[A]

The area enclosed by this ellipse measures out to:

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

Use the determinant of A to duplicate this calculation.

Just go with |Det[A]| π:

Abs[Det[A]]π

The reasons:
If the columns of A are positively oriented,then Det[A] =  + xstretch ystretch.
If the columns of A are negatively oriented,then Det[A] =  - xstretch ystretch.
Either way:   |Det[A]|  = xstretch ystretch.

B.5.b.iv)  If you interchange the vertical columns of a 2D matrix, you change the sign but not the absolute value of the determinant

Here's a random 2D matrix A:

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

A=(({{a[1, 1], a[1, 2]}, {a[2, 1], a[2, 2]}}));
MatrixForm[A]

Here's the matrix you get when you interchange the two columns of A:

interchangedA = A.(({{0, 1.0}, {1.0, 0}}));
MatrixForm[interchangedA]

Calculate the determinants of each:

{Det[A], Det[interchangedA]}

The result:
            Det[interchangedA] = - Det[A].
Explain why it had to turn out this way

Go with the unit square with corners at {0,0},{1,0},{1,1} and {0,1}:

Clear[hitplotter, matrix];
hitplotter[matrix_] :=Show[Graphics[Line[{matrix.{0, 0},matrix.{1, 0},matrix.{1, 1},matrix.{0, 1},matrix.{0, 0}}]],Arrow[matrix.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[matrix.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1]",0.6 matrix.{1, 0}]}],Graphics[{Text["col[2]",0.5  matrix.{0, 1}]}],
PlotLabel ->If[ Det[matrix] > 0,"\!\(\*
StyleBox[\"Positive\",\nFontColor->RGBColor[0, 0, 1]]\) Orientation",If[Det[matrix]  < 0,"\!\(\*
StyleBox[\"Negative\",\nFontColor->RGBColor[1, 0, 0]]\) Orientation","No Orientation"]],Axes -> True,AxesLabel -> {"x", "y"}];
hitplotter[
        IdentityMatrix[2]];

Here's the parallelogram you get when you hit everything with  A:

Ahit  = hitplotter[A];

Here's the parallelogram you get when you hit everything with  interchangedA:

interchangedAhit  = 
        hitplotter[interchangedA];

That's the parallelogram defined by the columns of interchangedA. 
Notice that both parallelograms are the same physical parallelograms.

Show[GraphicsArray[{Ahit, interchangedAhit}]];

So 
              enclosed area = |Det[A]| = |Det[interchangedA]|.

But the orientation of the columns of interchangedA is opposite to the orientation of the columns of A.
So Det[A] and Det[interchangedA] have opposite signs.

) B.5.c) The short, sweet formula Det[(({{a, b}, {c, d}}))]  =   a d  - b c

Look at Mathematica's calculation of the determinant of a cleared matrix A = (({{a, b}, {c, d}})):

Clear[a, b, c, d];
A=(({{a, b}, {c, d}}));
Det[A]

Explain where this short, sweet formula comes from.

Case 1:  The columns of A are positively oriented (so Det[A] = xstretch ystretch).

Hit the matrix on:

unitsquare =Show[Graphics[
              Line[{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}}]],Arrow[{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],Axes -> True,AxesLabel -> {"x", "y"}];

to get:

{a, b, c, d}   =  {2.2, 1.1, 0.5, 1.8};

A=(({{a, b}, {c, d}}));
hitplot =Show[Graphics[Line[{A.{0, 0},A.{1, 0},A.{1, 1},A.{0, 1},A.{0, 0}}]],Arrow[A.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[A.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1]= A.{1,0}",0.6 A.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  A.{0, 1}]}],Axes -> True,AxesLabel -> {"x", "y"}];

In this sample, the smaller angle running from col[1] to col[2] is counterclockwise signalling columns of A are in positive orientation. So Det[A] = xstretch ystretch.  
And because the area of the square measures out to 1, the area of the parallelogram measures out to 
              area = Det[A].

Now measure the area a different way.
Look again at A = (({{a, b}, {c, d}})):
The left column of A is

Clear[col];
col[1] ={a,c}

The right column of A is:

col[2]={b,d}

Make a vector perpendicular to col[2]

Clear[perpcol];
perpcol[2] = {d,-b}

Throw it into the plot:

Show[hitplot,Arrow[perpcol[2],Tail -> {0, 0},VectorColor -> GosiaGreen],
	Graphics[Text["perpcol[2]", 0.5  perpcol[2]]]];

The area of the parallelogram measures out to
           area =   ||col[1]||  ||col[2]||  Sin[short angle from col[1] to col[2]] .
So 
        Det[A] = area =   ||col[1]||  ||col[2]||  Sin[short angle from col[1] to col[2]] .   .
  This is the same as
             Det[A] =    ||col[1]||  ||col[2]||  Cos[short angle from col[1] to perpcol[2]]  .
             
 And because 
             ||col[2]||  = (Sqrt[(b^2) + (d^2)]) = (Sqrt[(d^2) +  (((-b))^2)]) = ||perpcol[2]||,
             
          Det[A] =     ||col[1]||  ||perpcol[2]|| Cos[short angle from col[1] to perpcol[2]] .
          
And this is the same as the dot product
         Det[A] = col[1]].perpcol[2]
                     = {a,c}.{d,-b} = a d - b c.

So in the case that the columns of A are positively oriented, the formula
                  Det[(({{a, b}, {c, d}}))] = a d - b c 
is explained.

Case 2:  The columns of A are negatively oriented (so Det[A] = -xstretch ystretch).

Now see what happens when you hit a matrix whose columns are negatively oriented on the same unit square.

{a, b, c, d}   =  {0.5, 1.7, 2.2, 0.9};

A=(({{a, b}, {c, d}}));
hitplot =Show[Graphics[Line[{A.{0, 0},A.{1, 0},A.{1, 1},A.{0, 1},A.{0, 0}}]],Arrow[A.{1, 0},Tail -> {0, 0},VectorColor -> NavyBlue,HeadSize -> 0.2],  Arrow[A.{0, 1},Tail -> {0, 0},VectorColor -> AlizarinCrimson,HeadSize -> 0.2],
Graphics[{Text["col[1]= A.{1,0}",0.6 A.{1, 0}]}],Graphics[{Text["col[2] = A.{0,1}",0.5  A.{0, 1}]}],Axes -> True,AxesLabel -> {"x", "y"}];

The smaller angle running from col[1] to col[2] is clockwise, signalling that the columns of A are negatively oriented. 
So the area of the parallelogram measures out to
               area = —Det[A].

Now measure the area a different way.
Look again at A = (({{a, b}, {c, d}})):
The left column of A is

Clear[col];
col[1] ={a,c}

The right column of A is:

col[2]={b,d}

Make a vector perpendicular to col[2]

Clear[perpcol];
perpcol[2] = {-d,b}

Throw it into the plot:

Show[hitplot,Arrow[perpcol[2],Tail -> {0, 0},VectorColor -> GosiaGreen],
	Graphics[Text["perpcol[2]", 0.5  perpcol[2]]]];

The area of the parallelogram measures out to
           area =   ||col[1]||  ||col[2]||  Sin[short angle from col[1] to col[2]] .
So 
        -Det[A] = area =   ||col[1]||  ||col[2]||  Sin[short angle from col[1] to col[2]] .   .
  This is the same as
        -Det[A] =    ||col[1]||  ||col[2]||  Cos[short angle from col[1] to perpcol[2]]  .
             
 And because 
               ||col[2]||  = (Sqrt[(b^2) + (d^2)]) = (Sqrt[(((-d))^2) +  (b^2)]) = ||perpcol[2]||,
             
          -Det[A] =     ||col[1]||  ||perpcol[2]|| Cos[short angle from col[1] to perpcol[2]] .
          
And this is the same as the dot product
            - Det[A] = col[1]].perpcol[2]
                     = {a,c}.{-d,b} = -a d + b c.

Multiply through by - 1 to get
                Det[A] = a d - b c

So in the case that the columns of A are negatively oriented, the formula
                  Det[(({{a, b}, {c, d}}))] = a d - b c 
is explained.

Case3:  The columns of A are neither positively or negatively oriented.
Go with (({{a, b}, {c, d}})).
In this case  the columns point in the same or opposite direction.
In this case the parallelogram collapses to a straight line. So the area of the parallelogram measures out to
0 .
Because area= |Det[A]|, this tells you, Det[A] = 0.
Also in this case  col[1]  = u col[2]
So unless col[2] = {0,0}, you can be sure col[1]  = u col[2] a number u.
This gives {a,c} = {u b, u d} and 
             a d - b c = u b d -  u d b = 0.
And if col[2] = {0,0}, then a d - b c = a 0 - b 0 = 0.
The upshot: In this case
     Det[A] = a d - b c as well.
Now you are at the point where you know why

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