-
Notifications
You must be signed in to change notification settings - Fork 1
/
smr.js
executable file
·157 lines (117 loc) · 3.87 KB
/
smr.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict'
var rref = require('rref')
function MatrixProduct(options) {
this.product = squareMatrix(options)
}
MatrixProduct.prototype.addRowAndColumn = function(options) {
for(var c = 0; c < options.lhsColumn.length; c++)
for(var r = 0; r < options.rhsRow.length; r++)
this.product[c][r] += options.lhsColumn[c] * options.rhsRow[r]
}
MatrixProduct.prototype.push = MatrixProduct.prototype.addRowAndColumn
function Regression(options) {
if(!options)
throw new Error('missing options')
if(!('numX' in options))
throw new Error(
'you must give the width of the X dimension as the property numX')
if(!('numY' in options))
throw new Error(
'you must give the width of the X dimension as the property numY')
this.transposeOfXTimesX = new MatrixProduct({
numRows: options.numX,
numColumns: options.numX
})
this.transposeOfXTimesY = new MatrixProduct({
numRows: options.numX,
numColumns: options.numY
})
this.identity = identity(options.numX)
}
Regression.prototype.addObservation = function(options) {
if(!options)
throw new Error('missing options')
if(!(options.x instanceof Array) || !(options.y instanceof Array))
throw new Error('x and y must be given as arrays')
this.transposeOfXTimesX.addRowAndColumn({
lhsColumn: options.x,
rhsRow: options.x
})
this.transposeOfXTimesY.addRowAndColumn({
lhsColumn: options.x,
rhsRow: options.y
})
// Adding an observation invalidates our coefficients.
delete this.coefficients
}
Regression.prototype.push = Regression.prototype.addObservation
Regression.prototype.calculateCoefficients = function() {
var xTx = this.transposeOfXTimesX.product
var xTy = this.transposeOfXTimesY.product
var inv = inverse(xTx, this.identity)
this.coefficients = multiply(inv, xTy)
return this.coefficients
}
Regression.prototype.calculate = Regression.prototype.calculateCoefficients
// Hypothesize a particular row of dependent variables
// from a row of independent variables.
// Lazily recalculate coefficients if necessary.
Regression.prototype.hypothesize = function(options) {
if(!options)
throw new Error('missing options')
if(!(options.x instanceof Array))
throw new Error('x property must be given as an array')
if(!this.coefficients) this.calculateCoefficients()
var hypothesis = []
for(var x = 0; x < this.coefficients.length; x++) {
var coefficientRow = this.coefficients[x]
for(var y = 0; y < coefficientRow.length; y++)
hypothesis[y] = (hypothesis[y] || 0) + coefficientRow[y] * options.x[x]
}
return hypothesis
}
exports.MatrixProduct = MatrixProduct
exports.Regression = Regression
exports.multiply = multiply
function inverse(matrix, identity) {
var size = matrix.length
var result = new Array(size)
for(var i = 0; i < size; i++)
result[i] = matrix[i].concat(identity[i])
result = rref(result)
for(var i = 0; i < size; i++) result[i].splice(0, size)
return result
}
function identity(size) {
var matrix = squareMatrix({ numRows: size, numColumns: size })
for(var i = 0; i < size; i++) matrix[i][i] = 1
return matrix
}
function multiply(lhs, rhs) {
var options = { numRows: lhs.length, numColumns: rhs[0].length }
var streamingProduct = new MatrixProduct(options)
for(var x = 0; x < rhs.length; x++) {
var lhsColumn = []
// Get the xth column of lhs.
for(var r = 0; r < lhs.length; r++)
lhsColumn.push(lhs[r][x])
// Get the xth row of rhs.
var rhsRow = rhs[x]
streamingProduct.addRowAndColumn({
lhsColumn: lhsColumn,
rhsRow: rhsRow
})
}
return streamingProduct.product
}
function squareMatrix(options) {
var matrix = new Array(options.numRows)
for(var r = 0; r < options.numRows; r++) {
var row = new Array(options.numColumns)
matrix[r] = row
for(var c = 0; c < options.numColumns; c++) {
row[c] = 0
}
}
return matrix
}