Podczas laboratorium zaimplementujemy kilka klas pozwalających na reprezentację prostych wyrażeń matematycznych (funkcji jednej lub kilku zmiennych) jako grafów. Podobna reprezentacja jest rdzeniem funkcji oferowanych na przykład przez https://live.sympy.org/ lub https://www.derivative-calculator.net/. Nie będziemy jednak “parsowali” wyrażeń, czyli budowali grafowej reprezentacji na podstawie specyfikacji tekstowej. Zamiast tego, wyrażenia będą budowane za pomocą odpowiednio skonstruowanego kodu.
Założona funkcjonalność:
Przeanalizujmy wyrażenie $ 2x^3 + x^2 -2x + 7 $
Jego elementami są:
Power(arg,p)
Prod(args…)
Sum(args…)
Wyrażenie $ 2x^3 + x^2 -2x + 7 $ może być zapisane jako Sum(Prod(2,Power(x,3)),Power(x,2),Prod(-2,x),7)
. Zakładając, że każdy z tych elementów będzie obiektem, otrzymamy reprezentację w postaci acyklicznego grafu, jak na poniższym rysunku. Węzłami grafu są stałe, zmienne, operacje i funkcje, natomiast krawędzie odpowiadają argumentom poszczególnych operacji.
W zasadzie jest to drzewo, którego liśćmi są zmienne i stałe. Ponieważ zmienne mogą powtarzać się, liście będące zmiennymi zostały złączone
Zaimplementujemy więc klasy, jak na poniższym diagramie i dodamy wspólnego przodka, abstrakcyjną klasę Node
. Niebieskie linie to asocjacje/agregacje łączące węzły nadrzędne (opreacje, funkcje) i ich argumenty.
Power
jest jakieś wyrażenie, czyli Node
.Sum
może mieć więcej argumentów, stąd agregacja elementów Node
Prod
(product) to iloczyn większej liczby czynników Node
abstract public class Node { int sign=1; Node minus(){ sign = -1; return this; } Node plus(){ sign = 1; return this; } int getSign(){return sign;} /** * Oblicza wartość wyrażenia dla danych wartości zmiennych * występujących w wyrażeniu */ abstract double evaluate(); /** * * zwraca tekstową reprezentację wyrażenia */ public String toString(){return "";} /** * * Zwraca liczbę argumentów węzła */ int getArgumentsCount(){return 0;} }
W klasie Node
wprowadzono atrybut sign
znak, dziedziczony przez klasy potomne. Potraktujmy to następująco. Załóżmy, że reprezentacją tekstową węzła jest abcd
sign<0
reprezentacją tekstową będzie -(abcd)
[w nawiasach]sign>=0
będzie to po prostu abcd
[bez nawiasów]public class Constant extends Node { double value; Constant(double value){ this.sign = value<0?-1:1; this.value = value<0?-value:value; } @Override double evaluate() { return sign*value; } @Override public String toString() { String sgn=sign<0?"-":""; // return sgn+Double.toString(value); DecimalFormat format = new DecimalFormat("0.#####",new DecimalFormatSymbols(Locale.US)); return sgn+format.format(value); } }
Stosując DecimalFormat
pozbędziemy się niepotrzebnych zer na końcu wartości double
.
Klasa Variable
reprezentuje zmienną, która może być użyta w wyrażeniach.
public class Variable extends Node { String name; Double value; Variable(String name){ this.name = name; } void setValue(double d){ value = d; // value = d<0?-value:value; // sign = d<0?-1:1; } @Override double evaluate() { //return sign*value; return value; } @Override public String toString() { String sgn=sign<0?"-":""; return sgn+name; } }
Power
jest jedyną zaimplementowaną funkcją. Zauważmy, że $Power(x,-1)=\frac{1}{x}$. Argumentem Power
nie musi być pojedyncza zmienna. Może to być np.:
Power(Sum(x,2),-2)
, czyli $\frac{1}{(x+2)^2}$
W kodzie pokazano przykładową implementację toString()
z próbą wstawienia nawiasów w takich przypadkach, jak $-(-x^5)$ lub $(x+1)^2$
public class Power extends Node { double p; Node arg; Power(Node n,double p){ arg = n; this.p = p; } @Override double evaluate() { double argVal = arg.evaluate(); return Math.pow(argVal,p); } int getArgumentsCount(){return 1;} @Override public String toString() { StringBuilder b = new StringBuilder(); if(sign<0)b.append("-"); int argSign = arg.getSign(); int cnt = arg.getArgumentsCount(); boolean useBracket = false; if(argSign<0 ||cnt>1)useBracket = true; String argString = arg.toString(); if(useBracket)b.append("("); b.append(argString); if(useBracket)b.append(")"); b.append("^"); b.append(p); return b.toString(); } }
Klasa Sum
jest wyrażeniem reprezentującą sumę argumentów. Zawiera listę węzłów List<Node> args = new ArrayList<>();
Teoretycznie, lista argumentów może liczyć 0,1,2,… elementów. Metoda add()
dodaje składniki do listy
public class Sum extends Node { List<Node> args = new ArrayList<>(); Sum(){} Sum(Node n1, Node n2){ args.add(n1); args.add(n2); } Sum add(Node n){ args.add(n); return this; } Sum add(double c){ args.add(new Constant(c)); return this; } Sum add(double c, Node n) { Node mul = new Prod(c,n); args.add(mul); return this; } @Override double evaluate() { double result =0; oblicz sumę wartości zwróconych przez wywołanie evaluate skłądników sumy return sign*result; } int getArgumentsCount(){return args.size();} public String toString(){ StringBuilder b = new StringBuilder(); if(sign<0)b.append("-("); //zaimplementuj if(sign<0)b.append(")"); return b.toString(); } }
Prod
to iloczyn (ang. product). Reprezentuje wyrażenie będące iloczynem czynników. Metoda mul()
dodaje czynnik do listy.
public class Prod extends Node { List<Node> args = new ArrayList<>(); Prod(){} Prod(Node n1){ args.add(n1); } Prod(double c){ wywołaj konstruktor jednoargumentowy przekazując new Constant(c) } Prod(Node n1, Node n2){ args.add(n1); args.add(n2); } Prod(double c, Node n){ wywołaj konstruktor dwuargumentowy } Prod mul(Node n){ args.add(n); return this; } Prod mul(double c){ ??? } @Override double evaluate() { double result =1; // oblicz iloczyn czynników wołąjąc ich metodę evaluate return sign*result; } int getArgumentsCount(){return args.size();} public String toString(){ StringBuilder b = new StringBuilder(); if(sign<0)b.append("-"); // ... zaimplementuj return b.toString(); } }
static void buildAndPrint(){ Variable x = new Variable("x"); Node exp = new Sum() .add(2.1,new Power(x,3)) .add(new Power(x,2)) .add(-2,x) .add(7); System.out.println(exp.toString()); }
Oczekiwany wynik: 2.1*x^3 + x^2 + (-2)*x + 7
static void buildAndEvaluate(){ Variable x = new Variable("x"); Node exp = new Sum() .add(new Power(x,3)) .add(-2,new Power(x,2)) .add(-1,x) .add(2); for(double v=-5;v<5;v+=0.1){ x.setValue(v); System.out.printf(Locale.US,"f(%f)=%f\n",v,exp.evaluate()); }
Sprawdź, jakie są pierwiastki? Możesz użyć
static void defineCircle(){ Variable x = new Variable("x"); Variable y = new Variable("y"); Node circle = new Sum() .add(new Power(x,2)) .add(new Power(y,2)) .add(8,x) .add(4,y) .add(16); System.out.println(circle.toString()); double xv = 100*(Math.random()-.5); double yv = 100*(Math.random()-.5); x.setValue(xv); y.setValue(yv); double fv = circle.evaluate(); System.out.print(String.format("Punkt (%f,%f) leży %s koła %s",xv,yv,(fv<0?"wewnątrz":"na zewnątrz"),circle.toString())); }
Znajdź i wypisz 100 punktów leżących wewnątrz okręgu…. Oczywiście napisz kod, który je znajduje
Zadanie do realizacji w domu.
Pochodna wyrażenia jest również wyrażeniem… Dodajmy metodę diff()
w klasie Node
abstract Node diff(Variable var);
Dodajmy jeszcze metodę
abstract boolean isZero();
która będzie służyła do optymalizacji wywołań (pomijamy wyrażenia o wartości 0).
Zawsze pochodną stałej jest zero.
@Override Node diff(Variable var) { return new Constant(0); }
Pochodna $\frac{d}{dx}(x)=1$, natomiast $\frac{d}{dx}(y)=0$
Node diff(Variable var) { if(var.name.equals(name))return new Constant(sign); else return new Constant(0); }
Z definicji $\frac{d}{dx}(x^n)=nx^{n-1}$, ale tak naprawdę powinniśmy potraktować to jako złożenie funkcji $Power(arg(x)),p$, stąd
$$\frac{d}{dx}(arg(x)^n) = n\cdot arg(x)^{n-1}\cdot \frac{d}{dx}arg(x)$$
Node diff(Variable var) { Prod r = new Prod(sign*p,new Power(arg,p-1)); r.mul(arg.diff(var)); return r; }
Pochodna sumy jest sumą pochodnych. Najprostsza implementacja jest podana poniżej.
Node diffVanilla(Variable var) { Sum r = new Sum(); for(Node n:args){ r.add(n.diff(var)); } return r; }
Niestety, dużo pochodnych składowych będzie zerowych. Stąd propozycja usprawnienia przez sprawdzenie przed dodaniem, czy wyrażenie nie jest zerem.
Ogólny algorytm iloczynu jest podany np. tu https://en.wikipedia.org/wiki/Product_rule.
Zauważmy, że stosuje się to także do funkcji stałych (w projekcie Constant
):
$$\frac{d}{dx}(2\cdot f(x))=\frac{d}{dx}(2)\cdot f(x) + 2\cdot \frac{d}{dx}f(x)$$ $$=0\cdot f(x) + 2\cdot \frac{d}{dx} f(x)$$
Stąd najprostsza implementacja ma postać:
Node diffVanilla(Variable var) { Sum r = new Sum(); for(int i=0;i<args.size();i++){ Prod m= new Prod(); for(int j=0;j<args.size();j++){ Node f = args.get(j); if(j==i)m.mul(f.diff(var)); else m.mul(f); } r.add(m); } return r; }
Niestety, w jej wyniku może powstać sporo wyrażeń zerowych…
static void diffPoly() { Variable x = new Variable("x"); Node exp = new Sum() .add(2,new Power(x,3)) .add(new Power(x,2)) .add(-2,x) .add(7); System.out.print("exp="); System.out.println(exp.toString()); Node d = exp.diff(x); System.out.print("d(exp)/dx="); System.out.println(d.toString()); }
Wynik
exp=2*x^3 + x^2 + (-2)*x + 7 d(exp)/dx=0*x^3 + 2*3*x^2*1 + 2*x^1*1 + 0*x + (-2)*1 + 0
static void diffCircle() { Variable x = new Variable("x"); Variable y = new Variable("y"); Node circle = new Sum() .add(new Power(x,2)) .add(new Power(y,2)) .add(8,x) .add(4,y) .add(16); System.out.print("f(x,y)="); System.out.println(circle.toString()); Node dx = circle.diff(x); System.out.print("d f(x,y)/dx="); System.out.println(dx.toString()); System.out.print("d f(x,y)/dy="); Node dy = circle.diff(y); System.out.println(dy.toString()); }
Wynik
f(x,y)=x^2 + y^2 + 8*x + 4*y + 16 d f(x,y)/dx=2*x^1*1 + 2*y^1*0 + 0*x + 8*1 + 0*y + 4*0 + 0 d f(x,y)/dy=2*x^1*0 + 2*y^1*1 + 0*x + 8*0 + 0*y + 4*1 + 0
Pomijaj przy sumowaniu wyrażenia zerowe Przed utworzeniem węzłów Sum
i Prod
umieść wyrażenia na listach.
new Constant(0)
Wynik dla circle:
f(x,y)=x^2 + y^2 + 8*x + 4*y + 16 d f(x,y)/dx=2*x^1*1 + 8*1 d f(x,y)/dy=2*y^1*1 + 4*1
Dodaj metodę simplify()
, która zastąpi iloczyn stałych pojedynczą stałą. Spłaszcz strukturę Constant()*Product(args)
do pojedynczego iloczynu.
exp=2*x^3 + x^2 + (-2)*x + 7 d(exp)/dx=6*x^2 + 2*x^1 + (-2) f(x,y)=x^2 + y^2 + 8*x + 4*y + 16 d f(x,y)/dx=2*x^1 + 8 d f(x,y)/dy=2*y^1 + 4
Dodaj klasy odpowiadające innym funkcjom, np. exp(), log(), sin(), cos(), itd… A w przyszłości może uda się rozwinąć program do postaci podobnej do https://www.derivative-calculator.net/
Dla zainteresowanych
Zaimplementuj metodę expand() na podstawie https://en.wikipedia.org/wiki/Multinomial_theorem
Na pewno interesującym problemem jest tu generacja wszystkich krotek $(k_1,k_2,\dots,k_m)$ spełniających $k_1+\dots+k_m=n$
Dla zainteresowanych. Nie jest to zadanie do wykonania, ale gotowy kod do poeksperymentowania…
O metodzie możesz przeczytać tu https://pl.wikipedia.org/wiki/Metoda_gradientu_prostego.
Jest to podstawowa metoda stosowana w uczeniu maszynowym. Zmiennymi są wagi modelu, w kolejnych iteracjach są one uaktualniane, aby zminimalizować funkcję celu.
W przypadku wielu klasycznych algorytmów funkcja celu jest funkcją wypukłą i metoda zmierza do minimum globalnego. Dla sieci neuronowych z reguły funkcja ma wiele minimów lokalnych i proces optymalizacji może zmierzać do jednego z nich.
Kluczowym elementem współczesnych implementacji jest symboliczne wyznaczenie pochodnych w postaci grafu obliczeniowego, który może być wykonywany na GPU.
W poniższym przykładzie minimalizowana jest funkcja celu
$$f(x_0,\dots,x_{n-1})=\sum_{i=0}^{n-1}a_i x_i^2$$
Jej współczynniki $a_i$ oraz początkowe wartości zmiennych $x_i$ są losowane, stąd za każdym razem przebieg będzie inny. Dla konkretnej funkcji celu mozna/należy eksperymentalnie dobrać liczbę iteracji maxIter
oraz stałą uczenia learningRate
.
static void testOptimization(){ // rozmiar problemu int n=10; // hiperparametry int maxIter=1000; double learningRate=0.1; Random rand = new Random(); // Utwórz zmienne List<Variable> vars= new ArrayList<>(); for(int i=0;i<n;i++){ vars.add(new Variable("var"+i)); } // Zdefiniuj funkcję celu jako sum(a_i*x_i^2) Sum goal = new Sum(); for(int i=0;i<n;i++){ double a = rand.nextDouble(); Node b = new Power(vars.get(i),2); goal.add(new Prod(new Constant(a),b)); } // Wyznacz symbolicznie gradienty funkcji celu względem zmiennych x_i ArrayList<Node> grads = new ArrayList<>(); for(int i=0;i<vars.size();i++){ grads.add(goal.diff(vars.get(i))); } // Wylosuj poczatkowe wartosci zmiennych z przedziału [-500,500] for(int i=0;i<vars.size();i++){ vars.get(i).setValue(rand.nextDouble()*1000-500); } // iteracja double[]grad_values = new double[n]; for(int iter=0;iter<maxIter;iter++){ // oblicz wartosc funkcji celu double goal_value = goal.evaluate(); System.out.printf(Locale.US,"[%d] goal:%f\n",iter,goal_value); // oblicz wartosci gradientów // symboliczne gradienty korzystają z tych samych zmiennych, co funkcja celu for(int i=0;i<n;i++){ grad_values[i] = grads.get(i).evaluate(); } // uaktualnij wartosci zmiennych wg. wzoru x_i = x_i-lr*gradient_i for(int i=0;i<n;i++){ Variable v = vars.get(i); v.setValue(v.getValue()-learningRate*grad_values[i]); } } double goal_value = goal.evaluate(); System.out.printf(Locale.US,"[at end] goal:%f",goal_value); }
Poniżej przykładowy wynik (bardzo udany, często są znacznie gorsze). Oczywiście rozwiązaniem jest wektor z samymi zerami. Jeśli chcesz możesz wydrukować wartości rozwiązania w kolejnych iteracjach.
[0] goal:497945.411139 [1] goal:358421.084154 [2] goal:261261.945738 [3] goal:193012.852980 [4] goal:144625.847295 [5] goal:109985.516384 [6] goal:84935.043961 [7] goal:66631.223694 [8] goal:53116.025550 [9] goal:43031.027181 [10] goal:35426.331320 [11] goal:29632.149331 [12] goal:25172.079663 [13] goal:21704.227883 [14] goal:18980.992937 [15] goal:16821.424551 [16] goal:15092.089356 [17] goal:13693.727905 [18] goal:12551.876689 [19] goal:11610.222737 [20] goal:10825.854697 [21] goal:10165.839926 [22] goal:9604.736015 [23] goal:9122.766116 [24] goal:8704.469798 [25] goal:8337.697383 [26] goal:8012.854503 [27] goal:7722.330436 [28] goal:7460.062523 [29] goal:7221.202133 [30] goal:7001.856962 [31] goal:6798.891146 [32] goal:6609.769403 [33] goal:6432.434965 [34] goal:6265.213551 [35] goal:6106.737536 [36] goal:5955.885852 [37] goal:5811.736192 [38] goal:5673.526897 [39] goal:5540.626461 [40] goal:5412.509076 [41] goal:5288.734975 [42] goal:5168.934585 [43] goal:5052.795730 [44] goal:4940.053275 [45] goal:4830.480728 [46] goal:4723.883416 [47] goal:4620.092930 [48] goal:4518.962598 [49] goal:4420.363779 [50] goal:4324.182846 [51] goal:4230.318695 [52] goal:4138.680713 [53] goal:4049.187102 [54] goal:3961.763501 [55] goal:3876.341844 [56] goal:3792.859423 [57] goal:3711.258105 [58] goal:3631.483691 [59] goal:3553.485375 [60] goal:3477.215298 [61] goal:3402.628175 [62] goal:3329.680984 [63] goal:3258.332703 [64] goal:3188.544092 [65] goal:3120.277506 [66] goal:3053.496740 [67] goal:2988.166896 [68] goal:2924.254268 [69] goal:2861.726251 [70] goal:2800.551250 [71] goal:2740.698617 [72] goal:2682.138585 [73] goal:2624.842215 [74] goal:2568.781350 [75] goal:2513.928574 [76] goal:2460.257174 [77] goal:2407.741111 [78] goal:2356.354986 [79] goal:2306.074019 [80] goal:2256.874024 [81] goal:2208.731386 [82] goal:2161.623042 [83] goal:2115.526466 [84] goal:2070.419647 [85] goal:2026.281077 [86] goal:1983.089737 [87] goal:1940.825080 [88] goal:1899.467022 [89] goal:1858.995924 [90] goal:1819.392589 [91] goal:1780.638243 [92] goal:1742.714527 [93] goal:1705.603490 [94] goal:1669.287573 [95] goal:1633.749605 [96] goal:1598.972792 [97] goal:1564.940705 [98] goal:1531.637280 [99] goal:1499.046798 [100] goal:1467.153887 [101] goal:1435.943510 [102] goal:1405.400956 [103] goal:1375.511837 [104] goal:1346.262076 [105] goal:1317.637902 [106] goal:1289.625846 [107] goal:1262.212729 [108] goal:1235.385659 [109] goal:1209.132025 [110] goal:1183.439489 [111] goal:1158.295979 [112] goal:1133.689687 [113] goal:1109.609061 [114] goal:1086.042797 [115] goal:1062.979840 [116] goal:1040.409370 [117] goal:1018.320804 [118] goal:996.703788 [119] goal:975.548192 [120] goal:954.844103 [121] goal:934.581826 [122] goal:914.751874 [123] goal:895.344965 [124] goal:876.352018 [125] goal:857.764147 [126] goal:839.572661 [127] goal:821.769055 [128] goal:804.345008 [129] goal:787.292377 [130] goal:770.603199 [131] goal:754.269678 [132] goal:738.284191 [133] goal:722.639277 [134] goal:707.327635 [135] goal:692.342124 [136] goal:677.675756 [137] goal:663.321693 [138] goal:649.273247 [139] goal:635.523871 [140] goal:622.067161 [141] goal:608.896850 [142] goal:596.006808 [143] goal:583.391036 [144] goal:571.043663 [145] goal:558.958946 [146] goal:547.131266 [147] goal:535.555123 [148] goal:524.225138 [149] goal:513.136045 [150] goal:502.282695 [151] goal:491.660047 [152] goal:481.263168 [153] goal:471.087234 [154] goal:461.127522 [155] goal:451.379411 [156] goal:441.838382 [157] goal:432.500011 [158] goal:423.359968 [159] goal:414.414018 [160] goal:405.658017 [161] goal:397.087908 [162] goal:388.699724 [163] goal:380.489582 [164] goal:372.453682 [165] goal:364.588305 [166] goal:356.889813 [167] goal:349.354647 [168] goal:341.979322 [169] goal:334.760430 [170] goal:327.694634 [171] goal:320.778670 [172] goal:314.009344 [173] goal:307.383531 [174] goal:300.898171 [175] goal:294.550271 [176] goal:288.336904 [177] goal:282.255201 [178] goal:276.302359 [179] goal:270.475633 [180] goal:264.772337 [181] goal:259.189843 [182] goal:253.725579 [183] goal:248.377028 [184] goal:243.141726 [185] goal:238.017265 [186] goal:233.001285 [187] goal:228.091477 [188] goal:223.285583 [189] goal:218.581393 [190] goal:213.976744 [191] goal:209.469518 [192] goal:205.057644 [193] goal:200.739094 [194] goal:196.511886 [195] goal:192.374076 [196] goal:188.323766 [197] goal:184.359095 [198] goal:180.478244 [199] goal:176.679433 [200] goal:172.960917 [201] goal:169.320993 [202] goal:165.757991 [203] goal:162.270277 [204] goal:158.856253 [205] goal:155.514354 [206] goal:152.243050 [207] goal:149.040842 [208] goal:145.906263 [209] goal:142.837879 [210] goal:139.834284 [211] goal:136.894105 [212] goal:134.015997 [213] goal:131.198642 [214] goal:128.440753 [215] goal:125.741068 [216] goal:123.098353 [217] goal:120.511401 [218] goal:117.979029 [219] goal:115.500081 [220] goal:113.073424 [221] goal:110.697951 [222] goal:108.372577 [223] goal:106.096240 [224] goal:103.867902 [225] goal:101.686546 [226] goal:99.551177 [227] goal:97.460821 [228] goal:95.414525 [229] goal:93.411357 [230] goal:91.450403 [231] goal:89.530770 [232] goal:87.651584 [233] goal:85.811988 [234] goal:84.011144 [235] goal:82.248233 [236] goal:80.522453 [237] goal:78.833017 [238] goal:77.179158 [239] goal:75.560122 [240] goal:73.975174 [241] goal:72.423592 [242] goal:70.904672 [243] goal:69.417722 [244] goal:67.962068 [245] goal:66.537047 [246] goal:65.142012 [247] goal:63.776330 [248] goal:62.439381 [249] goal:61.130557 [250] goal:59.849264 [251] goal:58.594922 [252] goal:57.366960 [253] goal:56.164821 [254] goal:54.987961 [255] goal:53.835846 [256] goal:52.707952 [257] goal:51.603770 [258] goal:50.522798 [259] goal:49.464547 [260] goal:48.428537 [261] goal:47.414299 [262] goal:46.421374 [263] goal:45.449311 [264] goal:44.497671 [265] goal:43.566024 [266] goal:42.653947 [267] goal:41.761027 [268] goal:40.886862 [269] goal:40.031054 [270] goal:39.193219 [271] goal:38.372975 [272] goal:37.569954 [273] goal:36.783791 [274] goal:36.014132 [275] goal:35.260629 [276] goal:34.522941 [277] goal:33.800735 [278] goal:33.093685 [279] goal:32.401472 [280] goal:31.723783 [281] goal:31.060313 [282] goal:30.410761 [283] goal:29.774836 [284] goal:29.152250 [285] goal:28.542722 [286] goal:27.945977 [287] goal:27.361746 [288] goal:26.789767 [289] goal:26.229781 [290] goal:25.681535 [291] goal:25.144783 [292] goal:24.619283 [293] goal:24.104798 [294] goal:23.601097 [295] goal:23.107952 [296] goal:22.625142 [297] goal:22.152449 [298] goal:21.689661 [299] goal:21.236569 [300] goal:20.792970 [301] goal:20.358663 [302] goal:19.933454 [303] goal:19.517152 [304] goal:19.109569 [305] goal:18.710521 [306] goal:18.319830 [307] goal:17.937321 [308] goal:17.562820 [309] goal:17.196160 [310] goal:16.837176 [311] goal:16.485708 [312] goal:16.141596 [313] goal:15.804687 [314] goal:15.474829 [315] goal:15.151875 [316] goal:14.835679 [317] goal:14.526099 [318] goal:14.222997 [319] goal:13.926236 [320] goal:13.635684 [321] goal:13.351210 [322] goal:13.072687 [323] goal:12.799990 [324] goal:12.532996 [325] goal:12.271586 [326] goal:12.015642 [327] goal:11.765051 [328] goal:11.519700 [329] goal:11.279478 [330] goal:11.044279 [331] goal:10.813996 [332] goal:10.588528 [333] goal:10.367772 [334] goal:10.151631 [335] goal:9.940007 [336] goal:9.732805 [337] goal:9.529934 [338] goal:9.331302 [339] goal:9.136820 [340] goal:8.946402 [341] goal:8.759962 [342] goal:8.577417 [343] goal:8.398685 [344] goal:8.223686 [345] goal:8.052343 [346] goal:7.884579 [347] goal:7.720318 [348] goal:7.559487 [349] goal:7.402015 [350] goal:7.247831 [351] goal:7.096866 [352] goal:6.949053 [353] goal:6.804326 [354] goal:6.662620 [355] goal:6.523873 [356] goal:6.388021 [357] goal:6.255005 [358] goal:6.124765 [359] goal:5.997243 [360] goal:5.872382 [361] goal:5.750127 [362] goal:5.630423 [363] goal:5.513216 [364] goal:5.398455 [365] goal:5.286087 [366] goal:5.176064 [367] goal:5.068336 [368] goal:4.962855 [369] goal:4.859575 [370] goal:4.758448 [371] goal:4.659430 [372] goal:4.562477 [373] goal:4.467546 [374] goal:4.374595 [375] goal:4.283581 [376] goal:4.194465 [377] goal:4.107207 [378] goal:4.021768 [379] goal:3.938111 [380] goal:3.856197 [381] goal:3.775990 [382] goal:3.697456 [383] goal:3.620558 [384] goal:3.545262 [385] goal:3.471536 [386] goal:3.399346 [387] goal:3.328660 [388] goal:3.259448 [389] goal:3.191677 [390] goal:3.125318 [391] goal:3.060342 [392] goal:2.996719 [393] goal:2.934421 [394] goal:2.873422 [395] goal:2.813692 [396] goal:2.755207 [397] goal:2.697940 [398] goal:2.641865 [399] goal:2.586959 [400] goal:2.533195 [401] goal:2.480551 [402] goal:2.429003 [403] goal:2.378529 [404] goal:2.329105 [405] goal:2.280710 [406] goal:2.233323 [407] goal:2.186922 [408] goal:2.141487 [409] goal:2.096998 [410] goal:2.053435 [411] goal:2.010778 [412] goal:1.969009 [413] goal:1.928110 [414] goal:1.888061 [415] goal:1.848846 [416] goal:1.810447 [417] goal:1.772846 [418] goal:1.736029 [419] goal:1.699977 [420] goal:1.664675 [421] goal:1.630107 [422] goal:1.596259 [423] goal:1.563114 [424] goal:1.530659 [425] goal:1.498880 [426] goal:1.467761 [427] goal:1.437289 [428] goal:1.407451 [429] goal:1.378233 [430] goal:1.349623 [431] goal:1.321608 [432] goal:1.294176 [433] goal:1.267314 [434] goal:1.241010 [435] goal:1.215253 [436] goal:1.190032 [437] goal:1.165335 [438] goal:1.141151 [439] goal:1.117470 [440] goal:1.094281 [441] goal:1.071575 [442] goal:1.049340 [443] goal:1.027567 [444] goal:1.006247 [445] goal:0.985370 [446] goal:0.964927 [447] goal:0.944908 [448] goal:0.925306 [449] goal:0.906110 [450] goal:0.887314 [451] goal:0.868908 [452] goal:0.850885 [453] goal:0.833236 [454] goal:0.815953 [455] goal:0.799030 [456] goal:0.782458 [457] goal:0.766230 [458] goal:0.750340 [459] goal:0.734779 [460] goal:0.719542 [461] goal:0.704621 [462] goal:0.690010 [463] goal:0.675702 [464] goal:0.661692 [465] goal:0.647972 [466] goal:0.634538 [467] goal:0.621382 [468] goal:0.608500 [469] goal:0.595884 [470] goal:0.583531 [471] goal:0.571435 [472] goal:0.559589 [473] goal:0.547989 [474] goal:0.536630 [475] goal:0.525507 [476] goal:0.514615 [477] goal:0.503949 [478] goal:0.493504 [479] goal:0.483276 [480] goal:0.473260 [481] goal:0.463453 [482] goal:0.453848 [483] goal:0.444443 [484] goal:0.435233 [485] goal:0.426215 [486] goal:0.417383 [487] goal:0.408735 [488] goal:0.400266 [489] goal:0.391972 [490] goal:0.383851 [491] goal:0.375899 [492] goal:0.368111 [493] goal:0.360485 [494] goal:0.353017 [495] goal:0.345704 [496] goal:0.338542 [497] goal:0.331530 [498] goal:0.324662 [499] goal:0.317937 [500] goal:0.311352 [501] goal:0.304903 [502] goal:0.298588 [503] goal:0.292404 [504] goal:0.286348 [505] goal:0.280417 [506] goal:0.274610 [507] goal:0.268923 [508] goal:0.263354 [509] goal:0.257900 [510] goal:0.252560 [511] goal:0.247330 [512] goal:0.242209 [513] goal:0.237194 [514] goal:0.232282 [515] goal:0.227473 [516] goal:0.222763 [517] goal:0.218151 [518] goal:0.213635 [519] goal:0.209212 [520] goal:0.204881 [521] goal:0.200639 [522] goal:0.196486 [523] goal:0.192418 [524] goal:0.188435 [525] goal:0.184534 [526] goal:0.180715 [527] goal:0.176974 [528] goal:0.173311 [529] goal:0.169724 [530] goal:0.166211 [531] goal:0.162771 [532] goal:0.159402 [533] goal:0.156103 [534] goal:0.152873 [535] goal:0.149709 [536] goal:0.146611 [537] goal:0.143577 [538] goal:0.140606 [539] goal:0.137696 [540] goal:0.134847 [541] goal:0.132056 [542] goal:0.129324 [543] goal:0.126648 [544] goal:0.124028 [545] goal:0.121461 [546] goal:0.118948 [547] goal:0.116487 [548] goal:0.114077 [549] goal:0.111717 [550] goal:0.109406 [551] goal:0.107143 [552] goal:0.104926 [553] goal:0.102756 [554] goal:0.100630 [555] goal:0.098548 [556] goal:0.096510 [557] goal:0.094513 [558] goal:0.092558 [559] goal:0.090644 [560] goal:0.088769 [561] goal:0.086933 [562] goal:0.085135 [563] goal:0.083374 [564] goal:0.081650 [565] goal:0.079961 [566] goal:0.078308 [567] goal:0.076688 [568] goal:0.075102 [569] goal:0.073549 [570] goal:0.072028 [571] goal:0.070539 [572] goal:0.069080 [573] goal:0.067651 [574] goal:0.066253 [575] goal:0.064883 [576] goal:0.063541 [577] goal:0.062227 [578] goal:0.060941 [579] goal:0.059680 [580] goal:0.058447 [581] goal:0.057238 [582] goal:0.056055 [583] goal:0.054896 [584] goal:0.053761 [585] goal:0.052650 [586] goal:0.051561 [587] goal:0.050495 [588] goal:0.049451 [589] goal:0.048429 [590] goal:0.047428 [591] goal:0.046447 [592] goal:0.045487 [593] goal:0.044547 [594] goal:0.043626 [595] goal:0.042725 [596] goal:0.041841 [597] goal:0.040977 [598] goal:0.040130 [599] goal:0.039300 [600] goal:0.038488 [601] goal:0.037693 [602] goal:0.036913 [603] goal:0.036151 [604] goal:0.035403 [605] goal:0.034672 [606] goal:0.033955 [607] goal:0.033254 [608] goal:0.032566 [609] goal:0.031893 [610] goal:0.031234 [611] goal:0.030589 [612] goal:0.029957 [613] goal:0.029338 [614] goal:0.028732 [615] goal:0.028138 [616] goal:0.027556 [617] goal:0.026987 [618] goal:0.026429 [619] goal:0.025883 [620] goal:0.025349 [621] goal:0.024825 [622] goal:0.024312 [623] goal:0.023810 [624] goal:0.023318 [625] goal:0.022836 [626] goal:0.022364 [627] goal:0.021902 [628] goal:0.021450 [629] goal:0.021007 [630] goal:0.020573 [631] goal:0.020148 [632] goal:0.019731 [633] goal:0.019324 [634] goal:0.018925 [635] goal:0.018534 [636] goal:0.018151 [637] goal:0.017776 [638] goal:0.017409 [639] goal:0.017049 [640] goal:0.016697 [641] goal:0.016352 [642] goal:0.016014 [643] goal:0.015684 [644] goal:0.015360 [645] goal:0.015043 [646] goal:0.014732 [647] goal:0.014428 [648] goal:0.014130 [649] goal:0.013838 [650] goal:0.013552 [651] goal:0.013272 [652] goal:0.012998 [653] goal:0.012730 [654] goal:0.012467 [655] goal:0.012209 [656] goal:0.011957 [657] goal:0.011710 [658] goal:0.011468 [659] goal:0.011232 [660] goal:0.011000 [661] goal:0.010773 [662] goal:0.010550 [663] goal:0.010332 [664] goal:0.010119 [665] goal:0.009910 [666] goal:0.009705 [667] goal:0.009505 [668] goal:0.009309 [669] goal:0.009117 [670] goal:0.008928 [671] goal:0.008744 [672] goal:0.008563 [673] goal:0.008387 [674] goal:0.008213 [675] goal:0.008044 [676] goal:0.007878 [677] goal:0.007715 [678] goal:0.007556 [679] goal:0.007400 [680] goal:0.007247 [681] goal:0.007098 [682] goal:0.006951 [683] goal:0.006808 [684] goal:0.006667 [685] goal:0.006529 [686] goal:0.006395 [687] goal:0.006263 [688] goal:0.006133 [689] goal:0.006007 [690] goal:0.005883 [691] goal:0.005761 [692] goal:0.005642 [693] goal:0.005526 [694] goal:0.005412 [695] goal:0.005300 [696] goal:0.005191 [697] goal:0.005084 [698] goal:0.004979 [699] goal:0.004876 [700] goal:0.004775 [701] goal:0.004677 [702] goal:0.004580 [703] goal:0.004486 [704] goal:0.004393 [705] goal:0.004302 [706] goal:0.004214 [707] goal:0.004127 [708] goal:0.004042 [709] goal:0.003958 [710] goal:0.003876 [711] goal:0.003796 [712] goal:0.003718 [713] goal:0.003641 [714] goal:0.003566 [715] goal:0.003493 [716] goal:0.003421 [717] goal:0.003350 [718] goal:0.003281 [719] goal:0.003213 [720] goal:0.003147 [721] goal:0.003082 [722] goal:0.003018 [723] goal:0.002956 [724] goal:0.002895 [725] goal:0.002835 [726] goal:0.002777 [727] goal:0.002719 [728] goal:0.002663 [729] goal:0.002608 [730] goal:0.002555 [731] goal:0.002502 [732] goal:0.002450 [733] goal:0.002400 [734] goal:0.002350 [735] goal:0.002302 [736] goal:0.002254 [737] goal:0.002208 [738] goal:0.002162 [739] goal:0.002118 [740] goal:0.002074 [741] goal:0.002031 [742] goal:0.001989 [743] goal:0.001948 [744] goal:0.001908 [745] goal:0.001869 [746] goal:0.001830 [747] goal:0.001792 [748] goal:0.001755 [749] goal:0.001719 [750] goal:0.001684 [751] goal:0.001649 [752] goal:0.001615 [753] goal:0.001582 [754] goal:0.001549 [755] goal:0.001517 [756] goal:0.001486 [757] goal:0.001455 [758] goal:0.001425 [759] goal:0.001396 [760] goal:0.001367 [761] goal:0.001339 [762] goal:0.001311 [763] goal:0.001284 [764] goal:0.001258 [765] goal:0.001232 [766] goal:0.001206 [767] goal:0.001181 [768] goal:0.001157 [769] goal:0.001133 [770] goal:0.001110 [771] goal:0.001087 [772] goal:0.001064 [773] goal:0.001042 [774] goal:0.001021 [775] goal:0.001000 [776] goal:0.000979 [777] goal:0.000959 [778] goal:0.000939 [779] goal:0.000920 [780] goal:0.000901 [781] goal:0.000882 [782] goal:0.000864 [783] goal:0.000846 [784] goal:0.000829 [785] goal:0.000812 [786] goal:0.000795 [787] goal:0.000779 [788] goal:0.000763 [789] goal:0.000747 [790] goal:0.000731 [791] goal:0.000716 [792] goal:0.000702 [793] goal:0.000687 [794] goal:0.000673 [795] goal:0.000659 [796] goal:0.000645 [797] goal:0.000632 [798] goal:0.000619 [799] goal:0.000606 [800] goal:0.000594 [801] goal:0.000582 [802] goal:0.000570 [803] goal:0.000558 [804] goal:0.000546 [805] goal:0.000535 [806] goal:0.000524 [807] goal:0.000513 [808] goal:0.000503 [809] goal:0.000492 [810] goal:0.000482 [811] goal:0.000472 [812] goal:0.000462 [813] goal:0.000453 [814] goal:0.000444 [815] goal:0.000434 [816] goal:0.000426 [817] goal:0.000417 [818] goal:0.000408 [819] goal:0.000400 [820] goal:0.000391 [821] goal:0.000383 [822] goal:0.000376 [823] goal:0.000368 [824] goal:0.000360 [825] goal:0.000353 [826] goal:0.000345 [827] goal:0.000338 [828] goal:0.000331 [829] goal:0.000325 [830] goal:0.000318 [831] goal:0.000311 [832] goal:0.000305 [833] goal:0.000299 [834] goal:0.000292 [835] goal:0.000286 [836] goal:0.000281 [837] goal:0.000275 [838] goal:0.000269 [839] goal:0.000264 [840] goal:0.000258 [841] goal:0.000253 [842] goal:0.000248 [843] goal:0.000242 [844] goal:0.000237 [845] goal:0.000233 [846] goal:0.000228 [847] goal:0.000223 [848] goal:0.000218 [849] goal:0.000214 [850] goal:0.000210 [851] goal:0.000205 [852] goal:0.000201 [853] goal:0.000197 [854] goal:0.000193 [855] goal:0.000189 [856] goal:0.000185 [857] goal:0.000181 [858] goal:0.000177 [859] goal:0.000174 [860] goal:0.000170 [861] goal:0.000167 [862] goal:0.000163 [863] goal:0.000160 [864] goal:0.000157 [865] goal:0.000153 [866] goal:0.000150 [867] goal:0.000147 [868] goal:0.000144 [869] goal:0.000141 [870] goal:0.000138 [871] goal:0.000135 [872] goal:0.000133 [873] goal:0.000130 [874] goal:0.000127 [875] goal:0.000124 [876] goal:0.000122 [877] goal:0.000119 [878] goal:0.000117 [879] goal:0.000115 [880] goal:0.000112 [881] goal:0.000110 [882] goal:0.000108 [883] goal:0.000105 [884] goal:0.000103 [885] goal:0.000101 [886] goal:0.000099 [887] goal:0.000097 [888] goal:0.000095 [889] goal:0.000093 [890] goal:0.000091 [891] goal:0.000089 [892] goal:0.000087 [893] goal:0.000086 [894] goal:0.000084 [895] goal:0.000082 [896] goal:0.000080 [897] goal:0.000079 [898] goal:0.000077 [899] goal:0.000076 [900] goal:0.000074 [901] goal:0.000072 [902] goal:0.000071 [903] goal:0.000069 [904] goal:0.000068 [905] goal:0.000067 [906] goal:0.000065 [907] goal:0.000064 [908] goal:0.000063 [909] goal:0.000061 [910] goal:0.000060 [911] goal:0.000059 [912] goal:0.000058 [913] goal:0.000056 [914] goal:0.000055 [915] goal:0.000054 [916] goal:0.000053 [917] goal:0.000052 [918] goal:0.000051 [919] goal:0.000050 [920] goal:0.000049 [921] goal:0.000048 [922] goal:0.000047 [923] goal:0.000046 [924] goal:0.000045 [925] goal:0.000044 [926] goal:0.000043 [927] goal:0.000042 [928] goal:0.000041 [929] goal:0.000040 [930] goal:0.000040 [931] goal:0.000039 [932] goal:0.000038 [933] goal:0.000037 [934] goal:0.000036 [935] goal:0.000036 [936] goal:0.000035 [937] goal:0.000034 [938] goal:0.000034 [939] goal:0.000033 [940] goal:0.000032 [941] goal:0.000031 [942] goal:0.000031 [943] goal:0.000030 [944] goal:0.000030 [945] goal:0.000029 [946] goal:0.000028 [947] goal:0.000028 [948] goal:0.000027 [949] goal:0.000027 [950] goal:0.000026 [951] goal:0.000026 [952] goal:0.000025 [953] goal:0.000025 [954] goal:0.000024 [955] goal:0.000024 [956] goal:0.000023 [957] goal:0.000023 [958] goal:0.000022 [959] goal:0.000022 [960] goal:0.000021 [961] goal:0.000021 [962] goal:0.000020 [963] goal:0.000020 [964] goal:0.000020 [965] goal:0.000019 [966] goal:0.000019 [967] goal:0.000018 [968] goal:0.000018 [969] goal:0.000018 [970] goal:0.000017 [971] goal:0.000017 [972] goal:0.000017 [973] goal:0.000016 [974] goal:0.000016 [975] goal:0.000016 [976] goal:0.000015 [977] goal:0.000015 [978] goal:0.000015 [979] goal:0.000014 [980] goal:0.000014 [981] goal:0.000014 [982] goal:0.000013 [983] goal:0.000013 [984] goal:0.000013 [985] goal:0.000013 [986] goal:0.000012 [987] goal:0.000012 [988] goal:0.000012 [989] goal:0.000012 [990] goal:0.000011 [991] goal:0.000011 [992] goal:0.000011 [993] goal:0.000011 [994] goal:0.000010 [995] goal:0.000010 [996] goal:0.000010 [997] goal:0.000010 [998] goal:0.000010 [999] goal:0.000009 [at end] goal:0.000009