c# – 使用Microsoft Solution Foundation定义目标

计划目的:整合。我正在为高维数(最多100个)实现自适应正交(aka数值积分)算法。这个想法是通过使用与该点上的误差估计成正比的采样密度来评估点来随机地将体积分解成更小的部分。早在我的“老化”一个统一的样本,然后随机选择点按照高斯分布估计误差。以类似于模拟退火的方式,我“降低温度”并随着时间的推移降低了我的高斯的标准偏差,所以低误差点最初有一个很好的选择机会,但后来选择的是稳步下降的可能性。这使得程序可以绊倒由于错误功能中的缺陷而可能错过的尖峰。 (我的算法在精神上与马尔可夫链蒙特卡罗集成相似)。

功能特点整合功能是由于自然灾害而导致的多个建筑物的保险单损失。政策功能不顺利:有免赔额,最高限额,层次(例如零支付高达100万美元损失,100%支付从1-2百万美元,然后零支付超过200万美元)和其他奇怪的政策条款。这引入了在许多平面中没有导数的非线性行为和函数。在政策功能之上,是由于飓风的建筑类型和强度而有所不同的破坏功能,绝对不是钟形的。

问题背景:错误功能。困难在于选择一个很好的错误功能。对于每个点,我记录了对此有用的措施:函数的大小,由于以前的度量(一阶导数的代理)的结果而改变了多少,点占据的区域的体积(较大的体积可以隐藏错误更好),以及与区域形状相关的几何因子。我的错误功能将是这些措施的线性组合,其中每个度量被分配不同的权重。 (如果我得到不好的结果,我会考虑非线性函数。)为了帮助我做这个努力,我决定对每个权重的各种可能的值进行优化,因此是微软解决方案基金会。

什么优化:错误排名。我的措施正常化,从零到一。随着集成进行以反映函数值,变化等的最近平均值,这些错误值被逐渐修改。因此,我不是想产生一个产生实际错误值的函数,而是产生一个与真正的错误,即如果所有采样点按照该估计的误差值进行排序,则它们应该接收到与通过真实误差排序的等级相似的等级。

并不是所有的分数都相等。如果#1真正错误的点区域排名为#1000(反之亦然),我非常关心,但如果#500点排名为#1000,则很关心。我的成功措施是在算法执行的一个中间点,将许多地区的以下总和最小化:

ABS(Log2(trueErrorRank) – Log2(estimatedErrorRank))

对于Log2,我使用的函数返回两个小于或等于该数字的最大幂。从这个定义可以得出有用的结果。交换#1和#2花费了一点,但交换#2和#3没有任何成本。这具有将点分成两个范围的权力的效果。在一个范围内交换的点不会添加到该功能中。

我怎么评价我已经构建了一个名为Rank的类:

>通过真错误一次排列所有地区。
>对于每个单独的一组参数化权重,它计算
该地区的审判(估计)错误。
>按该试验错误对区域进行排序。
>计算每个地区的试用等级。
增加两个队列和通话记录的绝对差异
这个参数值的值,因此值就是
最小化。

C#代码。完成所有这些,我只需要一种方法来设置Microsoft Solver Foundation来找到我最好的参数。语法让我失望了这是我迄今为止的C#代码。在其中,您将看到我已经确定的三个问题的意见。也许你可以发现更多!任何想法如何使这项工作?

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

更新:我决定寻找另一个库作为后备,并找到了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中创建了一个模拟来设置测试数据并对其进行评分。从算法回归的结果并不完美,但给出了很好的解决方案。

这是我的TL; DR摘要:他不知道如何最小化LinearTrial的返回值,它需要一个双精度数组。该数组中的每个值都有自己的最小/最大值,并且他使用决策建模。

如果这是正确的,似乎你可以做以下:

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

NelderMeadSolver是MSF 3.0中的新功能。 Solve静态方法根据MSF程序集中的文档找到指定函数的最小值(尽管MSDN文档为空,显示错误的函数签名)。

免责声明:我不是无国界医生专家,但上述工作对我和我的测试目标函数(加权)。

http://stackoverflow.com/questions/12819916/defining-the-goal-using-microsoft-solution-foundation

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c# – 使用Microsoft Solution Foundation定义目标