Воспроизведение Excel Solver GRG Нелинейная оптимизация в Visual Basic .NET
Я пытаюсь воспроизвести следующую нелинейную оптимизацию Excel Solver GRG с использованием Microsoft Solver Foundation в VB.NET (цифры в этом примере упрощены):
- Цель: общий расход газа = 100000
- Переменная: скважина 1, дебит нефти
- Ограничения: 0 <= дебит скважины 1 <= 1000, дебит скважины 2 = 2000
Эта оптимизация подчиняется следующим отношениям:
- Скважина 1 Расход газа = Скважина 1 Расход нефти * 5
- Общий дебит газа = дебит скважины 1 + дебит скважины 2
Можно ли решить такую проблему с помощью Solver Foundation? При попытке реализовать это я боролся с двумя вещами:
- Похоже, что модели Solver Foundation имеют только два GoalKind's: минимальный и максимальный. В моем случае я пытаюсь оптимизировать под конкретное значение. Есть какой-либо способ сделать это?
- Как мне определить вышеуказанные отношения? Я думаю, что последний будет определен как часть определения цели (например,
model.AddGoal("total_gas_rate", GoalKind.[not sure what goes here], Well1PGasRate + Well2PGasRate
), но как мне определить другой?
Спасибо!
2 ответа
Этот ответ касается только первой части вашего вопроса и концептуально, но, надеюсь, он будет полезен. Если вы пытаетесь оптимизировать для конкретного значения target
и результат вашей функции output
тогда вы можете попробовать что-то вроде этого псевдокода:
minimize(absolute_value(output/target-1))
По сути, это даст вам значение, которое достигает нуля, когда выход вашей функции приближается к целевому значению. Таким образом, вы все еще можете использовать механизм оптимизации, который минимизирует конечный результат вашей функции.
Ответ на С#:
static void SolverGasRate()
{
Console.WriteLine("\nBegin Solver Gas Rate using Solver Context MSF\n");
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
var decisionWell1OilRate = new Decision(Domain.IntegerNonnegative, "Well1OilRate");
model.AddDecision(decisionWell1OilRate);
var decisionWell2GasRate = new Decision(Domain.IntegerNonnegative, "Well2GasRate");
model.AddDecision(decisionWell2GasRate);
Goal goal = model.AddGoal("Goal", GoalKind.Maximize, TotalGasRateTerm(decisionWell1OilRate, decisionWell2GasRate));
model.AddConstraint("Objective", TotalGasRateTerm(decisionWell1OilRate, decisionWell2GasRate) <= 100000);
model.AddConstraint("Constraint1", decisionWell1OilRate * 5 >= 0);
model.AddConstraint("Constraint2", decisionWell1OilRate * 5 <= 1000);
model.AddConstraint("Constraint3", decisionWell2GasRate <= 2000);
var solution = solver.Solve();
double Well1OilRate = decisionWell1OilRate.GetDouble();
double Well2GasRate = decisionWell2GasRate.GetDouble();
Console.WriteLine("Well1OilRate: " + (Well1OilRate).ToString());
Console.WriteLine("Well1GasRate: " + (Well1OilRate*5).ToString());
Console.WriteLine("Well2GasRate: " + (Well2GasRate).ToString());
Console.WriteLine("TotalGasRate: " + TotalGasRate(Well1OilRate, Well2GasRate).ToString());
Console.WriteLine("\nEnd Solver demo\n");
}
static Term TotalGasRateTerm(Decision decisionWell1OilRate, Decision decisionWell2GasRate)
{
return (decisionWell1OilRate * 5) + decisionWell2GasRate;
}
static double TotalGasRate(double Well1OilRate, double Well2GasRate)
{
return (Well1OilRate * 5) + Well2GasRate;
}
Выход:
Begin Solver Gas Rate using Solver Context MSF
Well1OilRate: 200
Well1GasRate: 1000
Well2GasRate: 2000
TotalGasRate: 3000
End Solver demo