Подтвердить что ты не робот

Определение цели с помощью Microsoft Solution Foundation

Цель программы: интеграция. Я реализую алгоритм адаптивного квадратурного (так называемого численного интегрирования) для высоких измерений (до 100). Идея состоит в том, чтобы случайным образом разбить объем на более мелкие участки, оценивая точки, используя плотность выборки, пропорциональную оценке ошибки в этой точке. Раньше я "сжигал" единый образец, затем произвольно выбирал точки по гауссовскому распределению по оценочной ошибке. Подобным образом, как и симуляционный отжиг, я "понижаю температуру" и уменьшаю стандартное отклонение от своего гауссова с течением времени, так что точки с низкой ошибкой изначально имеют достаточную вероятность выбора, но позже выбираются с неуклонным уменьшением вероятность. Это позволяет программе наткнуться на всплески, которые могут быть упущены из-за несовершенства функции ошибки. (Мой алгоритм похож по духу на Интеграция Марков-Цепочка Монте-Карло.)

Функциональные характеристики. Функция, которая должна быть интегрирована, представляет собой оценку потери страхового полиса для нескольких зданий из-за стихийного бедствия. Функции политики не являются гладкими: есть франшизы, максимумы, уровни (например, нулевая выплата до 1 миллиона долларов убытков, 100% выплата с 1-2 миллионов долларов, затем нулевая выплата выше 2 миллионов долларов) и другие нечетные условия политики. Это вводит нелинейное поведение и функции, не имеющие производной в многочисленных плоскостях. В дополнение к функции политики функция повреждения, которая зависит от типа здания и силы урагана и, безусловно, не колоколообразна.

Контекст проблемы: функция ошибки. Трудность заключается в выборе хорошей функции ошибки. Для каждой точки я записываю меры, которые кажутся полезными для этого: величина функции, насколько она изменилась в результате предыдущей меры (прокси для первой производной), объем области, в которой находится точка (большие объемы могут скрыть ошибку лучше) и геометрический фактор, связанный с формой области. Моя функция ошибки будет линейной комбинацией этих мер, где каждому измерению присваивается другой вес. (Если я получаю плохие результаты, я буду рассматривать нелинейные функции.) Чтобы помочь мне в этом, я решил выполнить оптимизацию по широкому диапазону возможных значений для каждого веса, следовательно, Microsoft Solution Foundation.

Что оптимизировать: уровень ошибок. Мои меры нормированы, от нуля до единицы. Эти значения ошибок постепенно пересматриваются по мере того, как интеграция продолжает отражать последние средние значения функций, изменения и т.д. В результате я не пытаюсь сделать функцию, которая дает фактические значения ошибок, но вместо этого дает число, которое сортирует то же самое, что и истинная ошибка, т.е. если все выборочные точки сортируются по этому оценочному значению ошибки, они должны получить ранг, аналогичный рангу, который они будут получать, если отсортировать по истинной ошибке.

Не все точки равны. Я очень волнуюсь, если точка-область с истинной ошибкой # 1 занимает # 1000 (или наоборот), но очень мало заботится, если точка № 500 занимает # 1000. Моя мера успеха заключается в том, чтобы МИНИМИЗИРОВАТЬ сумму следующих по многим регионам в одной точке в процессе выполнения алгоритма:

ABS (Log2 (trueErrorRank) - Log2 (оцененныйErrorRank))

Для Log2 я использую функцию, которая возвращает наибольшую мощность из двух, меньших или равных числу. Из этого определения приходят полезные результаты. Обмен # 1 и # 2 стоит одной точки, но замена # 2 и # 3 ничего не стоит. Это приводит к тому, что стратификационные точки попадают в силу двух диапазонов. Точки, которые меняются в пределах диапазона, не добавляют к функции.

Как я оцениваю. Я построил класс под названием Ранг, который делает это:

  • Один раз помечает все регионы с помощью истинной ошибки.

  • Для каждого отдельного набора параметризованных весов он вычисляет пробная (оценочная) ошибка для этого региона.

  • Сортирует регионы по этой пробной ошибке.

  • Вычисляет пробный ранг для каждой области.

  • Добавляет абсолютную разницу в журналах двух рангов и звонков это значение параметризации, следовательно, значение, которое должно быть сведено к минимуму.

Код С#, Сделав все это, мне просто нужно настроить Microsoft Solver Foundation, чтобы найти лучшие параметры. Синтаксис меня насторожил. Вот мой код С#, который у меня есть до сих пор. В нем вы увидите комментарии по трем проблемам, которые я определил. Может быть, вы сможете увидеть еще больше! Любые идеи, как сделать эту работу?

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

UPDATE: я решил искать другую библиотеку в качестве резервной копии и нашел DotNumerics (http://dotnumerics.com/). Их решение Nelder-Mead Simplex было легко назвать:

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

Все, что мне было нужно, это реализовать ObjectiveFunction как метод, использующий двойной массив:

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

Я не пробовал его против реальных данных, но я создал симуляцию в Excel для установки тестовых данных и оценки. Результаты, полученные от их алгоритма, были не идеальными, но дали очень хорошее решение.

4b9b3361

Ответ 1

Здесь мой TL; Резюме DR: он не знает, как минимизировать возвращаемое значение LinearTrial, которое принимает массив удвоений. Каждое значение в этом массиве имеет собственное значение min/max, и он моделирует, используя Decisions.

Если это правильно, похоже, вы могли бы просто сделать следующее:

double[] minimums = Parameters.Select(p => p.Value.Item1).ToArray();
double[] maximums = Parameters.Select(p => p.Value.Item2).ToArray();
// Some initial values, here it 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++;
}        

NelderMeadSolver является новым в MSF 3.0. Статический метод Solve "находит минимальное значение указанной функции" в соответствии с документацией в сборке MSF (несмотря на то, что документация MSDN пуста и показывает неправильную подпись функции).

Отказ от ответственности: я не эксперт MSF, но выше это работало для меня и моей целевой целевой функции (суммируйте веса).