visual studio remarks example c# ms-solver-foundation numerical-integration

remarks - summary c# visual studio



Definiendo el objetivo utilizando la FundaciĆ³n de soluciones de Microsoft (1)

Aquí está mi resumen de TL; DR: Él no sabe cómo minimizar el valor de retorno de LinearTrial , que tiene una serie de dobles. Cada valor en esta matriz tiene su propio valor mínimo / máximo, y está modelando eso utilizando Decisions .

Si eso es correcto, parece que podrías hacer lo siguiente:

double[] minimums = Parameters.Select(p => p.Value.Item1).ToArray(); double[] maximums = Parameters.Select(p => p.Value.Item2).ToArray(); // Some initial values, here it''s a quick and dirty average double[] initials = Parameters.Select(p => (p.Item1 + p.Item2)/2.0).ToArray(); var solution = NelderMeadSolver.Solve( x => myRanker.LinearTrial(x, false), initials, minimums, maximums); // Make sure you check solution.Result to ensure that it found a solution. // For this, I''ll assume it did. // Value 0 is the minimized value of LinearTrial int i = 1; foreach (var param in Parameters) { Console.WriteLine("{0}: {1}", param.Key, solution.GetValue(i)); i++; }

El NelderMeadSolver es nuevo en MSF 3.0. El método estático Solve "encuentra el valor mínimo de la función especificada" de acuerdo con la documentación en el ensamblaje de MSF (a pesar de que la documentación de MSDN está en blanco y muestra la firma de la función incorrecta).

Descargo de responsabilidad: no soy un experto en MSF, pero lo anterior funcionó para mí y para mi función de objetivo de prueba (suma los pesos).

Propósito del programa: Integración. Estoy implementando un algoritmo de cuadratura adaptativa (también conocido como integración numérica) para altas dimensiones (hasta 100). La idea es dividir aleatoriamente el volumen en secciones más pequeñas mediante la evaluación de los puntos utilizando una densidad de muestreo proporcional a una estimación del error en ese punto. Al principio, "quemo" una muestra uniforme, luego elijo puntos al azar de acuerdo con una distribución gaussiana sobre el error estimado. De una manera similar al recocido simulado, "baje la temperatura" y reduzco la desviación estándar de mi gaussiano a medida que pasa el tiempo, de modo que los puntos de bajo error inicialmente tienen una buena posibilidad de ser elegidos, pero luego se eligen con una disminución constante probabilidad. Esto permite al programa tropezar con picos que pueden perderse debido a imperfecciones en la función de error. (Mi algoritmo es similar en espíritu a la integración de Markov-Chain Monte-Carlo ).

Características de la función. La función que se integrará es la pérdida de póliza de seguro estimada para varios edificios debido a un desastre natural. Las funciones de la política no son fluidas: hay deducibles, máximos, capas (por ejemplo, pago cero hasta pérdida de 1 millón de dólares, pago del 100% de 1 a 2 millones de dólares, luego pago cero por encima de los 2 millones de dólares) y otros términos de política impares. Esto introduce comportamientos no lineales y funciones que no tienen derivados en numerosos planos. Encima de la función de política está la función de daño, que varía según el tipo de edificio y la fuerza del huracán y definitivamente no tiene forma de campana.

Contexto del problema: Función de error . La dificultad es elegir una buena función de error. Para cada punto, registro medidas que parecen útiles para esto: la magnitud de la función, cuánto cambió como resultado de una medición previa (un proxy para la primera derivada), el volumen de la región que ocupa el punto (los volúmenes más grandes pueden oculta el error mejor), y un factor geométrico relacionado con la forma de la región. Mi función de error será una combinación lineal de estas medidas donde a cada medida se le asigna un peso diferente. (Si obtengo resultados deficientes, contemplaré funciones no lineales). Para ayudarme en este esfuerzo, decidí realizar una optimización en un amplio rango de valores posibles para cada peso, por lo tanto, Microsoft Solution Foundation.

Qué optimizar: Rango de error . Mis medidas están normalizadas, de cero a una. Estos valores de error se revisan progresivamente a medida que la integración avanza para reflejar promedios recientes para valores de función, cambios, etc. el error verdadero, es decir, si todos los puntos muestreados están ordenados por este valor de error estimado, deberían recibir un rango similar al rango que recibirían si estuvieran clasificados por el error verdadero.

No todos los puntos son iguales. Me importa mucho si la región del punto con el error verdadero # 1 ocupa el puesto # 1000 (o viceversa), pero importa muy poco si el punto # 500 ocupa el puesto # 1000. Mi medida de éxito es MINIMIZAR la suma de lo siguiente en muchas regiones en un punto parcial a la ejecución del algoritmo:

ABS (Log2 (trueErrorRank) - Log2 (estimadoErrorRank))

Para Log2, estoy usando una función que devuelve la mayor potencia de dos menos que o igual al número. De esta definición, vienen resultados útiles. El intercambio de los números 1 y 2 cuesta un punto, pero el cambio de los números 2 y 3 no cuesta nada. Esto tiene el efecto de estratificar los puntos en el poder de dos rangos. Los puntos que se intercambian dentro de un rango no se agregan a la función.

Cómo evalúo . He construido una clase llamada Rango que hace esto:

  1. Clasifica todas las regiones por error verdadero una vez.

  2. Para cada conjunto separado de ponderaciones parametrizadas, calcula el error de prueba (estimado) para esa región.

  3. Ordena las regiones por ese error de prueba.

  4. Calcula el rango de prueba para cada región.

  5. Suma la diferencia absoluta de los registros de los dos rangos y llama a esto el valor de la parametrización, de ahí el valor que se debe minimizar.

Código C # . Después de hacer todo eso, solo necesito una forma de configurar Microsoft Solver Foundation para encontrar los mejores parámetros. La sintaxis me ha dejado perplejo. Aquí está mi código C # que tengo hasta ahora. En ella podrás ver comentarios para los tres problemas que he identificado . ¡Tal vez puedas detectar aún más! ¿Alguna idea de cómo hacer que esto funcione?

public void Optimize() { // Get the parameters from the GUI and figures out the low and high values for each weight. ParseParameters(); // Computes the true rank for each region according to true error. var myRanker = new Rank(ErrorData, false); // Obtain Microsoft Solver Foundation''s core solver object. var solver = SolverContext.GetContext(); var model = solver.CreateModel(); // Create a delegate that can extract the current value of each solver parameter // and stuff it in to a double array so we can later use it to call LinearTrial. Func<Model, double[]> marshalWeights = (Model m) => { var i = 0; var weights = new double[myRanker.ParameterCount]; foreach (var d in m.Decisions) { weights[i] = d.ToDouble(); i++; } return weights; }; // Make a solver decision for each GUI defined parameter. // Parameters is a Dictionary whose Key is the parameter name, and whose // value is a Tuple of two doubles, the low and high values for the range. // All are Real numbers constrained to fall between a defined low and high value. foreach (var pair in Parameters) { // PROBLEM 1! Should I be using Decisions or Parameters here? var decision = new Decision(Domain.RealRange(ToRational(pair.Value.Item1), ToRational(pair.Value.Item2)), pair.Key); model.AddDecision(decision); } // PROBLEM 2! This calls myRanker.LinearTrial immediately, // before the Decisions have values. Also, it does not return a Term. // I want to pass it in a lambda to be evaluated by the solver for each attempted set // of decision values. model.AddGoal("Goal", GoalKind.Minimize, myRanker.LinearTrial(marshalWeights(model), false) ); // PROBLEM 3! Should I use a directive, like SimplexDirective? What type of solver is best? var solution = solver.Solve(); var report = solution.GetReport(); foreach (var d in model.Decisions) { Debug.WriteLine("Decision " + d.Name + ": " + d.ToDouble()); } Debug.WriteLine(report); // Enable/disable buttons. UpdateButtons(); }

ACTUALIZACIÓN: decidí buscar otra biblioteca como alternativa y encontré DotNumerics ( http://dotnumerics.com/ ). Su solucionador Nelder-Mead Simplex fue fácil de llamar:

Simplex simplex = new Simplex() { MaxFunEvaluations = 20000, Tolerance = 0.001 }; int numVariables = Parameters.Count(); OptBoundVariable[] variables = new OptBoundVariable[numVariables]; //Constrained Minimization on the intervals specified by the user, initial Guess = 1; foreach (var x in Parameters.Select((parameter, index) => new { parameter, index })) { variables[x.index] = new OptBoundVariable(x.parameter.Key, 1, x.parameter.Value.Item1, x.parameter.Value.Item2); } double[] minimum = simplex.ComputeMin(ObjectiveFunction, variables); Debug.WriteLine("Simplex Method. Constrained Minimization."); for (int i = 0; i < minimum.Length; i++) Debug.WriteLine(Parameters[i].Key + " = " + minimum[i].ToString());

Todo lo que necesitaba era implementar ObjectiveFunction como método tomando una doble matriz:

private double ObjectiveFunction(double[] weights) { return Ranker.LinearTrial(weights, false); }

No lo he probado contra datos reales, pero creé una simulación en Excel para configurar los datos de prueba y calificarlos. Los resultados que regresaron de su algoritmo no fueron perfectos, pero dieron una muy buena solución.