c# – 将地理分布表示为线性概率约束?
作者:互联网
我现在正在学习Solver Foundation.我实际上是为我的项目插入lpsolve,但我认为我的问题是如何最好地表示我的约束的一般问题.
我认为,我有一个相当典型的背包或包装问题.我有一系列的位置,每个都有一个’得分’.我想选择满足目标“分数”的最小位置数.
(实际上,它比这更复杂 – 每个位置都有许多不同的属性,我经常会在多个属性中进行定位).
到现在为止还挺好.但是,我有一个额外的限制 – 我想最大化我选择的位置的地理分散.我该如何表示这种约束?
这是我现在所拥有的基本例子:
static void Main(string[] args)
{
var locations = new List<LocationWithScore>()
{
new LocationWithScore() { LocationID = 0, Latitude = 43.644274M, Longitude = -79.478703M, Score = 20 },
new LocationWithScore() { LocationID = 1, Latitude = 43.644709M, Longitude = -79.476814M, Score = 20 },
new LocationWithScore() { LocationID = 2, Latitude = 43.643063M, Longitude = -79.477458M, Score = 20 },
new LocationWithScore() { LocationID = 3, Latitude = 43.650516M, Longitude = -79.469562M, Score = 20 },
new LocationWithScore() { LocationID = 4, Latitude = 43.642659M, Longitude = -79.463124M, Score = 20 }
};
SolverContext sContext = SolverContext.GetContext();
sContext.ClearModel();
Model model = sContext.CreateModel();
model.Name = "LocationWithScore";
Set items = new Set(Domain.Any, "candidates");
Decision take = new Decision(Domain.Boolean, "candidate", items);
model.AddDecision(take);
Parameter scoreParam = new Parameter(Domain.RealNonnegative, "score", items);
scoreParam.SetBinding(locations, "Score", "LocationID");
model.AddParameters(scoreParam);
model.AddConstraint("scoreConstraint", Model.Sum(Model.ForEach(items, item => scoreParam[item] * take[item])) >= 60);
model.AddGoal("locationGoal", GoalKind.Minimize, Model.Sum(Model.ForEach(items, item => take[item])));
var solution = sContext.Solve(new LpSolveDirective());
var report = solution.GetReport();
Console.WriteLine(report.ToString());
Console.WriteLine("Done");
Console.ReadKey();
}
internal class LocationWithScore
{
public int LocationID { get; set; }
public decimal Latitude { get; set; }
public decimal Longitude { get; set; }
public double Score { get; set; }
}
这将只选择前三个位置,这给我的目标是60,但这三个位置非常紧密地聚集在一起.我更喜欢的是它选择前三个(ID 0 – 2)和后两个(ID 3和4)中的一个,它们会进一步扩展.
有人可以提供一些指导吗?提前谢谢了.
解决方法:
问题比我最初想的要复杂一些.就像我上面提到的,你需要计算色散.但是,地理点标准差的计算并不简单.这是一个MathWorks的解释.
似乎如果您的点不跨越大的地理区域,您可以通过计算2维的标准差来近似分散.否则,您将必须编写类似于MatLab,stdm中提供的函数.
更新
我花了一段时间,但我想我已经解决了这个问题.我必须说整套解算器程序很复杂.我在您提供的示例上测试了以下代码,它正确地选择了0,3和4.代码更改如下.
以下部分计算从位置i到位置j的距离,其中i和j是所提供目标集的元素.数据绑定到参数,以便稍后在目标中查询.
var dist = from l1 in locations
from l2 in locations
select new {ID1 = l1.LocationID, ID2 = l2.LocationID, dist = GetDistance(l1.Latitude, l1.Longitude, l2.Latitude, l2.Longitude)};
Parameter distance = new Parameter(Domain.RealNonnegative, "Location", items, items);
distance.SetBinding(dist, "dist", "ID1", "ID2");
model.AddParameter(distance);
最终目标实际上由两部分组成.第一个目标是最大化分数,第二个目标是最大化位置的分散.在这种情况下,我已将色散抽象为所选位置之间的总距离.我得到了一个例外,“模型有多个目标”,当我添加2个目标时,我必须将它们组合成一个目标,如下所示.
double maxDist = (from distances in dist select distances.dist).Max();
Term goal1 = Model.Sum(Model.ForEach(items, item => take[item] * scoreParam[item]));
Term goal2 = Model.Sum(Model.ForEach(items, i => Model.ForEach(items, j => take[i] * take[j] * distance[i, j])));
model.AddGoal("Dispersion", GoalKind.Maximize, Model.Sum(Model.Sum(goal1, maxDist), goal2));
GetDistance()使用System.Device.Location.GeoCoordinate计算2个坐标之间的距离;事实证明有一个C#实现.我将纬度和经度类型更改为两倍以避免类型转换.在使用大型案例之前,此代码需要更新.
public static double GetDistance(double lat1, double long1, double lat2, double long2)
{
GeoCoordinate geo1 = new GeoCoordinate(lat1, long1);
GeoCoordinate geo2 = new GeoCoordinate(lat2, long2);
return geo1.GetDistanceTo(geo2);
}
标签:c,linear-programming,ms-solver-foundation,lpsolve 来源: https://codeday.me/bug/20190630/1332864.html