使用求解器在 2D 区域上查找最佳点
本文关键字:区域 查找 最佳 2D | 更新日期: 2023-09-27 18:35:22
这是我第一次使用求解器基金会,我不明白如何指定目标函数。我试图使用求解器解决的问题是根据目标函数在 2D 表面上找到最佳点。作为输入数据,我在这个表面上有 3 个点,声波需要从源(最佳点)到达这三个点的时间之间的差异。这种时间差导致距离差。
这是我的代码:
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
decisionX = new Decision( Domain.Real, "X" );
decisionY = new Decision( Domain.Real, "Y" );
model.AddDecision( decisionX );
model.AddDecision( decisionY );
model.AddGoal( "Goal", GoalKind.Minimize, GoalFunction() );
var solution = solver.Solve();
Console.WriteLine("X " + decisionX.GetDouble());
Console.WriteLine("Y " + decisionY.GetDouble());
GoalFunction() 定义如下:
double GoalFunction() {
Location X = new Location( decisionX.ToDouble(), decisionY.ToDouble() );
var rA = A.Location.Distance( X );
var rB = B.Location.Distance( X );
var rC = C.Location.Distance( X );
rA = (Distance)( rA - dsA );
rB = (Distance)( rB - dsA );
rC = (Distance)( rC - dsA );
return ( rA * rA + rB * rB + rC * rC ) / 3;
}
上面的代码抛出异常(decisionX.ToDouble()
),因为此时决策尚未初始化。
任何人都可以帮我重写吗?
我已经将我的GoalFunction重写为all-Model.methods-calls。
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
decisionX = new Decision( Domain.Real, "X" );
decisionY = new Decision( Domain.Real, "Y" );
model.AddDecision( decisionX );
model.AddDecision( decisionY );
var rA = Model.Difference(
Model.Sqrt(
Model.Sum(
Model.Power( Model.Difference( decisionX, A.Location.X ), 2 ),
Model.Power( Model.Difference( decisionY, A.Location.Y ), 2 )
)
),
dsA.Value
);
var rB = Model.Difference(
Model.Sqrt(
Model.Sum(
Model.Power( Model.Difference( decisionX, B.Location.X ), 2 ),
Model.Power( Model.Difference( decisionY, B.Location.Y ), 2 )
)
),
dsB.Value
);
var rC = Model.Difference(
Model.Sqrt(
Model.Sum(
Model.Power( Model.Difference( decisionX, C.Location.X ), 2 ),
Model.Power( Model.Difference( decisionY, C.Location.Y ), 2 )
)
),
dsC.Value
);
var miner = Model.Min( rA, rB, rC );
rA = Model.Difference( rA, miner );
rB = Model.Difference( rB, miner );
rC = Model.Difference( rC, miner );
var goal = Model.Sum(
Model.Power( rA, 2 ),
Model.Power( rB, 2 ),
Model.Power( rC, 2 )
);
model.AddGoal( "Goal", GoalKind.Minimize, goal );
var solution = solver.Solve();
var q = solution.Quality;
double x = decisionX.GetDouble();
double y = decisionY.GetDouble();
solution.GetNext();
x = decisionX.GetDouble();
y = decisionY.GetDouble();
此代码有效,但返回 {0.0} 作为 LocalOptimal 解决方案,而 optimal 为 {2,2}(我检查过,GoalFunction 为 {2,2} 返回 0,为 {0,0} 返回更高的值。可能 {0,0} 是决策是 Domain.Real 时的起点。
Solution.GetNext() 不会改变任何内容。
decisionX = new Decision( Domain.RealRange( -10, 10 ), "X" );
decisionY = new Decision( Domain.RealRange( -10, 10 ), "Y" );
如果我限制域,返回的解决方案是{1.9999999984154413,1.99999999990963979},所以它是正确的。
但是为什么求解器没有启动完整的真实域?
也许有一天有人会回答...我希望,但我将下面的答案标记为正确。
自己不是无国界医生的专家,但据我所知,你的model.AddGoal()
陈述是不正确的。根据文档,第三个参数应该是一个术语。Term 有一个从 double 到 Term 的隐式强制转换运算符,因此 model.AddGoal()
语句中唯一发生的事情是GoalFunction
被调用一次(并引发异常,因为决策一开始没有初始化)。
在 MSF 示例中,有一些有关如何创建目标的示例。
更新
基于这些示例,我创建了一个简单的目标(Rosenbrock banana函数),并将该目标合并到AddGoal
调用中,如下所示:
var goal = Model.Sum(Model.Power(1.0 - decisionX, 2.0),
Model.Product(100.0, Model.Power(decisionY - Model.Power(decisionX, 2.0), 2.0)));
model.AddGoal( "Goal", GoalKind.Minimize, goal);
希望这可以引导你朝着制定目标函数的方向前进。