The problem is a little more complicated than I thought. As I mentioned above, you need to calculate the variance. However, calculating the standard deviation of geographic points is not easy. Here is a description of MathWorks .
It seems that if your points do not cover a large geographic area, you can approximate the variance by calculating a standard deviation of 2 dimensions. Otherwise, you will have to write a function such as in MatLab, stdm .
Update
It took me a while, but I decided that I had solved the problem. I have to say that the entire Solver suite of programs is complex. I checked the following code with the example you provided, and it correctly selects 0, 3, and 4. The code changes below.
The next section computes the distance from location i to location j, where i and j are elements of the provided target set. Data is tied to Parameter , so it can be requested later in the target.
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);
The final goal actually consists of two parts. The first goal is to maximize the score, and the second goal is to maximize the variance of locations. In this case, I scattered the variance as the total distance between the selected locations. I received an exception: βThe model has more than one goalβ when I added 2 goals, so I had to combine them into one goal, as you can see below.
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() calculates the distance between two coordinates using System.Device.Location.GeoCoordinate ; it turns out there is a C # implementation. I changed the latitude and longitude types to double to avoid type casting. This code will need to be updated before use in large cases.
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); }