Finding optimal point on 2D area using Solver

364 views Asked by At

It's my first time with Solver Foundation, and I don't understand how to specify goal function. Problem I'm trying to solve using Solver is finding optimal point on 2D surface basing on goal function. As input data, I have 3 point on this surface and difference between times that sound wave needs to get from source (optimal point) to those three points. This time difference leads to distance difference.

And here is my code:

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() is defined as follows:

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;
}

The code above throws exception (decisionX.ToDouble()), because decisions are not initialized at this point.

Anybody can help me rewrite it ?


I have rewritten my GoalFunction to 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();

This code works, but returns {0.0} as a LocalOptimal solution, while optimal is {2,2} (I checked, GoalFunction returns 0 for {2,2} and much higher value for {0,0}. Probably {0,0} is starting point when decisions are Domain.Real.

Solution.GetNext() changes nothing.


decisionX = new Decision( Domain.RealRange( -10, 10 ), "X" );
decisionY = new Decision( Domain.RealRange( -10, 10 ), "Y" );

if I limit the Domain, solution returned is {1.9999999984154413,1.9999999990963979} so it's correct.

but why the solver doesn't start for full real domain ? still dunno

maybe someone will answer someday ... I hope, but I'm marking the answer below as correct.

1

There are 1 answers

7
Anders Gustafsson On BEST ANSWER

I am no expert on MSF myself, but as far as I can tell your model.AddGoal() statement is incorrect. According to the documentation the third argument should be a Term. Term has an implicit cast operator from double to Term so the only thing that happens in your model.AddGoal() statement is that GoalFunction is invoked once (and throws exception because decisions are not initialized at first).

In the MSF samples there are some examples of how goals can be created.

UPDATE

Based on these samples I have created a simple goal (Rosenbrock banana function) and incorporated this goal in the AddGoal call instead, like this:

    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);

Hopefully this could lead you in the direction in formulating your goal function.