Solver does not calculate solution for model

Asked

Viewed 183 times

0

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

To make this calculation I’m using the Solver Foundation of MS.

At first I choose the decisions with the maximum and minimum values of each ingredient (I want the percentage of each ingredient that should be inserted into the ration, the sum of each percentage should be 100). Then I make another restriction which 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 present the cheapest formula, since the ingredients have a price.

Follows 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 model is not solved as the ingredients are set to the minimum value defined in the decision.

My question is: because the values of decisions are defined with the declared minimum value instead of being calculated by the solver?

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 all the constraints and also an oml file and then import it in excel to test the model. I updated my code in the question to show the creation of the files.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.