OUTPUT FIRST, PYTHON SECOND
The square matrix, TRM, of data in the following table represents the flow of goods and services in a complete directed multigraph of 7 nodes as valued in a single currency. The nodes of the graph might represent the nations of a small world. The data can be interpreted in either of two ways. Here we choose the interpretation that the value, X, in the cell corresponding to row 0 and column 1 is the amount received by node 0 from node 1. The value, Y, corresponding to row 1 and column 0 is the amount received by node 1 from node 0. One of these values will generally be greater than(though possibly equal to) the other. The net effect is a positive flow of |X-Y| in one direction or the other. A negative entry represents a flow in the direction opposite to a given edge in the graph. The column, R, is the sum along each row, and represents the total amount received from the network for each node. The row, S, represents the amount sent into the network for each node. The column, R-S, represents the net inflow or outflow of money for each node during a given time step. The data for this table was generated with a random variable from a half-normal distribution, i.e. |Z| where Z ~ N(0,sigma^2). TRM is my abbreviation for transaction matrix.
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| TRM | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+=======+=========+==========+=========+=========+=========+=========+=========+=====+==========+=====+==========+
| N0 | 1606.00 | 877.00 | 343.00 | 764.00 | 731.00 | 495.00 | 1351.00 | | 6167.00 | | -859.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N1 | 459.00 | 1154.00 | 678.00 | 817.00 | 719.00 | 367.00 | 2389.00 | | 6583.00 | | -4081.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N2 | 1160.00 | 1838.00 | 539.00 | 295.00 | 672.00 | 582.00 | 193.00 | | 5279.00 | | -1926.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N3 | 1100.00 | 2073.00 | 888.00 | 1065.00 | 330.00 | 1092.00 | 542.00 | | 7090.00 | | 1607.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N4 | 588.00 | 1241.00 | 1516.00 | 1399.00 | 468.00 | 9.00 | 436.00 | | 5657.00 | | 197.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N5 | 1628.00 | 951.00 | 1535.00 | 114.00 | 1333.00 | 666.00 | 17.00 | | 6244.00 | | 2711.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| N6 | 485.00 | 2530.00 | 1706.00 | 1029.00 | 1207.00 | 322.00 | 1872.00 | | 9151.00 | | 2351.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| | | | | | | | | | | | |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
| S | 7026.00 | 10664.00 | 7205.00 | 5483.00 | 5460.00 | 3533.00 | 6800.00 | | 46171.00 | | 0.00 |
+-------+---------+----------+---------+---------+---------+---------+---------+-----+----------+-----+----------+
To see the net effect of money transfers from node to node, we first form a skew-symmetric matrix(each entry is the negative of it's mirror reflection through the main diagonal) from TRM given by SKEW = TRM - TRM.transpose().
+--------+------+------+-------+-------+-------+-------+-------+
| SKEW | N0 | N1 | N2 | N3 | N4 | N5 | N6 |
+========+======+======+=======+=======+=======+=======+=======+
| N0 | 0 | 418 | -817 | -336 | 143 | -1133 | 866 |
+--------+------+------+-------+-------+-------+-------+-------+
| N1 | -418 | 0 | -1160 | -1256 | -522 | -584 | -141 |
+--------+------+------+-------+-------+-------+-------+-------+
| N2 | 817 | 1160 | 0 | -593 | -844 | -953 | -1513 |
+--------+------+------+-------+-------+-------+-------+-------+
| N3 | 336 | 1256 | 593 | 0 | -1069 | 978 | -487 |
+--------+------+------+-------+-------+-------+-------+-------+
| N4 | -143 | 522 | 844 | 1069 | 0 | -1324 | -771 |
+--------+------+------+-------+-------+-------+-------+-------+
| N5 | 1133 | 584 | 953 | -978 | 1324 | 0 | -305 |
+--------+------+------+-------+-------+-------+-------+-------+
| N6 | -866 | 141 | 1513 | 487 | 771 | 305 | 0 |
+--------+------+------+-------+-------+-------+-------+-------+
Next, we set the negative entries of SKEW to 0, and keep the rest to obtain the matrix, NET. For instance if you send me $10, and I send you $5, then the net effect is you sent me $5, and I sent you $0, we're just expressing everything in non-negative numbers. We could apply x*H(x) where H is the Heaviside step function to each entry of SKEW to obtain NET. Note that the R-S column vector for NET has not changed from that of TRM. We also note that for any square matrix, the sum over the R vector equals the sum over the S vector which is just the sum of all entries in the matrix, and therefore the R-S vector always sums to 0.
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| NET | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+=======+=========+=========+=========+=========+=========+=========+========+=====+==========+=====+==========+
| N0 | 0.00 | 418.00 | 0.00 | 0.00 | 143.00 | 0.00 | 866.00 | | 1427.00 | | -859.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N1 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 0.00 | | -4081.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N2 | 817.00 | 1160.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 1977.00 | | -1926.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N3 | 336.00 | 1256.00 | 593.00 | 0.00 | 0.00 | 978.00 | 0.00 | | 3163.00 | | 1607.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N4 | 0.00 | 522.00 | 844.00 | 1069.00 | 0.00 | 0.00 | 0.00 | | 2435.00 | | 197.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N5 | 1133.00 | 584.00 | 953.00 | 0.00 | 1324.00 | 0.00 | 0.00 | | 3994.00 | | 2711.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| N6 | 0.00 | 141.00 | 1513.00 | 487.00 | 771.00 | 305.00 | 0.00 | | 3217.00 | | 2351.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| | | | | | | | | | | | |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
| S | 2286.00 | 4081.00 | 3903.00 | 1556.00 | 2238.00 | 1283.00 | 866.00 | | 16213.00 | | 0.00 |
+-------+---------+---------+---------+---------+---------+---------+--------+-----+----------+-----+----------+
Closer analysis using some graph theory and linear algebra allows us to express the net effect of all transactions in TRM efficiently as the projection of TRM into the cocycle space of the complete directed multigraph on N vertices and 2*N*(N-1) edges. The dimension of the cocycle space is N-1. Projecting TRM thusly we obtain the skew-symmetric matrix, LMD. I called it this for no good reason having inherited it from a Visual Basic version I wrote a number of years ago. Note here also, the R-S vector remains unchanged from TRM. As a further note the numbers here are rounded to two decimal places whereas they have many more significant digits so the numbers may not add up exactly, if checking.
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| LMD | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+=======+=========+=========+=========+=========+=========+==========+==========+=====+==========+=====+==========+
| N0 | 0.00 | 230.14 | 76.21 | -176.14 | -75.43 | -255.00 | -229.29 | | -429.50 | | -859.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N1 | -230.14 | 0.00 | -153.93 | -406.29 | -305.57 | -485.14 | -459.43 | | -2040.50 | | -4081.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N2 | -76.21 | 153.93 | 0.00 | -252.36 | -151.64 | -331.21 | -305.50 | | -963.00 | | -1926.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N3 | 176.14 | 406.29 | 252.36 | 0.00 | 100.71 | -78.86 | -53.14 | | 803.50 | | 1607.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N4 | 75.43 | 305.57 | 151.64 | -100.71 | 0.00 | -179.57 | -153.86 | | 98.50 | | 197.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N5 | 255.00 | 485.14 | 331.21 | 78.86 | 179.57 | 0.00 | 25.71 | | 1355.50 | | 2711.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| N6 | 229.29 | 459.43 | 305.50 | 53.14 | 153.86 | -25.71 | 0.00 | | 1175.50 | | 2351.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| | | | | | | | | | | | |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
| S | 429.50 | 2040.50 | 963.00 | -803.50 | -98.50 | -1355.50 | -1175.50 | | 0.00 | | 0.00 |
+-------+---------+---------+---------+---------+---------+----------+----------+-----+----------+-----+----------+
To express the transactions in LMD as non-negative numbers only form SKEW = LMD - LMD.transpose, and set the negatives to 0. We obtain the matrix NETL. Again R-S is unchanged.
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| NETL | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+========+=========+=========+=========+========+========+======+=======+=====+=========+=====+==========+
| N0 | 0.00 | 460.29 | 152.43 | 0.00 | 0.00 | 0.00 | 0.00 | | 612.71 | | -859.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N1 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 0.00 | | -4081.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N2 | 0.00 | 307.86 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | | 307.86 | | -1926.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N3 | 352.29 | 812.57 | 504.71 | 0.00 | 201.43 | 0.00 | 0.00 | | 1871.00 | | 1607.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N4 | 150.86 | 611.14 | 303.29 | 0.00 | 0.00 | 0.00 | 0.00 | | 1065.29 | | 197.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N5 | 510.00 | 970.29 | 662.43 | 157.71 | 359.14 | 0.00 | 51.43 | | 2711.00 | | 2711.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| N6 | 458.57 | 918.86 | 611.00 | 106.29 | 307.71 | 0.00 | 0.00 | | 2402.43 | | 2351.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| | | | | | | | | | | | |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
| S | 1471.71 | 4081.00 | 2233.86 | 264.00 | 868.29 | 0.00 | 51.43 | | 8970.29 | | 0.00 |
+--------+---------+---------+---------+--------+--------+------+-------+-----+---------+-----+----------+
Any matrix where the R-S vector is the 0-vector(not merely summing to 0, but every entry is 0) lies in the cycle space of the complete directed graph. We can project TRM into the cycle space to obtain a matrix, CYC. This can be obtained by simply subtracting LMD from TRM, thus CYC = TRM - LMD. CYC can be broken down further into symmetric and skew-symmetric matrices, CYCS and CYCK respectively where CYCS = (CYC + CYC.transpose())/2 and CYCK = (CYC - CYC.transpose())/2. We have TRM = LMD + CYCS + CYCK.
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| CYCS | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+========+=========+=========+=========+=========+=========+=========+=========+=====+==========+=====+=======+
| N0 | 1606.00 | 668.00 | 751.50 | 932.00 | 659.50 | 1061.50 | 918.00 | | 6596.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N1 | 668.00 | 1154.00 | 1258.00 | 1445.00 | 980.00 | 659.00 | 2459.50 | | 8623.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N2 | 751.50 | 1258.00 | 539.00 | 591.50 | 1094.00 | 1058.50 | 949.50 | | 6242.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N3 | 932.00 | 1445.00 | 591.50 | 1065.00 | 864.50 | 603.00 | 785.50 | | 6286.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N4 | 659.50 | 980.00 | 1094.00 | 864.50 | 468.00 | 671.00 | 821.50 | | 5558.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N5 | 1061.50 | 659.00 | 1058.50 | 603.00 | 671.00 | 666.00 | 169.50 | | 4888.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| N6 | 918.00 | 2459.50 | 949.50 | 785.50 | 821.50 | 169.50 | 1872.00 | | 7975.50 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| | | | | | | | | | | | |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
| S | 6596.50 | 8623.50 | 6242.00 | 6286.50 | 5558.50 | 4888.50 | 7975.50 | | 46171.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+----------+-----+-------+
The space of all N×N square matrices' dimension is N^2. The cocycle space is dimension N-1, so that the cycle space is dimension N^2 - N + 1. The cycle space is further broken down into the symmetric cycles and the skew-symmetric cycles. Every symmetric matrix is a cycle, and the dimension of the symmetric matrices is N*(N+1)/2. The dimension of the skew-symmetric matrices is N*(N-1)/2 leaving the dimension of the skew-symmetric cycles (N-1)*(N-2)/2.
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| CYCK | N0 | N1 | N2 | N3 | N4 | N5 | N6 | | R | | R-S |
+========+=========+=========+=========+=========+=========+=========+=========+=====+=======+=====+=======+
| N0 | 0.00 | -21.14 | -484.71 | 8.14 | 146.93 | -311.50 | 662.29 | | -0.00 | | -0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N1 | 21.14 | 0.00 | -426.07 | -221.71 | 44.57 | 193.14 | 388.93 | | 0.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N2 | 484.71 | 426.07 | 0.00 | -44.14 | -270.36 | -145.29 | -451.00 | | 0.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N3 | -8.14 | 221.71 | 44.14 | 0.00 | -635.21 | 567.86 | -190.36 | | 0.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N4 | -146.93 | -44.57 | 270.36 | 635.21 | 0.00 | -482.43 | -231.64 | | 0.00 | | 0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N5 | 311.50 | -193.14 | 145.29 | -567.86 | 482.43 | 0.00 | -178.21 | | -0.00 | | -0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| N6 | -662.29 | -388.93 | 451.00 | 190.36 | 231.64 | 178.21 | 0.00 | | -0.00 | | -0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| | | | | | | | | | | | |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
| S | 0.00 | 0.00 | 0.00 | 0.00 | -0.00 | 0.00 | 0.00 | | -0.00 | | -0.00 |
+--------+---------+---------+---------+---------+---------+---------+---------+-----+-------+-----+-------+
from tabulate import tabulate
#
nn=7
TRM=matrix(RR,nn,nn)
for ii in [1..nn]:
for jj in [1..nn]:
TRM[ii-1,jj-1]=int(round(abs(normalvariate(0,1000))))
NET = TRM-TRM.transpose()
for ii in [1..nn]:
for jj in [1..nn]:
if NET[ii-1,jj-1] < 0.0: NET[ii-1,jj-1] = 0.0
b=[0.0]*nn
x=[0.0]*(nn-1)
for kk in [1..nn]:
for ii in [1..nn]:
b[kk-1] = b[kk-1]-TRM[ii-1,kk-1]+TRM[kk-1,ii-1]
m = 2*nn
for ii in [1..nn-1]:
for jj in [1..nn-1]:
x[ii-1] = b[jj-1] + x[ii-1]
if ii == jj: x[ii-1] = b[jj-1] + x[ii-1]
x[ii-1] = x[ii-1]/m
LMD = matrix(RR,nn,nn)
for ii in [2..nn]:
for jj in [1..ii-1]:
for kk in [1..nn-1]:
if ii==kk: LMD[ii-1,jj-1] = LMD[ii-1,jj-1] + x[kk-1]
if jj==kk: LMD[ii-1,jj-1] = LMD[ii-1,jj-1] - x[kk-1]
LMD[jj-1,ii-1] = -LMD[ii-1,jj-1]
print(' ')
NETL = LMD-LMD.transpose()
for ii in range(nn):
for jj in range(nn):
if NETL[ii,jj] < 0.0: NETL[ii,jj] = 0.0
CYC = TRM-LMD
CYCS = (CYC+CYC.transpose())/2 # symmetric cycle
CYCK = (CYC-CYC.transpose())/2 # skew-symmetric cycle
#rep=matrix(ZZ,nn,1,[1]*nn)
recvTRM = matrix(RR,nn,1,0)
sendTRM = matrix(RR,nn,1,0)
recvNET = matrix(RR,nn,1,0)
sendNET = matrix(RR,nn,1,0)
recvLMD = matrix(RR,nn,1,0)
sendLMD = matrix(RR,nn,1,0)
recvNETL = matrix(RR,nn,1,0)
sendNETL = matrix(RR,nn,1,0)
recvCYCS = matrix(RR,nn,1,0)
sendCYCS = matrix(RR,nn,1,0)
recvCYCK = matrix(RR,nn,1,0)
sendCYCK = matrix(RR,nn,1,0)
for ii in range(nn):
recvTRM[ii,0] = sum(TRM[ii])
recvNET[ii,0] = sum(NET[ii])
recvLMD[ii,0] = sum(LMD[ii])
recvNETL[ii,0] = sum(NETL[ii])
recvCYCS[ii,0] = sum(CYCS[ii])
recvCYCK[ii,0] = sum(CYCK[ii])
sendTRM[ii,0] = sum(TRM.transpose()[ii])
sendNET[ii,0] = sum(NET.transpose()[ii])
sendLMD[ii,0] = sum(LMD.transpose()[ii])
sendNETL[ii,0] = sum(NETL.transpose()[ii])
sendCYCS[ii,0] = sum(CYCS.transpose()[ii])
sendCYCK[ii,0] = sum(CYCK.transpose()[ii])
Nodes = [' ']
for ii in range(nn):
Nodes.append('N'+str(ii))
Nodes.append(' ')
Nodes.append('R')
Nodes.append(' ')
Nodes.append('R-S')
TRMdata=[]
NETdata=[]
LMDdata=[]
NETLdata=[]
CYCSdata = []
CYCKdata = []
for ii in range(nn):
rowT = [Nodes[ii+1]]
rowN = [Nodes[ii+1]]
rowL = [Nodes[ii+1]]
rowNL = [Nodes[ii+1]]
rowCS = [Nodes[ii+1]]
rowCK = [Nodes[ii+1]]
for jj in range(nn):
rowT.append('{0:.2f}'.format(TRM[ii,jj]))
rowN.append('{0:.2f}'.format(NET[ii,jj]))
rowL.append('{0:.2f}'.format(LMD[ii,jj]))
rowNL.append('{0:.2f}'.format(NETL[ii,jj]))
rowCS.append('{0:.2f}'.format(CYCS[ii,jj]))
rowCK.append('{0:.2f}'.format(CYCK[ii,jj]))
rowT.append(' ')
rowT.append('{0:.2f}'.format(recvTRM[ii,0]))
rowT.append(' ')
rowT.append('{0:.2f}'.format((recvTRM-sendTRM)[ii,0]))
rowN.append(' ')
rowN.append('{0:.2f}'.format(recvNET[ii,0]))
rowN.append(' ')
rowN.append('{0:.2f}'.format((recvNET-sendNET)[ii,0]))
rowL.append(' ')
rowL.append('{0:.2f}'.format(recvLMD[ii,0]))
rowL.append(' ')
rowL.append('{0:.2f}'.format((recvLMD-sendLMD)[ii,0]))
rowNL.append(' ')
rowNL.append('{0:.2f}'.format(recvNETL[ii,0]))
rowNL.append(' ')
rowNL.append('{0:.2f}'.format((recvNETL-sendNETL)[ii,0]))
rowCS.append(' ')
rowCS.append('{0:.2f}'.format(recvCYCS[ii,0]))
rowCS.append(' ')
rowCS.append('{0:.2f}'.format((recvCYCS-sendCYCS)[ii,0]))
rowCK.append(' ')
rowCK.append('{0:.2f}'.format(recvCYCK[ii,0]))
rowCK.append(' ')
rowCK.append('{0:.2f}'.format((recvCYCK-sendCYCK)[ii,0]))
TRMdata.append(rowT)
NETdata.append(rowN)
LMDdata.append(rowL)
NETLdata.append(rowNL)
CYCSdata.append(rowCS)
CYCKdata.append(rowCK)
TRMdata.append([' ']*(nn+5))
TRMdata.append([' ']*(nn+5))
TRMdata[nn+1][0] = 'S'
TRMdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvTRM)))
TRMdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvTRM-sendTRM)))
NETdata.append([' ']*(nn+5))
NETdata.append([' ']*(nn+5))
NETdata[nn+1][0] = 'S'
NETdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvNET)))
NETdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvNET-sendNET)))
LMDdata.append([' ']*(nn+5))
LMDdata.append([' ']*(nn+5))
LMDdata[nn+1][0] = 'S'
LMDdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvLMD)))
LMDdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvLMD-sendLMD)))
NETLdata.append([' ']*(nn+5))
NETLdata.append([' ']*(nn+5))
NETLdata[nn+1][0] = 'S'
NETLdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvNETL)))
NETLdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvNETL-sendNETL)))
CYCSdata.append([' ']*(nn+5))
CYCSdata.append([' ']*(nn+5))
CYCSdata[nn+1][0] = 'S'
CYCSdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvCYCS)))
CYCSdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvCYCS-sendCYCS)))
CYCKdata.append([' ']*(nn+5))
CYCKdata.append([' ']*(nn+5))
CYCKdata[nn+1][0] = 'S'
CYCKdata[nn+1][nn+2] = '{0:.2f}'.format(sum(vector(recvCYCK)))
CYCKdata[nn+1][nn+4] = '{0:.2f}'.format(sum(vector(recvCYCK-sendCYCK)))
SKEW = TRM-TRM.transpose()
SKEWdata = []
for ii in range(nn):
TRMdata[nn+1][ii+1]='{0:.2f}'.format(sendTRM[ii,0])
NETdata[nn+1][ii+1]='{0:.2f}'.format(sendNET[ii,0])
LMDdata[nn+1][ii+1]='{0:.2f}'.format(sendLMD[ii,0])
NETLdata[nn+1][ii+1]='{0:.2f}'.format(sendNETL[ii,0])
CYCSdata[nn+1][ii+1]='{0:.2f}'.format(sendCYCS[ii,0])
CYCKdata[nn+1][ii+1]='{0:.2f}'.format(sendCYCK[ii,0])
rowSK = [Nodes[ii+1]]
for jj in range(nn):
rowSK.append('{0:.2f}'.format(SKEW[ii][jj]))
SKEWdata.append(rowSK)
cola = ["right" for x in Nodes]
cola[0] = "center"
Nodes[0]='TRM'
mystring = 'The square matrix, TRM, of data in the following table represents the flow of goods and services in a complete directed multigraph of '+str(nn)+' nodes as valued in a single currency. The nodes of the graph might represent the nations of a small world. The data can be interpreted in either of two ways. Here we choose the interpretation that the value, X, in the cell corresponding to row 0 and column 1 is the amount received by node 0 from node 1. The value, Y, corresponding to row 1 and column 0 is the amount received by node 1 from node 0. One of these values will generally be greater than(though possibly equal to) the other. The net effect is a positive flow of |X-Y| in one direction or the other. A negative entry represents a flow in the direction opposite to a given edge in the graph. The column, R, is the sum along each row, and represents the total amount received from the network for each node. The row, S, represents the amount sent into the network for each node. The column, R-S, represents the net inflow or outflow of money for each node during a given time step. The data for this table was generated with a random variable from a half-normal distribution, i.e. |Z| where Z ~ N(0,sigma^2). TRM is my abbreviation for transaction matrix.'
print(mystring)
print(tabulate(TRMdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')
cola2 = ["right" for ii in range(nn)]
cola2[0] = 'center'
Nodes[0] = 'SKEW'
mystring = "To see the net effect of money transfers from node to node, we first form a skew-symmetric matrix(each entry is the negative of it's mirror reflection through the main diagonal) from TRM given by SKEW = TRM - TRM.transpose()."
print(mystring)
print(tabulate(SKEWdata, headers=Nodes, tablefmt="grid", colalign=cola2))
print(' ')
Nodes[0]='NET'
mystring = "Next, we set the negative entries of SKEW to 0, and keep the rest to obtain the matrix, NET. For instance if you send me $10, and I send you $5, then the net effect is you sent me $5, and I sent you $0, we're just expressing everything in non-negative numbers. We could apply x*H(x) where H is the Heaviside step function to each entry of SKEW to obtain NET. Note that the R-S column vector for NET has not changed from that of TRM. We also note that for any square matrix, the sum over the R vector equals the sum over the S vector which is just the sum of all entries in the matrix, and therefore the R-S vector always sums to 0."
print(mystring)
print(tabulate(NETdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')
Nodes[0]='LMD'
mystring = 'Closer analysis using some graph theory and linear algebra allows us to express the net effect of all transactions in TRM efficiently as the projection of TRM into the cocycle space of the complete directed multigraph on N vertices and 2*N*(N-1) edges. The dimension of the cocycle space is N-1. Projecting TRM thusly we obtain the skew-symmetric matrix, LMD. I called it this for no good reason having inherited it from a Visual Basic version I wrote a number of years ago. Note here also, the R-S vector remains unchanged from TRM. As a further note the numbers here are rounded to two decimal places whereas they have many more significant digits so the numbers may not add up exactly, if checking.'
print(mystring)
print(tabulate(LMDdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')
Nodes[0]='NETL'
mystring = 'To express the transactions in LMD as non-negative numbers only form SKEW = LMD - LMD.transpose, and set the negatives to 0. We obtain the matrix NETL. Again R-S is unchanged.'
print(mystring)
print(tabulate(NETLdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')
Nodes[0]='CYCS'
mystring = "Any matrix where the R-S vector is the 0-vector(not merely summing to 0, but every entry is 0) lies in the cycle space of the complete directed graph. We can project TRM into the cycle space to obtain a matrix, CYC. This can be obtained by simply subtracting LMD from TRM, thus CYC = TRM - LMD. CYC can be broken down further into symmetric and skew-symmetric matrices, CYCS and CYCK respectively where CYCS = (CYC + CYC.transpose())/2 and CYCK = (CYC - CYC.transpose())/2. We have TRM = LMD + CYCS + CYCK."
print(mystring)
print(tabulate(CYCSdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')
Nodes[0]='CYCK'
mystring = 'Die Quantenmechanik ist sehr achtung-gebietend. Aber eine innere Stimme sagt mir, daß das doch nicht der wahre Jakob ist. Die Theorie liefert viel, aber dem Geheimnis des Alten bringt sie uns kaum näher. Jedenfalls bin ich überzeugt, daß der nicht würfelt.'
mystring = "The space of all N×N square matrices' dimension is N^2. The cocycle space is dimension N-1, so that the cycle space is dimension N^2 - N + 1. The cycle space is further broken down into the symmetric cycles and the skew-symmetric cycles. Every symmetric matrix is a cycle, and the dimension of the symmetric matrices is N*(N+1)/2. The dimension of the skew-symmetric matrices is N*(N-1)/2 leaving the dimension of the skew-symmetric cycles (N-1)*(N-2)/2."
print(mystring)
print(tabulate(CYCKdata, headers=Nodes, tablefmt="grid", colalign=cola))
print(' ')