Ejemplo n.º 1
0
        public bool PlaceIcons(DBSpecGen.DBSpecGen ui)
        {
            _explored = 0;
            DateTime start = DateTime.Now;

            InitializeIcons();
            InitializePossibleLocations();

            bool cancel = false;

            if (_bVerbose)
            {
                ulong configs = configurations(_iconsPerRow * _numSiteRows, _icons.Count);
                DBSpecGen.DBSpecGen.ShowProgress("Generating datamodel diagram: " + _icons.Count + " icons, " + (_iconsPerRow * _numSiteRows) + " locations.", -1, false, ui, out cancel);
                DBSpecGen.DBSpecGen.ShowProgress("  possible configurations: " + ((configs == 0) ? "more than 18446744073709551615 (ulong overflow)" : configs.ToString(CultureInfo.CurrentCulture)), -1, false, ui, out cancel);
                if (cancel)
                {
                    DBSpecGen.DBSpecGen.ShowProgress("Operation canceled", 0, true, ui, out cancel);
                    return(false);
                }
            }

            InitializeLinkedIcons(_icons);
            _initialized = true;

            Randomize(_icons);

            // use simulated annealing here to try and minimize both the
            // length of the lines connecting the icons, and the number of
            // crossings of the line segments...
            if (this._numLinkedIcons > 0)
            {
                if (anneal(_icons, ui) == -1)
                {
                    return(false);
                }
            }

            // move the diagram up as far as we can into the upper left corner.
            ShiftDiagram();

            // put the icons with no links along the bottom.
            PlaceUnlinkedIcons();

            // set the size of out canvas.
            SetCanvasBoundaries();

            if (_bVerbose)
            {
                DBSpecGen.DBSpecGen.ShowProgress("  finished, time: " + (DateTime.Now - start), -1, false, ui, out cancel);
                DBSpecGen.DBSpecGen.ShowProgress("  explored configurations: " + _explored, -1, false, ui, out cancel);
                if (cancel)
                {
                    DBSpecGen.DBSpecGen.ShowProgress("Operation canceled", 0, true, ui, out cancel);
                    return(false);
                }
            }
            return(true);
        }
Ejemplo n.º 2
0
        private double anneal(SortedList icons, DBSpecGen.DBSpecGen ui)
        {
            double lowestEnergy   = energy(icons);
            double currentEnergy  = lowestEnergy;
            double delta          = 0;
            int    lastCost       = Cost(icons);
            int    variationLimit = 30 * _numLinkedIcons;           // maximum number of variations at a fixed temperature
            int    successLimit   = 10 * _numLinkedIcons;           // maximum number of successful variations at a fixed temp

            // first we need to figure out what the starting temperature should be.
            // this is the average difference in length for a few different configurations.
            // let's take 10 configurations, compute the delta from one to the next, and
            // take that average.
            double     avg        = 0;
            int        numConfigs = 10;
            Point      dummy      = null;
            double     energy1    = 0;
            SortedList iconsCopy  = icons;
            double     energy2    = energy(iconsCopy);

            for (int i = 0; i < numConfigs; ++i)
            {
                energy1 = energy2;
                wiggle(iconsCopy, ref dummy);
                energy2 = energy(iconsCopy);
                avg    += Math.Abs(energy1 - energy2);
            }

            bool cancel = false;

            if (_bVerbose)
            {
                DBSpecGen.DBSpecGen.ShowProgress("  successLimit, variationLimit: " + successLimit + "," + variationLimit, -1, false, ui, out cancel);
                if (cancel)
                {
                    DBSpecGen.DBSpecGen.ShowProgress("Operation canceled", 0, true, ui, out cancel);
                    return(-1);
                }
            }

            // ok, let's set the temperature at the
            // average difference of these configurations
            double temperature = avg / numConfigs;

            // keep track of number of zero, positive,
            // and negative energy steps
            int    numDeltaZero  = 0;
            int    numDeltaPlus  = 0;
            int    numDeltaMinus = 0;
            double avgEnergyUp   = 0;
            double avgEnergyDown = 0;

            // take no more than 100 temperature steps...
            for (int tempStep = 0; tempStep < 100; ++tempStep)
            {
                // to print out the diagram as it cools so we can look at intermediate states.
                // need to set a breakpoint here if you want to do this.  should comment out for release.
                //string s = "<html xmlns:v='urn:schemas-microsoft-com:vml'><body>" + GenerateHtmlString() + "</body></html>";
                //System.IO.StreamWriter sw = System.IO.File.CreateText("dork.htm");
                //sw.Write(s);
                //sw.Close();

                // decrease the temperature
                temperature *= .90;

                // how many successful moves we have made at this temperature
                int successfulMoves = 0;
                int failedMoves     = 0;
                numDeltaZero  = 0;
                numDeltaPlus  = 0;
                numDeltaMinus = 0;
                avgEnergyUp   = 0;
                avgEnergyDown = 0;

                // for each temperature, try variationLimit different moves
                for (int i = 0; i < variationLimit; ++i)
                {
                    // wiggle the current configuration...
                    Point  movedFrom  = null;
                    Icon[] iconsMoved = wiggle(icons, ref movedFrom);
                    _explored++;

                    // ok, we moved an icon.  should we keep it?
                    currentEnergy = energy(icons);
                    delta         = currentEnergy - lowestEnergy;
                    double probability = _random.NextDouble();
                    double boltzmann   = Math.Exp(-delta / temperature);

                    // here's the key.  we never move back if delta is negative.
                    // but sometimes, we even keep it if delta is positive.
                    // the probability that we keep an uphill evolution
                    // depends exponentially on how big delta is compared
                    // with the temperature
                    bool bMoveBack = (probability < boltzmann) ? false : true;

                    if (bMoveBack)
                    {
                        // ah well.  didn't work this time.
                        ++failedMoves;

                        // move the icon back where it was.
                        if (iconsMoved[1] != null)
                        {
                            SwapIcons(iconsMoved[0], iconsMoved[1], icons);
                        }
                        else
                        {
                            MoveIcon(iconsMoved[0], movedFrom, icons);
                        }
                        continue;
                    }
                    else
                    {
                        if (delta == 0)
                        {
                            ++numDeltaZero;
                        }
                        else if (delta < 0)
                        {
                            ++numDeltaMinus;
                            avgEnergyDown += delta;
                        }
                        else if (delta > 0)
                        {
                            ++numDeltaPlus;
                            avgEnergyUp += delta;
                        }
                        lowestEnergy = currentEnergy;
                        ++successfulMoves;
                        if (successfulMoves > successLimit)
                        {
                            break;
                        }
                    }
                }

                if (_bVerbose)
                {
                    DBSpecGen.DBSpecGen.ShowProgress("  (+[avg],-[avg],0,T,E) = (" + numDeltaPlus + "[" + (int)(avgEnergyUp / numDeltaPlus) + "], " + numDeltaMinus + "[" + (int)(avgEnergyDown / numDeltaMinus) + "], " + numDeltaZero + ", " + (int)temperature + ", " + (int)lowestEnergy + ")", -1, false, ui, out cancel);
                    if (cancel)
                    {
                        DBSpecGen.DBSpecGen.ShowProgress("Operation canceled", 0, true, ui, out cancel);
                        return(-1);
                    }
                }

                // if we didn't get very many successful moves
                // at this temperature, let's give up.  we are cold enough.
                // that is, when the temperature is very low, we almost never
                // take an uphill step, so if we are near a minimum,
                // we will be trapped in it if the tempertature is low.
                //if ((double)successfulMoves / (double)successLimit < .1)
                if ((double)numDeltaMinus / (double)successLimit < .1)
                {
                    break;
                }

                /*
                 * // see if most of the moves were zero delta. zero delta moves
                 * // happen a lot once the configuration is pretty much frozen,
                 * // where you might have one icon flipping back and forth
                 * // between equivalent energy states.  basically we are in
                 * // a metastable state, where there is no cost for an icon
                 * // hopping back and forth.
                 * if (numDeltaZero > numDeltaMinus)
                 * {
                 *      break;
                 * }
                 */
            }
            return(temperature);
        }