在 Optano 建模中使用方法作为目标
我正在尝试在 C# 中使用 Optano 建模(带有 GLPK 求解器)来最小化函数。目标函数不是一个简单的公式,而是返回单个数字的方法中的一系列计算(在本例中是数据集的方差,但还有其他我需要解决的问题也需要方法)。我希望能够将这种方法作为目标传递。
我能够使用 Microsoft.Solver.Foundation 做到这一点,但 a) 十年没有支持,b) 规模受许可证限制,c) 我很确定其中存在一个错误,破坏了我的一个模型。
我的 Optano 设置如下。
using (ModelScope modelScope = new ModelScope())
{
OPTANO.Modeling.Optimization.Model model = new OPTANO.Modeling.Optimization.Model();
foreach (KeyValuePair<string, decimal> weight in Weights)
{
model.AddVariable(new Variable(weight.Key, 0, 1, VariableType.Continuous));
}
model.AddConstraint(Expression.Sum(model.Variables) == 1);
model.AddObjective(new Objective(Expression.Sum(GetResult(model.Variables.ToArray())), "MinimumResult", ObjectiveSense.Minimize));
List<double> GetResult(Variable[] variables)
{
//*****Calculate stuff*****
return result;//Return a List<double> containing a single element.
}
using (GLPKSolver solver = new GLPKSolver())
{
var solution = solver.Solve(model);
if (solution.ModelStatus == OPTANO.Modeling.Optimization.Solver.ModelStatus.Feasible)
{
Console.WriteLine("Minimum result: " + solution.GetObjectiveValue("MinimumResult"));
Console.WriteLine("\nWeights:");
foreach (KeyValuePair<string, double> solvedValue in solution.VariableValues)
{
Console.WriteLine(solvedValue);
}
}
}
}
如果我从 GetResult() 方法返回双精度值,则会出现类型冲突,因为 AddObjective() 需要一个 Objective,而 Objective 本身需要一个表达式。但是,Expression.Sum() 接受一个列表并返回一个表达式,这就是为什么我向它传递一个单长度列表,然后将其依次传递给一个新的目标。
无论我做什么,它总是将方差最小化为 0 并返回变量(其中有 5 个),其中一个等于 1,其余为 0。我知道 Excel Solver 的实际结果应该是什么(只有其中两个应该)为零,方差应为 0.032)。
所以问题是,如何让求解器最小化 GetResult() 方法的结果?
I'm trying to use Optano Modelling (with a GLPK solver) in C# to minimise a function. The objective function is not a straightforward formula but a series of calculations in a method that returns a single number (in this case, the variance of a dataset, but there are other things I need to solve for as well that require methods). I want to be able to pass this method in as the objective.
I was able to do this with Microsoft.Solver.Foundation, but that's a) ten years out of support, b) restricted in scale by the license and c) I'm pretty sure there's a bug in that breaks one of my models.
My Optano setup is as follows.
using (ModelScope modelScope = new ModelScope())
{
OPTANO.Modeling.Optimization.Model model = new OPTANO.Modeling.Optimization.Model();
foreach (KeyValuePair<string, decimal> weight in Weights)
{
model.AddVariable(new Variable(weight.Key, 0, 1, VariableType.Continuous));
}
model.AddConstraint(Expression.Sum(model.Variables) == 1);
model.AddObjective(new Objective(Expression.Sum(GetResult(model.Variables.ToArray())), "MinimumResult", ObjectiveSense.Minimize));
List<double> GetResult(Variable[] variables)
{
//*****Calculate stuff*****
return result;//Return a List<double> containing a single element.
}
using (GLPKSolver solver = new GLPKSolver())
{
var solution = solver.Solve(model);
if (solution.ModelStatus == OPTANO.Modeling.Optimization.Solver.ModelStatus.Feasible)
{
Console.WriteLine("Minimum result: " + solution.GetObjectiveValue("MinimumResult"));
Console.WriteLine("\nWeights:");
foreach (KeyValuePair<string, double> solvedValue in solution.VariableValues)
{
Console.WriteLine(solvedValue);
}
}
}
}
If I return a double from the GetResult() method, there's a type conflict because AddObjective() expects an Objective, which itself expects an expression. However, Expression.Sum() takes a List and returns an Expression, which is why I pass a single-length List to it, and pass that in turn to a new Objective.
Whatever I do, it always minimises the variance to 0 and returns the variables (of which there are 5) with one being equal to 1 and the rest 0. I know what the actual result should be from Excel Solver (only two of them should be zero and the variance should be 0.032).
So the question is, how can I get the solver to minimise the result of the GetResult() method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一些注意事项:我不了解 Optano 框架,也不了解 C#,但我熟悉您正在使用的求解器。我认为您对模型的构造有误解......
求解器需要一个可以计算任意次数的表达式。它无法访问您神奇的
GetResult
函数。 Optano 只是构建一个表达式,求解器可以在内部计算任意次数,因此不可能在函数中执行一些任意复杂的数学运算并返回一个数字,并将该数字作为目标值传递。因此,您需要在 Optano 框架中构建一个表达式并返回该表达式,这应该只是对模型中的变量和常量执行简单的数学运算...
也许有一种方法可以在之前打印您的模型你尝试解决它来验证你的表达是否良好?
A couple caveats: I don't know Optano framework, and not much C#, but I am familiar with the solver you are using. I think you have a misconception regarding the construction of a model...
The solver needs an expression that it can evaluate an arbitrary number of times. It does not have access to your magic
GetResult
function. Optano is just building an expression that the solver can evaluate an arbitrary number of times internally, so it isn't possible to do some arbitrarily complicated math in a function and return a number, and pass along that number as the objective value.So, you need to build an expression in the Optano framework and return that, which should just be simple math performed on variables and constants in the model...
Perhaps there is a way to print your model before you try to solve it to verify that you have a good expression?
“目标函数不是一个简单的公式,而是返回单个数字的方法中的一系列计算(在本例中是数据集的方差,但还有其他我需要解决的问题,需要方法)。”我希望您意识到 GLPK 仅适用于线性模型。
"The objective function is not a straightforward formula but a series of calculations in a method that returns a single number (in this case, the variance of a dataset, but there are other things I need to solve for as well that require methods)." I hope you realize that GLPK is only for linear models.