2012-10-10 42 views
18

程序目的:集成。我正在实现高维(高达100)的自适应正交(又名数值积分)算法。这个想法是通过使用与该点处的误差估计成比例的采样密度来评估点来将音量随机分成更小的部分。在我“初始化”一个统一样本的早期,然后根据估计误差上的高斯分布随机选择点。以类似于模拟退火的方式,随着时间的推移,我“降低温度”并降低我的高斯的标准偏差,所以低误差点最初具有被选择的合理机会,但随后选择稳定下降可能性。这使程序能够偶然发现由于错误功能中的缺陷而可能遗漏的尖峰。 (我的算法在本质上马尔可夫链蒙特卡罗整合类似。)使用Microsoft Solution Foundation定义目标

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

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

什么优化:错误排名。我的措施正常化,从零到一。这些错误值会随着集成的进行而逐步修改,以反映函数值,更改等的近期平均值。因此,我并不试图创建一个生成实际错误值的函数,而是生成一个与之相同的数字真正的误差,即如果所有的采样点都按这个估计的误差值排序,那么他们应该得到一个与他们按照真实误差排序会得到的排名相似的排名。

并非所有的点都相等。如果#1真正错误的点区域排名在#1000(反之亦然),我非常关心,但如果#500点排名在#1000,则非常小心。我衡量成功的标准是以下过在一个点上许多地区的总和MINIMIZE中途到算法的执行:

ABS(LOG 2(trueErrorRank) - LOG2(estimatedErrorRank))

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

我如何评估。通过真正的错误

  1. 队伍所有地区一次:我已经建立了一个名为排名类,做到这一点。

  2. 对于每个单独的一组参数化权重,它计算该区域的 试验(估计)误差。

  3. 按该试错误对区域进行排序。

  4. 计算每个地区的试验等级。

  5. 加起来两个队伍的日志的绝对差,并调用 这个参数化的值,因此,将被最小化 的值。

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/)。他们内尔德-Mead单纯求解器很容易拨打:

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中创建了一个模拟来设置测试数据并对其进行评分。他们算法的结果并不完美,但提供了一个很好的解决方案。

+4

我开始认为人们对“TLDNR”的一键式选择是UpVote。我可以通过提出一个令人难以置信的复杂问题来检验这个理论,并放弃一些先进的计算算法流行词和一些代码片段。呃,不要介意,我只需要为此付出代价。 :-) – kingdango

回答

4

这是我的TL; DR总结:他不知道如何最小化LinearTrial的返回值,这需要一个双倍数组。此数组中的每个值都有其自己的最小/最大值,并且使用Decisions对其进行建模。

如果这是正确的,看来你可能只是做到以下几点:

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是新的。根据MSF程序集中的文档(尽管MSDN文档空白并显示错误的函数签名),静态方法“找到指定函数的最小值”。

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

相关问题