2012-10-10 41 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文檔空白並顯示錯誤的函數簽名),靜態方法「找到指定函數的最小值」。

免責聲明:我不是無國界醫生的專家,但上述工作爲我和我的測試目標函數(總和權重)。

相關問題