1414 < canvas id ="grid " width ="600px " height ="600px "> </ canvas >
1515 < canvas id ="fn2 " width ="600px " height ="600px "> </ canvas >
1616 < canvas id ="gp_mean " width ="600px " height ="600px "> </ canvas >
17+ < canvas id ="gp_conv " width ="600px " height ="600px "> </ canvas >
18+ < canvas id ="gp_acq_pi " width ="600px " height ="600px "> </ canvas >
19+ < canvas id ="gp_acq_ei " width ="600px " height ="600px "> </ canvas >
20+ < canvas id ="gp_acq_scaled_ei " width ="600px " height ="600px "> </ canvas >
1721 < canvas id ="observations " width ="600px " height ="600px "> </ canvas >
1822</ div >
23+ < div style ="width:600px;height:600px;padding-left:620px ">
24+ < label > Kernel Parameter</ label > < input type ="range " min ="1 " max ="30 " value ="10 "
25+ onchange ="window.updateKernelParam(this.value); "> </ input >
26+ < br />
27+ < button onclick ="clearObservations() "> Clear Observations</ button >
28+ < br />
29+ < button onclick ="addRandomObservationPoint() "> Add random Observation Point</ button >
30+ < br />
31+ < button onclick ="addEiSuggestedObservationPoint() "> Add EI suggested Observation Point</ button >
32+ < br />
33+ < button onclick ="addScaledEiSuggestedObservationPoint() "> Add ScaledEI suggested Observation Point</ button >
34+ </ div >
35+
1936
2037< script src ="https://cdnjs.cloudflare.com/ajax/libs/mathjs/6.6.4/math.min.js "> </ script >
2138< script src ="graphplot.js " type ="module "> </ script >
2239< script type ="module ">
23- import { drawFunction , drawGrid , drawPoints , xPixToCoord , xCoordToPix } from './graphplot.js' ;
40+ import { clear , drawFunction , drawGrid , drawPoints , lineToPoints , xCoordToPix , xPixToCoord , yCoordToPix } from './graphplot.js' ;
2441
2542 const canvas = document . getElementById ( "grid" ) ;
2643 const config = {
27- xMin : - 0.2 ,
28- xMax : 3.4 ,
29- yMin : - 0 .2,
30- yMax : 4 .2,
44+ xMin : - 1 ,
45+ xMax : 2 ,
46+ yMin : - 2 .2,
47+ yMax : 2 .2,
3148 ctx : canvas . getContext ( "2d" )
3249 } ;
3350
4360 const configGpMean = Object . assign ( { } , config ) ;
4461 configGpMean . ctx = canvasGpMean . getContext ( "2d" ) ;
4562
63+ const canvasGpConv = document . getElementById ( "gp_conv" ) ;
64+ const configGpConv = Object . assign ( { } , config ) ;
65+ configGpConv . ctx = canvasGpConv . getContext ( "2d" ) ;
66+
67+ const canvasGpAcqPi = document . getElementById ( "gp_acq_pi" ) ;
68+ const configGpAcqPi = Object . assign ( { } , config ) ;
69+ configGpAcqPi . ctx = canvasGpAcqPi . getContext ( "2d" ) ;
70+
71+ const canvasGpAcqEi = document . getElementById ( "gp_acq_ei" ) ;
72+ const configGpAcqEi = Object . assign ( { } , config ) ;
73+ configGpAcqEi . ctx = canvasGpAcqEi . getContext ( "2d" ) ;
74+
75+ const canvasGpAcqScaledEi = document . getElementById ( "gp_acq_scaled_ei" ) ;
76+ const configGpAcqScaledEi = Object . assign ( { } , config ) ;
77+ configGpAcqScaledEi . ctx = canvasGpAcqScaledEi . getContext ( "2d" ) ;
78+
4679 drawGrid ( config ) ;
4780 const func = x => {
48- if ( ( x < 0 ) || ( x > Math . PI ) ) return 0 ;
49- let result = 0 ;
50- for ( let i = 1 ; i <= 10 ; i ++ ) {
51- result += Math . sin ( x ) * Math . pow ( Math . sin ( i * x * x / Math . PI ) , 20 ) ;
52- }
81+ let result = - x * Math . sin ( 10 * x ) ;
82+ if ( ( x < - 1 ) || ( x > 2 ) ) return - 2 ;
5383 return result ;
5484 } ;
55- drawFunction ( configF2 , "#000000" , func ) ;
56-
57- let observationsX = [ 0.2 , 0.5 , 0.9 , 1.2 , 1.5 , 1.6 , 1.7 , 1.8 , 1.9 , 2.0 , 2.1 , 2.5 , 2.8 , 3 ] ;
58- let observationsY = observationsX . map ( x => func ( x ) ) ;
59- let observations = observationsX . map ( x => [ x , func ( x ) ] ) ;
60- drawPoints (
61- configObs ,
62- "#0000FF" ,
63- observations
64- ) ;
85+ drawFunction ( configF2 , "#606060" , func ) ;
6586
66- const kernel = function ( x1 , x2 ) {
87+ const kernelWithParameter = function ( x1 , x2 , param ) {
6788 let n = math . norm ( math . subtract ( x1 , x2 ) ) ;
68- return math . exp ( - 0.5 * n * n ) ;
89+ return math . exp ( - 0.5 * param * n * n ) ;
6990 }
7091
7192 const K = function ( x0 , x1 , kernel ) {
81102 }
82103
83104 const posterioriMean = function ( x , x_new , sigma , y , kernel ) {
84- let scope = {
105+ const scope = {
85106 x_new : x_new ,
86107 x : x ,
87108 xl : x . length ,
88109 sigma : sigma ,
89110 y : y ,
90111 K : ( x1 , x2 ) => K ( x1 , x2 , kernel )
91- }
112+ } ;
113+ //Seite 8 Conditional of a joint Gaussian
114+ //http://cs229.stanford.edu/section/more_on_gaussians.pdf
115+ //und
116+ //GP-Buch Seite 15, 16
92117 return math . evaluate ( 'K(x_new,x) * inv(K(x,x) + sigma .* identity(xl)) * transpose(y)' , scope ) ;
93- }
118+ } ;
119+
120+ const posteriorCov = function ( x , x_new , sigma , kernel ) {
121+ const scope = {
122+ x : x ,
123+ xl : x . length ,
124+ sigma : sigma ,
125+ K : ( x1 , x2 ) => K ( x1 , x2 , kernel )
126+ } ;
94127
95- const zip = function ( a , b ) {
96- let zip = [ ] ;
97- for ( let i = 0 ; i < a . length ; i ++ ) {
98- zip . push ( [ a [ i ] , b [ i ] ] ) ;
128+ const r = [ ] ;
129+ const invSigma = math . evaluate ( 'inv(K(x,x) + sigma .* identity(xl))' , scope ) . valueOf ( ) ;
130+ for ( let x_i_new of x_new ) {
131+ const scope2 = {
132+ x_new : [ x_i_new ] ,
133+ x : x ,
134+ xl : x . length ,
135+ sigma : sigma ,
136+ K : ( x1 , x2 ) => K ( x1 , x2 , kernel ) ,
137+ invSigma : invSigma
138+ } ;
139+ const stdSqr = math . evaluate ( 'K(x_new, x_new) - K(x_new, x) * invSigma * K(x, x_new)' , scope2 ) . valueOf ( ) [ 0 ] [ 0 ] ;
140+ r . push ( math . abs ( stdSqr ) ) ;
99141 }
100- return zip ;
101- }
142+ return r ;
143+ } ;
102144
103- const x_new = [ ] ;
104- const xCoordStart = xCoordToPix ( config , - 0.2 ) ;
105- const xCoordEnd = xCoordToPix ( config , 3.4 ) ;
106- for ( let i = xCoordStart ; i < xCoordEnd ; i ++ ) {
107- x_new . push ( xPixToCoord ( config , i ) )
108- }
109- const y_new = posterioriMean ( observationsX , x_new , 1e-10 , observationsY , kernel ) . valueOf ( ) ;
110- const xy_new = zip ( x_new , y_new ) ;
111- drawPoints (
112- configGpMean ,
113- "#00FF00" ,
114- xy_new
115- ) ;
116- drawFunction ( configGpMean , "#00ff00" , ( x ) => {
117- const w = xCoordToPix ( config , x ) ;
118- return y_new [ w - xCoordStart ] ;
119- } ) ;
145+ const cdfNormal = function ( x ) {
146+ return ( 1 - math . erf ( - x / Math . sqrt ( 2 ) ) ) / 2 ;
147+ } ;
148+
149+ const pdfNormal = function ( x ) {
150+ const m = Math . sqrt ( 2 * Math . PI ) ;
151+ const e = Math . exp ( - Math . pow ( x , 2 ) / 2 ) ;
152+ return e / m ;
153+ } ;
154+
155+
156+ const acquisitionPI = function ( mean , standardDeviation , fMax ) {
157+ const pi = [ ] ;
158+ for ( let w = 0 ; w < mean . length ; w ++ ) {
159+ pi . push ( cdfNormal ( ( mean [ w ] - fMax ) / standardDeviation [ w ] , 0 , 1 ) ) ;
160+ }
161+ return pi ;
162+ } ;
163+
164+ const acquisitionEI = function ( mean , standardDeviation , fMax , xi ) {
165+ const eis = [ ] ;
166+ let maxValue = 0 ;
167+ let minValue = 1000 ;
168+
169+ for ( let w = 0 ; w < mean . length ; w ++ ) {
170+ if ( standardDeviation [ w ] === 0 ) {
171+ eis . push ( 0 ) ;
172+ continue ;
173+ }
174+ const std = standardDeviation [ w ] ;
175+ let dx = mean [ w ] - fMax - xi ;
176+ dx = Math . max ( - 7 , Math . min ( 7 , dx / std ) ) * std ;
177+ let z = dx / std ;
178+ let ei = dx * cdfNormal ( z ) + std * pdfNormal ( z ) ;
179+
180+ if ( isNaN ( ei ) ) {
181+ ei . push ( 0 ) ;
182+ continue ;
183+ }
184+
185+ maxValue = Math . max ( maxValue , ei ) ;
186+ minValue = Math . min ( minValue , ei ) ;
187+ eis . push ( ei ) ;
188+ }
189+ return eis . map ( v => ( v - minValue ) / ( maxValue - minValue ) ) ;
190+ } ;
191+
192+ const acquisitionScaledEI = function ( mean , standardDeviation , fMax , xi ) {
193+ const scaledEis = [ ] ;
194+ let maxValue = 0 ;
195+ let minValue = 1000 ;
196+
197+ for ( let w = 0 ; w < mean . length ; w ++ ) {
198+ if ( standardDeviation [ w ] === 0 ) {
199+ scaledEis . push ( 0 ) ;
200+ continue ;
201+ }
202+ const std = standardDeviation [ w ] ;
203+ let dx = mean [ w ] - fMax - xi ;
204+ dx = Math . max ( - 5 , Math . min ( 5 , dx / std ) ) * std ;
205+ let z = dx / std ;
206+ const ei = dx * cdfNormal ( z ) + std * pdfNormal ( z ) ;
207+ const vi = std * std * ( ( z * z + 1 ) * cdfNormal ( z ) + z * pdfNormal ( z ) ) - ei * ei ;
208+ const scaledEi = ei / math . sqrt ( vi ) ;
209+
210+ if ( isNaN ( scaledEi ) ) {
211+ scaledEis . push ( 0 ) ;
212+ continue ;
213+ }
214+
215+ maxValue = Math . max ( maxValue , scaledEi ) ;
216+ minValue = Math . min ( minValue , scaledEi ) ;
217+ scaledEis . push ( scaledEi ) ;
218+ }
219+ return scaledEis . map ( v => ( v - minValue ) / ( maxValue - minValue ) ) ;
220+ } ;
221+
222+ let observationsX = [ - 0.75 , 0.1 , 1.2 , 1.65 ] ;
223+ let observationsY = observationsX . map ( x => func ( x ) ) ;
224+ let observations = observationsX . map ( x => [ x , func ( x ) ] ) ;
225+ let kernelParam = 10 ;
226+ let acquisitionEi = [ ] ;
227+ let acquisitionScaledEi = [ ] ;
228+
229+ const drawAll = function ( ) {
230+ drawPoints (
231+ configObs ,
232+ "#0000FF" ,
233+ observations
234+ ) ;
235+
236+ const kernel = ( x1 , x2 ) => kernelWithParameter ( x1 , x2 , kernelParam ) ;
237+ const sigma = 0.000001 ;
238+ const x_new = [ ] ;
239+ const xCoordStart = xCoordToPix ( config , config . xMin ) ;
240+ const xCoordEnd = xCoordToPix ( config , config . xMax ) ;
241+ for ( let i = xCoordStart ; i < xCoordEnd ; i ++ ) {
242+ x_new . push ( xPixToCoord ( config , i ) )
243+ }
244+ const mean = posterioriMean ( observationsX , x_new , sigma , observationsY , kernel ) . valueOf ( ) ;
245+ drawFunction ( configGpMean , "#000000" , ( x ) => {
246+ const w = xCoordToPix ( config , x ) ;
247+ return mean [ w - xCoordStart ] ;
248+ } ) ;
249+
250+ const standardDeviation = posteriorCov ( observationsX , x_new , sigma , kernel ) ;
251+
252+ const xs = [ ...Array ( config . ctx . canvas . width ) . keys ( ) ] ;
253+ const ysU = xs . map ( x => {
254+ return mean [ x ] + 1.96 * standardDeviation [ x ] ;
255+ } ) ;
256+ const ysL = xs . map ( x => {
257+ return mean [ x ] - 1.96 * standardDeviation [ x ] ;
258+ } ) ;
259+ const acquisitionPi = acquisitionPI ( mean , standardDeviation , Math . max ( ...observationsY ) ) ;
260+ acquisitionEi = acquisitionEI ( mean , standardDeviation , Math . max ( ...observationsY ) , 0.01 ) ;
261+ acquisitionScaledEi = acquisitionScaledEI ( mean , standardDeviation , Math . max ( ...observationsY ) , 0 ) ;
262+
263+ clear ( configGpConv ) ;
264+ configGpConv . ctx . fillStyle = "#0000b050" ;
265+ configGpConv . ctx . lineWidth = 3 ;
266+ configGpConv . ctx . beginPath ( ) ;
267+ lineToPoints ( configGpConv , xs , ysU ) ;
268+ lineToPoints ( configGpConv , [ ...xs ] . reverse ( ) , [ ...ysL ] . reverse ( ) ) ;
269+ configGpConv . ctx . fill ( ) ;
270+
271+
272+ drawFunction ( configGpAcqEi , "#008000" , ( x ) => {
273+ const w = xCoordToPix ( config , x ) ;
274+ return acquisitionEi [ w - xCoordStart ] + config . yMin + 0.01 ;
275+ } ) ;
276+
277+ /*
278+ drawFunction(configGpAcqScaledEi, "#000080", (x) => {
279+ const w = xCoordToPix(config, x);
280+ return acquisitionScaledEi[w - xCoordStart] + config.yMin+0.01;
281+ });
282+ */
283+ } ;
284+
285+ window . updateKernelParam = function ( param ) {
286+ kernelParam = param ;
287+ drawAll ( ) ;
288+ } ;
289+ window . addRandomObservationPoint = function ( ) {
290+ const x = math . random ( ) * ( config . xMax - config . xMin ) + config . xMin ;
291+ observationsX . push ( x ) ;
292+ observationsY = observationsX . map ( x => func ( x ) ) ;
293+ observations = observationsX . map ( x => [ x , func ( x ) ] ) ;
294+ drawAll ( ) ;
295+ } ;
296+ window . addEiSuggestedObservationPoint = function ( ) {
297+ const observationsW = observationsX . map ( x => xCoordToPix ( config , x ) ) ;
298+ function argMax ( array ) {
299+ return array . map ( ( y , i ) => [ i , y ] ) . filter ( a => ! observationsW . includes ( a [ 0 ] ) ) . reduce ( ( r , a ) => ( a [ 1 ] > r [ 1 ] ? a : r ) ) [ 0 ] ;
300+ }
301+ const x = xPixToCoord ( config , argMax ( acquisitionEi ) ) ;
302+ observationsX . push ( x ) ;
303+ observationsY = observationsX . map ( x => func ( x ) ) ;
304+ observations = observationsX . map ( x => [ x , func ( x ) ] ) ;
305+ drawAll ( ) ;
306+ } ;
307+ window . addScaledEiSuggestedObservationPoint = function ( ) {
308+ const observationsW = observationsX . map ( x => xCoordToPix ( config , x ) ) ;
309+ function argMax ( array ) {
310+ return array . map ( ( y , i ) => [ i , y ] ) . filter ( a => ! observationsW . includes ( a [ 0 ] ) ) . reduce ( ( r , a ) => ( a [ 1 ] > r [ 1 ] ? a : r ) ) [ 0 ] ;
311+ }
312+ const w = argMax ( acquisitionScaledEi ) ;
313+ const x = xPixToCoord ( config , w ) ;
314+ observationsX . push ( x ) ;
315+ observationsY = observationsX . map ( x => func ( x ) ) ;
316+ observations = observationsX . map ( x => [ x , func ( x ) ] ) ;
317+ drawAll ( ) ;
318+ } ;
319+ window . clearObservations = function ( ) {
320+ observationsX = [ ] ;
321+ window . addRandomObservationPoint ( ) ;
322+ } ;
120323
324+ drawAll ( ) ;
121325</ script >
122326
123327
124328< script src ="https://polyfill.io/v3/polyfill.min.js?features=es6 "> </ script >
125329< script id ="MathJax-script " async
126330 src ="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js ">
127331</ script >
128- < div style ="width:600px;padding-top:620px ">
332+ < div style ="width:600px;padding-top:20px ">
129333 < h3 > Plot of function</ h3 >
130334
131335 < p >
132- \[ f(x) = \sum_{i=1}^{10}\sin(x)\ \sin(\frac{i\ x^2}{\pi})^{20} \]
336+ \[ f(x) = - x \sin(10 x) \]
133337 </ p >
134338</ div >
0 commit comments