1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /*!
21 * \file la_op.cc
22 * \brief CPU implementation of Operators for advanced linear algebra.
23 */
24
25 #include "./la_op.h"
26 #include "./la_op-inl.h"
27
28 namespace mxnet {
29 namespace op {
30
31 DMLC_REGISTER_PARAMETER(LaMatrixMacParam);
32 DMLC_REGISTER_PARAMETER(LaMatrixMultParam);
33 DMLC_REGISTER_PARAMETER(LaCholeskyParam);
34 DMLC_REGISTER_PARAMETER(LaTriangMatrixMultParam);
35 DMLC_REGISTER_PARAMETER(LaDiagParam);
36 DMLC_REGISTER_PARAMETER(LaTrianParam);
37 DMLC_REGISTER_PARAMETER(LaSyrkParam);
38
39 NNVM_REGISTER_OP(_linalg_gemm)
40 .add_alias("linalg_gemm")
41 .describe(R"code(Performs general matrix multiplication and accumulation.
42 Input are tensors *A*, *B*, *C*, each of dimension *n >= 2* and having the same shape
43 on the leading *n-2* dimensions.
44
45 If *n=2*, the BLAS3 function *gemm* is performed:
46
47 *out* = *alpha* \* *op*\ (*A*) \* *op*\ (*B*) + *beta* \* *C*
48
49 Here, *alpha* and *beta* are scalar parameters, and *op()* is either the identity or
50 matrix transposition (depending on *transpose_a*, *transpose_b*).
51
52 If *n>2*, *gemm* is performed separately for a batch of matrices. The column indices of the matrices
53 are given by the last dimensions of the tensors, the row indices by the axis specified with the *axis*
54 parameter. By default, the trailing two dimensions will be used for matrix encoding.
55
56 For a non-default axis parameter, the operation performed is equivalent to a series of swapaxes/gemm/swapaxes
57 calls. For example let *A*, *B*, *C* be 5 dimensional tensors. Then gemm(*A*, *B*, *C*, axis=1) is equivalent
58 to the following without the overhead of the additional swapaxis operations::
59
60 A1 = swapaxes(A, dim1=1, dim2=3)
61 B1 = swapaxes(B, dim1=1, dim2=3)
62 C = swapaxes(C, dim1=1, dim2=3)
63 C = gemm(A1, B1, C)
64 C = swapaxis(C, dim1=1, dim2=3)
65
66 When the input data is of type float32 and the environment variables MXNET_CUDA_ALLOW_TENSOR_CORE
67 and MXNET_CUDA_TENSOR_OP_MATH_ALLOW_CONVERSION are set to 1, this operator will try to use
68 pseudo-float16 precision (float32 math with float16 I/O) precision in order to use
69 Tensor Cores on suitable NVIDIA GPUs. This can sometimes give significant speedups.
70
71 .. note:: The operator supports float32 and float64 data types only.
72
73 Examples::
74
75 Single matrix multiply-add
76 A = [[1.0, 1.0], [1.0, 1.0]]
77 B = [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
78 C = [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]
79 gemm(A, B, C, transpose_b=True, alpha=2.0, beta=10.0)
80 = [[14.0, 14.0, 14.0], [14.0, 14.0, 14.0]]
81
82 Batch matrix multiply-add
83 A = [[[1.0, 1.0]], [[0.1, 0.1]]]
84 B = [[[1.0, 1.0]], [[0.1, 0.1]]]
85 C = [[[10.0]], [[0.01]]]
86 gemm(A, B, C, transpose_b=True, alpha=2.0 , beta=10.0)
87 = [[[104.0]], [[0.14]]]
88 )code" ADD_FILELINE)
89 .set_num_inputs(3)
90 .set_num_outputs(1)
91 .set_attr_parser(ParamParser<LaMatrixMacParam>)
92 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400830102(const NodeAttrs& attrs) 93 { return std::vector<std::string>{"A", "B", "C"}; } )
94 .set_attr<mxnet::FInferShape>("FInferShape", LaMatrixMultMacOpShape)
95 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<3, 1>)
96 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830202(const NodeAttrs& attrs) 97 { return std::vector<std::pair<int, int>>{{2, 0}}; })
98 .set_attr<FCompute>("FCompute<cpu>", LaOpGemmForward<cpu, 2, 2, 3, 1, gemm>)
99 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_linalg_gemm"})
100 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices")
101 .add_argument("B", "NDArray-or-Symbol", "Tensor of input matrices")
102 .add_argument("C", "NDArray-or-Symbol", "Tensor of input matrices")
103 .add_arguments(LaMatrixMacParam::__FIELDS__());
104
105 NNVM_REGISTER_OP(_backward_linalg_gemm)
106 .set_num_inputs(4)
107 .set_num_outputs(3)
108 .set_attr_parser(ParamParser<LaMatrixMacParam>)
109 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830302(const NodeAttrs& attrs) 110 { return std::vector<std::pair<int, int> >{{2, 1}, {3, 2}}; })
111 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400830402(const NodeAttrs& attrs) 112 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
113 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
114 .set_attr<FCompute>("FCompute<cpu>", LaOpGemmBackward<cpu, 2, 2, 4, 3, gemm_backward>);
115
116 NNVM_REGISTER_OP(_linalg_gemm2)
117 .add_alias("linalg_gemm2")
118 .describe(R"code(Performs general matrix multiplication.
119 Input are tensors *A*, *B*, each of dimension *n >= 2* and having the same shape
120 on the leading *n-2* dimensions.
121
122 If *n=2*, the BLAS3 function *gemm* is performed:
123
124 *out* = *alpha* \* *op*\ (*A*) \* *op*\ (*B*)
125
126 Here *alpha* is a scalar parameter and *op()* is either the identity or the matrix
127 transposition (depending on *transpose_a*, *transpose_b*).
128
129 If *n>2*, *gemm* is performed separately for a batch of matrices. The column indices of the matrices
130 are given by the last dimensions of the tensors, the row indices by the axis specified with the *axis*
131 parameter. By default, the trailing two dimensions will be used for matrix encoding.
132
133 For a non-default axis parameter, the operation performed is equivalent to a series of swapaxes/gemm/swapaxes
134 calls. For example let *A*, *B* be 5 dimensional tensors. Then gemm(*A*, *B*, axis=1) is equivalent to
135 the following without the overhead of the additional swapaxis operations::
136
137 A1 = swapaxes(A, dim1=1, dim2=3)
138 B1 = swapaxes(B, dim1=1, dim2=3)
139 C = gemm2(A1, B1)
140 C = swapaxis(C, dim1=1, dim2=3)
141
142 When the input data is of type float32 and the environment variables MXNET_CUDA_ALLOW_TENSOR_CORE
143 and MXNET_CUDA_TENSOR_OP_MATH_ALLOW_CONVERSION are set to 1, this operator will try to use
144 pseudo-float16 precision (float32 math with float16 I/O) precision in order to use
145 Tensor Cores on suitable NVIDIA GPUs. This can sometimes give significant speedups.
146
147 .. note:: The operator supports float32 and float64 data types only.
148
149 Examples::
150
151 Single matrix multiply
152 A = [[1.0, 1.0], [1.0, 1.0]]
153 B = [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]
154 gemm2(A, B, transpose_b=True, alpha=2.0)
155 = [[4.0, 4.0, 4.0], [4.0, 4.0, 4.0]]
156
157 Batch matrix multiply
158 A = [[[1.0, 1.0]], [[0.1, 0.1]]]
159 B = [[[1.0, 1.0]], [[0.1, 0.1]]]
160 gemm2(A, B, transpose_b=True, alpha=2.0)
161 = [[[4.0]], [[0.04 ]]]
162 )code" ADD_FILELINE)
163 .set_num_inputs(2)
164 .set_num_outputs(1)
165 .set_attr_parser(ParamParser<LaMatrixMultParam>)
166 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400830502(const NodeAttrs& attrs) 167 { return std::vector<std::string>{"A", "B"}; } )
168 .set_attr<mxnet::FInferShape>("FInferShape", LaMatrixMultMacOpShape)
169 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<2, 1>)
170 .set_attr<FCompute>("FCompute<cpu>", LaOpGemmForward<cpu, 2, 2, 2, 1, gemm2>)
171 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_linalg_gemm2"})
172 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices")
173 .add_argument("B", "NDArray-or-Symbol", "Tensor of input matrices")
174 .add_arguments(LaMatrixMultParam::__FIELDS__());
175
176 NNVM_REGISTER_OP(_backward_linalg_gemm2)
177 .set_num_inputs(3)
178 .set_num_outputs(2)
179 .set_attr_parser(ParamParser<LaMatrixMultParam>)
180 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830602(const NodeAttrs& attrs) 181 { return std::vector<std::pair<int, int> >{{2, 1}}; })
182 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400830702(const NodeAttrs& attrs) 183 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
184 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
185 .set_attr<FCompute>("FCompute<cpu>", LaOpGemmBackward<cpu, 2, 2, 3, 2, gemm2_backward>);
186
187 NNVM_REGISTER_OP(_linalg_potrf)
188 .add_alias("linalg_potrf")
189 .describe(R"code(Performs Cholesky factorization of a symmetric positive-definite matrix.
190 Input is a tensor *A* of dimension *n >= 2*.
191
192 If *n=2*, the Cholesky factor *B* of the symmetric, positive definite matrix *A* is
193 computed. *B* is triangular (entries of upper or lower triangle are all zero), has
194 positive diagonal entries, and:
195
196 *A* = *B* \* *B*\ :sup:`T` if *lower* = *true*
197 *A* = *B*\ :sup:`T` \* *B* if *lower* = *false*
198
199 If *n>2*, *potrf* is performed separately on the trailing two dimensions for all inputs
200 (batch mode).
201
202 .. note:: The operator supports float32 and float64 data types only.
203
204 Examples::
205
206 Single matrix factorization
207 A = [[4.0, 1.0], [1.0, 4.25]]
208 potrf(A) = [[2.0, 0], [0.5, 2.0]]
209
210 Batch matrix factorization
211 A = [[[4.0, 1.0], [1.0, 4.25]], [[16.0, 4.0], [4.0, 17.0]]]
212 potrf(A) = [[[2.0, 0], [0.5, 2.0]], [[4.0, 0], [1.0, 4.0]]]
213 )code" ADD_FILELINE)
214 .set_num_inputs(1)
215 .set_num_outputs(1)
216 .set_attr_parser(ParamParser<LaCholeskyParam>)
217 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400830802(const NodeAttrs& attrs) 218 { return std::vector<std::string>{"A"}; } )
219 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
220 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
221 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830902(const NodeAttrs& attrs) 222 { return std::vector<std::pair<int, int>>{{0, 0}}; })
223 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 1, 1, potrf>)
224 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseOut{"_backward_linalg_potrf"})
225 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices to be decomposed");
226
227 NNVM_REGISTER_OP(_backward_linalg_potrf)
228 .set_num_inputs(2)
229 .set_num_outputs(1)
230 .set_attr_parser(ParamParser<LaCholeskyParam>)
231 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830a02(const NodeAttrs& attrs) 232 { return std::vector<std::pair<int, int> >{{0, 0}}; })
233 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400830b02(const NodeAttrs& attrs) 234 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
235 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
236 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 2, 1, potrf_backward>);
237
238
239 NNVM_REGISTER_OP(_linalg_potri)
240 .add_alias("linalg_potri")
241 .describe(R"code(Performs matrix inversion from a Cholesky factorization.
242 Input is a tensor *A* of dimension *n >= 2*.
243
244 If *n=2*, *A* is a triangular matrix (entries of upper or lower triangle are all zero)
245 with positive diagonal. We compute:
246
247 *out* = *A*\ :sup:`-T` \* *A*\ :sup:`-1` if *lower* = *true*
248 *out* = *A*\ :sup:`-1` \* *A*\ :sup:`-T` if *lower* = *false*
249
250 In other words, if *A* is the Cholesky factor of a symmetric positive definite matrix
251 *B* (obtained by *potrf*), then
252
253 *out* = *B*\ :sup:`-1`
254
255 If *n>2*, *potri* is performed separately on the trailing two dimensions for all inputs
256 (batch mode).
257
258 .. note:: The operator supports float32 and float64 data types only.
259
260 .. note:: Use this operator only if you are certain you need the inverse of *B*, and
261 cannot use the Cholesky factor *A* (*potrf*), together with backsubstitution
262 (*trsm*). The latter is numerically much safer, and also cheaper.
263
264 Examples::
265
266 Single matrix inverse
267 A = [[2.0, 0], [0.5, 2.0]]
268 potri(A) = [[0.26563, -0.0625], [-0.0625, 0.25]]
269
270 Batch matrix inverse
271 A = [[[2.0, 0], [0.5, 2.0]], [[4.0, 0], [1.0, 4.0]]]
272 potri(A) = [[[0.26563, -0.0625], [-0.0625, 0.25]],
273 [[0.06641, -0.01562], [-0.01562, 0,0625]]]
274 )code" ADD_FILELINE)
275 .set_num_inputs(1)
276 .set_num_outputs(1)
277 .set_attr_parser(ParamParser<LaCholeskyParam>)
278 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400830c02(const NodeAttrs& attrs) 279 { return std::vector<std::string>{"A"}; } )
280 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
281 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
282 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400830d02(const NodeAttrs& attrs) 283 { return std::vector<std::pair<int, int>>{{0, 0}}; })
284 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 1, 1, potri>)
285 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseInOut{"_backward_linalg_potri"})
286 .add_argument("A", "NDArray-or-Symbol", "Tensor of lower triangular matrices");
287
288 NNVM_REGISTER_OP(_backward_linalg_potri)
289 .set_num_inputs(3)
290 .set_num_outputs(1)
291 .set_attr_parser(ParamParser<LaCholeskyParam>)
292 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400830e02(const NodeAttrs& attrs) 293 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
294 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
295 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 3, 1, potri_backward>);
296
297 NNVM_REGISTER_OP(_linalg_trmm)
298 .add_alias("linalg_trmm")
299 .describe(R"code(Performs multiplication with a lower triangular matrix.
300 Input are tensors *A*, *B*, each of dimension *n >= 2* and having the same shape
301 on the leading *n-2* dimensions.
302
303 If *n=2*, *A* must be triangular. The operator performs the BLAS3 function
304 *trmm*:
305
306 *out* = *alpha* \* *op*\ (*A*) \* *B*
307
308 if *rightside=False*, or
309
310 *out* = *alpha* \* *B* \* *op*\ (*A*)
311
312 if *rightside=True*. Here, *alpha* is a scalar parameter, and *op()* is either the
313 identity or the matrix transposition (depending on *transpose*).
314
315 If *n>2*, *trmm* is performed separately on the trailing two dimensions for all inputs
316 (batch mode).
317
318 .. note:: The operator supports float32 and float64 data types only.
319
320 Examples::
321
322 Single triangular matrix multiply
323 A = [[1.0, 0], [1.0, 1.0]]
324 B = [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]
325 trmm(A, B, alpha=2.0) = [[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]]
326
327 Batch triangular matrix multiply
328 A = [[[1.0, 0], [1.0, 1.0]], [[1.0, 0], [1.0, 1.0]]]
329 B = [[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5]]]
330 trmm(A, B, alpha=2.0) = [[[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]],
331 [[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]]]
332 )code" ADD_FILELINE)
333 .set_num_inputs(2)
334 .set_num_outputs(1)
335 .set_attr_parser(ParamParser<LaTriangMatrixMultParam>)
336 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400830f02(const NodeAttrs& attrs) 337 { return std::vector<std::string>{"A", "B"}; } )
338 .set_attr<mxnet::FInferShape>("FInferShape", LaTriangMatrixMultOpShape)
339 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<2, 1>)
340 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400831002(const NodeAttrs& attrs) 341 { return std::vector<std::pair<int, int>>{{1, 0}}; })
342 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 2, 1, trmm>)
343 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_linalg_trmm"})
344 .add_argument("A", "NDArray-or-Symbol", "Tensor of lower triangular matrices")
345 .add_argument("B", "NDArray-or-Symbol", "Tensor of matrices")
346 .add_arguments(LaTriangMatrixMultParam::__FIELDS__());
347
348 NNVM_REGISTER_OP(_backward_linalg_trmm)
349 .set_num_inputs(3)
350 .set_num_outputs(2)
351 .set_attr_parser(ParamParser<LaTriangMatrixMultParam>)
352 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400831102(const NodeAttrs& attrs) 353 { return std::vector<std::pair<int, int> >{{0, 1}}; })
354 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831202(const NodeAttrs& attrs) 355 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
356 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
357 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 3, 2, trmm_backward>);
358
359 NNVM_REGISTER_OP(_linalg_trsm)
360 .add_alias("linalg_trsm")
361 .describe(R"code(Solves matrix equation involving a lower triangular matrix.
362 Input are tensors *A*, *B*, each of dimension *n >= 2* and having the same shape
363 on the leading *n-2* dimensions.
364
365 If *n=2*, *A* must be triangular. The operator performs the BLAS3 function
366 *trsm*, solving for *out* in:
367
368 *op*\ (*A*) \* *out* = *alpha* \* *B*
369
370 if *rightside=False*, or
371
372 *out* \* *op*\ (*A*) = *alpha* \* *B*
373
374 if *rightside=True*. Here, *alpha* is a scalar parameter, and *op()* is either the
375 identity or the matrix transposition (depending on *transpose*).
376
377 If *n>2*, *trsm* is performed separately on the trailing two dimensions for all inputs
378 (batch mode).
379
380 .. note:: The operator supports float32 and float64 data types only.
381
382 Examples::
383
384 Single matrix solve
385 A = [[1.0, 0], [1.0, 1.0]]
386 B = [[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]]
387 trsm(A, B, alpha=0.5) = [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]
388
389 Batch matrix solve
390 A = [[[1.0, 0], [1.0, 1.0]], [[1.0, 0], [1.0, 1.0]]]
391 B = [[[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]],
392 [[4.0, 4.0, 4.0], [8.0, 8.0, 8.0]]]
393 trsm(A, B, alpha=0.5) = [[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]],
394 [[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]
395 )code" ADD_FILELINE)
396 .set_num_inputs(2)
397 .set_num_outputs(1)
398 .set_attr_parser(ParamParser<LaTriangMatrixMultParam>)
399 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400831302(const NodeAttrs& attrs) 400 { return std::vector<std::string>{"A", "B"}; } )
401 .set_attr<mxnet::FInferShape>("FInferShape", LaTriangMatrixMultOpShape)
402 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<2, 1>)
403 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400831402(const NodeAttrs& attrs) 404 { return std::vector<std::pair<int, int>>{{1, 0}}; })
405 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 2, 1, trsm>)
406 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseInOut{"_backward_linalg_trsm"})
407 .add_argument("A", "NDArray-or-Symbol", "Tensor of lower triangular matrices")
408 .add_argument("B", "NDArray-or-Symbol", "Tensor of matrices")
409 .add_arguments(LaTriangMatrixMultParam::__FIELDS__());
410
411 NNVM_REGISTER_OP(_backward_linalg_trsm)
412 .set_num_inputs(4)
413 .set_num_outputs(2)
414 .set_attr_parser(ParamParser<LaTriangMatrixMultParam>)
415 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400831502(const NodeAttrs& attrs) 416 { return std::vector<std::pair<int, int> >{{0, 1}, {1, 0}}; })
417 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831602(const NodeAttrs& attrs) 418 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
419 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
420 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 4, 2, trsm_backward>);
421
422 NNVM_REGISTER_OP(_linalg_sumlogdiag)
423 .add_alias("linalg_sumlogdiag")
424 .describe(R"code(Computes the sum of the logarithms of the diagonal elements of a square matrix.
425 Input is a tensor *A* of dimension *n >= 2*.
426
427 If *n=2*, *A* must be square with positive diagonal entries. We sum the natural
428 logarithms of the diagonal elements, the result has shape (1,).
429
430 If *n>2*, *sumlogdiag* is performed separately on the trailing two dimensions for all
431 inputs (batch mode).
432
433 .. note:: The operator supports float32 and float64 data types only.
434
435 Examples::
436
437 Single matrix reduction
438 A = [[1.0, 1.0], [1.0, 7.0]]
439 sumlogdiag(A) = [1.9459]
440
441 Batch matrix reduction
442 A = [[[1.0, 1.0], [1.0, 7.0]], [[3.0, 0], [0, 17.0]]]
443 sumlogdiag(A) = [1.9459, 3.9318]
444 )code" ADD_FILELINE)
445 .set_num_inputs(1)
446 .set_num_outputs(1)
447 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400831702(const NodeAttrs& attrs) 448 { return std::vector<std::string>{"A"}; } )
449 .set_attr<mxnet::FInferShape>("FInferShape", LaReduceShape<2>)
450 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
451 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 0, 1, 1, sumlogdiag>)
452 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_linalg_sumlogdiag"})
453 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrices");
454
455 NNVM_REGISTER_OP(_backward_linalg_sumlogdiag)
456 .set_num_inputs(2)
457 .set_num_outputs(1)
458 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400831802(const NodeAttrs& attrs) 459 { return std::vector<std::pair<int, int>>{{1, 0}}; })
460 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831902(const NodeAttrs& attrs) 461 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
462 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
463 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 2, 1, sumlogdiag_backward>);
464
465 NNVM_REGISTER_OP(_linalg_extractdiag)
466 .add_alias("linalg_extractdiag")
467 .describe(R"code(Extracts the diagonal entries of a square matrix.
468 Input is a tensor *A* of dimension *n >= 2*.
469
470 If *n=2*, then *A* represents a single square matrix which diagonal elements get extracted as a 1-dimensional tensor.
471
472 If *n>2*, then *A* represents a batch of square matrices on the trailing two dimensions. The extracted diagonals are returned as an *n-1*-dimensional tensor.
473
474 .. note:: The operator supports float32 and float64 data types only.
475
476 Examples::
477
478 Single matrix diagonal extraction
479 A = [[1.0, 2.0],
480 [3.0, 4.0]]
481
482 extractdiag(A) = [1.0, 4.0]
483
484 extractdiag(A, 1) = [2.0]
485
486 Batch matrix diagonal extraction
487 A = [[[1.0, 2.0],
488 [3.0, 4.0]],
489 [[5.0, 6.0],
490 [7.0, 8.0]]]
491
492 extractdiag(A) = [[1.0, 4.0],
493 [5.0, 8.0]]
494 )code" ADD_FILELINE)
495 .set_num_inputs(1)
496 .set_num_outputs(1)
497 .set_attr_parser(ParamParser<LaDiagParam>)
498 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400831a02(const NodeAttrs& attrs) 499 { return std::vector<std::string>{"A"}; } )
500 .set_attr<mxnet::FInferShape>("FInferShape", LaDiagTrianShape<true, true>)
501 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
502 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 1, 1, 1, copydiag>)
503 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_linalg_extractdiag"})
504 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrices")
505 .add_arguments(LaDiagParam::__FIELDS__());
506
507 NNVM_REGISTER_OP(_backward_linalg_extractdiag)
508 .set_num_inputs(1)
509 .set_num_outputs(1)
510 .set_attr_parser(ParamParser<LaDiagParam>)
511 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831b02(const NodeAttrs& attrs) 512 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
513 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
514 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 1, 2, 1, 1, copydiag>);
515
516 NNVM_REGISTER_OP(_linalg_makediag)
517 .add_alias("linalg_makediag")
518 .describe(R"code(Constructs a square matrix with the input as diagonal.
519 Input is a tensor *A* of dimension *n >= 1*.
520
521 If *n=1*, then *A* represents the diagonal entries of a single square matrix. This matrix will be returned as a 2-dimensional tensor.
522 If *n>1*, then *A* represents a batch of diagonals of square matrices. The batch of diagonal matrices will be returned as an *n+1*-dimensional tensor.
523
524 .. note:: The operator supports float32 and float64 data types only.
525
526 Examples::
527
528 Single diagonal matrix construction
529 A = [1.0, 2.0]
530
531 makediag(A) = [[1.0, 0.0],
532 [0.0, 2.0]]
533
534 makediag(A, 1) = [[0.0, 1.0, 0.0],
535 [0.0, 0.0, 2.0],
536 [0.0, 0.0, 0.0]]
537
538 Batch diagonal matrix construction
539 A = [[1.0, 2.0],
540 [3.0, 4.0]]
541
542 makediag(A) = [[[1.0, 0.0],
543 [0.0, 2.0]],
544 [[3.0, 0.0],
545 [0.0, 4.0]]]
546 )code" ADD_FILELINE)
547 .set_num_inputs(1)
548 .set_num_outputs(1)
549 .set_attr_parser(ParamParser<LaDiagParam>)
550 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400831c02(const NodeAttrs& attrs) 551 { return std::vector<std::string>{"A"}; } )
552 .set_attr<mxnet::FInferShape>("FInferShape", LaDiagTrianShape<true, false>)
553 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
554 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 1, 2, 1, 1, copydiag>)
555 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_linalg_makediag"})
556 .add_argument("A", "NDArray-or-Symbol", "Tensor of diagonal entries")
557 .add_arguments(LaDiagParam::__FIELDS__());
558
559 NNVM_REGISTER_OP(_backward_linalg_makediag)
560 .set_num_inputs(1)
561 .set_num_outputs(1)
562 .set_attr_parser(ParamParser<LaDiagParam>)
563 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831d02(const NodeAttrs& attrs) 564 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
565 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
566 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 1, 1, 1, copydiag>);
567
568 NNVM_REGISTER_OP(_linalg_extracttrian)
569 .add_alias("linalg_extracttrian")
570 .describe(R"code(Extracts a triangular sub-matrix from a square matrix.
571 Input is a tensor *A* of dimension *n >= 2*.
572
573 If *n=2*, then *A* represents a single square matrix from which a triangular sub-matrix is extracted as a 1-dimensional tensor.
574
575 If *n>2*, then *A* represents a batch of square matrices on the trailing two dimensions. The extracted triangular sub-matrices are returned as an *n-1*-dimensional tensor.
576
577 The *offset* and *lower* parameters determine the triangle to be extracted:
578
579 - When *offset = 0* either the lower or upper triangle with respect to the main diagonal is extracted depending on the value of parameter *lower*.
580 - When *offset = k > 0* the upper triangle with respect to the k-th diagonal above the main diagonal is extracted.
581 - When *offset = k < 0* the lower triangle with respect to the k-th diagonal below the main diagonal is extracted.
582
583 .. note:: The operator supports float32 and float64 data types only.
584
585 Examples::
586
587 Single triagonal extraction
588 A = [[1.0, 2.0],
589 [3.0, 4.0]]
590
591 extracttrian(A) = [1.0, 3.0, 4.0]
592 extracttrian(A, lower=False) = [1.0, 2.0, 4.0]
593 extracttrian(A, 1) = [2.0]
594 extracttrian(A, -1) = [3.0]
595
596 Batch triagonal extraction
597 A = [[[1.0, 2.0],
598 [3.0, 4.0]],
599 [[5.0, 6.0],
600 [7.0, 8.0]]]
601
602 extracttrian(A) = [[1.0, 3.0, 4.0],
603 [5.0, 7.0, 8.0]]
604 )code" ADD_FILELINE)
605 .set_num_inputs(1)
606 .set_num_outputs(1)
607 .set_attr_parser(ParamParser<LaTrianParam>)
608 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400831e02(const NodeAttrs& attrs) 609 { return std::vector<std::string>{"A"}; } )
610 .set_attr<mxnet::FInferShape>("FInferShape", LaDiagTrianShape<false, true>)
611 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
612 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 1, 1, 1, copytrian>)
613 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_linalg_extracttrian"})
614 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrices")
615 .add_arguments(LaTrianParam::__FIELDS__());
616
617 NNVM_REGISTER_OP(_backward_linalg_extracttrian)
618 .set_num_inputs(1)
619 .set_num_outputs(1)
620 .set_attr_parser(ParamParser<LaTrianParam>)
621 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400831f02(const NodeAttrs& attrs) 622 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
623 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
624 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 1, 2, 1, 1, copytrian>);
625
626 NNVM_REGISTER_OP(_linalg_maketrian)
627 .add_alias("linalg_maketrian")
628 .describe(R"code(Constructs a square matrix with the input representing a specific triangular sub-matrix.
629 This is basically the inverse of *linalg.extracttrian*. Input is a tensor *A* of dimension *n >= 1*.
630
631 If *n=1*, then *A* represents the entries of a triangular matrix which is lower triangular if *offset<0* or *offset=0*, *lower=true*. The resulting matrix is derived by first constructing the square
632 matrix with the entries outside the triangle set to zero and then adding *offset*-times an additional
633 diagonal with zero entries to the square matrix.
634
635 If *n>1*, then *A* represents a batch of triangular sub-matrices. The batch of corresponding square matrices is returned as an *n+1*-dimensional tensor.
636
637 .. note:: The operator supports float32 and float64 data types only.
638
639 Examples::
640
641 Single matrix construction
642 A = [1.0, 2.0, 3.0]
643
644 maketrian(A) = [[1.0, 0.0],
645 [2.0, 3.0]]
646
647 maketrian(A, lower=false) = [[1.0, 2.0],
648 [0.0, 3.0]]
649
650 maketrian(A, offset=1) = [[0.0, 1.0, 2.0],
651 [0.0, 0.0, 3.0],
652 [0.0, 0.0, 0.0]]
653 maketrian(A, offset=-1) = [[0.0, 0.0, 0.0],
654 [1.0, 0.0, 0.0],
655 [2.0, 3.0, 0.0]]
656
657 Batch matrix construction
658 A = [[1.0, 2.0, 3.0],
659 [4.0, 5.0, 6.0]]
660
661 maketrian(A) = [[[1.0, 0.0],
662 [2.0, 3.0]],
663 [[4.0, 0.0],
664 [5.0, 6.0]]]
665
666 maketrian(A, offset=1) = [[[0.0, 1.0, 2.0],
667 [0.0, 0.0, 3.0],
668 [0.0, 0.0, 0.0]],
669 [[0.0, 4.0, 5.0],
670 [0.0, 0.0, 6.0],
671 [0.0, 0.0, 0.0]]]
672 )code" ADD_FILELINE)
673 .set_num_inputs(1)
674 .set_num_outputs(1)
675 .set_attr_parser(ParamParser<LaTrianParam>)
676 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400832002(const NodeAttrs& attrs) 677 { return std::vector<std::string>{"A"}; } )
678 .set_attr<mxnet::FInferShape>("FInferShape", LaDiagTrianShape<false, false>)
679 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
680 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 1, 2, 1, 1, copytrian>)
681 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseNone{"_backward_linalg_maketrian"})
682 .add_argument("A", "NDArray-or-Symbol", "Tensor of triangular matrices stored as vectors")
683 .add_arguments(LaTrianParam::__FIELDS__());
684
685 NNVM_REGISTER_OP(_backward_linalg_maketrian)
686 .set_num_inputs(1)
687 .set_num_outputs(1)
688 .set_attr_parser(ParamParser<LaTrianParam>)
689 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832102(const NodeAttrs& attrs) 690 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
691 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
692 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 1, 1, 1, copytrian>);
693
694 NNVM_REGISTER_OP(_linalg_syrk)
695 .add_alias("linalg_syrk")
696 .describe(R"code(Multiplication of matrix with its transpose.
697 Input is a tensor *A* of dimension *n >= 2*.
698
699 If *n=2*, the operator performs the BLAS3 function *syrk*:
700
701 *out* = *alpha* \* *A* \* *A*\ :sup:`T`
702
703 if *transpose=False*, or
704
705 *out* = *alpha* \* *A*\ :sup:`T` \ \* *A*
706
707 if *transpose=True*.
708
709 If *n>2*, *syrk* is performed separately on the trailing two dimensions for all
710 inputs (batch mode).
711
712 .. note:: The operator supports float32 and float64 data types only.
713
714 Examples::
715
716 Single matrix multiply
717 A = [[1., 2., 3.], [4., 5., 6.]]
718 syrk(A, alpha=1., transpose=False)
719 = [[14., 32.],
720 [32., 77.]]
721 syrk(A, alpha=1., transpose=True)
722 = [[17., 22., 27.],
723 [22., 29., 36.],
724 [27., 36., 45.]]
725
726 Batch matrix multiply
727 A = [[[1., 1.]], [[0.1, 0.1]]]
728 syrk(A, alpha=2., transpose=False) = [[[4.]], [[0.04]]]
729 )code" ADD_FILELINE)
730 .set_num_inputs(1)
731 .set_num_outputs(1)
732 .set_attr_parser(ParamParser<LaSyrkParam>)
733 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400832202(const NodeAttrs& attrs) 734 { return std::vector<std::string>{"A"}; } )
735 .set_attr<mxnet::FInferShape>("FInferShape", LaSyrkShape)
736 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
737 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 1, 1, syrk>)
738 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_linalg_syrk"})
739 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices")
740 .add_arguments(LaSyrkParam::__FIELDS__());
741
742 NNVM_REGISTER_OP(_backward_linalg_syrk)
743 .set_num_inputs(2)
744 .set_num_outputs(1)
745 .set_attr_parser(ParamParser<LaSyrkParam>)
746 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832302(const NodeAttrs& attrs) 747 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
748 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
749 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 2, 1, syrk_backward>);
750
751 NNVM_REGISTER_OP(_linalg_gelqf)
752 .add_alias("linalg_gelqf")
753 .describe(R"code(LQ factorization for general matrix.
754 Input is a tensor *A* of dimension *n >= 2*.
755
756 If *n=2*, we compute the LQ factorization (LAPACK *gelqf*, followed by *orglq*). *A*
757 must have shape *(x, y)* with *x <= y*, and must have full rank *=x*. The LQ
758 factorization consists of *L* with shape *(x, x)* and *Q* with shape *(x, y)*, so
759 that:
760
761 *A* = *L* \* *Q*
762
763 Here, *L* is lower triangular (upper triangle equal to zero) with nonzero diagonal,
764 and *Q* is row-orthonormal, meaning that
765
766 *Q* \* *Q*\ :sup:`T`
767
768 is equal to the identity matrix of shape *(x, x)*.
769
770 If *n>2*, *gelqf* is performed separately on the trailing two dimensions for all
771 inputs (batch mode).
772
773 .. note:: The operator supports float32 and float64 data types only.
774
775 Examples::
776
777 Single LQ factorization
778 A = [[1., 2., 3.], [4., 5., 6.]]
779 Q, L = gelqf(A)
780 Q = [[-0.26726124, -0.53452248, -0.80178373],
781 [0.87287156, 0.21821789, -0.43643578]]
782 L = [[-3.74165739, 0.],
783 [-8.55235974, 1.96396101]]
784
785 Batch LQ factorization
786 A = [[[1., 2., 3.], [4., 5., 6.]],
787 [[7., 8., 9.], [10., 11., 12.]]]
788 Q, L = gelqf(A)
789 Q = [[[-0.26726124, -0.53452248, -0.80178373],
790 [0.87287156, 0.21821789, -0.43643578]],
791 [[-0.50257071, -0.57436653, -0.64616234],
792 [0.7620735, 0.05862104, -0.64483142]]]
793 L = [[[-3.74165739, 0.],
794 [-8.55235974, 1.96396101]],
795 [[-13.92838828, 0.],
796 [-19.09768702, 0.52758934]]]
797 )code" ADD_FILELINE)
798 .set_num_inputs(1)
799 .set_num_outputs(2)
800 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400832402(const NodeAttrs& attrs) 801 { return std::vector<std::string>{"A"}; } )
802 .set_attr<mxnet::FInferShape>("FInferShape", LaLQFactShape)
803 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 2>)
804 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400832502(const NodeAttrs& attrs) 805 { return std::vector<std::pair<int, int>>{{0, 0}}; })
806 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832602(const NodeAttrs& attrs) 807 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
808 .set_attr<THasDeterministicOutput>("THasDeterministicOutput", true)
809 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 1, 2, gelqf>)
810 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseOut{"_backward_linalg_gelqf"})
811 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices to be factorized");
812
813 NNVM_REGISTER_OP(_backward_linalg_gelqf)
814 .set_num_inputs(4)
815 .set_num_outputs(1)
816 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400832702(const NodeAttrs& attrs) 817 { return std::vector<std::pair<int, int> >{{0, 0}}; })
818 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832802(const NodeAttrs& attrs) 819 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
820 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
821 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 4, 1, gelqf_backward>);
822
823 NNVM_REGISTER_OP(_linalg_syevd)
824 .describe(R"code(Eigendecomposition for symmetric matrix.
825 Input is a tensor *A* of dimension *n >= 2*.
826
827 If *n=2*, *A* must be symmetric, of shape *(x, x)*. We compute the eigendecomposition,
828 resulting in the orthonormal matrix *U* of eigenvectors, shape *(x, x)*, and the
829 vector *L* of eigenvalues, shape *(x,)*, so that:
830
831 *U* \* *A* = *diag(L)* \* *U*
832
833 Here:
834
835 *U* \* *U*\ :sup:`T` = *U*\ :sup:`T` \* *U* = *I*
836
837 where *I* is the identity matrix. Also, *L(0) <= L(1) <= L(2) <= ...* (ascending order).
838
839 If *n>2*, *syevd* is performed separately on the trailing two dimensions of *A* (batch
840 mode). In this case, *U* has *n* dimensions like *A*, and *L* has *n-1* dimensions.
841
842 .. note:: The operator supports float32 and float64 data types only.
843
844 .. note:: Derivatives for this operator are defined only if *A* is such that all its
845 eigenvalues are distinct, and the eigengaps are not too small. If you need
846 gradients, do not apply this operator to matrices with multiple eigenvalues.
847
848 Examples::
849
850 Single symmetric eigendecomposition
851 A = [[1., 2.], [2., 4.]]
852 U, L = syevd(A)
853 U = [[0.89442719, -0.4472136],
854 [0.4472136, 0.89442719]]
855 L = [0., 5.]
856
857 Batch symmetric eigendecomposition
858 A = [[[1., 2.], [2., 4.]],
859 [[1., 2.], [2., 5.]]]
860 U, L = syevd(A)
861 U = [[[0.89442719, -0.4472136],
862 [0.4472136, 0.89442719]],
863 [[0.92387953, -0.38268343],
864 [0.38268343, 0.92387953]]]
865 L = [[0., 5.],
866 [0.17157288, 5.82842712]]
867 )code" ADD_FILELINE)
868 .set_num_inputs(1)
869 .set_num_outputs(2)
870 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400832902(const NodeAttrs& attrs) 871 { return std::vector<std::string>{"A"}; } )
872 .set_attr<mxnet::FInferShape>("FInferShape", LaEigFactShape)
873 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 2>)
874 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400832a02(const NodeAttrs& attrs) 875 { return std::vector<std::pair<int, int>>{{0, 0}}; })
876 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832b02(const NodeAttrs& attrs) 877 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
878 .set_attr<THasDeterministicOutput>("THasDeterministicOutput", true)
879 .set_attr<FCompute>("FCompute<cpu>", LaOpForwSyevd<cpu, syevd>)
880 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseOut{"_backward_linalg_syevd"})
881 .add_argument("A", "NDArray-or-Symbol", "Tensor of input matrices to be factorized");
882
883 NNVM_REGISTER_OP(_backward_linalg_syevd)
884 .set_num_inputs(4)
885 .set_num_outputs(1)
886 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400832c02(const NodeAttrs& attrs) 887 { return std::vector<std::pair<int, int> >{{0, 0}}; })
888 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400832d02(const NodeAttrs& attrs) 889 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
890 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
891 .set_attr<FCompute>("FCompute<cpu>", LaOpBackwSyevd<cpu, syevd_backward>);
892
893 NNVM_REGISTER_OP(_linalg_inverse)
894 .add_alias("linalg_inverse")
895 .add_alias("_npi_inv")
896 .describe(R"code(Compute the inverse of a matrix.
897 Input is a tensor *A* of dimension *n >= 2*.
898
899 If *n=2*, *A* is a square matrix. We compute:
900
901 *out* = *A*\ :sup:`-1`
902
903 If *n>2*, *inverse* is performed separately on the trailing two dimensions
904 for all inputs (batch mode).
905
906 .. note:: The operator supports float32 and float64 data types only.
907
908 Examples::
909
910 Single matrix inverse
911 A = [[1., 4.], [2., 3.]]
912 inverse(A) = [[-0.6, 0.8], [0.4, -0.2]]
913
914 Batch matrix inverse
915 A = [[[1., 4.], [2., 3.]],
916 [[1., 3.], [2., 4.]]]
917 inverse(A) = [[[-0.6, 0.8], [0.4, -0.2]],
918 [[-2., 1.5], [1., -0.5]]]
919 )code" ADD_FILELINE)
920 .set_num_inputs(1)
921 .set_num_outputs(1)
922 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400832e02(const NodeAttrs& attrs) 923 { return std::vector<std::string>{"A"}; } )
924 .set_attr<mxnet::FInferShape>("FInferShape", InverseShape)
925 .set_attr<nnvm::FInferType>("FInferType", ElemwiseType<1, 1>)
926 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400832f02(const NodeAttrs& attrs) 927 { return std::vector<std::pair<int, int>>{{0, 0}}; })
928 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400833002(const NodeAttrs& attrs) 929 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
930 .set_attr<THasDeterministicOutput>("THasDeterministicOutput", true)
931 .set_attr<FCompute>("FCompute<cpu>", LaOpForward<cpu, 2, 2, 1, 1, inverse>)
932 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseOut{"_backward_linalg_inverse"})
933 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrix");
934
935 NNVM_REGISTER_OP(_backward_linalg_inverse)
936 .set_num_inputs(2)
937 .set_num_outputs(1)
938 .set_attr<nnvm::FInplaceOption>("FInplaceOption", [](const NodeAttrs& attrs)
__anond0b400833102(const NodeAttrs& attrs) 939 { return std::vector<std::pair<int, int> >{{0, 0}}; })
940 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400833202(const NodeAttrs& attrs) 941 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
942 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
943 .set_attr<FCompute>("FCompute<cpu>", LaOpBackward<cpu, 2, 2, 2, 1, inverse_backward>);
944
945 NNVM_REGISTER_OP(_linalg_det)
946 .add_alias("linalg_det")
947 .add_alias("_npi_det")
948 .describe(R"code(Compute the determinant of a matrix.
949 Input is a tensor *A* of dimension *n >= 2*.
950
951 If *n=2*, *A* is a square matrix. We compute:
952
953 *out* = *det(A)*
954
955 If *n>2*, *det* is performed separately on the trailing two dimensions
956 for all inputs (batch mode).
957
958 .. note:: The operator supports float32 and float64 data types only.
959 .. note:: There is no gradient backwarded when A is non-invertible (which is
960 equivalent to det(A) = 0) because zero is rarely hit upon in float
961 point computation and the Jacobi's formula on determinant gradient
962 is not computationally efficient when A is non-invertible.
963
964 Examples::
965
966 Single matrix determinant
967 A = [[1., 4.], [2., 3.]]
968 det(A) = [-5.]
969
970 Batch matrix determinant
971 A = [[[1., 4.], [2., 3.]],
972 [[2., 3.], [1., 4.]]]
973 det(A) = [-5., 5.]
974 )code" ADD_FILELINE)
975 .set_num_inputs(1)
976 .set_num_outputs(3)
977 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400833302(const NodeAttrs& attrs) 978 { return std::vector<std::string>{"A"}; })
__anond0b400833402(const NodeAttrs& attrs) 979 .set_attr<nnvm::FNumVisibleOutputs>("FNumVisibleOutputs", [](const NodeAttrs& attrs) {
980 return 1; })
981 .set_attr<mxnet::FInferShape>("FInferShape", DetShape<1>)
982 .set_attr<nnvm::FInferType>("FInferType", DetType<1>)
983 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400833502(const NodeAttrs& attrs) 984 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
985 .set_attr<THasDeterministicOutput>("THasDeterministicOutput", true)
986 .set_attr<FCompute>("FCompute<cpu>", LaOpDetForward<cpu, 1, det>)
987 .set_attr<nnvm::FGradient>("FGradient", ReduceDetGrad<1>{"_backward_linalg_det"})
988 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrix");
989
990 NNVM_REGISTER_OP(_backward_linalg_det)
991 .set_num_inputs(4)
992 .set_num_outputs(1)
993 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400833602(const NodeAttrs& attrs) 994 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
995 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
996 .set_attr<FCompute>("FCompute<cpu>", LaOpDetBackward<cpu, 1, det_backward>);
997
998 NNVM_REGISTER_OP(_linalg_slogdet)
999 .add_alias("linalg_slogdet")
1000 .add_alias("_npi_slogdet")
1001 .describe(R"code(Compute the sign and log of the determinant of a matrix.
1002 Input is a tensor *A* of dimension *n >= 2*.
1003
1004 If *n=2*, *A* is a square matrix. We compute:
1005
1006 *sign* = *sign(det(A))*
1007 *logabsdet* = *log(abs(det(A)))*
1008
1009 If *n>2*, *slogdet* is performed separately on the trailing two dimensions
1010 for all inputs (batch mode).
1011
1012 .. note:: The operator supports float32 and float64 data types only.
1013 .. note:: The gradient is not properly defined on sign, so the gradient of
1014 it is not backwarded.
1015 .. note:: No gradient is backwarded when A is non-invertible. Please see
1016 the docs of operator det for detail.
1017
1018 Examples::
1019
1020 Single matrix signed log determinant
1021 A = [[2., 3.], [1., 4.]]
1022 sign, logabsdet = slogdet(A)
1023 sign = [1.]
1024 logabsdet = [1.609438]
1025
1026 Batch matrix signed log determinant
1027 A = [[[2., 3.], [1., 4.]],
1028 [[1., 2.], [2., 4.]],
1029 [[1., 2.], [4., 3.]]]
1030 sign, logabsdet = slogdet(A)
1031 sign = [1., 0., -1.]
1032 logabsdet = [1.609438, -inf, 1.609438]
1033 )code" ADD_FILELINE)
1034 .set_num_inputs(1)
1035 .set_num_outputs(4)
1036 .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs)
__anond0b400833702(const NodeAttrs& attrs) 1037 { return std::vector<std::string>{"A"}; })
__anond0b400833802(const NodeAttrs& attrs) 1038 .set_attr<nnvm::FNumVisibleOutputs>("FNumVisibleOutputs", [](const NodeAttrs& attrs) {
1039 return 2; })
1040 .set_attr<mxnet::FInferShape>("FInferShape", DetShape<2>)
1041 .set_attr<nnvm::FInferType>("FInferType", DetType<2>)
1042 .set_attr<FCompute>("FCompute<cpu>", LaOpDetForward<cpu, 2, slogdet>)
1043 .set_attr<nnvm::FGradient>("FGradient", ReduceDetGrad<2>{"_backward_linalg_slogdet"})
1044 .add_argument("A", "NDArray-or-Symbol", "Tensor of square matrix");
1045
1046 NNVM_REGISTER_OP(_backward_linalg_slogdet)
1047 .set_num_inputs(5)
1048 .set_num_outputs(1)
1049 .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& attrs)
__anond0b400833902(const NodeAttrs& attrs) 1050 { return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; })
1051 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
1052 .set_attr<FCompute>("FCompute<cpu>", LaOpDetBackward<cpu, 2, slogdet_backward>);
1053
1054 } // namespace op
1055 } // namespace mxnet
1056