Tutorial 3 -  Linear Algebra 1

generic ECE - U. Houston

Han Q. Le (c) copyrighted

1. Vector dot (inner) product

1.1 Example 1

Consider this data:

Exercise 1.1

Define variable ntrip that contains data of the first row, and mileage that contains the data in the second row. Then find the total frequent-flyer mileage.

Answer

ntrip={5,2,6,3,3,1,4} ;
mileage={1052,740,576,1380,824,10850,438} ;
ntrip  . mileage

END exercise

In the above, we see that any one-D array can be considered as a vector in space (linear algebra concept). The length of the array is the dimension of the space.

What we learn above with vector ntrip and mileage is their “dot product”, one of the MOST frequent and useful math operations of array data.

Consider this example: one has a number of shares of various stock shareX at priceX, what is the value of each stock and what is the net value?

priceX={52.,86.4,22.5,134}; shareX={500,250,400,300};
valueEach=priceX *shareX
Total[valueEach]

Length[priceX]

The dimension of the space of priceX is 4.

1.2 Dot product

The operation between 2 arrays:
       {(Subscript[x, 1]), (Subscript[x, 2]), (Subscript[x, 3]), ..} and {(Subscript[y, 1]), (Subscript[y, 2]), (Subscript[y, 3]),..}
        (Subscript[x, 1])*(Subscript[y, 1])+(Subscript[x, 2])*(Subscript[y, 2])+ (Subscript[x, 3])*(Subscript[y, 3]) +... (Subscript[x, n])*(Subscript[y, n])
as mentioned, a most common operation in computer calculation of arrays, is mathematically formally defined as the dot product:
        (Subscript[x, 1])*(Subscript[y, 1])+(Subscript[x, 2])*(Subscript[y, 2])+ (Subscript[x, 3])*(Subscript[y, 3]) +... (Subscript[x, n])*(Subscript[y, n]) ≡ x . y    
where x array and y array are considered as vectors.

In all higher-level language, using function dot means we can skip step in more basic language, such as using do loop:

priceX={52.,86.4,22.5,134}; shareX={500,250,400,300};
total=0;
Do[
total=total+  priceX[[i]]* shareX[[i]]
,{i,1,Length[shareX]}
] ;
total

The trend of computing is to create more and more built-in high-level functions such that the user can obtain results with less and less programming effort. Mathematica, Matlab, high-level library and special packages (R, Spyder) in Python, etc. are designed toward this goal.

Examples of dot product are abound and common in spreadsheet calculations. In fact, even the sum (total) of an array is considered as the dot product of the array and vector {1,1,1,...}.

Here is a common application:

workername={"John","Jane","Bob","George","Sue"};
workerhours={35,40,45,20, 38} ;
payrate={15,30,27,38,22};
payrolltotal=payrate . workerhours

Column[{
Grid[{workername,workerhours,payrate,workerhours*payrate},Frame-> All]
,Grid[{{"total = ",payrolltotal}}]
}]

Below is what we learn about dot product between physical vector in 2 D space:

Manipulate[
pdotq=p . q ; θpq=VectorAngle[p,q] ;
pθ=Arg[{1, I} . p ] ;qθ=Arg[{1, I} . q ] ;
unitp=If[p . p==0.,{0,1.},(p/(Sqrt[p . p]))];
unitq=If[q . q==0.,{0,1.},(q/(Sqrt[q . q]))];
ptP=unitp *(( pdotq)/(Sqrt[p . p]));  ptQ=unitq *(pdotq/(Sqrt[q . q])) ;
(* repetitive (Sqrt[p . p]) and (Sqrt[q . q]) are for illustration 
Function is Norm[p] = (Sqrt[p . p])  *)
If[(pdotq^2)< (p . p)  (q . q) -0.01
,sP=((p-ptQ)/(Norm[p-ptQ])) ;sQ=((q-ptP)/(Norm[q-ptP])) ;
isquare=True
,isquare=False];
projline=Graphics[{
Thickness[0.0015],Dashed
,Hue[0.5,1,1],Line[{pt0,ptP}]
,Hue[0.15,1,1],Line[{pt0, ptQ}]
,White,Line[{p,ptQ}],Line[{q,ptP}]
}];
squaregr=If[TrueQ[isquare]
,Graphics[{Hue[0.85,0.35,1,0.75]
,Polygon[ptP+#& /@ {pt0,0.1unitp,0.1unitp+0.1 sQ ,0.1 sQ,pt0}]
,Hue[0.48,0.6,1,0.75]
,Polygon[ptQ+#& /@ {pt0,0.1unitq,0.1unitq+0.1 sP ,0.1 sP,pt0}]
}]
,Graphics[{Point[{-5,-5}]}]
];
(* # is equivalent with lambda-argument function in Python  *)
(* aka anonymous function in programming languages *)
vectors=Graphics[{
Hue[0.15,1,1,0.8],Disk[pt0,0.2,{pθ,qθ}]
,Thickness[0.006],Arrowheads[0.08]
,Hue[0.35,1,1],Arrow[{pt0,p}]
,Hue[0.08,1,1],Arrow[{pt0,q}]
,Text[Style["p",20,Hue[0.38,1,1]
,Bold, FontFamily->"Times New Roman"],p+0.12 unitp]
,Text[Style["q",20,Hue[0.07,1,1]
,Bold, FontFamily->"Times New Roman"],q+0.12 unitq]
,Text[Style["p . q = "<>ToString[NumberForm[pdotq,{3,2}]]
,20,White,Bold, FontFamily->"Times New Roman"]
,{0,1.2}]}];
Show[frame0,projline,squaregr,vectors
,PlotRange-> {{-1.2,1.2},{-1.2,1.3}}
,Background->Black
,AspectRatio->Automatic]

,{{p,{0.5,0.8}},{-1,-1},{1,1},Locator}
,{{q,{-0.6,0.7}},{-1,-1},{1,1},Locator}
,Initialization:>{
pt0={0,0};
frame0=Graphics[{White, Thickness[0.002]
,Arrowheads[0.05]
,Arrow[{{-1.15,0},{1.15,0}}]
,Arrow[{{0,-1.15},{0,1.15}}]}];

}]

Exercise 1.2

Consider a circuit with n devices, make your choice of n between 5 and 8. Generate arrays of the device voltages and currents (your choice of values). Find the net power consumption of all devices.

Answer

ndev=RandomInteger[{5,8}]
voltage=RandomReal[{-10,10},ndev]
current=RandomReal[{-1,1},ndev]
voltage . current
ListPlot[Transpose[{current, voltage}]
,PlotRange-> All
,PlotStyle-> {PointSize[0.025],Blue}
,Filling->0.
, Frame-> True
,GridLines->Automatic]

Exercise 1.3

Consider the score of a student as a two-D vector: {homework, classwork}. One way to combine this into a final score is to assign a weight to each score, for example:
              (Subscript[w, 1])*homework+(1-(Subscript[w, 1])) classwork
Generate a multinormal random distribution to simulate a class (e. g. 100), and obtain a histogram of the combined score as a function of weight

Answer (given)

Manipulate[
If[TrueQ[SIMscore] || !TrueQ[npopold==npop] 
,scores0=RandomVariate[BinormalDistribution[μscore,σsc,ρsc],npop];
scores=Table[{Max[0,s[[1]]],Max[0,s[[2]] ]},{s,scores0}];
μhat=Mean[scores]; Σh=Covariance[scores];
{eigenλ,eigenvect}=Eigensystem[Σh] ;
axL=Sqrt[eigenλ];
ellips=Graphics[{Thickness[0.003],Arrowheads[0.08]
,Table[{Hue[hax[[i]],1,1,1],Arrow[μhat+# & /@ (2*axL[[i]]*{eigenvect[[i]],-eigenvect[[i]]})]
}
,{i,Length[axL]}]
,White,PointSize[0.05],Point[μhat]
,Hue[0,1,1,1],PointSize[0.03],Point[μhat]
,Hue[0.15,1,1,0.2],Ellipsoid[μhat,4* Σh]
}];
scoreGraph=Graphics[{PointSize[0.025]
,Table[{Hue[((i-1)/(Length[scores]+1)),0.65,1,0.85],Point[scores[[i]]]},{i,Length[scores]}]}];
SIMscore=False; npopold=npop
,];
wunit={weigh,1-weigh}/Norm[{weigh,1-weigh}];
wvec=Graphics[{Dashed,Thickness[0.0025]
,Hue[0.45,1,1,1],Line[{{100,0},{0,100}}]
,White,Line[{{0,0},300*{weigh,1-weigh}}]
,Dashing[{1,0}],Hue[0.,1,1,0.8],Thickness[0.0075],Arrowheads[0.075]
,Arrow[{{0.,0.},100*{weigh,1-weigh}}]
,}];
scoreComb=(scores . {weigh,1-weigh}) ;
scproj=scoreComb /Norm[{weigh,1-weigh}] ;
scprojGr=If[TrueQ[PROJ]
,Graphics[{Table[{PointSize[0.017]
,Hue[((i-1)/(Length[scproj]+1)),0.65,1],Point[scproj[[i]] wunit]
,PointSize[0.01],Hue[0,1,1,1]
,Point[scproj[[i]] wunit]
,White, Thickness[0.001],Dashed
,Line[{scproj[[i]] wunit,scores[[i]] }]}
,{i,Length[scproj]}]}]
,bogusgr];
Grid[{{Show[scoreGraph,wvec,scprojGr
,If[TrueQ[ELLIPS],ellips,bogusgr]
,PlotRange-> {{0,150},{0,150}},Frame-> True
,FrameStyle-> White
,Background-> Black
,ImageSize-> 350]
,Histogram[scoreComb,25,ChartStyle->"BrightBands"
,PlotRange->All
,Frame->True, GridLines->Automatic
,ImageSize->350]
}}]

,Grid[{{Button["simulate",SIMscore=True],Control[{{npop,50},{10,20,50,100}}]
,Button["projection",PROJ=!PROJ],Button["ellipsoid",ELLIPS=!ELLIPS]}}]
,{{weigh,0.5},0.,1}
,Initialization:>{PROJ=False;ELLIPS=False;
μscore={80.,90.};σsc={30.,20.};
ρsc=0.6 ;hax={0.35,0.08,0.88};
SIMscore=True;
bogusgr=Graphics[{PointSize[0.0001],Point[{-1,-1}]}]
}]

2. Matrix and vector product

2.1 Table of higher dimension: List of List

Consider this:

How do we represent such data? It is a table. The first row is just

{"","","price($)/unit","","",""}

{"","# units","store A","store B","store C","store D"}
{"juice",3,1.55,1.45,1.65,1.4}

grocerylist= 
{
{"","","price($)/unit","","",""}
,{"","# units","store A","store B","store C","store D"}
,{"juice",3,1.55`,1.45`,1.65`,1.4`}
,{"eggs",4,1.95`,2.4`,2,2.2`}
,{"fruits",12,0.85`,0.8`,0.7`,0.8`}
,{"vegetables",8,1.35`,1,1,1.1`}
,{"milk",2,2.55`,2.25`,2.55`,3.1`}
,{"cereals",6,2.7`,3.35`,3.05`,3.45`}
,{"coffee",1,10.85`,7.5`,8.45`,8.5`}
,{"tea",2,4.2`,4.15`,3.75`,3.95`}
,{"ice cream",3,7.35`,6.75`,6.75`,4.95`}
,{"napkins",5,1.1`,1.2`,1.2`,1.25`}
,{"foils",2,3.5`,3.75`,3.6`,3.75`}
,{"storage bags",10,0.8`,0.7`,0.85`,0.7`}
,{"toothpaste",4,1.6`,1.6`,1.55`,1.6`}
,{"shampoo",3,3.55`,2.6`,2.9`,2.7`}
,{"detergent",2,9.55`,9.05`,8.65`,7.1`}
};

Grid[grocerylist,Frame->All, BaseStyle->{18, FontFamily->"Calibri"}]

Exercise 2.1

Import the data from .csv file given, obtain the price table and name it something.

Answer

importgroc=Import["http://courses.egr.uh.edu/ECE/ECE3340/Homework/grocery_price_data.csv"]

grocerylist=importgroc

Grid[grocerylist,Frame->All, BaseStyle->{18, FontFamily->"Calibri"}]

In typical Jupyter notebook, this is what it looks like

2.2 Referencing elements from a multi-D array

2.2.1 Review: from Tutorial 2

Consider this two dimensional array

example341=Table[i*8+j,{i,0,4},{j,0,7}] ;
Grid[example341]

example341[[3,7]]

Manipulate[
ex341grdisp=ex341gr;
ex341grdisp[[i+1,j+1]]=Item[Style[example341[[i,j]],19,Bold,White]
,Background->Hue[0.,1,1]];
Grid[{{Grid[{{Style["arrayname[["<>ToString[i]<>","<>ToString[j]<>"]]"
,20,FontFamily->"Times New Roman"]}
,{Item[Style[example341[[i,j]],28,FontFamily->"Calibri",Bold,White]
,Background->Red]}}
,Frame->All
]
,Grid[ex341grdisp
,Frame-> All,BaseStyle->{20,FontFamily->"Calibri"}
,Background->{Join[{Hue[0.77,0.5,1]},Table[If[j==n,Hue[0.05,0.5,1],],{n,1,col+1}]]
,Join[{Hue[0.47,0.5,1]},Table[If[i==m,Hue[0.3,0.5,1],],{m,1,row+1}]]}]}}]
,{i,1,5,1},{j,1,8,1}
,Initialization:>{
example341=RandomInteger[{0,50},{5,8}] ;
{row,col}=Dimensions[example341];
ex341gr=MapThread[Prepend,{Join[{Range[col]},example341]
,Join[{Item[Style["i/j",Bold,White,FontFamily->"Arial"]
,Background->Black]},Range[row]]}];
}]

2.2.2 Sub-array and slice

Consider this:

What if we want a row or a column of the above? Obviously, we can use Table:

itemunit=Table[grocerylist[[ j ,2 ]],{j,3,Length[grocerylist]}]

But there is a way to do that with less typing

itemunit=grocerylist[[ 3 ;;   ,  2 ]]

Exercise 2.2

Define variable itemname and obtain from the table.

Answer

itemname=grocerylist[[ 3 ;;   ,  1 ]]

Don’t forget to do conversion from string to float.

For an experienced numpy user:

Exercise 2.3

Define variable storename and obtain from the table.

Answer

storename=grocerylist[[ 2        ,   3 ;; ]]

2.3 Matrix and vector dot product

Now, should we obtain the price list of each store? It’s OK to do for 4 stores, but what if you are doing market research for 10,000’s of store in the US? We don’t do price list for each store, we do for all stores.

storeprice=grocerylist[[  3 ;;        ,   3 ;; ]] ;
Grid[storeprice,Frame-> All,BaseStyle->{18,FontFamily->"Calibri"}]

storeprice is now a 2D-array, which can also be called matrix.
Now, it is too tall, for convenience, we will flip it to the side, this is called Transpose

storePrT=Transpose[storeprice] ;
Grid[storePrT,Frame-> All,BaseStyle->{16,FontFamily->"Calibri"}]

what is the first row of storePrT?

storePrT[[1]]

this is the price of store A. Thus:

Manipulate[
Column[{storename[[i]]
,Grid[{itemname
,storePrT[[i]]}
,Frame->All,BaseStyle->{13,FontFamily->"Calibri"}
,Background->{Table[Hue[((i-1)/(Length[itemname])),0.5,1],{i,Length[itemname]}]
,{GrayLevel[1],}}]
}]
,{i,1,4,1}
,Initialization:>{
storename={"store A","store B","store C","store D"};
itemname={"juice","eggs","fruits","vegetables","milk","cereals","coffee","tea","ice cream","napkins","foils","storage bags","toothpaste","shampoo","detergent"};
storePrT={{1.55`,1.95`,0.85`,1.35`,2.55`,2.7`,10.85`,4.2`,7.35`,1.1`,3.5`,0.8`,1.6`,3.55`,9.55`},{1.45`,2.4`,0.8`,1,2.25`,3.35`,7.5`,4.15`,6.75`,1.2`,3.75`,0.7`,1.6`,2.6`,9.05`},{1.65`,2,0.7`,1,2.55`,3.05`,8.45`,3.75`,6.75`,1.2`,3.6`,0.85`,1.55`,2.9`,8.65`},{1.4`,2.2`,0.8`,1.1`,3.1`,3.45`,8.5`,3.95`,4.95`,1.25`,3.75`,0.7`,1.6`,2.7`,7.1`}};
}]

So, it is easy to calculate the cost for each store:

cost=Table[itemunit . sp,{sp,storePrT}]

Is it the same as matrix vector product? The answer is yes, and we can simply the code by do this:

cost=storePrT . itemunit

For writing, this is what it usually looks like:

MatrixForm[storePrT].  MatrixForm[ itemunit]

But as we learn in linear algebra, we can also do this:

MatrixForm[{itemunit}] . MatrixForm[storeprice]

itemunit . storeprice

So, the HW 1B problem is quite simple with a few lines:

grocerylist=Import["http://courses.egr.uh.edu/ECE/ECE3340/Homework/grocery_price_data.csv"];
itemunit=grocerylist[[ 3 ;;   ,   2 ]]
storeprice=grocerylist[[  3 ;;        ,   3 ;; ]] 
storename=grocerylist[[ 2  ,   3  ;;]]
cost=itemunit . storeprice
resultcalc=Transpose[{cost,storename}]
Grid[{{"the lowest cost is ",Sort[resultcalc][[1]]}}]
BarChart3D[cost,ChartLegends->storename
,ChartElementFunction->"ProfileCube"
,ChartStyle->"BrightBands"]
BarChart[cost,ChartLegends->storename
,ChartElementFunction->"GlassRectangle"
,ChartStyle->"Pastel"]

2.4 Use App to review matrix dot product

Mathematically, we have two common cases of matrix - vector dot product:

m × n matrix          n-vector                   m-vector
 (({{(Subscript[a, 11]), (Subscript[a, 12]), ⋯, (Subscript[a, 1n])}, {(Subscript[a, 21]), (Subscript[a, 22]), ⋯, (Subscript[a, 2n])}, {⋮, ⋮, ⋱, ⋮}, {(Subscript[a, m 1]), (Subscript[a, m 2]), ⋯, (Subscript[a, m n])}}))   .   (({{(Subscript[x, 1])}, {(Subscript[x, 2])}, {⋮}, {(Subscript[x, n])}}))   =      (({{(Subscript[a, 11])(Subscript[x, 1])+⋯ +(Subscript[a, 1n])(Subscript[x, n]) }, {(Subscript[a, 21])(Subscript[x, 1])+⋯ +(Subscript[a, 2n])(Subscript[x, n])}, {⋮}, {(Subscript[a, m 1])(Subscript[x, 1])+⋯ +(Subscript[a, m n])(Subscript[x, n])}}))

and this:

m-vector                   m × n matrix                          n-vector                
 (({{(Subscript[x, 1]), (Subscript[x, 2]), ⋯, (Subscript[x, m])}})) .(({{(Subscript[a, 11]), (Subscript[a, 12]), ⋯, (Subscript[a, 1n])}, {(Subscript[a, 21]), (Subscript[a, 22]), ⋯, (Subscript[a, 2n])}, {⋮, ⋮, ⋱, ⋮}, {(Subscript[a, m 1]), (Subscript[a, m 2]), ⋯, (Subscript[a, m n])}}))  = (({{(Subscript[a, 11])(Subscript[x, 1])+⋯ +(Subscript[a, 1n])(Subscript[x, n]), ⋯, ⋯, (Subscript[a, m 1])(Subscript[x, 1])+⋯ +(Subscript[a, m n])(Subscript[x, n])}}))

Explore the app below:

By theorem:     (((A . x))^T)=(x^T) . (A^T)

Hence, we can use transpose whenever convenient.

2.5 Apply learning above with portfolio_data.csv

Exercise 2.4

Write a block code to do similar things as the example with grocery data file for portfolio_data.csv.
Define variables: dateList, stocksymb, shares, pricedata, with appropriate values.
(follow instructions in class if needed).

Hyperlink["the data is here","http://courses.egr.uh.edu/ECE/ECE3340/Homework/portfolio_data.csv"]

Answer

We can use exactly the same code for the grocery shopping problem  to get answer. Except the variable names are changed or generic (just to avoid confusion)

Also, we use DateListPlot instead of barchart.

datageneric=Import["http://courses.egr.uh.edu/ECE/ECE3340/Homework/portfolio_data.csv"];
itemunit=datageneric[[ 3 ;;   ,   2 ]];
price=datageneric[[  3 ;;        ,   3 ;; ]] ;
date=datageneric[[ 2  ,   3  ;;]];
value=itemunit . price;
portvals=Transpose[{date,value}];
DateListPlot[portvals, PlotRange->All
,PlotStyle->{Thickness[0.01],Hue[0.38,1,0.6]}
,Filling-> {1-> {Axis, Hue[0.32,0.7,1,0.4]}}
,Frame-> True, GridLines-> Automatic
,LabelStyle->{14,Black,FontFamily->"Arial"}
,FrameLabel->(Style[#,18,Black, FontFamily->"Calibri"] & /@ {"date","portfolio value ($)"})
,ImageSize->500, AspectRatio->1]

However, if we want to use the same code over and over, we can define a block code.

dataimport[fileinp_]:=Block[{ximpdat}
,ximpdat=Import[fileinp];
{ximpdat[[2,3 ;; ]]  (* dateList in this case, but can be anything for others *)
,ximpdat[[ 3 ;; , 1 ]]  (* stock symbols or others *)
,ximpdat[[ 3 ;; ,2  ]]   (* shares owned or others *)
,ximpdat[[3 ;;   , 3 ;;   ]]  (* price table: data matrix *)
}
] ;

Then, we CAN name variables from the generic data according our interest:

filenm="http://courses.egr.uh.edu/ECE/ECE3340/Homework/portfolio_data.csv";
{dateList, stocksymb, shares, pricedata} =dataimport[filenm];

We can find portfolio value at just one time point, say at:

dateList[[4]]
shares  . pricedata[[;; , 4]]   // Floor

END exercise

We can do some more for fun:

valuestock=Transpose[{dateList,#}] & /@ (shares*pricedata);
(* it's OK if you don't understand the anonymous function above;
below is equivalent and just as good *)
valuestock=Table[Transpose[{dateList,u}] ,{u,shares*pricedata}];
DateListPlot[valuestock, PlotRange->All
,PlotLayout->"Stacked"
,PlotStyle->Table[{Thickness[0.005],Hue[((i-1)/(Length[valuestock])),1,0.75]}
,{i,Length[valuestock]}]
,Filling->Join[{1-> {0,Hue[0.,0.7,1,0.4]}}
,Table[ i-> {{i-1}, Hue[((i-1)/(Length[valuestock])),0.7,1,0.4]}
,{i,2,Length[valuestock]}]]
,Frame-> True, GridLines->Automatic
,FrameLabel->(Style[#,16,Black, FontFamily->"Calibri"] & /@ {"date","portfolio value ($)"})
,LabelStyle->{13,Black,FontFamily->"Arial"}
,PlotLegends->stocksymb
,ImageSize->500, AspectRatio->1.3]

Exercise 2.5

Find the portfolio values (name it value) as a function of time (hint: matrix vector product).

Answer

Should we do this?

Table[shares . pricedata[[;; ,i]]   ,{i, Dimensions[pricedata][[2]]}] // Floor

The answer is no. There is a much more elegant, mathematically correct, and code-wise efficient way to do, it is matrix vector product:

value=shares . pricedata  +0.5 //Floor

Exercise 2.6

Use DateListPlot to plot portfolio value vs time. You need to pair date (time) with its corresponding portfolio value.

Answer

DateListPlot[Transpose[{dateList,portvals}],PlotRange->All
,Frame->True, GridLines->Automatic]

Below shows some styling approach:

DateListPlot[portvals, PlotRange->All
,PlotStyle->{Thickness[0.01],Hue[0.38,1,0.6]}
,Filling-> {1-> {Axis, Hue[0.32,0.7,1,0.4]}}
,Frame-> True, GridLines-> Automatic
,LabelStyle->{14,Black,FontFamily->"Arial"}
,FrameLabel->(Style[#,18,Black, FontFamily->"Calibri"] & /@ {"date","portfolio value ($)"})
,ImageSize->500, AspectRatio->1]

Mathematically, this is what it looks like:

nrow=Dimensions[pricedata][[2]];
portvals=shares . pricedata ;
Animate[
Column[{
Grid[{{"price matrix",,"shares\nvector",,"output ($K)"}
,{Grid[{stocksymb} ,BaseStyle->{10.7, FontFamily->"ArialNarrow"},Frame-> All
,Background->Hue[0.35,1,1]],,,,}
,{Grid[Transpose @ pricedata
 ,BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->{,Table[Hue[0.35,If[m==i,0.5,0],1],{m,1,nrow}]}]
,Style["·",Red,Bold,48]
,Column[shares,BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->Yellow]
,Style["=",Red,Bold,36]
,Column[portvals/1000.,BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->Table[Hue[0.85,If[m==i,0.35,0],1],{m,nrow}]]}}
,BaseStyle->{20,FontFamily->"Century Gothic"}]
,"This is how row dot with column "
,Grid[{{"take row "<>ToString @ i,}
,{Grid[{pricedata[[;;,i]]},BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->Hue[0.35,0.5,1]],}
,{"multiply 1-by-1 with column vector",}
,{Grid[{shares},BaseStyle->{12, FontFamily->"ArialNarrow"},Frame-> All
,Background->Hue[0.17,1,1]],,}
,{"output in $K ",}
,{Grid[{pricedata[[;; , i]]*shares/1000.},BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->Hue[0.45,0.4,1]], }
,{"total",Item[portvals[[i]]/1000.,Frame->True
,Background->Hue[0.85,0.35,1]]}
},BaseStyle->{16, FontFamily->"ArialNarrow"} ]
},BaseStyle->{20,FontFamily->"Century Gothic"},Frame-> All]
,{i,1,nrow,1, AnimationDirection->ForwardBackward}]

This is known as matrix “dot” vector product. In this case, the vector is a column. Each element of a row of the matrix is multiplied with the same index element of the column, and all are summed together to give an element of the output, which is the value of the portfolio.

For display convenience, we have transposed the price matrix so that each row corresponds to a time point, and the column are the prices of the stocks in green above.

3  General matrix dot product

3.1 Example: hypothetical portfolios

Consider that there are more than 1 client, and the shares are as follow:

sharesJohn=shares;
sharesJane={0,150,50,200,40,0,250,30,300,50,0,100,175,100,0,50,250,300,700,1000};
sharesBob={100,0,0,100,0,250,120,175,50,0,100,100,0,125,50,150,0,400,300,500};
sharesAll={sharesJohn,sharesJane,sharesBob};
sharesAllT=Transpose @ sharesAll;

Now, how do we calculate the portfolio for each of them?

nrow=Dimensions[pricedata][[2]];
portvalsAll=sharesAll . pricedata/1000. ;portvalsAllT=Transpose@ portvalsAll;
Animate[Grid[{{"price matrix",,"shares\nvector",,"output ($K)"}
,{Grid[{stocksymb} ,BaseStyle->{9, FontFamily->"ArialNarrow"},Frame-> All
,Background->Hue[0.35,1,1]],
,Grid[{{"John","Jane","Bob"}},BaseStyle->{10.7, FontFamily->"ArialNarrow"},Frame-> All
,Background->{{Hue[0.85,0.35,1],Hue[0.08,0.5,1],Hue[0.45,0.5,1]},}]
,
,Grid[{{"John","Jane","Bob"}},BaseStyle->{14, FontFamily->"ArialNarrow"},Frame-> All
,Background->{{Hue[0.85,0.35,1],Hue[0.08,0.5,1],Hue[0.45,0.5,1]},}]}
,{Grid[Transpose @ pricedata
 ,BaseStyle->{8, FontFamily->"ArialNarrow"},Frame-> All
,Background->{,Table[Hue[0.03,If[m==i,0.5,0],1],{m,1,nrow}]}]
,Style["·",Red,Bold,48]
,Grid[sharesAllT,BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->{{Hue[0.85,0.35,1],Hue[0.08,0.5,1],Hue[0.45,0.5,1]},}]
,Style["=",Red,Bold,36]
,Grid[portvalsAllT,BaseStyle->{10, FontFamily->"ArialNarrow"},Frame-> All
,Background->{{Hue[0.85,0.32,1],Hue[0.08,0.3,1],Hue[0.45,0.3,1]}
,Table[Hue[0.03,If[m==i,0.5,0],1],{m,nrow}]}]}}
,BaseStyle->{20,FontFamily->"Century Gothic"}]
,{i,1,nrow,1, AnimationDirection->ForwardBackward}]

As shown, it is straightforward: the share data are now a matrix of 3 columns for 3 clients (imagine, a brokerage may have millions of clients, and how big their share data matrix is).

This is known as matrix product ot matrix multiplication and matrix-vector dot product is just a special case of matrix dot product.

Review the Matrix Dot Product App again (see 2.4 above):

3.2 Matrix dot product associative property

What if we have this “cascade” problem:

Three bakeries purchase certain quantities of flour and eggs per week as shown below. Given the prices each week, what is the cost of each bakery each week? This is a straight forward matrix multiplication (dot).

matp2=Floor[0.5+2*RandomReal[{15,24},{4,2}]]/2.;wks=Join[{""},StringJoin["week ",ToString @ #] & /@ Range[4]];
nmat2={{63.5,71.5,50},{117.25,143.5,91}};
Grid[{{Grid[MapThread[Prepend,{Join[{{"flour ($)","eggs ($)"}},matp2]
,wks}], Frame-> All]
,Grid[MapThread[Append,{Join[{{"bakery A","bakery B", "bakery C"}},nmat2]
,{"","flour quantity","egg quantity"}}]
,Frame-> All]
}}, Alignment-> Top]

Data matrices

Exercise 3.1

Three bakeries purchase certain quantities of flour and eggs per week as shown. Given the prices each week, what is the cost of each bakery each week?

Answer

This is a straight forward matrix multiplication

Grid[{{Grid[matp2,Frame->True]," . ",Grid[nmat2,Frame->True],"=",matp2 . nmat2 // Grid}}, Alignment->Top]

Column[{"weekly costs of the bakeries"
,Grid[MapThread[Prepend,{Join[{{"bakery A","bakery B", "bakery C"}},matp2 . nmat2]
,wks}],Frame->All]}]

Exercise 3.2

But now, we can get more into the details. There are 5 types of cakes, the quantity of flour and eggs for each type is shown below

cakes={,,,,};
ingrmat={{0.,0.3,0.1,0.5,0.4},{0.75,0.25,0.5,0.2,0.6}};
Grid[MapThread[Prepend,{Join[{cakes},ingrmat]
,{"","flour quantity","egg quantity"}}],Frame->All]

And the daily quantities of each cake produced by the bakeries are as follow:

prodmat={{55,70,40},{80,50,40},{30,45,30},{25,40,30},{60,80,50}};
Grid[MapThread[Append,{Join[{{"bakery A","bakery B", "bakery C"}},prodmat]
,Join[{""},cakes]}]
,Frame->All]

What are the daily ingredient demands of the bakeries?

Answer

This is what gives the net four and egg demands of the bakeries each week:

Grid[MapThread[Append,{Join[{{"bakery A","bakery B", "bakery C"}},ingrmat . prodmat ]
,{"","flour quantity","egg quantity"}}]
,Frame->All]

This is what we did:

demandmat= ingrmat . prodmat ;
Grid[demandmat, Frame-> All]

Then, we multiply the price matrix to the demand matrix to get the cost matrix for the 3 bakeries:

Grid[matp2 . demandmat, Frame-> All]

End exercise

In other words: costmatrix = pricematrix . demandmatrix
                       costmatrix = pricematrix . (ingredientmatrix .  bakeryproductionmatrix)
                         4 × 3                 4×2           (      2×5                               5×3        )

However, can we do this?
                       costmatrix = (pricematrix . ingredientmatrix)  .  bakeryproductionmatrix

because pricematrix . ingredientmatrix = cakeunitcostmatrix 
and the total cost can also be obtained by multiplying cake unit cost with the cake production matrix. This is the cake unit cost

Exercise 3.3

Find the weekly cost of each type of cake, based on the weekly price of the ingredients and the ingredient requirement of each cake type.

Answer

Grid[{{Grid[MapThread[Prepend,{Join[{{"flour ($)","eggs ($)"}},matp2]
,wks}], Frame-> All]
,Grid[MapThread[Append,{Join[{cakes},ingrmat]
,{"","flour quantity","egg quantity"}}],Frame->All]}}]

cakewkcost=matp2  . ingrmat ;
Column[{"cost of each cake each week"
,Grid[MapThread[Prepend,{Join[{cakes},cakewkcost]
,wks}],Frame->All]}]

End exercise

If we know the weekly ingredient cost of each type of cake, and we know how many cakes of each type each bakery makes daily, then, can we find the net weekly ingredient costs of the bakeries? This is the next exercise

Exercise 3.3

Find the weekly ingredient costs of the bakeries, based on the weekly ingredient cost of each type of cake, and the quantities of cakes of the bakeries.

Answer

We can just multiply this with a # of cakes produced by each bakery per week to get the cost

cakewkcost=matp2  . ingrmat;
Grid[ cakewkcost .prodmat ,Frame->All]

End exercise

Clearly:  
              costmatrix = pricematrix . (ingredientmatrix .  bakeryproductionmatrix)
                        = (pricematrix . ingredientmatrix ).  bakeryproductionmatrix

In other words, there are more than one way to cut a cake. We can calculate the total flour and egg demand of each bakery per week, and multiply the ingredient prices to get the cost
                                            OR
we can multiply the ingredient amount of each cake with the weekly ingredient price to get the weekly cost of each cake, and multiply to the production volume of the cakes.
Both give the same result.

Mathematically, what it means is that for 3 matrices A, B, C:
                                 (A . B) . C = A . (B . C)
This is known as associative property. From now on, we don’t have to use parentheses when multiplying many matrices together.

matA=RandomInteger[{-5,5},{5,3}];
matB=RandomInteger[{-5,5},{3,6}];
matC=RandomInteger[{-5,5},{6,4}];
ab=matA. matB ; bc= matB. matC ;
Grid[{{"A.B",,"C",,"(A.B).C"}
,{MatrixForm[ ab],".",MatrixForm[matC],"=",MatrixForm[ab . matC]}
,{"A",,"B.C",,"A.(B.C)"}
,{MatrixForm[matA ],".",MatrixForm[bc],"=",MatrixForm[matA . bc]}}
,Frame-> {,All}, BaseStyle->{18,FontFamily->"Calibri"}]

Exercise 3.4

Do a demonstration similar to the above to show the associative property of dot product. It is OK to copy and paste the code. But you must choose the range of random integer and the matrix dimensions according to this:
Range of random integer {-r, r} where r is the 2nd largest digit of your Student ID, but not smaller than 3. For example 1094724 is your ID. The second largest digit is 7 (9 is the largest).
For matrix dimensions, we need this: {m, n},{n, p},{p, q}
Let m=3rd largest digit of your ID, but not smaller than 3, n=Min[8, birth month +2], p=Max[3,Floor[birth date/4.]], q=Max[2,Ceiling[last digit birth year/2]].
If you cannot calculate, use the App below (but you should verify to understand and know why the results are what they are).

Manipulate[
ndiglist=DeleteDuplicates[ReverseSort@ IntegerDigits[stuID]];
rint=Max[3,If[Length[ndiglist]≥ 2,ndiglist[[2]],ndiglist[[1]]]];
m= Max[3,If[Length[ndiglist]≥ 3,ndiglist[[3]]
,rint]];
n=Min[8,mb+2];p=Max[3,Floor[db/4.]];
q=Max[2,Ceiling[yrb/2.]];

Grid[{{
Column[{"your student ID"
,InputField[Dynamic[stuID],Number,FieldSize->8
,FieldHint->"your student ID"]
}]
,Column[{
Grid[{{"rand. integer rng -> ",- rint, rint}}]
,Grid[{{"m","n","p","q"},{m,n,p,q}},Frame-> All]
}]
}}, BaseStyle->{18,FontFamily->"Calibri"}
,Alignment-> Top
,Frame->All]
,{{db,15,"birth date"},Range[31]}
,{{mb,5,"birth month"},Range[12],SetterBar}
,{{yrb,8,"last digit birth year"},Range[0,9], SetterBar}
,Initialization:>{
stuID=1234567;
}]

Answer

matA=RandomInteger[{-rint,rint},{m,n}];
matB=RandomInteger[{-rint,rint},{n,p}];
matC=RandomInteger[{-rint,rint},{p,q}];
ab=matA. matB ; bc= matB. matC ;
Grid[{{"A.B",,"C",,"(A.B).C"}
,{MatrixForm[ ab],".",MatrixForm[matC],"=",MatrixForm[ab . matC]}
,{"A",,"B.C",,"A.(B.C)"}
,{MatrixForm[matA ],".",MatrixForm[bc],"=",MatrixForm[matA . bc]}}
,Frame-> {,All}, BaseStyle->{18,FontFamily->"Calibri"}]

3.3 Transpose theorem

One more frequently-used property is:
                                       (((A . B))^T) =(B^T) . (A^T)

matA=RandomInteger[{-5,5},{5,3}];mAT=Transpose[matA];
matB=RandomInteger[{-5,5},{3,6}]; mBT=Transpose[matB];
ab=matA. matB ; bc= matB. matC ;
Grid[{{"A","B","A.B","(A.B)^T"}
,MatrixForm /@ {matA,matB,matA.matB,Transpose[matA.matB]}
,{"(A^T)","(B^T)",,"(B^T).(A^T)"}
,MatrixForm /@{mAT,mBT,"",mBT . mAT}}
,Frame-> {,All}, BaseStyle->{18,FontFamily->"Calibri"}]

Exercise 3.5

Do a demonstration of the transpose theorem like above, but matA and matB are based on your range and dimension from Exercise 3.4.

Answer

matA=RandomInteger[{-rint,rint},{n,m}];mAT=Transpose[matA];
matB=RandomInteger[{-rint,rint},{m,p}]; mBT=Transpose[matB];
ab=matA. matB ; bc= matB. matC ;
Grid[{{"A","B","A.B","(A.B)^T"}
,MatrixForm /@ {matA,matB,matA.matB,Transpose[matA.matB]}
,{"(A^T)","(B^T)",,"(B^T).(A^T)"}
,MatrixForm /@{mAT,mBT,"",mBT . mAT}}
,Frame-> {,All}, BaseStyle->{18,FontFamily->"Calibri"}]

End exercise

3.4  Serious and common errors

vt3=RandomInteger[{-5,5},5]

matx3=RandomInteger[{-5,5},{5,3}] ;
matx3 // MatrixForm

Shoud we do vt3 . matx3 or matx3 . vt3?

matx3 . vt3

Error because we are doing this:

(({{-5, 3, 4}, {-5, -3, -1}, {-3, -3, 1}, {0, -4, 2}, {-2, -5, -4}})). (({{5}, {5}, {-4}, {4}, {-1}}))

The number of row must match with the number of column. We should do this instead: 
(({{5, 5, -4, 4, -1}})). (({{-5, 3, 4}, {-5, -3, -1}, {-3, -3, 1}, {0, -4, 2}, {-2, -5, -4}}))

vt3 . matx 3

The rule is simple:

Dimensions[matx3]

If we have a vector of length 5, it should be on the left side of the matrix. If length 3, it should be on the right side. The actual orientation, row or column doesn’t matter, because Mathematica knows that if it is on the left, it is automatically row, and column if on the right. Hence:

matx3 . {3,-1,7}

But the above is not the worst error, because it tells us if there is an error. This is actually worse:

matx4=RandomInteger[{-5,5},{5,5}] ;
matx4 // MatrixForm

now

vt3 . matx4

matx4 . vt3

The above are totally different, but there is no execution error warning. This type of hidden bug is far more serious. It is up to the programmer to determine which one is correct.

Exercise 3.6

Generate an {m,n} matrix and an{n,p} of your choice, such that n≠m≠p. 
Try to dot {n,p} to {m,n} and observe error. Then, do the dot the correct order to obtain answer.

Answer

3.5  Inverse matrix and determinant

Consider this problem:

purch5=(({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}}))

the items purchased are  (({{apple}, {orange}, {pear}}))

Consider that the cost ($) for the above purchase is: (({{10.6}, {17.1}, {11.4}}))

What are the prices of apple, orange, and pear? This is the equation:

(({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})) .  (({{apple}, {orange}, {pear}}))==(({{10.6}, {17.1}, {11.4}}))

How do we solve?

Solve[(({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})) .  (({{apple}, {orange}, {pear}}))==(({{10.6}, {17.1}, {11.4}})) ,{apple,orange,pear}]

The linear algebraic way to do it is to take the inverse matrix:
                        (({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})) .  (({{apple}, {orange}, {pear}}))==(({{10.6}, {17.1}, {11.4}})) 
    (((({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})))^(-1)) . (({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})) .  (({{apple}, {orange}, {pear}}))==(((({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})))^(-1)) . (({{10.6}, {17.1}, {11.4}})) 
 By definition:
          (((({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})))^(-1)) . (({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}}))= (({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}})) 
Hence:          
    (({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}})) .  (({{apple}, {orange}, {pear}}))==(((({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})))^(-1)) . (({{10.6}, {17.1}, {11.4}}))     
                     (({{apple}, {orange}, {pear}}))==(((({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}})))^(-1)) . (({{10.6}, {17.1}, {11.4}}))

Inverse[(({{4, 2, 4}, {3, 3, 9}, {9, 0, 3}}))] .  (({{10.6}, {17.1}, {11.4}}))

indeed, these are the prices.

Exercise 3.7

Create 2 equations with 2 unknowns, use inverse matrix to solve it.

Answer

Problem 3.8

Consider this circuit:

Solve for its response. Find  steady-state voltage (Subscript[v, X]) for harmonic (Subscript[v, s]) and (Subscript[v, c]) of arbitrary input frequency, amplitude, and relative phase.

Answer given

The mesh-current equations of the Laplace-transformed circuit is:

(({{(Subscript[R, 1])+(Subscript[L, 1]) s+(1/((Subscript[C, 1])s)), -(1/((Subscript[C, 1])s)), 0}, {-(1/((Subscript[C, 1])s)), (1/((Subscript[C, 1])s))+(Subscript[R, 2]) +(Subscript[L, 2]) s, -(Subscript[L, 2]) s}, {0, -(Subscript[L, 2]) s, (Subscript[L, 2]) s+(1/((Subscript[C, 2])s))+(Subscript[R, 3])}})) . (({{(Subscript[J, 1])}, {(Subscript[J, 2])}, {(Subscript[J, 3])}}))=(({{(Subscript[V, S])[s] +(Subscript[L, 1]) (Subscript[i, 0;1])-((Subscript[v, 0;1])/s)}, {((Subscript[v, 0;1])/s)-(Subscript[L, 2]) (Subscript[i, 0;2])}, {(Subscript[V, c])[s] -((Subscript[v, 0;2])/s)+(Subscript[L, 2]) (Subscript[i, 0;2])}}))

where (Subscript[i, 0;m]) is the initial current in (Subscript[L, m]) inductor, and (Subscript[v, 0;n]) is the initial voltage of (Subscript[C, n]) capacitor.

Define     Z=(({{(Subscript[R, 1])+(Subscript[L, 1]) s+(1/((Subscript[C, 1])s)), -(1/((Subscript[C, 1])s)), 0}, {-(1/((Subscript[C, 1])s)), (1/((Subscript[C, 1])s))+(Subscript[R, 2]) +(Subscript[L, 2]) s, -(Subscript[L, 2]) s}, {0, -(Subscript[L, 2]) s, (Subscript[L, 2]) s+(1/((Subscript[C, 2])s))+(Subscript[R, 3])}}))  
We can write the Laplace-transformed mesh current simply:
                            (({{(Subscript[J, 1])}, {(Subscript[J, 2])}, {(Subscript[J, 3])}}))= (Z^(-1)) ·  (({{(Subscript[V, S])[s] +(Subscript[L, 1]) (Subscript[i, 0;1])-((Subscript[v, 0;1])/s)}, {((Subscript[v, 0;1])/s)-(Subscript[L, 2]) (Subscript[i, 0;2])}, {(Subscript[V, c])[s] -((Subscript[v, 0;2])/s)+(Subscript[L, 2]) (Subscript[i, 0;2])}}))            
we can find (Z^(-1)) although it is rather messy:

(* lower case (Subscript[c, m]) below because C is reserved*)
Z=(({{(Subscript[R, 1])+(Subscript[L, 1]) s+(1/((Subscript[c, 1])s)), -(1/((Subscript[c, 1])s)), 0}, {-(1/((Subscript[c, 1])s)), (1/((Subscript[c, 1])s))+(Subscript[R, 2]) +(Subscript[L, 2]) s, -(Subscript[L, 2]) s}, {0, -(Subscript[L, 2]) s, (Subscript[L, 2]) s+(1/((Subscript[c, 2])s))+(Subscript[R, 3])}}));
Zinv=FullSimplify[Inverse[Z] ];
Zinv // TraditionalForm

It is much easier to look at with substituted numerical values for the components

(* lower case (Subscript[c, m]) below because C is reserved*)
Z=(({{(Subscript[R, 1])+(Subscript[L, 1]) s+(1/((Subscript[c, 1])s)), -(1/((Subscript[c, 1])s)), 0}, {-(1/((Subscript[c, 1])s)), (1/((Subscript[c, 1])s))+(Subscript[R, 2]) +(Subscript[L, 2]) s, -(Subscript[L, 2]) s}, {0, -(Subscript[L, 2]) s, (Subscript[L, 2]) s+(1/((Subscript[c, 2])s))+(Subscript[R, 3])}}));
Z1=Z  /. {(Subscript[R, 1])-> 1,(Subscript[R, 2])-> 2,(Subscript[R, 3])-> 1, (Subscript[L, 1])->2, (Subscript[c, 1])-> (1/2), (Subscript[L, 2])->2, (Subscript[c, 2])->(1/2)} ;
Grid[{{"Z =",Z1 }}] // TraditionalForm
Zinv1=FullSimplify[Inverse[Z1] ];
Grid[{{"(Z^(-1)) =",Zinv1 }}]   // TraditionalForm
detZ1=FullSimplify[Det[Zinv1] ];
Grid[{{"det[Z] =",detZ1  }}]   // TraditionalForm
detDenom=Denominator[detZ1];
roots1=s /. Solve[detDenom==0,s] ;
Grid[{{"roots det[Z] =",roots1  }}]   // TraditionalForm
Style["Below are the root temporal responses",22,Blue,Italic,FontFamily->"Times New Roman"]
Plot[Release @ Table[InverseLaplaceTransform[Product[(1./(z-roots1 [[2m+j]])),{j,2}],z,t]
,{m,0,1}]
,{t,0.,20.}, PlotRange-> All
,PlotStyle-> {Hue[0.08,1,1],Hue[0.5,1,1]}
,Background->Black]

The roots indicate the transient responses, which can be overdamped, underdamped, or critically damped.

If we are interested only steady state solutions, we can ignore all the transient terms. Start with:

vs=(Subscript[a, s]) Cos[(Subscript[ω, s]) t]; vc=(Subscript[a, c]) Cos[(Subscript[ω, c]) t+ϕ];
Vs=LaplaceTransform[vs,t,s] ;
Vc=LaplaceTransform[vc,t,s] ;
{Vs,Vc} // TraditionalForm

Then, because we care only for steady-state solutions, we can also ignore and make all the initial conditions such as current (Subscript[i, 0;m]) in inductors and voltage (Subscript[v, 0;n]) in capacitors to be zero. Then:
      (({{(Subscript[J, 1])}, {(Subscript[J, 2])}, {(Subscript[J, 3])}}))= (Z^(-1)) ·  (({{(Subscript[V, S])[s] }, {0}, {(Subscript[V, c])[s] }})) = (Z^(-1)) ·  (({{((s (Subscript[a, s]))/((s^2)+(Subscript[ω, s]^2)))}, {0}, {(((Subscript[a, c]) (s cos(ϕ)-(Subscript[ω, c]) sin(ϕ)))/((Subscript[ω, c]^2)+(s^2)))}}))     
The mes current vector (({{(Subscript[i, 1])}, {(Subscript[i, 2])}, {(Subscript[i, 3])}})) is obtained by Inverse-Laplace transforming (({{(Subscript[J, 1])}, {(Subscript[J, 2])}, {(Subscript[J, 3])}}))

Demo of numerical calculation

ClearAll[Z,Z1,Z1inv,det,roots
,R1old,R2old,R3old,L1old,L2old,C1old,C2old
,ws,wc,tmax,icurL, msteady,uq,qq,icurr,icurrgr
,hcur,currlabel,s] ;

Block[{Z,Z1,Z1inv,det,roots
,R1old,R2old,R3old,L1old,L2old,C1old,C2old,iRECALC
,ws,wc,tmax,icurL, msteady,uq,qq,icurr,icurrgr
,wsold,asold,wcold,acold,ϕcold
,hcur,currlabel}
,Manipulate[
If[TrueQ[RUNLinCirDemo== ]
,Manipulate[
If[!TrueQ[{R1old,R2old,R3old,L1old,L2old,C1old,C2old}=={R1,R2,R3,L1,L2,C1,C2}]
,
 Z1 = Z /. {(Subscript[R, 1])-> R1,(Subscript[R, 2])-> R2,(Subscript[R, 3])-> R3, (Subscript[L, 1])-> L1, (Subscript[c, 1])-> C1, (Subscript[L, 2])-> L2, (Subscript[c, 2])-> C2};
det=Det[Z1];
roots=s /. NSolve[det==0,s]; zM=Max[Abs[roots]];
Z1inv=Inverse[Z1]; iRECALC=True;
{R1old,R2old,R3old,L1old,L2old,C1old,C2old}={R1,R2,R3,L1,L2,C1,C2}
,
];
 ws=10.^(0.1  wsdB); wc=10.^(0.1  wcdB);
tmax=((2 π 25)/(Min[ws,wc]));
If[!TrueQ[{wsold,asold,wcold,acold,ϕcold}=={ws,as,wc,ac,ϕc}] ||  iRECALC
,
icurL=Apart[Z1inv . {as(s/((s^2)+(ws^2))),0,ac((s Cos[ϕc]-wc Sin[ϕc])/((s^2)+(wc^2)))},s];
msteady=Reap[Do[uq=Table[s /. NSolve[Denominator[iq[[m]]]==0 ,s]
,{m,Length[iq]}];
qq=Reap[Do[If[Abs[Re[uq[[m,1]]]]<(10^(-6))
,Sow[m],]
,{m,Length[uq]}]][[2,1]];
Sow[qq];
,{iq,icurL}]][[2,1]] ;
icurr=Table[Sum[InverseLaplaceTransform[icurL[[m,qm]],s,t],{qm,msteady[[m]]}]
,{m,Length[msteady]}];
icurrgr=Plot[Re[#[[1]]],{t,0,tmax},PlotRange->{-1.,1.}
,PlotStyle-> Hue[#[[2]],1,1]
,Frame-> True, FrameStyle->White
, GridLines->Automatic, GridLinesStyle->GrayLevel[0.7]
,Epilog->Inset[Style[#[[3]],24,Bold,White,FontFamily->"Times New Roman"]
,ImageScaled[{0.1,0.85}]]
,AspectRatio->0.25,ImageSize->400
,Background->Black] & /@ Transpose[{icurr,hcur,currlabel}];
iRECALC=False; 
{wsold,asold,wcold,acold,ϕcold}={ws,as,wc,ac,ϕc}
,
];
Column[{Grid[{{"steady state current",det}
,{Column[icurrgr]
,Show[CPPolargrid2[{1.1*zM,10,10},]
,CPPlot[roots, ,{0.012,0.1,0.25} , , ] 
,Background-> Black, ImageSize->175]}}] 
,Show[
,ImageSize-> 550]
}] 
,Grid[{{Control[{{wsdB,2.5,"(Subscript[ω, s]) (dB)"},-10,10}],Control[{as,1,0}],}
,{Control[{{wcdB,3,"(Subscript[ω, c]) (dB)"},-10,10}],Control[{ac,1,0}],Control[{{ϕc,0.5 π,"ϕc"},-π,π}]}}]
,Grid[{{Control[{{R1,1},1,4,1}],Control[{{R2,2},1,4,1}],Control[{{R3,1},1,4,1}]}
,{Control[{{L1,1},{(1/16),(1/9),(1/4),1,2,3,4,8},SetterBar}],Control[{{C1,1/4},{(1/16),(1/9),(1/4),1,2,3,4,8},SetterBar}],}
,{Control[{{L2,1},{(1/16),(1/9),(1/4),1,2,3,4,8},SetterBar}],Control[{{C2,1/4},{(1/16),(1/9),(1/4),1,2,3,4,8},SetterBar}],}
}]
]
,Button[Show[,ImageSize-> 400],RUNLinCirDemo= ]]
,Grid[{{Control[{{RUNLinCirDemo,,},{,},ControlType->Toggler}] 
,Item[Style["Demo linear circuit with linear algebra solution",16,FontFamily->"Century Gothic"]
,Background->Hue[0.5,0.4,1]]
}},Frame-> True, FrameStyle->White]
,Initialization:>{iRECALC=True;
hcur={0.15,0.35,0.5}; currlabel={"(Subscript[i, 1])","(Subscript[i, 2])","(Subscript[i, 3])"};
Z=(({{(Subscript[R, 1])+(Subscript[L, 1]) s+(1/((Subscript[c, 1])s)), -(1/((Subscript[c, 1])s)), 0}, {-(1/((Subscript[c, 1])s)), (1/((Subscript[c, 1])s))+(Subscript[R, 2]) +(Subscript[L, 2]) s, -(Subscript[L, 2]) s}, {0, -(Subscript[L, 2]) s, (Subscript[L, 2]) s+(1/((Subscript[c, 2])s))+(Subscript[R, 3])}}));
CPPlot[z_List,range_,sizeparm_,hueparm_,label_]:=Module[{Rx,n,t,r,h, huelist, m},
 n=Length[z] ;
If[TrueQ[range== Null],Rx=Max[Abs[z]] ,Rx=range]  ;
If[TrueQ[sizeparm== Null],{t,h,r}={Min[0.005,0.003*Rx],
Min[0.05,0.03*Rx],Min[0.025,0.017*Rx]} 
,{t,h,r}=sizeparm; r=Min[r,0.05*Rx]]  ;
If[TrueQ[hueparm== Null] ,
huelist=Table[0.07+(i-1)/(n+1),{i,1, n}] 
 ,huelist=hueparm]  ;  m=Length[huelist]+1;
If[TrueQ[label== Null],
Graphics[{(* Arrow[{{-1.2Rx,0},{1.2 Rx,0}}],Arrow[{{0,-1.2 Rx},{0,1.2 Rx}}]
,Inset["Re",{1.1 Rx,-0.1},BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,Inset["Im",{-0.1,1.1 Rx},BaseStyle-> {18, Bold,FontFamily-> "Calibri"} ]
,*)Table[{Hue[ huelist[[ Mod[i,m]  ]],1,0.8]
,Opacity[0.75],Disk[{Re[z[[i]] ],Im[z[[i]] ]},r]
,Thickness[t],Arrowheads[h],Arrow[{{0,0},{Re[z[[i]] ],Im[z[[i]] ]}}]},{i,1, n}]},
PlotRange-> {1.2*{-Rx,Rx},1.2*{-Rx,Rx}},
Frame-> True, GridLines-> Automatic]
,
Graphics[{(* Arrow[{{-1.2Rx,0},{1.2 Rx,0}}],Arrow[{{0,-1.2 Rx},{0,1.2 Rx}}]
,Inset["Re",{1.1 Rx,-0.1},BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,Inset["Im",{-0.1,1.1 Rx} ,BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,*)Table[{Hue[ huelist[[ Mod[i,m]  ]],1.,0.8]
,Inset[label[[i]],1.15 {Re[z[[i]] ],Im[z[[i]] ]} 
,BaseStyle-> {18, Bold,Italic,FontFamily-> "TimesNewRoman"}]
,Opacity[0.75],Disk[{Re[z[[i]] ],Im[z[[i]] ]},r]
,Thickness[t],Arrowheads[h],Arrow[{{0,0},{Re[z[[i]] ],Im[z[[i]] ]}}]},{i,1, n}]},
PlotRange-> {1.2*{-Rx,Rx},1.2*{-Rx,Rx}},
Frame-> True, GridLines-> Automatic]
]
];

CPPlot0[z_List,range_,sizeparm_,hueparm_,label_]:=Module[{Rx,n,t,r,h, huelist, m},
 n=Length[z] ;
If[TrueQ[range== Null],Rx=Max[Abs[z]] ,Rx=range]  ;
If[TrueQ[sizeparm== Null],{t,h,r}={Min[0.005,0.003*Rx],
Min[0.05,0.03*Rx],Min[0.025,0.017*Rx]} 
,{t,h,r}=sizeparm; r=Min[r,0.05*Rx]]  ;
If[TrueQ[hueparm== Null] ,
huelist=Table[0.07+(i-1)/(n+1),{i,1, n}] 
 ,huelist=hueparm]  ;  m=Length[huelist]+1;
If[TrueQ[label== Null],
Graphics[{(* Arrow[{{-1.2Rx,0},{1.2 Rx,0}}],Arrow[{{0,-1.2 Rx},{0,1.2 Rx}}]
,Inset["Re",{1.1 Rx,-0.1},BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,Inset["Im",{-0.1,1.1 Rx},BaseStyle-> {18, Bold,FontFamily-> "Calibri"} ]
,*)Table[{Hue[ huelist[[ Mod[i,m]  ]],1,1]
,Opacity[0.85],PointSize[0.05],Point[{Re[z[[i]] ],Im[z[[i]] ]}]
,Thickness[t],Arrowheads[h],Arrow[{{0,0},{Re[z[[i]] ],Im[z[[i]] ]}}]},{i,1, n}]},
PlotRange-> {1.2*{-Rx,Rx},1.2*{-Rx,Rx}},
Frame-> True, GridLines-> Automatic]
,
Graphics[{(* Arrow[{{-1.2Rx,0},{1.2 Rx,0}}],Arrow[{{0,-1.2 Rx},{0,1.2 Rx}}]
,Inset["Re",{1.1 Rx,-0.1},BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,Inset["Im",{-0.1,1.1 Rx} ,BaseStyle-> {18, Bold,FontFamily-> "Calibri"}]
,*)Table[{Hue[ huelist[[ Mod[i,m]  ]],1.,1]
,Inset[label[[i]],1.15 {Re[z[[i]] ],Im[z[[i]] ]} 
,BaseStyle-> {18, Bold,Italic,FontFamily-> "TimesNewRoman"}]
,Opacity[0.85],PointSize[0.05],Point[{Re[z[[i]] ],Im[z[[i]] ]}]
,Thickness[t],Arrowheads[h],Arrow[{{0,0},{Re[z[[i]] ],Im[z[[i]] ]}}]},{i,1, n}]},
PlotRange-> {1.2*{-Rx,Rx},1.2*{-Rx,Rx}},
Frame-> True, GridLines-> Automatic]
]
];

CPPolargrid2[{r_,n1_,n2_},plotparm_]:=Module[{thn,gl,glax},
If[TrueQ[plotparm==Null],gl=0.5; thn=0.001,{thn,gl} =plotparm 
 ] ; 
glax=If[gl<  0.5,0,1];
Graphics[{Dashed, GrayLevel[gl], Thickness[thn]
,Table[Line[{{0,0},{-r c,r (Sqrt[1-(c^2)])}}],{c,0,1,1./n1}]
,Table[Line[{{0,0},{-r c,-r (Sqrt[1-(c^2)])}}],{c,0,1,1./n1}]
,Table[Circle[{0,0},ar,{Pi/2.,3Pi/2.}],{ar,r/n2,r,r/n2}]
,Dashing[{1,0}],GrayLevel[glax],Opacity[1],Thickness[1.5*thn]
,Arrowheads[Min[0.08 r,0.1]]
,Arrow[{{-1.2r,0},{0.2 r,0}}],Arrow[{{0,-1.2 r},{0,1.2 r}}]
,Inset["Re",{-1.1 r,Min[-0.05 r,-0.1] }
,BaseStyle-> {16,GrayLevel[glax],FontFamily-> "Calibri"}]
,Inset["Im",{Min[-0.05 r,-0.1],1.1 r} 
,BaseStyle-> {16,GrayLevel[glax], FontFamily-> "Calibri"}]
}]  ];
}]
]

End exercise

Can we take the inverse of this?

matx5=RandomInteger[{-5,5},{3,5}] ;
matx5 // MatrixForm

Inverse[matx5]

Exercise 3.9

Generate an non-square {m,n} matrix, denote it A. Take the inverse of A and see what happens.
Then define a new matrice:               P=A · (A^T)      and      Q=(A^T)·A    
Which one, P or Q has inverse, which one doesn’t, and can you explain or guess why one does and the other doesn’t?

Answer

End exercise

By its definition, only square matrix can be inversed.

Note, by theorem, if  (A^(-1)) . A= I, where I is the identity matrix, then:
                A . (A^(-1))  = I  ,          ((((A^(-1))))^(-1)) = A    ,     and    ((((A^T)))^(-1))=((((A^(-1))))^T) 
These theorems simply follow the associative and transpose properties. For example:
Given A, let (Subscript[B, 1]) and (Subscript[B, 2]) be such that:  A . (Subscript[B, 1]) = I  and   (Subscript[B, 2]) .  A = I 
Then,            (Subscript[B, 2]) .  (A . (Subscript[B, 1])) = (Subscript[B, 2]) . I  = (Subscript[B, 2])
By associative:      ((Subscript[B, 2]) . A) . (Subscript[B, 1]) =  (Subscript[B, 2])
                                    I .  (Subscript[B, 1]) =  (Subscript[B, 2])  or  (Subscript[B, 1]) =  (Subscript[B, 2]) ≡ (A^(-1))

One important quantity of a square matrix is determinant. In Mathematica, Det[] gives the determinant of a matrix.

Demo: statistical property (Gaussian -> Laplacian distribution) of det of random matrix

Manipulate[
If[TrueQ[DETERMINANTrun== ]
,Manipulate[
If[TrueQ[RANDMAT6] || !TrueQ[ndimold== ndim]
,matx6=RandomInteger[{-5,5},{ndim,ndim}] ;
det=Det[matx6];
If[det≠0, mat6inv=Inverse[matx6],];
ftsz=Min[16,Floor[(16./ndim)+8.5]];
RANDMAT6=False; ndimold= ndim
,];
If[TrueQ[RUNSIM6]
,detout=Reap[Do[matx6s=RandomReal[{-1.,1.},{ndim,ndim}] ;
Sow[Det[matx6s]]
,{i,1,2000}]][[2,1]];
idetplot=True;
detgraph=ListLinePlot[detout,PlotRange-> All
,PlotStyle->Hue[0.35,1,1]
,Frame-> True, FrameStyle->White
,GridLines->Automatic, AspectRatio->0.25
,ImageSize->500
,Background->Black];
RUNSIM6=False
,];
Column[{Grid[{{"matrix","inverse"}
, {MatrixForm @ matx6
,If[det≠0,MatrixForm @ mat6inv,"inv not exist"]}
,{"mat dot mat inverse","determinant"}
,{If[det≠0,MatrixForm @  (matx6 . mat6inv),],det}
},BaseStyle->{ftsz,FontFamily->"Century Gothic"}
,Frame-> All]
,If[TrueQ[idetplot]
,Column[{
Style["Look for transition from Gaussian to 2-side Laplacian distribution
of the determinant distribution as ndim increases",Red,15,Italic,FontFamily->"Calibri"]
,detgraph
,Grid[{{
ListPlay[detout, PlayRange->All, SampleRate->2000]
,Histogram[detout,Automatic,"LogPDF",PlotRange-> All
,ImageSize->250]}}]
}],]
}]

,{ndim,2,8,1}
,Grid[{{Button["new random matrix",RANDMAT6=True]
,Button["RUN sim",RUNSIM6=True]}}]
]
,Button[Show[,ImageSize-> 400],DETERMINANTrun=]
]
,Grid[{{Control[{{DETERMINANTrun,,},{,},ControlType->Toggler}] 
,Style["Random matrix determinant",16,FontFamily->"Century Gothic"]}}, Background->Hue[0.7,0.25,1]]
,Initialization:>{
RANDMAT6=True;ftsz=16;
RUNSIM6=False; 
idetplot=False;
}]