Пример #1
0
        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;
            }
        }