我正在尝试使用Microsoft Solver Foundation来优化我涉及矩阵乘法的问题。我可以使用Excel的求解器来做到这一点,但我试图将它集成到C#中并且遇到了麻烦。以下是一个示例说明:
假设你有一个(3x3)矩阵 y ,定义为:
Double[][] y =
{
new Double[] { 5, 1, 0 },
new Double[] { 1, 9, 1 },
new Double[] { 0, 1, 9 },
};
我想找到(1x3)矩阵 x ,以便:x * y * x'
最小化。
此外, x 值必须总和为1,且 x 值均不得小于0.
这是我到目前为止的代码:
SolverContext context = SolverContext.GetContext(); // Get context environment
Model model = context.CreateModel(); // Create a new model
Decision d1 = new Decision(Domain.RealNonnegative, "d1"); // First item in "x" vector (must be >= 0)
Decision d2 = new Decision(Domain.RealNonnegative, "d2"); // Second item in "x" vector (must be >= 0)
Decision d3 = new Decision(Domain.RealNonnegative, "d3"); // Third item in "x" vector (must be >= 0)
model.AddDecisions(d1, d2, d3); // Add these to the model (this is where the outputs will be stored)
model.AddConstraints("limits", // Add constraints
0 <= d1 <= 1, // Each item must be between 0 and 1
0 <= d2 <= 1,
0 <= d3 <= 1,
d1 + d2 + d3 == 1); // All items must add up to 1
我坚持的部分是当你告诉它你想要最小化的时候:
model.AddGoal("min", GoalKind.Minimize, /* What goes here? */);
这部分通常包含一个等式(例如d1 * d2 + d3
),但矩阵乘法并不那么简单。
我可以创建一个执行乘法的函数并返回double
,但是AddGoal()
需要一个Term对象,而且我必须对Decision
个对象进行算术运算
或者,我可以将这个乘法分解为一个巨大的string
表达式(我已经完成了),但我更愿意,如果我不必这样做。
(此字符串类似于:"d1 * 5 + d2 * 1 + d3 * 0 ..."
)
有什么想法吗? 感谢。
PS:正确答案(根据Excel)是:
d1 = 0.503497
d2 = 0.216783
d3 = 0.27972
注意:解决方案必须可扩展,以便n
个“决策”
答案 0 :(得分:1)
以下结果是预期的解决方案:
using System;
using Microsoft.SolverFoundation.Services;
namespace akMSFStackOverflow
{
class Program
{
static void Main(string[] args)
{
Double[,] y =
{
{ 5, 1, 0 },
{ 1, 9, 1 },
{ 0, 1, 9 },
};
Term goal;
Term[,] tx;
Term[,] ty;
SolverContext context = SolverContext.GetContext(); // Get context environment
Model model = context.CreateModel(); // Create a new model
Decision d1 = new Decision(Domain.RealNonnegative, "d1"); // First item in "x" vector (must be >= 0)
Decision d2 = new Decision(Domain.RealNonnegative, "d2"); // Second item in "x" vector (must be >= 0)
Decision d3 = new Decision(Domain.RealNonnegative, "d3"); // Third item in "x" vector (must be >= 0)
model.AddDecisions(d1, d2, d3); // Add these to the model (this is where the outputs will be stored)
model.AddConstraints("limits", // Add constraints
0 <= d1 <= 1, // Each item must be between 0 and 1
0 <= d2 <= 1,
0 <= d3 <= 1,
d1 + d2 + d3 == 1); // All items must add up to 1
ty = matrix(y);
tx = new Term[,] { { d1, d2, d3 } };
goal = matMult(matMult(tx, ty), transpose(tx))[0, 0];
model.AddGoal("goal", GoalKind.Minimize, goal);
// Specifying the IPM solver, as we have a quadratic goal
Solution solution = context.Solve(new InteriorPointMethodDirective());
Report report = solution.GetReport();
Console.WriteLine("x {{{0}, {1}, {2}}}", d1, d2, d3);
Console.Write("{0}", report);
}
static Term[,] matrix(Double[,] m)
{
int rows = m.GetLength(0);
int cols = m.GetLength(1);
Term[,] r = new Term[rows, cols];
for (int row = 0; row < rows; row++)
for (int col = 0; col < cols; col++)
r[row, col] = m[row, col];
return r;
}
static Term[,] matMult(Term[,] a, Term[,] b)
{
int rows = a.GetLength(0);
int cols = b.GetLength(1);
Term[,] r = new Term[rows, cols];
for (int row = 0; row < rows; row++)
for (int col = 0; col < cols; col++)
{
r[row,col] = 0;
for (int k = 0; k < a.GetLength(1); k++)
{
r[row, col] += a[row, k] * b[k, col];
}
}
return r;
}
static Term[,] transpose(Term[,] m)
{
int rows = m.GetLength(0);
int cols = m.GetLength(1);
Term[,] r = new Term[cols, rows];
for (int row = 0; row < rows; row++)
for (int col = 0; col < cols; col++)
{
r[col, row] = m[row, col];
}
return r;
}
}
}