// strangerland®gmail.com
//***********************************************************************************************************************************************
//project transaction matrix into the cocycle subspace of a complete directed network where each vertex has a loop
//and each pair of vertices are connected by two edges of opposite orientation
package com.smkltd.app;
import java.util.Random;
public class Transaction
{
int Vertices;
int[] VertexList;
double[] B;
double[] Send;
double[] Receive;
double[] Change;
double[][] Matrix;
double[][] PositiveMatrix;
double[][] CoCycleProjection;
double[][] CycleProjection;
double[][] SymmCycleProjection;
double[][] SkewCycleProjection;
double[][] EffectiveMatrix;
public Transaction(int vertices)
{
this.Vertices = vertices;
this.VertexList = new int[vertices];
for (int ii=0; ii<vertices; ii++)
{
this.VertexList[ii] = ii;
}
this.Matrix = new double[vertices][vertices];
this.CoCycleProjection = new double[vertices][vertices];
this.CycleProjection = new double[vertices][vertices];
this.SymmCycleProjection = new double[vertices][vertices];
this.SkewCycleProjection = new double[vertices][vertices];
}
private double[][] Symm(double[][] mat, double a)
{
double[][] result = new double[Vertices][Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
result[ii][jj] = a*(mat[ii][jj] + mat[jj][ii]);
}
}
return result;
}
private double[][] Skew(double[][] mat, double a)
{
double[][] result = new double[Vertices][Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
result[ii][jj] = a*(mat[ii][jj] - mat[jj][ii]);
}
}
return result;
}
private double[][] MatAdd(double[][] mat1, double[][] mat2, double a, double b)
{
double[][] result = new double[Vertices][Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
result[ii][jj] = a*mat1[ii][jj] + b*mat2[jj][ii];
}
}
return result;
}
private double[][] PositivePart(double[][] mat)
{
double[][] result = new double[Vertices][Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
if (mat[ii][jj]>0) {
result[ii][jj] = mat[ii][jj];
}
}
}
return result;
}
private double[][] NegativePart(double[][] mat)
{
double[][] result = new double[Vertices][Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
if (mat[ii][jj]<0) {
result[ii][jj] = mat[ii][jj];
}
}
}
return result;
}
public byte[][] CoCycleBasisMatrix(int nn)
{
byte[][] result = new byte[Vertices][Vertices];
if ((nn<0)|(nn>=Vertices)) {
throw new IllegalArgumentException("index must be 0 < nn < Vertices in Transaction.CoCycleBasisMatrix(int nn)");
} else {
for (int ii=0; ii<Vertices; ii++)
{
result[nn][ii] = (byte)(-1 + result[nn][ii]);
result[ii][nn] = (byte)(1 + result[ii][nn]);
}
}
return result;
}
public void Change(double[][] mat)
{
Send = new double[Vertices];
Receive = new double[Vertices];
Change = new double[Vertices];
for (int ii=0; ii<Vertices; ii++)
{
for (int jj=0; jj<Vertices; jj++)
{
Send[ii] = Send[ii] + mat[ii][jj];
Receive[ii] = Receive[ii] + mat[jj][ii];
}
Change[ii] = Receive[ii] - Send[ii];
}
}
public void Projection()
{
B = new double[Vertices];
for (int kk=0; kk<Vertices; kk++)
{
B[kk] = 0;
for (int ii=0; ii<Vertices; ii++)
{
B[kk] = B[kk] + Matrix[ii][kk] - Matrix[kk][ii];
//B and Change should end up the same
}
}
int v2 = 2*Vertices;
double[] x = new double[Vertices-1];
for (int ii=0; ii<Vertices-1; ii++)
{
x[ii] = 0;
for (int jj=0; jj<Vertices-1; jj++)
{
x[ii] = B[jj] + x[ii];
if (ii==jj) {
x[ii] = B[jj] + x[ii];
}
}
x[ii] = x[ii]/v2;
//x[ii] are coefficients of the basis matrices L0,L1,...LV-1 see method CoCycleBasisMatrix(int nn)
}
CoCycleProjection = new double[Vertices][Vertices];
CoCycleProjection[0][0] = 0;
for (int ii=1; ii<Vertices; ii++)
{
CoCycleProjection[ii][ii] = 0;
for (int jj=0; jj<ii; jj++)
{
for (int kk=0; kk<Vertices-1; kk++)
{
if (ii==kk) {
CoCycleProjection[ii][jj] = CoCycleProjection[ii][jj] - x[kk];
}
if (jj==kk) {
CoCycleProjection[ii][jj] = CoCycleProjection[ii][jj] + x[kk];
}
}
CoCycleProjection[jj][ii] = -CoCycleProjection[ii][jj];
}
}
PositiveMatrix = PositivePart(Skew(Matrix,1));
EffectiveMatrix = PositivePart(Skew(CoCycleProjection,1));
CycleProjection = MatAdd(Matrix,CoCycleProjection,1,-1);
SymmCycleProjection = Symm(CycleProjection, .5);
SkewCycleProjection = Skew(CycleProjection, .5);
}
public void Printout(double[][] mat, String mssg)
{
System.out.println(" ");
System.out.println(mssg);
int nn = 0;
int mm;
int ll = String.valueOf(Vertices).length();
String sf = "% ,.2f";
for (int row = 0; row < Vertices; row++)
{
mm = String.format(sf,Send[row]).length();
if (nn<mm) {
nn=mm;
}
mm = String.format(sf,Receive[row]).length();
if (nn<mm) {
nn=mm;
}
mm = String.format(sf,Change[row]).length();
if (nn<mm) {
nn=mm;
}
for (int col = 0; col < Vertices; col++)
{
mm = String.format(sf,mat[row][col]).length();
if (nn<mm) {
nn=mm;
}
}
}
sf = "% ,"+nn+".2f ";
String rh = "";
mm = String.format(sf,mat[1][1]).length();
System.out.printf(" ");
for (int col = 0; col < Vertices; col++)
{
rh = String.format("v%d",col);
rh = String.format("%"+mm+"s", rh).replace(' ', ' ');
System.out.printf(rh);
}
System.out.printf(String.format("%"+mm+"s", " S").replace(' ', ' '));
System.out.println("");
for (int row = 0; row < Vertices; row++)
{
System.out.printf(" ");
System.out.printf("v%d",row);
for (int col = 0; col < Vertices; col++)
{
System.out.printf(String.format(sf,mat[row][col]));
}
System.out.printf(" ");
System.out.printf(String.format(sf,Send[row]));
System.out.println("");
}
System.out.println(" ");
System.out.printf(" ");
System.out.printf(String.format("%"+ll+"s", " R").replace(' ', ' '));
for (int col = 0; col < Vertices; col++)
{
System.out.printf(String.format(sf,Receive[col]));
}
System.out.println("");
System.out.println(" ");
System.out.printf(" ");
System.out.printf(String.format("%"+ll+"s", " C").replace(' ', ' '));
for (int col = 0; col < Vertices; col++)
{
System.out.printf(String.format(sf,Change[col]));
}
}
public static void main( String[] args )
{
double[][] MyTransactionMatrix = {
{ 49.4831220385154, 64.2770558819746, 32.4747427037916, 71.3890438058256, 73.7839820773905, 50.2432735942651, 32.673942098994},
{ 11.8284608293756, 18.9597904639655, 90.7330318298975, 24.6896681652731, 12.8824451824137, 25.3278371090856, 35.0159826539546},
{ 73.0064143638723, 54.7589670346052, 62.4752627471187, 16.4917827228854, 54.4976164116497, 68.9100260046704, 12.4932785458846},
{ 62.2628729509419, 2.97526585982973, 71.6486054086219, 28.3662108600914, 68.5645187256479, 61.4424040064482, 2.6807856968868},
{ 1.01524132010491, 39.4568144047003, 33.0720045167912, 43.7043490494094, 92.8541575108892, 52.2497375860926, 34.2681378183341},
{ 40.44683511173, 50.0802897026177, 39.1908463537231, 54.9247377187269, 21.714637386874, 15.2925022015582, 54.0756669054303},
{ 90.1722587607977, 42.2798467220186, 64.3415175210281, 57.2140232830873, 96.9356508407354, 27.0926286134315, 26.0774245798125}
};
Transaction MyTransaction = new Transaction(MyTransactionMatrix.length);
MyTransaction.Matrix = MyTransactionMatrix;
MyTransaction.Change(MyTransaction.Matrix);
String mssg = "\n\tMoney transfer from vertex[row] to vertex[col].\n\tA negative amount would be a transfer in the opposite direction.";
mssg=mssg+"\n\tR[col] is the amount total received by a vertex, S[row] is the total amount sent\n\tby a vertex, and the net amount for each vertex is C[col] = R[col] - S[col]";
MyTransaction.Printout(MyTransaction.Matrix,mssg);
MyTransaction.Projection();
MyTransaction.Change(MyTransaction.CoCycleProjection);
mssg = "\n\tThis is the projection of the above example into the cocycle space of the graph.\n";
MyTransaction.Printout(MyTransaction.CoCycleProjection,mssg);
mssg = "\n\tThis is the equivalent of the above matrix in terms of non-negative amounts.\n\tWe have taken the cocycle matrix minus its transpose and zeroed out the negatives.\n";
MyTransaction.Change(MyTransaction.EffectiveMatrix);
MyTransaction.Printout(MyTransaction.EffectiveMatrix,mssg);
Random fRandom = new Random();
double g;
for (int row = 0; row < MyTransaction.Vertices; row++)
{
for (int col = 0; col < MyTransaction.Vertices; col++)
{
g = fRandom.nextGaussian();
MyTransaction.Matrix[row][col] = 200*Math.pow(g,2);
}
}
MyTransaction.Change(MyTransaction.Matrix);
mssg = "\n\tA random example.\n";
MyTransaction.Printout(MyTransaction.Matrix,mssg);
MyTransaction.Projection();
MyTransaction.Change(MyTransaction.CoCycleProjection);
mssg = "\n\tThe cocycle projection.\n";
MyTransaction.Printout(MyTransaction.CoCycleProjection,mssg);
mssg = "\n\tThe effective transfers.\n";
MyTransaction.Change(MyTransaction.EffectiveMatrix);
MyTransaction.Printout(MyTransaction.EffectiveMatrix,mssg);
}
}