// *** Layout utils *** // *** experimental public static Bitmap __DrawElevation__(IEnumerable <Vector2D> layout, LayoutSettings layoutSettings, int matrixRows, int matrixCols) { double[,] elevData = ComputeLayoutElevation(layout, layoutSettings, matrixRows, matrixCols); Bitmap bmp = new Bitmap((int)Math.Ceiling(layoutSettings.Width), (int)Math.Ceiling(layoutSettings.Height)); Graphics gfx = Graphics.FromImage(bmp); Vector2D pixSz = new Vector2D(layoutSettings.Width / (double)matrixCols, layoutSettings.Height / (double)matrixRows); int row = 0; int oldY = 0; for (double y = pixSz.Y; row < elevData.GetLength(0); row++, y += pixSz.Y) { int _y = (int)Math.Round(y); int col = 0; int oldX = 0; for (double x = pixSz.X; col < elevData.GetLength(1); col++, x += pixSz.X) { int _x = (int)Math.Round(x); Brush brush = new SolidBrush(Color.FromArgb(255, 0, 0, (int)Math.Round(255.0 * elevData[row, col]))); gfx.FillRectangle(brush, oldX, oldY, _x - oldX, _y - oldY); brush.Dispose(); oldX = _x; } oldY = _y; } return(bmp); }
public static double[,] ComputeLayoutElevation(IEnumerable <Vector2D> layout, LayoutSettings layoutSettings, int matrixRows, int matrixCols, double sigma, double r, bool normalize, bool cut, double cutStdevMult) { Utils.ThrowException(layout == null ? new ArgumentNullException("layout") : null); Utils.ThrowException(layoutSettings == null ? new ArgumentNullException("layoutSettings") : null); Utils.ThrowException(matrixRows < 1 ? new ArgumentOutOfRangeException("matrixRows") : null); Utils.ThrowException(matrixCols < 1 ? new ArgumentOutOfRangeException("matrixCols") : null); Utils.ThrowException(sigma <= 0 ? new ArgumentOutOfRangeException("sigma") : null); LayoutSettings nrmLayoutSettings = layoutSettings.Clone(); double fX = 1.0 / (layoutSettings.Width - 2.0 * layoutSettings.MarginHoriz); double fY = 1.0 / (layoutSettings.Height - 2.0 * layoutSettings.MarginVert); nrmLayoutSettings.Width *= fX; nrmLayoutSettings.MarginHoriz *= fX; nrmLayoutSettings.Height *= fY; nrmLayoutSettings.MarginVert *= fY; Vector2D[] nrmLayout = nrmLayoutSettings.AdjustLayout(layout); LayoutIndex layoutIndex = new LayoutIndex(); layoutIndex.MaxPointsPerLeaf = 100; // *** hardcoded max points per leaf if (r > 0) { layoutIndex.BuildIndex(nrmLayout); } double[,] zMtx = new double[matrixRows, matrixCols]; Vector2D pixSz = new Vector2D(nrmLayoutSettings.Width / (double)matrixCols, nrmLayoutSettings.Height / (double)matrixRows); double maxZ = 0; double avgZ = 0; int row = 0; for (double y = pixSz.Y / 2.0; y < nrmLayoutSettings.Height; y += pixSz.Y, row++) { int col = 0; for (double x = pixSz.X / 2.0; x < nrmLayoutSettings.Width; x += pixSz.X, col++) { Vector2D pt0 = new Vector2D(x, y); double z = 0; if (r <= 0) { foreach (Vector2D pt in nrmLayout) { double dist = (pt - pt0).GetLength(); z += Math.Exp(-sigma * dist * dist); } } else { foreach (IdxDat <Vector2D> pt in layoutIndex.GetPoints(pt0, r)) { double dist = (pt.Dat - pt0).GetLength(); z += Math.Exp(-sigma * dist * dist); } } zMtx[row, col] = z; if (z > maxZ) { maxZ = z; } avgZ += z; } } avgZ /= (double)(matrixRows * matrixCols); if (avgZ > 0) { if (cut) { double stdev = 0; for (row = 0; row < zMtx.GetLength(0); row++) { for (int col = 0; col < zMtx.GetLength(1); col++) { stdev += (zMtx[row, col] - avgZ) * (zMtx[row, col] - avgZ); } } stdev = Math.Sqrt(stdev / (double)(matrixRows * matrixCols)); maxZ = avgZ + stdev * cutStdevMult; for (row = 0; row < zMtx.GetLength(0); row++) { for (int col = 0; col < zMtx.GetLength(1); col++) { if (zMtx[row, col] > maxZ) { zMtx[row, col] = maxZ; } } } } if (normalize && maxZ > 0) { for (row = 0; row < zMtx.GetLength(0); row++) { for (int col = 0; col < zMtx.GetLength(1); col++) { zMtx[row, col] /= maxZ; } } } } return(zMtx); }
public static double[,] ComputeLayoutElevation(IEnumerable <Vector2D> layout, LayoutSettings layoutSettings, int matrixRows, int matrixCols) { return(ComputeLayoutElevation(layout, layoutSettings, matrixRows, matrixCols, /*sigma=*/ 500, /*r=*/ 0.1, /*normalize=*/ true, /*cut=*/ false, 2)); }
public Vector2D[] ComputeLayout(LayoutSettings settings) { UnlabeledDataset <SparseVector <double> > dataset = new UnlabeledDataset <SparseVector <double> >(mDataset); // clustering mLogger.Info("ComputeLayout", "Clustering ..."); KMeansFast kMeans = new KMeansFast(mKClust); kMeans.Eps = mKMeansEps; kMeans.Random = mRandom; kMeans.Trials = 1; ClusteringResult clustering = kMeans.Cluster(mDataset); // throws ArgumentValueException // determine reference instances UnlabeledDataset <SparseVector <double> > dsRefInst = new UnlabeledDataset <SparseVector <double> >(); foreach (Cluster cluster in clustering.Roots) { SparseVector <double> centroid = cluster.Items.Count > 0 ? cluster.ComputeCentroid(mDataset, CentroidType.NrmL2) : new SparseVector <double>(); dsRefInst.Add(centroid); // dataset of reference instances dataset.Add(centroid); // add centroids to the main dataset } // position reference instances mLogger.Info("ComputeLayout", "Positioning reference instances ..."); SparseMatrix <double> simMtx = ModelUtils.GetDotProductSimilarity(dsRefInst, mSimThresh, /*fullMatrix=*/ false); StressMajorizationLayout sm = new StressMajorizationLayout(dsRefInst.Count, new DistFunc(simMtx)); sm.Random = mRandom; Vector2D[] centrPos = sm.ComputeLayout(); // k-NN mLogger.Info("ComputeLayout", "Computing similarities ..."); simMtx = ModelUtils.GetDotProductSimilarity(dataset, mSimThresh, /*fullMatrix=*/ true); mLogger.Info("ComputeLayout", "Constructing system of linear equations ..."); LabeledDataset <double, SparseVector <double> > lsqrDs = new LabeledDataset <double, SparseVector <double> >(); foreach (IdxDat <SparseVector <double> > simMtxRow in simMtx) { if (simMtxRow.Dat.Count <= 1) { mLogger.Warn("ComputeLayout", "Instance #{0} has no neighborhood.", simMtxRow.Idx); } ArrayList <KeyDat <double, int> > knn = new ArrayList <KeyDat <double, int> >(simMtxRow.Dat.Count); foreach (IdxDat <double> item in simMtxRow.Dat) { if (item.Idx != simMtxRow.Idx) { knn.Add(new KeyDat <double, int>(item.Dat, item.Idx)); } } knn.Sort(DescSort <KeyDat <double, int> > .Instance); int count = Math.Min(knn.Count, mKNN); SparseVector <double> eq = new SparseVector <double>(); double wgt = 1.0 / (double)count; for (int i = 0; i < count; i++) { eq.InnerIdx.Add(knn[i].Dat); eq.InnerDat.Add(-wgt); } eq.InnerIdx.Sort(); // *** sort only indices eq[simMtxRow.Idx] = 1; lsqrDs.Add(0, eq); } Vector2D[] layout = new Vector2D[dataset.Count - mKClust]; for (int i = dataset.Count - mKClust, j = 0; i < dataset.Count; i++, j++) { SparseVector <double> eq = new SparseVector <double>(new IdxDat <double>[] { new IdxDat <double>(i, 1) }); lsqrDs.Add(centrPos[j].X, eq); } LSqrModel lsqr = new LSqrModel(); lsqr.Train(lsqrDs); for (int i = 0; i < layout.Length; i++) { layout[i].X = lsqr.Solution[i]; } for (int i = lsqrDs.Count - mKClust, j = 0; i < lsqrDs.Count; i++, j++) { lsqrDs[i].Label = centrPos[j].Y; } lsqr.Train(lsqrDs); for (int i = 0; i < layout.Length; i++) { layout[i].Y = lsqr.Solution[i]; } return(settings == null ? layout : settings.AdjustLayout(layout)); }
public Vector2D[] ComputeLayout(LayoutSettings settings, Vector2D[] initLayout) { if (settings == null) { settings = new LayoutSettings(); } if (mNumPoints == 1) { return(settings.AdjustLayout(new Vector2D[] { new Vector2D() })); } // trivial case const double eps = 0.00001; Vector2D[] layout = new Vector2D[mNumPoints]; // initialize layout if (initLayout != null) { int initLen = Math.Min(mNumPoints, initLayout.Length); Array.Copy(initLayout, layout, initLen); for (int i = initLayout.Length; i < mNumPoints; i++) { layout[i] = new Vector2D(mRnd.NextDouble(), mRnd.NextDouble()); } } else { for (int i = 0; i < mNumPoints; i++) { layout[i] = new Vector2D(mRnd.NextDouble(), mRnd.NextDouble()); } } // main optimization loop double globalStress = 0, stressDiff = 0; double oldGlobalStress = double.MaxValue; for (int step = 0; step < mMaxSteps; step++) { globalStress = 0; for (int i = 0; i < mNumPoints; i++) { double div = 0; Vector2D newPos = new Vector2D(0, 0); for (int j = 0; j < mNumPoints; j++) { if (i != j) { double dIj = mDistFunc.GetDistance(i, j); if (dIj < eps) { dIj = eps; } double wIj = 1.0 / Math.Pow(dIj, 2); double xIMinusXJ = layout[i].X - layout[j].X; double yIMinusYJ = layout[i].Y - layout[j].Y; double denom = Math.Sqrt(Math.Pow(xIMinusXJ, 2) + Math.Pow(yIMinusYJ, 2)); if (denom < eps) { denom = eps; } // avoid dividing by zero div += wIj; newPos.X += wIj * (layout[j].X + dIj * (xIMinusXJ / denom)); newPos.Y += wIj * (layout[j].Y + dIj * (yIMinusYJ / denom)); if (i < j) { Vector2D diff = layout[i] - layout[j]; globalStress += wIj * Math.Pow(diff.GetLength() - dIj, 2); } } } layout[i].X = newPos.X / div; layout[i].Y = newPos.Y / div; } stressDiff = oldGlobalStress - globalStress; if ((step - 1) % 100 == 0) { mLogger.Info("ComputeLayout", "Global stress: {0:0.00} Diff: {1:0.0000}", globalStress, stressDiff); } oldGlobalStress = globalStress; if (stressDiff <= mMinDiff) { break; } } mLogger.Info("ComputeLayout", "Final global stress: {0:0.00} Diff: {1:0.0000}", globalStress, stressDiff); return(settings.AdjustLayout(layout)); }
public Vector2D[] ComputeLayout(LayoutSettings settings) { return(ComputeLayout(settings, /*initLayout=*/ null)); }