Solver does not calculate solution for model

0

I have implemented a routine that makes calculation of the appropriate percentage of ingredients that is necessary to formulate a ration.

To do this calculation I am using the Solver Foundation of MS .

At first I hedge the decisions with the maximum and minimum values of each ingredient (I want the percentage of each ingredient that should be inserted in the ration, the sum of each percentage should be 100). Then I make another restriction that is that of nutrients (each ingredient contributes more or less of a nutrient according to the percentage of the ingredient that is inserted). In the end my solution should have the cheapest formula, since the ingredients have a price.

Follow my code:

     private Solution FormularRacao()
     {
        var ingredientesRacao = _formulacaoRacao.CarregarIngredientesNutrientesFormulacao(true);
        var nutrientes = _formulacaoRacao.CarregarIngredientesNutrientesFormulacao(false);
        var formulacao = _formulacaoRacao.CarregarFormulacao();

        SolverContext context = SolverContext.GetContext();
        context.ClearModel();

        Model model = context.CreateModel();

        var objetivo = new SumTermBuilder(ingredientesRacao.Count);
        var totalIngrediente = new SumTermBuilder(ingredientesRacao.Count);

        List<SumTermBuilder> listaTotalNutriente = new List<SumTermBuilder>();

        //Set decisions
        foreach (var item in ingredientesRacao)
        {
            item.Nome = TratarNome(item.Nome);

            Decision d = new Decision(Domain.RealRange(Convert.ToDouble(item.Minimo), Convert.ToDouble(item.Maximo)), "d_" + item.Nome);

            model.AddDecision(d);

            objetivo.Add(Model.Product(d, Convert.ToDouble(item.Custo)));
            totalIngrediente.Add(d);
            listaTotalNutriente.Add(new SumTermBuilder(nutrientes.Count));
        }

        var SomaIngrediente = totalIngrediente.ToTerm();

        //total of values of decisions must be equal 100
        model.AddConstraint("c_totalIngrediente", SomaIngrediente == 100);

        //totalIngrediente;
        model.AddGoal("racao", GoalKind.Minimize, objetivo.ToTerm());

        int indexIngrediente = 0;
        int indexNutriente = 0;

        //each ingredient contributes with nutrients
        //each nutrient has a min and max set            
        foreach (var ingredienteRacao in ingredientesRacao)
        {
            Ingrediente ingrediente = _formulacaoRacao.CarregarIngrediente(ingredienteRacao.Id);
            indexNutriente = 0;
            ingredienteRacao.Nome = TratarNome(ingredienteRacao.Nome);
            Decision d = model.Decisions.First(x => x.Name == "d_" + ingredienteRacao.Nome);

            foreach (var nutriente in nutrientes)
            {
                var valor = new object();

                if (nutriente.AminoacidoDigestivo.Equals("S"))
                {
                    var aminoacidoDigestivo = _formulacaoRacao.CarregarAminoacidoDigestivo(ingredienteRacao.Id);
                    valor = aminoacidoDigestivo.GetType().GetProperty(nutriente.Nome).GetValue(aminoacidoDigestivo, null);
                }
                else
                {
                    nutriente.Nome = TratarNomeNutriente(nutriente.Nome);
                    valor = ingrediente.GetType().GetProperty(nutriente.Nome).GetValue(ingrediente, null);
                }

                var proporcaoNutriente = Convert.ToDouble(valor.ToString()) * d;

                listaTotalNutriente[indexNutriente].Add(proporcaoNutriente / 100);

                if (indexIngrediente == ingredientesRacao.Count - 1) //last iteration
                {
                    var totalNutriente = listaTotalNutriente[indexNutriente].ToTerm();
                    if (nutriente.Minimo == nutriente.Maximo)
                       model.AddConstraint("c_" + nutriente.Nome, totalNutriente == Convert.ToDouble(nutriente.Maximo));                        
                    else
                        model.AddConstraint("c" + nutriente.Nome, Convert.ToDouble(nutriente.Minimo) <= totalNutriente <= Convert.ToDouble(nutriente.Maximo));                        
                }

                indexNutriente++;
            }
            indexIngrediente++;
        }           

        //salva o modelo
        TextWriter tw = new StreamWriter("Caminho\arquivo.oml");
        context.SaveModel(FileFormat.OML, tw);
        tw.Close();

        //Imprime o modelo
        TextWriter txt = new StreamWriter("Caminho\arquivo.txt");
        foreach (var item in model.Constraints.ToList())
        {
            txt.WriteLine(item.Name + ":  " + item.Expression);
            txt.WriteLine();
        }
        txt.Close(); 

        Solution solution = context.Solve();

        return solution;
    }

The template is not solved since the ingredients are set to the minimum value defined in the decision declaration.

My question is: Why are decisions values set to the minimum declared value instead of being computed by solver ?     

asked by anonymous 23.08.2016 / 18:23

1 answer

0

The implementation was correct and the code also runs ok. The problem was the creation of the same model, because it could not find a solution that met all the restrictions. What helped me (and a lot) was to create a txt file and insert in it all constraints and also an oml file and then import it into excel to test the template. I updated my code in the question to show the creation of the files.

    
24.08.2016 / 21:49