Пример #1
0
        void PropagateByNeighborsSimple(Neighbor[][] nbList, float[][] a)
        {
            float avAff = 0.0f;

            MT.ForEach(nbList, nbs => {
                float s = nbs.Sum(nb => nb.distance * nb.distance);
                lock (this)
                    avAff += s;
            });
            avAff = (float)Math.Sqrt(avAff / (nbList.Length * nbList[0].Length));

            int rows    = a.Length;
            int columns = a[0].Length;

            MT.Loop(0, rows, row => {
                float[] newAff = new float[columns];
                float[] aR     = a[row];
                for (int col = 0; col < columns; col++)
                {
                    float aff = aR[col];
                    foreach (var nb in nbList[col])
                    {
                        if (nb.distance >= avAff)
                        {
                            break;
                        }
                        aff += aR[nb.index];
                    }
                    newAff[col] = aff;
                }
                a[row] = newAff;
            });
        }
Пример #2
0
        public float[][] AffinityToDistance(float[][] P, float[][] Q)
        {
            // Symmetrize P, Q to P
            const float eps     = 2.22e-16f;
            int         rows    = P.Length;
            int         columns = Q.Length;

            MT.Loop(0, rows, row => {
                for (int col = 0; col < columns; col++)
                {
                    P[row][col] = P[row][col] + Q[col][row];
                }
            });

            // Linearly map affinity to distance  in to the range [0, 1.0].
            var   mmm      = MinMaxMean(P);
            float range    = Math.Max(eps, mmm.Item2 - mmm.Item1);
            float maxValue = mmm.Item2;

            MT.Loop(0, rows, row => {
                for (int col = 0; col < columns; col++)
                {
                    P[row][col] = (maxValue - P[row][col]) / range;
                }
            });
            return(P);
        }
Пример #3
0
        static void WriteMarix(DxShader.GpuDevice gpu, GBuf buffer, float[][] matrix, int col0, int col1, float[] uploadBuf)
        {
            int rows = matrix.Length;

            Array.Clear(uploadBuf, 0, uploadBuf.Length);
            MT.Loop(col0, col1, col => {
                int offset = (col - col0) * rows;
                for (int row = 0; row < rows; row++)
                {
                    uploadBuf[offset + row] = matrix[row][col];
                }
            });
            gpu.WriteArray(uploadBuf, buffer);
        }
Пример #4
0
        // Find the kNN neighbors of each node based on distance matrix cDist[].
        Neighbor[][] FindNeighbors(float[][] cDist, int maxKnn)
        {
            int columns = cDist.Length;
            int kNN     = Math.Min(columns - 1, maxKnn);

            Neighbor[][] nbList = new Neighbor[columns][]; // each row stores the kNN closet columns of a column.

            MT.Loop(0, columns, col => {
                // find the kNN nearest columns/neighbors of col-the column.
                Neighbor[] nbs = nbList[col] = new Neighbor[kNN];
                int kNN2       = 0; // The actually number of neighbors in nbs[]
                for (int c = 0; c < columns; c++)
                {
                    if (c == col)
                    {
                        continue;
                    }
                    float dist = (c < col) ? cDist[col][c] : cDist[c][col];
                    if (dist <= 0)
                    {
                        continue;
                    }
                    int i = 0;
                    for (i = kNN2 - 1; i >= 0; i--)
                    {
                        if (nbs[i].distance <= dist)
                        {
                            break;
                        }
                    }
                    // at here we have nbs[i].distance <= dist < nbs[i+1].distance

                    kNN2 = Math.Min(kNN, kNN2 + 1);
                    i++;
                    // Copy nbs[i:*] to nbs[i+1:*]
                    int len = kNN2 - i - 1;
                    if (len > 0)
                    {
                        Array.Copy(nbs, i, nbs, i + 1, len);
                    }
                    if (i < kNN2)
                    {
                        nbs[i].distance = dist;
                        nbs[i].index    = c;
                    }
                }
            });
            return(nbList);
        }
Пример #5
0
        static float[][] Transpose(float[][] matrix)
        {
            int rows    = matrix.Length;
            int columns = matrix[0].Length;

            float[][] m = new float[columns][];
            MT.Loop(0, columns, row => {
                m[row] = new float[rows];
                for (int col = 0; col < rows; col++)
                {
                    m[row][col] = matrix[col][row];
                }
            });
            return(m);
        }
Пример #6
0
        void PreCalculate() {
            if (dataset == null)
                return;

            // Extract the relevant data table.
            var bs = dataset.BodyList;
            INumberTable nt = dataset.GetNumberTableView();
            toIdx = Enumerable.Range(0, bs.Count).Where(i => !bs[i].Disabled).ToArray();    // Indexes of enabled bodies.
            int N = nt.Rows - pcaSamples;
            int[] enabledRows = toIdx.Where(i => i < N).ToArray();

            if (enabledRows.Length == 0) 
                throw new TException("No data available!");
            P = new float[enabledRows.Length][];
            MT.Loop(0, P.Length, row => {
                float[] R = P[row] = new float[nt.Columns];
                double[] dsR = nt.Matrix[enabledRows[row]] as double[];
                for (int col = 0; col < nt.Columns; col++)
                    R[col] = (float)dsR[col];
            });

            // Reverse toIdx;
            int[] rIdx = Enumerable.Repeat(-1, bs.Count).ToArray();
            for (int i = 0; i < toIdx.Length; i++) rIdx[toIdx[i]] = i;
            toIdx = rIdx;

            using (var gpu = new VisuMap.DxShader.GpuDevice())
                dtP = DualAffinity.DotProduct(gpu, P, false);

            float[] singValues = new float[pcaMax];
            float[][] PC = FastPca.DoFastReduction(P, pcaMax, singValues, true); 
            P = VisuMap.MathUtil.NewMatrix<float>(PC.Length, pcaSamples);  // P now links data points with the injected points on the main PCA axis.
            float span = 4.0f * singValues[0];
            stepSize = span / (pcaSamples - 1);
            float x0 = - 0.5f * span;
            MT.ForEach(PC, (R, row) => {
                double yy = R.Skip(1).Sum(v => v * v);
                for (int col = 0; col < pcaSamples; col++) {
                    double x = R[0] - (x0 + col * stepSize);
                    P[row][col] = (float)Math.Sqrt(x * x + yy);
                }
            });
        }
Пример #7
0
        void PropagateByNeighbors(Neighbor[][] nbList, float[][] a)
        {
            int kNN     = nbList[0].Length;
            int rows    = a.Length;
            int columns = a[0].Length;

            // Calculate the average distance to kNN neighbors.
            float avAff = 0.0f;

            MT.ForEach(nbList, nbs => {
                float s = nbs.Sum(nb => nb.distance);
                lock (this)
                    avAff += s;
            });
            avAff /= nbList.Length * kNN;

            // Prepare the exponentially descreasing coefficent to propgate neighboring affinity.
            MT.ForEach(nbList, nbs => {
                for (int k = 0; k < kNN; k++)
                {
                    double e        = nbs[k].distance / avAff;
                    nbs[k].distance = (float)Math.Exp(-0.5 * e * e);
                }
            });

            // Propagate affinity from neibhoring columns.
            MT.Loop(0, rows, row => {
                float[] newAff = new float[columns];
                float[] aR     = a[row];
                for (int col = 0; col < columns; col++)
                {
                    var nbs   = nbList[col];
                    float aff = aR[col];
                    foreach (var nb in nbs)
                    {
                        aff += aR[nb.index] * nb.distance;
                    }
                    newAff[col] = aff;
                }
                a[row] = newAff;
            });
        }
Пример #8
0
        public List <string> Expression(List <string> selectedIds, double threshold)
        {
            const short maxExprIndex = 13; // number of expressed levels.
            const short indexShift   = 38;

            double[][]    M             = (double[][])(NumTable.Matrix);
            int           cellNr        = NumTable.Rows;
            int           geneNr        = NumTable.Columns;
            IList <int>   selectedCells = NumTable.IndexOfRows(selectedIds);
            IList <int>   selectedGenes = NumTable.IndexOfColumns(selectedIds);
            List <string> expressedId   = new List <string>();

            if (threshold == 0)                               // mark the genes/cells which have higher expression than the average of selected genes/cells.
            {
                if (GeneToCell)                               // Finding expressed cells for selected genes.  Gene->Cell operation.
                {
                    double[] expression = new double[cellNr]; // total expression of each cell.
                    MT.Loop(0, cellNr, row => {
                        foreach (int col in selectedGenes)
                        {
                            expression[row] += M[row][col];
                        }
                    });

                    double meanExp = expression.Sum() / cellNr;
                    double maxExp  = expression.Max();
                    double step    = (maxExp - meanExp) / maxExprIndex;

                    this.Genes = selectedGenes.Count;
                    this.Cells = 0;
                    for (int i = 0; i < cellNr; i++)   // for each cells.
                    {
                        double delta = expression[i] - meanExp;
                        int    bIdx  = row2bodyIdx[i];
                        if (delta > 0)
                        {
                            short v = Math.Min(maxExprIndex, (short)(delta / step));
                            BodyList[bIdx].Type = (short)(indexShift + v);
                            this.Cells++;
                            expressedId.Add(BodyList[bIdx].Id);
                        }
                        else
                        {
                            BodyList[bIdx].Type = OrgBodies[bIdx].Type;
                        }
                    }
                }
                else
                {
                    double[] expression = new double[geneNr]; // total expression of each gene.
                    MT.Loop(0, geneNr, col => {
                        foreach (int row in selectedCells)
                        {
                            expression[col] += M[row][col];
                        }
                    });
                    double meanExp = expression.Sum() / geneNr;
                    double maxExp  = expression.Max();
                    double step    = (maxExp - meanExp) / maxExprIndex;

                    // Finding expressed genes for selected cells. Cell->Gene operation.
                    this.Cells = selectedCells.Count;
                    this.Genes = 0;
                    for (int i = 0; i < geneNr; i++)    // for each gene.
                    {
                        double delta = expression[i] - meanExp;
                        int    bIdx  = col2bodyIdx[i];
                        if (delta > 0)
                        {
                            int v = Math.Min(maxExprIndex, (int)(delta / step));
                            BodyList[bIdx].Type = (short)(indexShift + v);
                            this.Genes++;
                            expressedId.Add(BodyList[bIdx].Id);
                        }
                        else
                        {
                            BodyList[bIdx].Type = OrgBodies[bIdx].Type;
                        }
                    }
                }
            }
            else     // Mark all those cells/genes which have above global average expressions.
            {
                if (GeneToCell)
                {
                    short[] expressed = new short[cellNr]; // count of expressed genes for each cell.
                    MT.Loop(0, cellNr, row => {
                        foreach (int col in selectedGenes)
                        {
                            if (M[row][col] > threshold)
                            {
                                expressed[row] += 1;
                            }
                        }
                    });

                    this.Genes = selectedGenes.Count;
                    this.Cells = expressed.Count(v => v > 0);
                    for (int i = 0; i < cellNr; i++)
                    {
                        short v    = Math.Min(maxExprIndex, expressed[i]);
                        int   bIdx = row2bodyIdx[i];
                        BodyList[bIdx].Type = (short)((v > 0) ? (indexShift + v) : OrgBodies[bIdx].Type);
                        if (v > 0)
                        {
                            expressedId.Add(BodyList[bIdx].Id);
                        }
                    }
                }
                else
                {
                    short[] expressed = new short[geneNr];  // count of expressed cells for each gene.
                    MT.Loop(0, geneNr, col => {
                        foreach (int row in selectedCells)
                        {
                            if (M[row][col] > threshold)
                            {
                                expressed[col] += 1;
                            }
                        }
                    });

                    this.Cells = selectedCells.Count;
                    this.Genes = expressed.Count(v => v > 0);
                    for (int i = 0; i < geneNr; i++)
                    {
                        short v    = Math.Min(maxExprIndex, expressed[i]);
                        int   bIdx = col2bodyIdx[i];
                        BodyList[bIdx].Type = (short)((v > 0) ? (indexShift + v) : OrgBodies[bIdx].Type);
                        if (v > 0)
                        {
                            expressedId.Add(BodyList[bIdx].Id);
                        }
                    }
                }
            }
            return(expressedId);
        }
Пример #9
0
        void PreCalculate()
        {
            if (dataset != null)
            {
                var          bs    = dataset.BodyList;
                INumberTable nt    = dataset.GetNumberTableView();
                int          nrows = nt.Rows - nt.Columns;
                toIdx = Enumerable.Range(0, bs.Count).Where(i => !bs[i].Disabled).ToArray();    // Indexes of enabled bodies.
                int[] selectedRows    = toIdx.Where(i => i < nrows).ToArray();
                int[] selectedColumns = toIdx.Where(i => i >= nrows).Select(i => i - nrows).ToArray();

                if ((selectedColumns.Length == 0) || (selectedRows.Length == 0))
                {
                    throw new TException("No-zero number of genes and cells must be selected!");
                }
                P = new float[selectedRows.Length][];
                MT.Loop(0, P.Length, row => {
                    float[] R    = P[row] = new float[selectedColumns.Length];
                    double[] dsR = nt.Matrix[selectedRows[row]] as double[];
                    for (int col = 0; col < selectedColumns.Length; col++)
                    {
                        R[col] = (float)dsR[selectedColumns[col]];
                    }
                });

                // Reverse toIdx;
                int[] rIdx = Enumerable.Repeat(-1, bs.Count).ToArray();
                for (int i = 0; i < toIdx.Length; i++)
                {
                    rIdx[toIdx[i]] = i;
                }
                toIdx = rIdx;
            }
            float[][] Q = Transpose(P);   // Q is the transpose of P.

            // Calculate the distance tables for P and Q.
            bool isPCor = (metricMode == MetricMode.CorCor) || (metricMode == MetricMode.CorEuc);
            bool isQCor = (metricMode == MetricMode.CorCor) || (metricMode == MetricMode.EucCor);

            if (isPCor)
            {
                Normalize(P);
            }
            if (isQCor)
            {
                Normalize(Q);
            }

            using (var gpu = new VisuMap.DxShader.GpuDevice())
                using (var cc = gpu.CreateConstantBuffer <ShaderConstant>(0))
                    using (var sd = gpu.LoadShader("SingleCellAnalysis.DotProduct.cso", Assembly.GetExecutingAssembly())) {
                        dtP = CallShadere(gpu, cc, sd, P, isPCor);
                        dtQ = CallShadere(gpu, cc, sd, Q, isQCor);
                    }

            /*
             * affinity-propagation enhances structure if colums or rows within clusters are
             * light occupied with high randomness. AP however dilutes clusters with few members.
             * For instance, singlton gene cluster (with only gene) will suppressed by AP due to
             * its aggregation with neighboring genes (which should be consdiered as separate
             * clusters.)
             *
             * ProbagateAffinity(dtQ, P); // Column<->Column affinity => Column->Row affinity
             * ProbagateAffinity(dtP, Q);  // Row<->Row affinity => Row->Column affinity.
             */

            // Calculates the distance between rows and columns into P.
            P = AffinityToDistance(P, Q);
            Q = null;
            var    app      = SingleCellPlugin.App.ScriptApp;
            double linkBias = app.GetPropertyAsDouble("SingleCell.Separation", 1.0);
            double pScale   = app.GetPropertyAsDouble("SingleCell.CellScale", 1.0);
            double qScale   = app.GetPropertyAsDouble("SingleCell.GeneScale", 1.0);
            //PowerMatrix(P, linkBias);

            // Scaling dtP, dtQ to the range of P.
            Func <float[][], float> aFct = AverageSqrt;
            double av = aFct(P);

            pScale *= av / aFct(dtP);
            qScale *= av / aFct(dtQ);
            ScaleMatrix(dtP, pScale);
            ScaleMatrix(dtQ, qScale);

            //ScaleMatrix(P, linkBias);
            ShiftMatrix(P, (float)(linkBias * av));
        }
Пример #10
0
        static float[][] CallShadere(DxShader.GpuDevice gpu, CBuf cc, ComputeShader sd, float[][] M, bool isCorrelation)
        {
            cc.c.N = M.Length;
            int       columns   = M[0].Length;
            const int groupSize = 256;
            int       distSize  = groupSize * cc.c.N;

            float[][] dMatrix = new float[M.Length][];
            for (int row = 0; row < M.Length; row++)
            {
                dMatrix[row] = new float[row];
            }
            int maxColumns = MaxGpuFloats / cc.c.N;
            int secSize    = Math.Min(columns, (maxColumns > 4096) ? 4096 : (maxColumns - 32));

            float[] uploadBuf = new float[cc.c.N * secSize];

            using (var dataBuf = gpu.CreateBufferRO(cc.c.N * secSize, 4, 0))
                using (var distBuf = gpu.CreateBufferRW(distSize, 4, 0))
                    using (var distStaging = gpu.CreateStagingBuffer(distBuf)) {
                        gpu.SetShader(sd);
                        for (int s0 = 0; s0 < columns; s0 += secSize)
                        {
                            int s1 = Math.Min(s0 + secSize, columns);
                            WriteMarix(gpu, dataBuf, M, s0, s1, uploadBuf);
                            float[] blockDist = new float[distSize];
                            for (cc.c.iBlock = 1; cc.c.iBlock < cc.c.N; cc.c.iBlock += groupSize)
                            {
                                cc.c.columns = s1 - s0;
                                cc.Upload();
                                gpu.Run(groupSize);
                                int iBlock2 = Math.Min(cc.c.iBlock + groupSize, cc.c.N);
                                int bSize   = (iBlock2 - cc.c.iBlock) * (iBlock2 + cc.c.iBlock - 1) / 2;
                                gpu.ReadRange <float>(blockDist, 0, distStaging, distBuf, bSize);

                                int offset = 0;
                                for (int row = cc.c.iBlock; row < iBlock2; row++)
                                {
                                    float[] R = dMatrix[row];
                                    for (int k = 0; k < row; k++)
                                    {
                                        R[k] += blockDist[offset + k];
                                    }
                                    offset += row;
                                }
                                Application.DoEvents();
                            }
                        }
                    }

            if (isCorrelation)
            {
                MT.ForEach(dMatrix, R => {
                    for (int col = 0; col < R.Length; col++)
                    {
                        R[col] = 1.0f - R[col];
                    }
                });
            }
            else     // Euclidean distance is wanted.
            {
                float[] norm2 = new float[M.Length];
                Array.Clear(norm2, 0, M.Length);
                int L = M[0].Length;
                MT.ForEach(M, (R, row) => {
                    float sumSquared = 0.0f;
                    for (int col = 0; col < L; col++)
                    {
                        sumSquared += R[col] * R[col];
                    }
                    norm2[row] = sumSquared;
                });
                MT.Loop(1, M.Length, row => {
                    float[] R = dMatrix[row];
                    for (int col = 0; col < row; col++)
                    {
                        R[col] = (float)Math.Sqrt(Math.Abs(norm2[row] + norm2[col] - 2 * R[col]));
                    }
                });
            }
            return(dMatrix);
        }