void ConstructLinearSystemFromMajorization(out SparseMatrix Lw, out SparseMatrix Lx) { int numEdges = GetNumberOfEdges(NodeVotings); #if SHARPKIT //SharpKit/Colin: multidimensional arrays not supported in JavaScript - https://code.google.com/p/sharpkit/issues/detail?id=340 var edgesDistance = new double[numEdges]; var edgesWeight = new double[numEdges]; #else var edges = new double[numEdges, 2]; #endif // list of undirected (symmetric) edges: [,0]=distance, [,1]=weight , every edge must be symmetric (thus exist once in each direction). //each element in the array corresponds to a node, the list corresponds to the adjacency list of that node. //int[0]: node id of adjacent node, int[1]: edge id of this edge var adjLists = new List <int[]> [NodeVotings.Count]; int row = 0; int edgeId = 0; foreach (NodeVoting nodeVoting in NodeVotings) { int targetId = nodeVoting.VotedNodeIndex; int numAdj = 0; nodeVoting.VotingBlocks.ForEach(block => numAdj += block.Votings.Count); var currentAdj = new List <int[]>(numAdj); if (row != targetId) { throw new ArgumentOutOfRangeException("VotedNodeIndex must be consecutive starting from 0"); } adjLists[row] = currentAdj; foreach (VoteBlock block in nodeVoting.VotingBlocks) { foreach (Vote voting in block.Votings) { //corresponds to an edge or an entry in the corresponding matrix int sourceId = voting.VoterIndex; #if SHARPKIT edgesDistance[edgeId] = voting.Distance; edgesWeight[edgeId] = voting.Weight * block.BlockWeight; #else edges[edgeId, 0] = voting.Distance; edges[edgeId, 1] = voting.Weight * block.BlockWeight; #endif currentAdj.Add(new[] { sourceId, edgeId }); edgeId++; } } row++; } //TODO check if sorting can be removed to make it faster. //sort the adjacency lists, so that we can create a sparse matrix where the ordering is important for (int rowC = 0; rowC < adjLists.Length; rowC++) { List <int[]> adjList = adjLists[rowC]; //add self loop, since there will be an entry in the matrix too. adjList.Add(new[] { rowC, -1 }); adjList.Sort((a, b) => a[0].CompareTo(b[0])); } numEdges += adjLists.Length; //self loop added to every node, so number of edges has increased by n. var diagonalPos = new int[adjLists.Length]; // points to the position of the i-th diagonal entry in the flatened value array Lw = new SparseMatrix(numEdges, adjLists.Length, adjLists.Length); Lx = new SparseMatrix(numEdges, adjLists.Length, adjLists.Length); int valPos = 0; for (int rowId = 0; rowId < adjLists.Length; rowId++) { List <int[]> adjList = adjLists[rowId]; double sumLw = 0; double sumLx = 0; foreach (var node in adjList) { int colId = node[0]; Lw.ColInd()[valPos] = colId; Lx.ColInd()[valPos] = colId; if (rowId == colId) { //on diagonal of matrix diagonalPos[rowId] = valPos; //we will fill in the value later with the sum of all row entries } else { #if SHARPKIT double distance = edgesDistance[node[1]]; // distance(rowId,colId) double weight = edgesWeight[node[1]]; // weight(rowId,colId) #else double distance = edges[node[1], 0]; // distance(rowId,colId) double weight = edges[node[1], 1]; // weight(rowId,colId) #endif // weighted laplacian fill Lw.Values()[valPos] = -weight; sumLw += weight; // Lx, which is similar to weighted laplacian but takes the distance into account //TODO extract the distance computation outside of this step to make the procedure faster double euclid = (Positions[rowId] - Positions[colId]).Length; double entry = -weight * distance / euclid; Lx.Values()[valPos] = entry; sumLx += entry; } valPos++; } //set the diagonal to the sum of all other entries in row Lw.Values()[diagonalPos[rowId]] = sumLw; Lx.Values()[diagonalPos[rowId]] = -sumLx; //mark row end in flatened list Lw.RowPtr()[rowId + 1] = valPos; Lx.RowPtr()[rowId + 1] = valPos; } }