1
+ let points , point_radius ;
2
+
3
+ let extent ;
4
+
5
+ let degree , thetas ;
6
+
7
+ let alpha = 1 ;
8
+
1
9
function update ( ) {
10
+ if ( points . length > 0 ) {
11
+ let temp_thetas = [ ] ;
12
+ for ( let i = 0 ; i < thetas . length ; i ++ ) {
13
+ temp_thetas . push ( 0 ) ;
14
+ }
15
+
16
+ for ( let j = 0 ; j < thetas . length ; j ++ ) {
17
+ let sum = 0 ;
18
+ for ( let i = 0 ; i < points . length ; i ++ ) {
19
+ sum += ( getY ( points [ i ] . x ) - points [ i ] . y ) * Math . pow ( points [ i ] . x , j ) ;
20
+ }
21
+ temp_thetas [ j ] = thetas [ j ] - alpha * sum / points . length ;
22
+ }
2
23
24
+ thetas = temp_thetas ;
25
+ updateParams ( "cost" ) ;
26
+ updateParams ( "coeffs" ) ;
27
+ }
3
28
}
4
29
5
30
function render ( ) {
31
+ context . fillStyle = "#000000" ;
32
+ context . fillRect ( 0 , 0 , canvas_width , canvas_height ) ;
33
+
34
+ context . strokeStyle = "#ffffff" ;
35
+ context . beginPath ( ) ;
36
+ context . moveTo ( 0 , canvas_height / 2 ) ;
37
+ context . lineTo ( canvas_width , canvas_height / 2 ) ;
38
+ context . stroke ( ) ;
6
39
40
+ context . beginPath ( ) ;
41
+ context . moveTo ( canvas_width / 2 , 0 ) ;
42
+ context . lineTo ( canvas_width / 2 , canvas_height ) ;
43
+ context . stroke ( ) ;
44
+
45
+ context . fillStyle = "#ffffff" ;
46
+ for ( let point of points ) {
47
+ context . beginPath ( ) ;
48
+ context . arc ( canvas_width / 2 + point . x * extent , canvas_height / 2 - point . y * extent , 5 , 0 , 2 * Math . PI ) ;
49
+ context . fill ( ) ;
50
+ }
51
+
52
+ context . fillStyle = "#0000ff" ;
53
+ for ( let x = - 1 ; x < 1 ; x += 1 / canvas_width ) {
54
+ let y = getY ( x ) ;
55
+ context . fillRect ( canvas_width / 2 + x * extent , canvas_height / 2 - y * extent , 2 , 2 ) ;
56
+ }
7
57
}
8
58
9
- function updateParams ( variable ) {
59
+ function getY ( x ) {
60
+ let value = 0 ;
61
+ for ( let i = 0 ; i < degree + 1 ; i ++ ) {
62
+ value += thetas [ i ] * Math . pow ( x , i ) ;
63
+ }
64
+ return value ;
65
+ }
10
66
67
+ function updateParams ( variable ) {
68
+ if ( variable == "degree" ) {
69
+ degree = Number . parseInt ( degree_input . value ) ;
70
+ degree_display . innerHTML = `Degree of fitting polynomial: ${ degree } ` ;
71
+ thetas = [ ] ;
72
+ for ( let i = 0 ; i < degree + 1 ; i ++ ) {
73
+ thetas . push ( 0 ) ;
74
+ }
75
+ updateParams ( "coeffs" ) ;
76
+ }
77
+ if ( variable == "alpha" ) {
78
+ alpha = Math . pow ( 10 , Number . parseFloat ( alpha_input . value ) ) ;
79
+ alpha_display . innerHTML = `Learning rate: ${ alpha . toFixed ( 3 ) } ` ;
80
+ }
81
+ if ( variable == "cost" ) {
82
+ if ( points . length > 0 ) {
83
+ cost_display . innerHTML = `Cost: ${ calculateCost ( ) . toFixed ( 6 ) } ` ;
84
+ }
85
+ else {
86
+ cost_display . innerHTML = "" ;
87
+ }
88
+ }
89
+ if ( variable == "coeffs" ) {
90
+ let string = "" ;
91
+ for ( let i = 0 ; i < thetas . length ; i ++ ) {
92
+ if ( i == 0 ) {
93
+ string += `${ thetas [ i ] . toFixed ( 6 ) } ` ;
94
+ }
95
+ else if ( i == 1 ) {
96
+ string += ` + ${ thetas [ i ] . toFixed ( 6 ) } x` ;
97
+ }
98
+ else {
99
+ string += ` + ${ thetas [ i ] . toFixed ( 6 ) } x<sup>${ i } </sup>` ;
100
+ }
101
+ }
102
+ coeffs_display . innerHTML = `Fitting polynomial: ${ string } ` ;
103
+ }
11
104
}
12
105
13
106
function initParams ( ) {
107
+ points = [ ] ;
108
+ point_radius = canvas_width / 40 ;
109
+ extent = canvas_width / 2 ;
110
+
111
+ updateParams ( "degree" ) ;
112
+ updateParams ( "alpha" ) ;
113
+ updateParams ( "cost" ) ;
114
+ updateParams ( "coeffs" ) ;
115
+ }
116
+
117
+ function calculateCost ( ) {
118
+ let sum = 0 ;
119
+ for ( let point of points ) {
120
+ sum += Math . pow ( getY ( point . x ) - point . y , 2 ) ;
121
+ }
122
+ return sum / ( 2 * points . length ) ;
123
+ }
124
+
125
+ function addPoint ( ) {
126
+ let x = ( click_x - canvas_width / 2 ) / extent ;
127
+ let y = ( canvas_height / 2 - click_y ) / extent ;
128
+
129
+ if ( ! checkPoint ( x , y ) ) {
130
+ points . push ( {
131
+ x : x ,
132
+ y : y
133
+ } ) ;
134
+ }
135
+ }
136
+
137
+ function checkPoint ( x , y ) {
138
+ for ( let point of points ) {
139
+ if ( Math . sqrt ( Math . pow ( x - point . x , 2 ) + Math . pow ( y - point . y , 2 ) ) < point_radius / extent ) {
140
+ points = points . filter ( p => p !== point ) ;
141
+ return true ;
142
+ }
143
+ }
144
+ return false ;
145
+ }
146
+
147
+ function resetTheta ( ) {
148
+ for ( let i = 0 ; i < thetas . length ; i ++ ) {
149
+ thetas [ i ] = 0 ;
150
+ }
151
+ updateParams ( "cost" ) ;
152
+ updateParams ( "coeffs" ) ;
153
+ }
14
154
155
+ function clearPoints ( ) {
156
+ points = [ ] ;
157
+ resetTheta ( ) ;
158
+ updateParams ( "cost" ) ;
159
+ updateParams ( "coeffs" ) ;
15
160
}
0 commit comments