I'm learning Solver Foundation right now. I'm actually plugging in lpsolve for my project, but I think my problem is a generic issue of how to best represent my constraints.
I have, what I think is, a fairly typical knapsack or packing problem. I have a collection of locations, and each has a 'score'. I want to select the minimum number of locations to meet a target 'score'.
(In practice, it's a bit more complex than that - each location has a number of different properties and I will often target across multiple properties).
So far so good. However, I have an additional constraint - I want to maximise the geographic dispersion of the locations that I choose. How can I represent that constraint?
Here is a basic example of what I have right now:
    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; }
    }
This will simply select the first three locations, which gives me my goal of 60 but these three locations are clustered very close together. What I would prefer is for it to select one of the first three (ID 0 - 2) and the last two (ID 3 and 4), which are spread further out.
Can someone offer some guidance here? Many thanks in advance.