/// <summary>Takes a model generated from the modeling engine and loads necessary data from the database to deliver relevance to a user interface.</summary>
        /// <param name="model">Model from modeling engine</param>
        /// <returns>CompiledModel object which contains full recipe information about the provided set.</returns>
        public CompiledModel Compile(Model model)
        {
            var results = new CompiledModel();

             var recipes = context.ReadRecipes(model.RecipeIds, ReadRecipeOptions.None);

             results.RecipeIds = model.RecipeIds;
             results.Pantry = model.Pantry;
             results.Briefs = recipes.Select(r => { return new RecipeBrief(r); }).ToArray();
             results.Recipes = recipes.Select(r => new SuggestedRecipe
             {
            Id = r.Id,
            Ingredients = context.AggregateRecipes(r.Id).ToArray()
             }).ToArray();

             return results;
        }
Exemplo n.º 2
0
        /// <summary>
        /// Generates a model with the specified number of recipes and returns the recipe IDs in the optimal order.
        /// </summary>
        /// <param name="recipes">Number of recipes to generate</param>
        /// <param name="scale">Scale indicating importance of optimal ingredient usage vs. user trend usage. 1 indicates ignore user trends, return most efficient set of recipes. 5 indicates ignore pantry and generate recipes user is most likely to rate high.</param>
        /// <returns>An array up to size "recipes" containing recipes from DBSnapshot.</returns>
        public Model Generate(int recipes, byte scale)
        {
            if (recipes > MaxSuggestions)
            {
                throw new ArgumentException("Modeler can only generate " + MaxSuggestions.ToString() + " recipes at a time.");
            }

            double temperature = 10000.0;
            double deltaScore = 0;
            const double AbsoluteTemperature = 0.00001;

            this.totals = new Dictionary<IngredientNode, IngredientUsage>(IngredientNode.NextKey);

            // Current set of recipes
            var currentSet = new RecipeNode[recipes];

            // Set to compare with current
            var nextSet = new RecipeNode[recipes];

            // Initialize with n random recipes
            this.InitializeSet(currentSet);

            // Check initial score
            var score = this.GetScore(currentSet, scale);

            var timer = new Stopwatch();
            timer.Start();

            while (temperature > AbsoluteTemperature)
            {
                nextSet = this.GetNextSet(currentSet); // Swap out a random recipe with another one from the available pool
                deltaScore = this.GetScore(nextSet, scale) - score;

                // if the new set has a smaller score (good thing)
                // or if the new set has a higher score but satisfies Boltzman condition then accept the set
                if ((deltaScore < 0) || (score > 0 && Math.Exp(-deltaScore / temperature) > this.random.NextDouble()))
                {
                    nextSet.CopyTo(currentSet, 0);
                    score += deltaScore;
                }

                // cool down the temperature
                temperature *= CoolingRate;
            }

            timer.Stop();
            Log.InfoFormat("Generating set of {0} recipes took {1}ms.", recipes, timer.ElapsedMilliseconds);

            var model = new Model(currentSet, this.profile.Pantry, score);
            return model;
        }