UNPKG

5.08 kBJavaScriptView Raw
1'use strict'
2
3const array = require('../../utils/array')
4const isInteger = require('../../utils/number').isInteger
5
6function factory (type, config, load, typed) {
7 const matrix = load(require('../../type/matrix/function/matrix'))
8
9 /**
10 * Create a diagonal matrix or retrieve the diagonal of a matrix
11 *
12 * When `x` is a vector, a matrix with vector `x` on the diagonal will be returned.
13 * When `x` is a two dimensional matrix, the matrixes `k`th diagonal will be returned as vector.
14 * When k is positive, the values are placed on the super diagonal.
15 * When k is negative, the values are placed on the sub diagonal.
16 *
17 * Syntax:
18 *
19 * math.diag(X)
20 * math.diag(X, format)
21 * math.diag(X, k)
22 * math.diag(X, k, format)
23 *
24 * Examples:
25 *
26 * // create a diagonal matrix
27 * math.diag([1, 2, 3]) // returns [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
28 * math.diag([1, 2, 3], 1) // returns [[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]]
29 * math.diag([1, 2, 3], -1) // returns [[0, 0, 0], [1, 0, 0], [0, 2, 0], [0, 0, 3]]
30 *
31 * // retrieve the diagonal from a matrix
32 * const a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
33 * math.diag(a) // returns [1, 5, 9]
34 *
35 * See also:
36 *
37 * ones, zeros, identity
38 *
39 * @param {Matrix | Array} x A two dimensional matrix or a vector
40 * @param {number | BigNumber} [k=0] The diagonal where the vector will be filled
41 * in or retrieved.
42 * @param {string} [format='dense'] The matrix storage format.
43 *
44 * @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix.
45 */
46 const diag = typed('diag', {
47 // FIXME: simplify this huge amount of signatures as soon as typed-function supports optional arguments
48
49 'Array': function (x) {
50 return _diag(x, 0, array.size(x), null)
51 },
52
53 'Array, number': function (x, k) {
54 return _diag(x, k, array.size(x), null)
55 },
56
57 'Array, BigNumber': function (x, k) {
58 return _diag(x, k.toNumber(), array.size(x), null)
59 },
60
61 'Array, string': function (x, format) {
62 return _diag(x, 0, array.size(x), format)
63 },
64
65 'Array, number, string': function (x, k, format) {
66 return _diag(x, k, array.size(x), format)
67 },
68
69 'Array, BigNumber, string': function (x, k, format) {
70 return _diag(x, k.toNumber(), array.size(x), format)
71 },
72
73 'Matrix': function (x) {
74 return _diag(x, 0, x.size(), x.storage())
75 },
76
77 'Matrix, number': function (x, k) {
78 return _diag(x, k, x.size(), x.storage())
79 },
80
81 'Matrix, BigNumber': function (x, k) {
82 return _diag(x, k.toNumber(), x.size(), x.storage())
83 },
84
85 'Matrix, string': function (x, format) {
86 return _diag(x, 0, x.size(), format)
87 },
88
89 'Matrix, number, string': function (x, k, format) {
90 return _diag(x, k, x.size(), format)
91 },
92
93 'Matrix, BigNumber, string': function (x, k, format) {
94 return _diag(x, k.toNumber(), x.size(), format)
95 }
96 })
97
98 diag.toTex = undefined // use default template
99
100 return diag
101
102 /**
103 * Creeate diagonal matrix from a vector or vice versa
104 * @param {Array | Matrix} x
105 * @param {number} k
106 * @param {string} format Storage format for matrix. If null,
107 * an Array is returned
108 * @returns {Array | Matrix}
109 * @private
110 */
111 function _diag (x, k, size, format) {
112 if (!isInteger(k)) {
113 throw new TypeError('Second parameter in function diag must be an integer')
114 }
115
116 const kSuper = k > 0 ? k : 0
117 const kSub = k < 0 ? -k : 0
118
119 // check dimensions
120 switch (size.length) {
121 case 1:
122 return _createDiagonalMatrix(x, k, format, size[0], kSub, kSuper)
123 case 2:
124 return _getDiagonal(x, k, format, size, kSub, kSuper)
125 }
126 throw new RangeError('Matrix for function diag must be 2 dimensional')
127 }
128
129 function _createDiagonalMatrix (x, k, format, l, kSub, kSuper) {
130 // matrix size
131 const ms = [l + kSub, l + kSuper]
132 // get matrix constructor
133 const F = type.Matrix.storage(format || 'dense')
134 // create diagonal matrix
135 const m = F.diagonal(ms, x, k)
136 // check we need to return a matrix
137 return format !== null ? m : m.valueOf()
138 }
139
140 function _getDiagonal (x, k, format, s, kSub, kSuper) {
141 // check x is a Matrix
142 if (type.isMatrix(x)) {
143 // get diagonal matrix
144 const dm = x.diagonal(k)
145 // check we need to return a matrix
146 if (format !== null) {
147 // check we need to change matrix format
148 if (format !== dm.storage()) { return matrix(dm, format) }
149 return dm
150 }
151 return dm.valueOf()
152 }
153 // vector size
154 const n = Math.min(s[0] - kSub, s[1] - kSuper)
155 // diagonal values
156 const vector = []
157 // loop diagonal
158 for (let i = 0; i < n; i++) {
159 vector[i] = x[i + kSub][i + kSuper]
160 }
161 // check we need to return a matrix
162 return format !== null ? matrix(vector) : vector
163 }
164}
165
166exports.name = 'diag'
167exports.factory = factory