2012-10-10 12 views
18

Cel programu: Integracja. Wprowadzam algorytm adaptacyjnej kwadratury (aka numerycznej integracji) dla wysokich wymiarów (do 100). Chodzi o to, aby losowo rozbić głośność na mniejsze sekcje, oceniając punkty, stosując gęstość próbkowania proporcjonalną do oszacowania błędu w tym punkcie. Na początku "wypalam" jednolitą próbkę, a następnie losowo wybieram punkty według rozkładu Gaussa ponad szacowany błąd. W podobny sposób do symulowanego wyżarzania, "obniżam temperaturę" i zmniejszam standardowe odchylenie mojego Gaussa w miarę upływu czasu, tak że punkty o niskim poziomie błędu początkowo mają spore szanse na bycie wybranymi, ale później są wybierane ze stale malejącym prawdopodobieństwo. Dzięki temu program może natknąć się na skoki, które mogą zostać pominięte z powodu niedoskonałości funkcji błędu. (Mój algorytm jest podobny w duchu do Złącze Markov-Chain Monte-Carlo.)Definiowanie celu za pomocą Microsoft Solution Foundation

Charakterystyka funkcji. Funkcja, która ma zostać zintegrowana, to szacowana utrata polisy ubezpieczeniowej dla wielu budynków z powodu klęski żywiołowej. Funkcje polityki nie są płynne: istnieją odliczenia, maksima, warstwy (na przykład zero wypłaty do 1 miliona dolarów straty, 100% wypłata z 1-2 milionów dolarów, potem zero wypłat powyżej 2 milionów dolarów) i inne dziwne warunki polityczne. Wprowadza to nieliniowe zachowanie i funkcje, które nie mają pochodnych w wielu płaszczyznach. Oprócz funkcji polityki jest funkcja obrażeń, która zależy od rodzaju budynku i siły huraganu i zdecydowanie nie ma kształtu dzwonka.

Problem Kontekst: Funkcja błędu. Trudność polega na wybraniu dobrej funkcji błędu. Dla każdego punktu zapisuję mi środki, które wydają się przydatne: wielkość funkcji, jak bardzo zmieniła się ona w wyniku poprzedniej miary (proxy dla pierwszej pochodnej), objętość regionu zajmowanego przez punkt (większe objętości mogą lepiej ukryj błąd) i czynnik geometryczny związany z kształtem regionu. Moja funkcja błędu będzie liniową kombinacją tych miar, w których każdemu działaniu przypisuje się inną wagę. (Jeśli otrzymam słabe wyniki, rozważę funkcje nieliniowe.) Aby pomóc mi w tych wysiłkach, postanowiłem przeprowadzić optymalizację w szerokim zakresie możliwych wartości dla każdej wagi, stąd Microsoft Solution Foundation.

Co zoptymalizować: Błąd w rankingu. Moje miary są znormalizowane, od zera do jednego. Te wartości błędów są stopniowo korygowane, ponieważ integracja postępuje w celu odzwierciedlenia ostatnich średnich dla wartości funkcji, zmian itp. W rezultacie nie próbuję utworzyć funkcji, która daje rzeczywiste wartości błędów, ale zamiast tego daje liczbę, która jest taka sama jak prawdziwy błąd, tj. jeśli wszystkie próbkowane punkty są sortowane według tej oszacowanej wartości błędu, powinny otrzymać pozycję podobną do rangi, jaką otrzymałyby po posortowaniu według prawdziwego błędu.

Nie wszystkie punkty są sobie równe. Bardzo mnie to obchodzi, jeśli region punktowy z błędem nr 1 jest w rankingu # 1000 (lub na odwrót), ale bardzo mało uwagi, jeśli punkt # 500 znajduje się w rankingu # 1000. Moja miarą sukcesu jest minimalizacja sumy następujących ciągu wielu regionach w punkcie partway do wykonania algorytmu jest:

ABS (log2 (trueErrorRank) - log2 (estimatedErrorRank))

Dla log2 używam funkcja, która zwraca największą moc dwóch mniejszą lub równą liczbie. Z tej definicji pochodzą przydatne wyniki. Zamiana # 1 i # 2 kosztuje punkt, ale zamiana # 2 i # 3 nic nie kosztuje. Powoduje to stratyfikację punktów do potęgi dwóch zakresów. Punkty zamienione w zakresie nie dodają do funkcji.

Jak oceniam.Mam zbudowany klasy o nazwie Rank, które wykonuje to:

  1. szeregach wszystkie regiony przez prawdziwego błędu raz.

  2. Dla każdego oddzielnego zestawu sparametryzowanych wag oblicza próbny (szacunkowy) błąd dla tego regionu.

  3. Sortuje regiony według tego błędu próbnego.

  4. Oblicza ranking prób dla każdego regionu.

  5. Dodaje bezwzględną różnicę dzienników obu rang i wywołuje tę wartość parametryzacji, a więc wartość jest zminimalizowana do wartości .

C# Kod. Po zrobieniu tego wszystkiego, potrzebuję tylko sposobu, aby skonfigurować Microsoft Solver Foundation, aby znaleźć mi najlepsze parametry. Składnia mnie zaskoczyła. Oto mój kod C#, który mam do tej pory. W nim zobaczysz komentarze do trzech problemów, które zidentyfikowałem:. Może możesz dostrzec jeszcze więcej! Jakieś pomysły, jak to działa?

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

UPDATE: postanowiłem poszukać innej biblioteki jako odwrotu i znalazł DotNumerics (http://dotnumerics.com/). Ich Nelder-Mead Simplex solver było łatwo zadzwonić:

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

Wszystko, co było potrzebne do wdrożenia ObjectiveFunction jako metoda podejmowania podwójne tablicy:

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

nie próbowałem go na rzeczywistych danych, ale Stworzyłem symulację w Excelu, aby ustawić dane testowe i zdobyć je. Wyniki wracające z ich algorytmu nie były doskonałe, ale dały bardzo dobre rozwiązanie.

+4

Zaczynam myśleć, że alternatywą dla "TLDNR" jest "UpVote". Mogę przetestować tę teorię, stawiając pytanie, które brzmi niesamowicie skomplikowane, upuszczając kilka zaawansowanych słów algorytmu buzz algorytmicznego i plusk fragmentów kodu. Eh, nieważne, zamiast tego wezmę to. :-) – kingdango

Odpowiedz

4

Oto moje podsumowanie TL; DR: Nie wie, jak zminimalizować wartość zwracaną przez LinearTrial, która pobiera tablicę podwójną. Każda wartość w tej tablicy ma swoją wartość min/max, a on modeluje ją przy użyciu Decisions.

Jeśli to prawda, wydaje się, można po prostu wykonaj następujące czynności:

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 nowego w MSF 3.0. Metoda statyczna "wyszukuje minimalną wartość określonej funkcji" zgodnie z dokumentacją w zespole MSF (mimo że dokumentacja MSDN jest pusta i zawiera złą sygnaturę funkcji).

Nota prawna: Nie jestem ekspertem od MSF, ale powyższe działanie zostało wykonane dla mnie i mojej funkcji celu testowego (podsumuj wagi).

Powiązane problemy