/// <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; }
/// <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; }