public static double DaviesBouldinIndex(Partition p) { //Insure all centroids are calculated KPoint[][] clusterPoints = new KPoint[p.Clusters.Count][]; for (int c = 0; c < p.Clusters.Count; c++) { clusterPoints[c] = p.GetClusterKPoints(c); } KPoint[] centers = p.Clusters.Select(c => new KPoint(clusterPoints[c.ClusterId])).ToArray(); double db = 0.0; for (int i = 0; i < p.Clusters.Count; i++) { double Oi = averageDistanceFromCentroid(clusterPoints[i]); double maxStat = 0.0; for (int j = 0; j < p.Clusters.Count; j++) { if (i != j) { double Oj = averageDistanceFromCentroid(clusterPoints[j]); double dbi = (Oi + Oj) / centers[i].elucideanDistance(centers[j]); if (dbi > maxStat) { maxStat = dbi; } } } db += maxStat; } return(db / (double)p.Clusters.Count); }
public int[] GetCounts(KPoint key, int linePtr) { if (_hiRez) { if (_countsRepoHiRez.ReadParts(key, _workResultHiRez)) { return(GetOneLineFromCountsBlock(_workResultHiRez.Counts, linePtr)); } else { return(null); } } else { if (_countsRepo.ReadParts(key, _workResult)) { return(GetOneLineFromCountsBlock(_workResult.Counts, linePtr)); } else { return(null); } } }
//This updates the weights of the neuron to pull towards public void updateWeights(KPoint target, double learningRate, double influence) { for (int i = 0; i < weights.Dimensions; i++) { weights[i] += (target[i] - weights[i]) * learningRate * influence; } }
public void WriteWorkResult(KPoint key, MapSectionWorkResult val, bool overwriteResults) { // When writing include the Area's offset. KPoint transKey = key.ToGlobal(_position); try { lock (_repoLock) { if (overwriteResults) { _countsRepo.Change(transKey, val); //WorkResultReWriteCount++; } else { _countsRepo.Add(transKey, val, saveOnWrite: false); //WorkResultWriteCount++; } } } catch { Debug.WriteLine($"Could not write data for x: {transKey.X} and y: {transKey.Y}."); } }
public static double SilhouetteIndex(ClusteredItem datum, Partition clusters) { //Calculate A double distA = 0.0; KPoint datumPoint = clusters.Points[datum.Id]; foreach (ClusteredItem d in clusters.Clusters[datum.ClusterId].Points) { distA += datumPoint.elucideanDistance(clusters.Points[d.Id]); } distA /= (double)(clusters.Clusters[datum.ClusterId].Points.Count - 1); double minB = double.MaxValue; for (int i = 0; i < clusters.Clusters.Count; i++) { if (i != datum.ClusterId) { double distB = 0.0; foreach (ClusteredItem d in clusters.Clusters[i].Points) { distB += datumPoint.elucideanDistance(clusters.Points[d.Id]); } distB /= (double)(clusters.Clusters[i].Points.Count); if (distB < minB) { minB = distB; } } } return((minB - distA) / Math.Max(minB, distA)); }
public SelfOrganizingMap(PointSet data, List <int> dimensions, int totalItt, double learningRate) { //Get initial learning rate this.initialLearningRate = learningRate; this.learningRate = learningRate; influence = 0; this.totalItterations = totalItt; itterations = 1; this.dimensions = dimensions; this.data = data; rng = new Random((int)DateTime.Now.Ticks); int numNeurons = 1; foreach (int d in dimensions) { numNeurons *= d; } int[] pos = new int[dimensions.Count]; for (int i = 0; i < dimensions.Count; i++) { pos[i] = 0; } //Scale each attribute from [0,1] and store the conversion matrix conversionMatrix = data.GetMinMaxWeights().Max.Coordinates; foreach (KPoint d in data.PointList) { d.Normalize(conversionMatrix); } //Here We will initialize Our Neurons neurons = new List <SOMNeuron>(); KPoint zero = KPoint.Zero(data[0].Dimensions); KPoint one = KPoint.One(data[0].Dimensions); for (int i = 0; i < numNeurons; i++) { //Generate our neurons double[] posNeuron = new double[dimensions.Count]; for (int d = 0; d < dimensions.Count; d++) { posNeuron[d] = (double)pos[d]; } SOMNeuron neuron = new SOMNeuron(zero, one, rng, new KPoint(posNeuron), i); neurons.Add(neuron); addOneCarry(ref pos, dimensions); } //Get the max radius setRadius(); this.timeConstant = (double)totalItterations / Math.Log(radius); }
public BallTreeNode(PointSet Points) { //if there is only a single point, set this as the data if (Points.Count == 1) { Point = Points[0]; } else { //Find the dimension of greatest spread var minMax = Points.GetMinMaxWeights(); double maxSpread = double.MinValue; int maxDim = 0; for (int d = 0; d < Points.Dimensions; d++) { double range = minMax.Max[d] - minMax.Min[d]; if (range > maxSpread) { maxSpread = d; maxSpread = range; } } PivotDim = maxDim; //Pivot Select, Replace with QuickSelect double[] pivots = new double[Points.Count]; for (int i = 0; i < Points.Count; i++) { pivots[i] = Points[i][PivotDim]; } Array.Sort(pivots); double pivotValue = pivots[(Points.Count - 1) / 2]; //Create left and right children List <KPoint> left = new List <KPoint>(); List <KPoint> right = new List <KPoint>(); for (int i = 0; i < Points.Count; i++) { if (Points[i][PivotDim] <= pivotValue) { left.Add(Points[i]); } else { right.Add(Points[i]); } } leftNode = new BallTreeNode(new PointSet(left)); rightNode = new BallTreeNode(new PointSet(right)); } }
public bool RetrieveWorkResultFromRepo(KPoint key, MapSectionWorkResult workResult) { // When writing include the Area's offset. KPoint transKey = key.ToGlobal(_position); lock (_repoLock) { bool result = _countsRepo.ReadParts(transKey, workResult); return(result); } }
public bool ContainsKey(KPoint key) { if (_hiRez) { return(_countsRepoHiRez.ContainsKey(key)); } else { return(_countsRepo.ContainsKey(key)); } }
private void MainCanvas_Paint(object sender, PaintEventArgs e) { var x0 = MainCanvas.Width / 2; var y0 = MainCanvas.Height / 2; e.Graphics.DrawLine(Pens.Black, new Point(x0, 0), new Point(x0, MainCanvas.Height)); e.Graphics.DrawLine(Pens.Black, new Point(0, y0), new Point(MainCanvas.Width, y0)); center = new KPoint { x = x0, y = y0 }; }
private CanvasSize GetImageSizeInBlocks(CountsRepoReader countsRepo) { bool foundMax = false; int w = 10; int h = 0; KPoint key = new KPoint(w, h); foundMax = !countsRepo.ContainsKey(key); if (foundMax) { return(new CanvasSize(0, 0)); } // Find max value where w and h are equal. while (!foundMax) { w++; h++; key = new KPoint(w, h); foundMax = !countsRepo.ContainsKey(key); } w--; h--; foundMax = false; // Find max value of h while (!foundMax) { h++; key = new KPoint(w, h); foundMax = !countsRepo.ContainsKey(key); } h--; foundMax = false; // Find max value of h while (!foundMax) { w++; key = new KPoint(w, h); foundMax = !countsRepo.ContainsKey(key); } //w--; return(new CanvasSize(w, ++h)); }
private MapSectionWorkResult RetrieveWorkResultFromRepo(KPoint key, Job localJob, bool readZValues) { MapSectionWorkResult workResult = GetEmptyResult(readZValues, Job.SECTION_WIDTH, Job.SECTION_HEIGHT); if (localJob.RetrieveWorkResultFromRepo(key, workResult)) { return(workResult); } else { return(null); } }
private MapSectionWorkResult GetEmptyResult(KPoint key) { //if(area.Size.W != SECTION_WIDTH || area.Size.H != SECTION_HEIGHT) //{ // Debug.WriteLine("Wrong Area."); //} if (_emptyResult == null) { _emptyResult = new MapSectionWorkResult(SECTION_WIDTH * SECTION_HEIGHT, hiRez: false, includeZValuesOnRead: false); } return(_emptyResult); }
private MapSectionResult ProcessSubJob(SubJob subJob) { if (subJob.ParentJob.CancelRequested) { Debug.WriteLine("Not Processing Sub Job."); return(null); } if (!(subJob.ParentJob is Job localJob)) { throw new InvalidOperationException("When processing a subjob, the parent job must be implemented by the Job class."); } MapSectionWorkRequest mswr = subJob.MapSectionWorkRequest; KPoint key = new KPoint(mswr.HPtr, mswr.VPtr); MapSectionWorkResult workResult = RetrieveWorkResultFromRepo(key, localJob, readZValues: false); MapSectionResult result; if (workResult == null) { result = CalculateMapValues(subJob, localJob, ref workResult); } else { if (workResult.IterationCount == 0 || workResult.IterationCount == mswr.MaxIterations) { // The WorkResult read from file has the correct iteration count. (Or we are not tracking the interation count.) result = new MapSectionResult(localJob.JobId, mswr.MapSection, workResult.Counts); } else if (workResult.IterationCount < mswr.MaxIterations) { // Fetch the entire WorkResult with ZValues workResult = RetrieveWorkResultFromRepo(key, localJob, readZValues: true); // Use the current work results to continue calculations to create // a result with the target iteration count. result = CalculateMapValues(subJob, localJob, ref workResult); } else { throw new InvalidOperationException("Cannot reduce the number of iterations of an existing job."); } } return(result); }
//public int WorkResultWriteCount = 0; //public int WorkResultReWriteCount = 0; public Job(SMapWorkRequest sMapWorkRequest) : base(sMapWorkRequest) { _position = new KPoint(sMapWorkRequest.Area.SectionAnchor.X, sMapWorkRequest.Area.SectionAnchor.Y); SamplePoints = GetSamplePoints(sMapWorkRequest); Reset(); string filename = RepoFilename; Debug.WriteLine($"Creating new Repo. Name: {filename}, JobId: {JobId}."); _countsRepo = new ValueRecords <KPoint, MapSectionWorkResult>(filename, useHiRezFolder: false); //Debug.WriteLine($"Starting to get histogram for {RepoFilename} at {DateTime.Now.ToString(DiagTimeFormat)}."); //Dictionary<int, int> h = GetHistogram(); //Debug.WriteLine($"Histogram complete for {RepoFilename} at {DateTime.Now.ToString(DiagTimeFormat)}."); }
private SOMNeuron GetBestMatchingUnit(KPoint data) { SOMNeuron best = null; double dist = Double.MaxValue; foreach (SOMNeuron n in neurons) { double d = n.weights.distanceSquared(data); if (d < dist) { dist = d; best = n; } } return best; }
public KMeans(PointSet points, int numClusters) { //Assign the points and number of clusters Points = points; NumClusters = numClusters; //Create our dataPoints ClusteredPoints = new List <ClusteredItem>(); for (int i = 0; i < points.Count; i++) { ClusteredPoints.Add(new ClusteredItem(i)); } //Create a new RNG Random rng = new Random(); //Now we find the min and max var minMax = points.GetMinMaxWeights(); //Now we generate our clusters //Make random clusters until we have 3 valid clusters _clusters = new Cluster[numClusters]; _clusterLocation = new KPoint[numClusters]; do { for (int c = 0; c < numClusters; c++) { _clusters[c] = new Cluster(c); _clusterLocation[c] = new KPoint(minMax.Min, minMax.Max, rng); } AssignPoints(); } while (!ValidClusters()); //KMeans Algorithm algo starts //1. assign points //2. calculate new centers do { foreach (Cluster cl in _clusters) { if (cl.Points.Count > 0) { _clusterLocation[cl.ClusterId] = new KPoint(cl.Points.Select(i => points[i.Id]).ToArray()); } } NumItterations++; } while (AssignPoints()); }
public MinHeapPriorityQueue <KPoint> NearestNeighbors(KPoint p, int k, MinHeapPriorityQueue <KPoint> Q, BallTreeNode B) { if (p[B.PivotDim] > Q.peek().elucideanDistance(p)) { return(Q); } else if (B.IsLeaf()) { if (p.elucideanDistance(B.Point) < p.elucideanDistance(Q.peek())) { if (Q.Count >= k) { Q.extractMin(); } } } return(Q); }
private MapSectionResult CalculateMapValues(SubJob subJob, Job localJob, ref MapSectionWorkResult workResult) { MapSectionWorkRequest mswr = subJob.MapSectionWorkRequest; bool overwriteResults; if (workResult == null) { workResult = BuildInitialWorkingValues(mswr); overwriteResults = false; } else { overwriteResults = true; } double[] xValues = localJob.SamplePoints.XValueSections[mswr.HPtr]; double[] yValues = localJob.SamplePoints.YValueSections[mswr.VPtr]; //DateTime t0 = DateTime.Now; //workResult = _mapCalculator.GetWorkingValues(xValues, yValues, mswr.MaxIterations, workResult); //DateTime t1 = DateTime.Now; //int[] testCounts = new int[10000]; //DateTime t2 = DateTime.Now; //_mapCalculator.ComputeApprox(xValues, yValues, mswr.MaxIterations, testCounts); //List<int> misMatcheIndexes = GetMismatchCount(workResult.Counts, testCounts, out double avgGap); //DateTime t3 = DateTime.Now; //Debug.WriteLine($"Block: v={mswr.VPtr}, h={mswr.HPtr} has {misMatcheIndexes.Count} mis matches, avgGap={avgGap} and avg {GetAverageCntValue(workResult.Counts)}."); //Debug.WriteLine($"Standard: {GetElaspedTime(t0, t1)}, Approx: {GetElaspedTime(t2, t3)}."); //_mapCalculator.ComputeApprox(xValues, yValues, mswr.MaxIterations, workResult.Counts); workResult = _mapCalculator.GetWorkingValues(xValues, yValues, mswr.MaxIterations, workResult); KPoint key = new KPoint(mswr.HPtr, mswr.VPtr); localJob.WriteWorkResult(key, workResult, overwriteResults); MapSectionResult msr = new MapSectionResult(localJob.JobId, mswr.MapSection, workResult.Counts); return(msr); }
public void Epoch(KPoint p) { //get a random item SOMNeuron bmu = GetBestMatchingUnit(p); neighborhoodRadius = radius * Math.Exp(-(double)itterations / timeConstant); double neighborSqr = neighborhoodRadius * neighborhoodRadius; QuadTreePointStruct center = new QuadTreePointStruct() { Index = -1, X = bmu.position[0], Y = bmu.position[1] }; QuadTreePointStruct halfLength = new QuadTreePointStruct() { Index = -1, X = neighborhoodRadius, Y = neighborhoodRadius }; List <int> neuronsInArea = neuronQuadTree.QueryRange(new QuadTreeBoundingBox() { Center = center, HalfLength = halfLength }); //Now we need to update each neuron foreach (int i in neuronsInArea) { SOMNeuron n = neurons[i]; double distToBMU = n.position.elucideanDistance(bmu.position); if (distToBMU <= neighborhoodRadius) { influence = Math.Exp(-(distToBMU * distToBMU) / (2 * neighborSqr)); n.updateWeights(p, learningRate, influence); } } learningRate = this.initialLearningRate * Math.Exp(-(double)itterations / (double)this.totalItterations); itterations++; }
public void Epoch(KPoint p) { //get a random item SOMNeuron bmu = GetBestMatchingUnit(p); neighborhoodRadius = radius * Math.Exp(-(double)itterations / timeConstant); double neighborSqr = neighborhoodRadius * neighborhoodRadius; //Now we need to update each neuron foreach (SOMNeuron n in neurons) { double distToBMUSqr = n.position.elucideanDistance(bmu.position); if (distToBMUSqr <= neighborSqr) { influence = Math.Exp(-(distToBMUSqr) / (2 * neighborSqr)); n.updateWeights(p, learningRate, influence); } } learningRate = this.initialLearningRate * Math.Exp(-(double)itterations / (double)this.totalItterations); itterations++; }
public static double getSqrdErrorDistortion(Partition p) { //Insure all centroids are calculated KPoint[][] clusterPoints = new KPoint[p.Clusters.Count][]; for (int c = 0; c < p.Clusters.Count; c++) { clusterPoints[c] = p.GetClusterKPoints(c); } KPoint[] centers = p.Clusters.Select(c => new KPoint(clusterPoints[c.ClusterId])).ToArray(); double sum = 0.0; for (int i = 0; i < p.Clusters.Count; i++) { for (int j = 0; j < clusterPoints[i].Length; j++) { sum += centers[i].distanceSquared(clusterPoints[i][j]); } } return(sum / (double)p.GetClusteredItemCount()); }
public static double DunnIndex(Partition p, DunnInterDistanceType distType, DunnIntraDistanceType intraDistType) { //Insure all centroids are calculated KPoint[][] clusterPoints = new KPoint[p.Clusters.Count][]; for (int c = 0; c < p.Clusters.Count; c++) { clusterPoints[c] = p.GetClusterKPoints(c); } KPoint[] centers = p.Clusters.Select(c => new KPoint(clusterPoints[c.ClusterId])).ToArray(); //Between 2 clusters(center) double minInter = double.MaxValue; for (int i = 0; i < p.Clusters.Count - 1; i++) { for (int j = i + 1; j < p.Clusters.Count; j++) { double distIJ = 0.0; if (distType == DunnInterDistanceType.CentroidDist) { distIJ = centers[i].elucideanDistance(centers[j]); } else if (distType == DunnInterDistanceType.MaxDist) { distIJ = getInterClusterDist(clusterPoints[i], clusterPoints[j], true); } else if (distType == DunnInterDistanceType.MinDist) { distIJ = getInterClusterDist(clusterPoints[i], clusterPoints[j], false); } else if (distType == DunnInterDistanceType.AverageDist) { double sumDist = 0.0; foreach (KPoint k in clusterPoints[i]) { foreach (KPoint l in clusterPoints[j]) { sumDist += k.elucideanDistance(l); } } distIJ = sumDist / (double)(clusterPoints[i].Length * clusterPoints[j].Length); } else if (distType == DunnInterDistanceType.AverageToCentroid) { double distCentI = 0.0; foreach (KPoint pointJ in clusterPoints[j]) { distCentI += centers[i].elucideanDistance(pointJ); } distCentI /= (double)clusterPoints[j].Length; double distCentJ = 0.0; foreach (KPoint pointI in clusterPoints[i]) { distCentJ += centers[j].elucideanDistance(pointI); } distCentJ /= (double)clusterPoints[i].Length; distIJ = Math.Min(distCentI, distCentJ); } minInter = (distIJ < minInter) ? distIJ : minInter; } } //Pairwise double maxIntraClusterDistance = 0.0; if (intraDistType == DunnIntraDistanceType.Complete) { foreach (Cluster c in p.Clusters) { for (int i = 0; i < c.Points.Count - 1; i++) { var pointI = clusterPoints[c.ClusterId][i]; for (int j = i + 1; j < c.Points.Count; j++) { var pointJ = clusterPoints[c.ClusterId][j]; double distIJ = pointI.elucideanDistance(pointJ); maxIntraClusterDistance = (distIJ > maxIntraClusterDistance) ? distIJ : maxIntraClusterDistance; } } } } else if (intraDistType == DunnIntraDistanceType.Average) { foreach (Cluster c in p.Clusters) { double sum = 0.0; for (int i = 0; i < clusterPoints[c.ClusterId].Length - 1; i++) { for (int j = i + 1; j < clusterPoints[c.ClusterId].Length; j++) { sum += clusterPoints[c.ClusterId][i].elucideanDistance(clusterPoints[c.ClusterId][j]); } } sum /= (double)(clusterPoints[c.ClusterId].Length * (clusterPoints[c.ClusterId].Length - 1)); maxIntraClusterDistance = (sum > maxIntraClusterDistance) ? sum : maxIntraClusterDistance; } } else if (intraDistType == DunnIntraDistanceType.AverageToCentroid) { foreach (Cluster c in p.Clusters) { double sum = 0.0; foreach (KPoint point in clusterPoints[c.ClusterId]) { sum += 2 * centers[c.ClusterId].elucideanDistance(point); } sum /= (double)(clusterPoints[c.ClusterId].Length); maxIntraClusterDistance = (sum > maxIntraClusterDistance) ? sum : maxIntraClusterDistance; } } double dunn = minInter / maxIntraClusterDistance; return(dunn); }
//Initialize tyhe weights with a randon between min and max public SOMNeuron(KPoint min, KPoint max, Random rng, KPoint position, int id) { weights = new KPoint(min, max, rng); this.position = position; this.id = id; }
public BallTree(KPoint points) { }
private void MouseMoveEvent(object s, MouseEventArgs e) { if (dragging && e.Button == MouseButtons.Left) { Left = mouseDownWindowLocation.x + (e.X - mouseDownLocation.x); Top = mouseDownWindowLocation.y + (e.Y - mouseDownLocation.y); mouseDownWindowLocation = new KPoint(Left, Top); } }
public void Build(string fn, bool hiRez) { // TODO: HiRez, blockWidth and blockHeight should come from the RepoFile. MapInfoWithColorMap miwcm = ReadFromJson(fn); int maxIterations = miwcm.MapInfo.MaxIterations; ColorMap colorMap = miwcm.ColorMap; string repofilename = miwcm.MapInfo.Name; //ValueRecords<KPoint, MapSectionWorkResult> countsRepo = new ValueRecords<KPoint, MapSectionWorkResult>(repofilename, useHiRezFolder: hiRez); //int blockLength = BlockWidth * BlockHeight; //MapSectionWorkResult workResult = new MapSectionWorkResult(blockLength, hiRez: hiRez, includeZValuesOnRead: false); //CanvasSize imageSizeInBlocks = GetImageSizeInBlocks(countsRepo); int blockLength = BlockWidth * BlockHeight; CountsRepoReader countsRepoReader = new CountsRepoReader(repofilename, hiRez, BlockWidth, BlockHeight); CanvasSize imageSizeInBlocks = GetImageSizeInBlocks(countsRepoReader); int w = imageSizeInBlocks.Width; int h = imageSizeInBlocks.Height; CanvasSize imageSize = new CanvasSize(w * BlockWidth, h * BlockHeight); string imagePath = GetImageFilename(fn, imageSize.Width, hiRez, BasePath); KPoint key = new KPoint(0, 0); using (PngImage pngImage = new PngImage(imagePath, imageSize.Width, imageSize.Height)) { for (int vBPtr = 0; vBPtr < h; vBPtr++) { key.Y = vBPtr; for (int lPtr = 0; lPtr < 100; lPtr++) { ImageLine iLine = pngImage.ImageLine; int linePtr = vBPtr * BlockHeight + lPtr; for (int hBPtr = 0; hBPtr < w; hBPtr++) { key.X = hBPtr; //if (countsRepo.ReadParts(key, workResult)) //{ // int[] allCounts = workResult.Counts; // int[] countsForThisLine = GetOneLineFromCountsBlock(allCounts, lPtr); // BuildPngImageLineSegment(hBPtr * BlockWidth, countsForThisLine, iLine, maxIterations, colorMap); //} //else //{ // BuildBlankPngImageLineSegment(hBPtr * BlockWidth, BlockWidth, iLine); //} int[] countsForThisLine = countsRepoReader.GetCounts(key, lPtr); if (countsForThisLine != null) { BuildPngImageLineSegment(hBPtr * BlockWidth, countsForThisLine, iLine, maxIterations, colorMap); } else { BuildBlankPngImageLineSegment(hBPtr * BlockWidth, BlockWidth, iLine); } } pngImage.WriteLine(iLine); } } } }
private void MouseDownEvent(object s, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { mouseDownLocation = new KPoint(e.Location.X, e.Location.Y); mouseDownWindowLocation = new KPoint(Left, Top); dragging = true; } }
public static double averageDistanceFromCentroid(KPoint[] points) { KPoint center = new KPoint(points); return(points.Select(p => p.elucideanDistance(center)).Sum() / (double)points.Length); }
public HexagonalSelfOrganizingMap(PointSet data, int dimension, double learningRate) { _dimension = dimension; //Get initial learning rate this.initialLearningRate = learningRate; this.learningRate = learningRate; influence = 0; itterations = 1; this.data = data; rng = new Random(); int numNeurons = dimension * dimension; //Scale each attribute from [0,1] and store the conversion matrix conversionMatrix = data.GetMinMaxWeights().Max.Coordinates; foreach (KPoint d in data.PointList) { d.Normalize(conversionMatrix); } //Here We will initialize Our Neurons neurons = new List <SOMNeuron>(); KPoint zero = KPoint.Zero(data[0].Dimensions); KPoint one = KPoint.One(data[0].Dimensions); double halfNeuronDelta = 1 / Math.Sqrt(3.0); //Initialize our Quadtree for reference double centerX = (dimension - 0.5) * (2 * halfNeuronDelta) / 2.0; double centerY = (dimension - 1.0) / 2.0; QuadTreePointStruct center = new QuadTreePointStruct() { Index = -1, X = centerX, Y = centerY }; QuadTreePointStruct halfDistance = new QuadTreePointStruct() { Index = -1, X = centerX + halfNeuronDelta, Y = centerY + 0.5 }; neuronQuadTree = new QuadTree(new QuadTreeBoundingBox() { Center = center, HalfLength = halfDistance }); int neuronIndex = 0; for (int r = 0; r < dimension; r++) { double xPos = (r % 2 == 1) ? halfNeuronDelta : 0.0; for (int c = 0; c < dimension; c++) { //Generate our neurons double[] posNeuron = { xPos, (double)r }; SOMNeuron neuron = new SOMNeuron(zero, one, rng, new KPoint(posNeuron), neuronIndex); QuadTreePointStruct neuronQTPos = new QuadTreePointStruct() { Index = neuronIndex, X = posNeuron[0], Y = posNeuron[1] }; neuronQuadTree.Insert(neuronQTPos); neurons.Add(neuron); xPos += 2 * halfNeuronDelta; neuronIndex++; } } //Get the max radius SetRadius(); timeConstant = (double)totalItterations / Math.Log(radius); }