/******************************************************************************* * Copyright (c) 2015-2018 Skymind, Inc. * * This program and the accompanying materials are made available under the * terms of the Apache License, Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * SPDX-License-Identifier: Apache-2.0 ******************************************************************************/ // // Created by Yurii Shyrma on 18.12.2017 // #include #include #include namespace nd4j { namespace ops { namespace helpers { ////////////////////////////////////////////////////////////////////////// BiDiagonalUp::BiDiagonalUp(const NDArray& matrix): _HHmatrix(nd4j::NDArrayFactory::create(matrix.ordering(), {matrix.sizeAt(0), matrix.sizeAt(1)}, matrix.dataType(), matrix.getContext())), _HHbidiag(nd4j::NDArrayFactory::create(matrix.ordering(), {matrix.sizeAt(1), matrix.sizeAt(1)}, matrix.dataType(), matrix.getContext())) { // input validation if(matrix.rankOf() != 2 || matrix.isScalar()) throw std::runtime_error("ops::helpers::biDiagonalizeUp constructor: input array must be 2D matrix !"); _HHmatrix.assign(&matrix); _HHbidiag.assign(0.); evalData(); } template void BiDiagonalUp::_evalData() { const auto rows = _HHmatrix.sizeAt(0); const auto cols = _HHmatrix.sizeAt(1); if(rows < cols) throw std::runtime_error("ops::helpers::BiDiagonalizeUp::evalData method: this procedure is applicable only for input matrix with rows >= cols !"); NDArray* bottomRightCorner(nullptr), *column(nullptr), *row(nullptr); T coeff, normX; T _x, _y; for(Nd4jLong i = 0; i < cols-1; ++i ) { // evaluate Householder matrix nullifying columns column = new NDArray(_HHmatrix({i,rows, i,i+1}, true)); _x = _HHmatrix.e(i,i); _y = _HHbidiag.e(i,i); Householder::evalHHmatrixDataI(*column, _x, _y); _HHmatrix.p(i, i, _x); _HHbidiag.p(i, i, _y); // multiply corresponding matrix block on householder matrix from the left: P * bottomRightCorner bottomRightCorner = new NDArray(_HHmatrix({i,rows, i+1,cols}, true)); // {i, cols} Householder::mulLeft(*bottomRightCorner, _HHmatrix({i+1,rows, i,i+1}, true), _HHmatrix.e(i,i)); delete bottomRightCorner; delete column; if(i == cols-2) continue; // do not apply right multiplying at last iteration // evaluate Householder matrix nullifying rows row = new NDArray(_HHmatrix({i,i+1, i+1,cols}, true)); _x = _HHmatrix.e(i,i+1); _y = _HHbidiag.e(i,i+1); Householder::evalHHmatrixDataI(*row, _x, _y); _HHmatrix.p(i, i+1, _x); _HHbidiag.p(i, i+1, _y); // multiply corresponding matrix block on householder matrix from the right: bottomRightCorner * P bottomRightCorner = new NDArray(_HHmatrix({i+1,rows, i+1,cols}, true)); // {i, rows} Householder::mulRight(*bottomRightCorner, _HHmatrix({i,i+1, i+2,cols}, true), _HHmatrix.e(i,i+1)); delete bottomRightCorner; delete row; } row = new NDArray(_HHmatrix({cols-2,cols-1, cols-1,cols}, true)); _x = _HHmatrix.e(cols-2,cols-1); _y = _HHbidiag.e(cols-2,cols-1); Householder::evalHHmatrixDataI(*row, _x, _y); _HHmatrix.p(cols-2,cols-1, _x); _HHbidiag.p(cols-2,cols-1, _y); delete row; column = new NDArray(_HHmatrix({cols-1,rows, cols-1,cols}, true)); _x = _HHmatrix.e(cols-1,cols-1); _y = _HHbidiag.e(cols-1,cols-1); Householder::evalHHmatrixDataI(*column, _x, _y); _HHmatrix.p(cols-1, cols-1, _x); _HHbidiag.p(cols-1, cols-1, _y); delete column; } ////////////////////////////////////////////////////////////////////////// void BiDiagonalUp::evalData() { auto xType = _HHmatrix.dataType(); BUILD_SINGLE_SELECTOR(xType, _evalData, ();, FLOAT_TYPES); } ////////////////////////////////////////////////////////////////////////// template HHsequence BiDiagonalUp::makeHHsequence_(const char type) const { if(type == 'u') { const int diagSize = _HHbidiag.sizeAt(0); auto colOfCoeffs = NDArrayFactory::create(_HHmatrix.ordering(), {diagSize, 1}, _HHmatrix.dataType(), _HHmatrix.getContext()); for(int i = 0; i < diagSize; ++i) colOfCoeffs.p(i, _HHmatrix.e(i,i)); return HHsequence(_HHmatrix, colOfCoeffs, type); } else { const int diagUpSize = _HHbidiag.sizeAt(0) - 1; NDArray colOfCoeffs = NDArrayFactory::create(_HHmatrix.ordering(), {diagUpSize, 1}, _HHmatrix.dataType(), _HHmatrix.getContext()); for(int i = 0; i < diagUpSize; ++i) colOfCoeffs.p(i, _HHmatrix.e(i,i+1)); HHsequence result(_HHmatrix, colOfCoeffs, type); result._diagSize = diagUpSize; result._shift = 1; return result; } } HHsequence BiDiagonalUp::makeHHsequence(const char type) const { auto xType = _HHmatrix.dataType(); BUILD_SINGLE_SELECTOR(xType, return makeHHsequence_, (type);, FLOAT_TYPES); } BUILD_SINGLE_TEMPLATE(template void BiDiagonalUp::_evalData, (), FLOAT_TYPES); BUILD_SINGLE_TEMPLATE(template HHsequence BiDiagonalUp::makeHHsequence_, (const char type) const, FLOAT_TYPES); } } }