private static SOMResult TrainSOM(SOMNode[] nodes, ISOMInput[] inputs, SOMRules rules, bool returnEmptyNodes = false)
        {
            double mapRadius = MathND.GetRadius(MathND.GetAABB(nodes.Select(o => o.Weights)));

            SOMNode[] returnNodes = nodes.
                                    Select(o => o.Clone()).
                                    ToArray();

            double timeConstant = rules.NumIterations / Math.Log(mapRadius);

            int iteration           = 0;
            int remainingIterations = rules.NumIterations;

            while (remainingIterations > 0)
            {
                foreach (ISOMInput input in UtilityCore.RandomOrder(inputs, Math.Min(remainingIterations, inputs.Length)))
                {
                    // Find closest node
                    SOMNode closest = GetClosest(returnNodes, input).Item1;

                    // Find other affected nodes (a node and distance squared)
                    double searchRadius = mapRadius * rules.InitialRadiusPercent * Math.Exp(-iteration / timeConstant);
                    Tuple <SOMNode, double>[] neigbors = GetNeighbors(returnNodes, closest, searchRadius);

                    double learningRate = rules.LearningRate * Math.Exp(-(double)iteration / (double)rules.NumIterations);

                    // Adjust the matched node (full learning rate)
                    AdjustNodeWeights(closest, input.Weights, learningRate);

                    foreach (var node in neigbors)
                    {
                        double influence = GetInfluence(rules.AttractionFunction, node.Item2, searchRadius);

                        // Adjust a neighbor
                        AdjustNodeWeights(node.Item1, input.Weights, learningRate * influence);
                    }

                    iteration++;
                }

                remainingIterations -= inputs.Length;
            }

            // See which images go with which nodes
            ISOMInput[][] inputsByNode = GetInputsByNode(returnNodes, inputs);

            SOMResult retVal = new SOMResult(returnNodes, inputsByNode, true);

            if (!returnEmptyNodes)
            {
                retVal = RemoveZeroNodes(retVal);
            }

            return(retVal);
        }
        public SOMNode Clone()
        {
            SOMNode retVal = new SOMNode();

            if (this.Weights != null)
            {
                retVal.Weights = this.Weights.Clone();
            }

            retVal.Position = this.Position.Clone();

            return(retVal);
        }
        public static Tuple <SOMNode, int> GetClosest(SOMNode[] nodes, ISOMInput input)
        {
            int     closestIndex = -1;
            double  closest      = double.MaxValue;
            SOMNode retVal       = null;

            for (int cntr = 0; cntr < nodes.Length; cntr++)
            {
                double distSquared = (nodes[cntr].Weights - input.Weights).LengthSquared;

                if (distSquared < closest)
                {
                    closestIndex = cntr;
                    closest      = distSquared;
                    retVal       = nodes[cntr];
                }
            }

            return(Tuple.Create(retVal, closestIndex));
        }
        private static Tuple <SOMNode, double>[] GetNeighbors(SOMNode[] nodes, SOMNode match, double maxDistance)
        {
            List <Tuple <SOMNode, double> > retVal = new List <Tuple <SOMNode, double> >();

            double maxDistanceSquared = maxDistance * maxDistance;

            for (int cntr = 0; cntr < nodes.Length; cntr++)
            {
                if (nodes[cntr].Token == match.Token)
                {
                    continue;
                }

                double distSquared = (nodes[cntr].Weights - match.Weights).LengthSquared;

                if (distSquared < maxDistanceSquared)
                {
                    retVal.Add(Tuple.Create(nodes[cntr], distSquared));     // no need for a square root.  The calling method needs it squared
                }
            }

            return(retVal.ToArray());
        }
Exemple #5
0
        private static Brush GetTiledSamples(Point[] edgePoints, ISOMInput[] samples, SOMNode node, int tileWidth, int tileHeight, Action <DrawTileArgs> drawTile)
        {
            var dimensions = GetTileImagePositions(samples.Length);

            // The image tiles will be drawn spiraling out from the center.  Order the list so that tiles closest to the node are first (so that
            // they are drawn closer to the center of the spiral)
            ISOMInput[] orderedSamples = samples.
                                         OrderBy(o => (o.Weights - node.Weights).LengthSquared).
                                         ToArray();

            //int tilehalf_left = tileWidth / 2;
            //int tilehalf_top = tileHeight / 2;
            //int tilehalf_right = tileWidth - tilehalf_left;
            //int tilehalf_bot = tileHeight - tilehalf_top;

            int imageWidth  = (dimensions.Item2.X - dimensions.Item1.X + 1) * tileWidth;
            int imageHeight = (dimensions.Item2.Y - dimensions.Item1.Y + 1) * tileHeight;

            //int offsetX = (Math.Abs(dimensions.Item1.X) * tileWidth) + tilehalf_left;
            //int offsetY = (Math.Abs(dimensions.Item1.Y) * tileHeight) + tilehalf_top;


            //TODO: Get the AABB of edgePoints.  If the bitmap will be bigger than the aabb, then draw just enough to totally fill the polygon



            //NOTE: Copied from UtilityWPF.GetBitmap

            WriteableBitmap bitmap = new WriteableBitmap(imageWidth, imageHeight, UtilityWPF.DPI, UtilityWPF.DPI, PixelFormats.Pbgra32, null);      // may want Bgra32 if performance is an issue

            int pixelWidth = bitmap.Format.BitsPerPixel / 8;
            int stride     = bitmap.PixelWidth * pixelWidth;  // this is the length of one row of pixels

            byte[] pixels = new byte[bitmap.PixelHeight * stride];

            DrawingVisual dv = new DrawingVisual();

            using (DrawingContext ctx = dv.RenderOpen())
            {
                for (int cntr = 0; cntr < orderedSamples.Length; cntr++)
                {
                    int x = (dimensions.Item3[cntr].X - dimensions.Item1.X) * tileWidth;
                    int y = (dimensions.Item3[cntr].Y - dimensions.Item1.Y) * tileWidth;

                    DrawTileArgs args = new DrawTileArgs(orderedSamples[cntr], tileWidth, tileHeight, pixels, x, y, stride, pixelWidth);
                    drawTile(args);
                }
            }

            bitmap.WritePixels(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight), pixels, stride, 0);

            return(new ImageBrush(bitmap)
            {
                Stretch = Stretch.None,
            });
        }
Exemple #6
0
        public static Color GetNodeColor(SOMNode node)
        {
            var raw = GetNodeColor_RGB(node.Weights);

            return(GetNodeColor_Finish(raw));
        }
        private static void AdjustNodeWeights(SOMNode node, VectorND position, double percent)
        {
            //W(t+1) = W(t) + (pos - W(t)) * %

            node.Weights += (position - node.Weights) * percent;
        }
Exemple #8
0
        /// <summary>
        /// This is a helper method to turn som node positions into points to pass to AddStaticItems()
        /// </summary>
        public static IEnumerable <Tuple <ISOMInput, Point3D> > GetSOMNodeStaticPositions(SOMNode node, SOMNode[] allNodes, double innerRadius)
        {
            // Convert to Point3D
            var initial = allNodes.
                          Select(o =>
            {
                Vector3D position = new Vector3D();
                if (o.Position.Size >= 1)
                {
                    position.X = o.Position[0];
                }
                if (o.Position.Size >= 2)
                {
                    position.Y = o.Position[1];
                }
                if (o.Position.Size >= 3)
                {
                    position.Z = o.Position[2];
                }

                return(Tuple.Create(o, position, position.Length));
            }).
                          OrderBy(o => o.Item3).
                          ToArray();

            // Find the closest one (that isn't the one passed in)
            var firstNonZero = initial.
                               Where(o => o.Item1.Token != node.Token).
                               FirstOrDefault(o => !o.Item3.IsNearZero());

            double scale = 1d;

            if (firstNonZero != null)
            {
                scale = (innerRadius * 1.25) / firstNonZero.Item3;
            }

            // Make sure they are spaced properly
            var scaled = initial.
                         Select(o => Tuple.Create(o.Item1, (o.Item2 * scale).ToPoint())).
                         ToArray();

            // These need to be centered over the origin, because the points will try to drift to the center
            Point3D  center = Math3D.GetCenter(scaled.Select(o => o.Item2));
            Vector3D offset = new Vector3D(-center.X, -center.Y, -center.Z);

            return(scaled.
                   Select(o => Tuple.Create((ISOMInput)o.Item1, o.Item2 + offset)).
                   ToArray());
        }