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
?