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