forked from josdejong/mathjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiag.js
More file actions
166 lines (145 loc) · 5.13 KB
/
diag.js
File metadata and controls
166 lines (145 loc) · 5.13 KB
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
158
159
160
161
162
163
164
165
166
import { isMatrix } from '../../utils/is.js'
import { arraySize } from '../../utils/array.js'
import { isInteger } from '../../utils/number.js'
import { factory } from '../../utils/factory.js'
const name = 'diag'
const dependencies = ['typed', 'matrix', 'DenseMatrix', 'SparseMatrix']
export const createDiag = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, DenseMatrix, SparseMatrix }) => {
/**
* Create a diagonal matrix or retrieve the diagonal of a matrix
*
* When `x` is a vector, a matrix with vector `x` on the diagonal will be returned.
* When `x` is a two dimensional matrix, the matrixes `k`th diagonal will be returned as vector.
* When k is positive, the values are placed on the super diagonal.
* When k is negative, the values are placed on the sub diagonal.
*
* Syntax:
*
* math.diag(X)
* math.diag(X, format)
* math.diag(X, k)
* math.diag(X, k, format)
*
* Examples:
*
* // create a diagonal matrix
* math.diag([1, 2, 3]) // returns [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
* math.diag([1, 2, 3], 1) // returns [[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]]
* math.diag([1, 2, 3], -1) // returns [[0, 0, 0], [1, 0, 0], [0, 2, 0], [0, 0, 3]]
*
* // retrieve the diagonal from a matrix
* const a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
* math.diag(a) // returns [1, 5, 9]
*
* See also:
*
* ones, zeros, identity
*
* @param {Matrix | Array} x A two dimensional matrix or a vector
* @param {number | BigNumber} [k=0] The diagonal where the vector will be filled
* in or retrieved.
* @param {string} [format='dense'] The matrix storage format.
*
* @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix.
*/
return typed(name, {
// FIXME: simplify this huge amount of signatures as soon as typed-function supports optional arguments
Array: function (x) {
return _diag(x, 0, arraySize(x), null)
},
'Array, number': function (x, k) {
return _diag(x, k, arraySize(x), null)
},
'Array, BigNumber': function (x, k) {
return _diag(x, k.toNumber(), arraySize(x), null)
},
'Array, string': function (x, format) {
return _diag(x, 0, arraySize(x), format)
},
'Array, number, string': function (x, k, format) {
return _diag(x, k, arraySize(x), format)
},
'Array, BigNumber, string': function (x, k, format) {
return _diag(x, k.toNumber(), arraySize(x), format)
},
Matrix: function (x) {
return _diag(x, 0, x.size(), x.storage())
},
'Matrix, number': function (x, k) {
return _diag(x, k, x.size(), x.storage())
},
'Matrix, BigNumber': function (x, k) {
return _diag(x, k.toNumber(), x.size(), x.storage())
},
'Matrix, string': function (x, format) {
return _diag(x, 0, x.size(), format)
},
'Matrix, number, string': function (x, k, format) {
return _diag(x, k, x.size(), format)
},
'Matrix, BigNumber, string': function (x, k, format) {
return _diag(x, k.toNumber(), x.size(), format)
}
})
/**
* Creeate diagonal matrix from a vector or vice versa
* @param {Array | Matrix} x
* @param {number} k
* @param {string} format Storage format for matrix. If null,
* an Array is returned
* @returns {Array | Matrix}
* @private
*/
function _diag (x, k, size, format) {
if (!isInteger(k)) {
throw new TypeError('Second parameter in function diag must be an integer')
}
const kSuper = k > 0 ? k : 0
const kSub = k < 0 ? -k : 0
// check dimensions
switch (size.length) {
case 1:
return _createDiagonalMatrix(x, k, format, size[0], kSub, kSuper)
case 2:
return _getDiagonal(x, k, format, size, kSub, kSuper)
}
throw new RangeError('Matrix for function diag must be 2 dimensional')
}
function _createDiagonalMatrix (x, k, format, l, kSub, kSuper) {
// matrix size
const ms = [l + kSub, l + kSuper]
if (format && format !== 'sparse' && format !== 'dense') {
throw new TypeError(`Unknown matrix type ${format}"`)
}
// create diagonal matrix
const m = format === 'sparse'
? SparseMatrix.diagonal(ms, x, k)
: DenseMatrix.diagonal(ms, x, k)
// check we need to return a matrix
return format !== null ? m : m.valueOf()
}
function _getDiagonal (x, k, format, s, kSub, kSuper) {
// check x is a Matrix
if (isMatrix(x)) {
// get diagonal matrix
const dm = x.diagonal(k)
// check we need to return a matrix
if (format !== null) {
// check we need to change matrix format
if (format !== dm.storage()) { return matrix(dm, format) }
return dm
}
return dm.valueOf()
}
// vector size
const n = Math.min(s[0] - kSub, s[1] - kSuper)
// diagonal values
const vector = []
// loop diagonal
for (let i = 0; i < n; i++) {
vector[i] = x[i + kSub][i + kSuper]
}
// check we need to return a matrix
return format !== null ? matrix(vector) : vector
}
})