00001
00013 #include <dlrCommon/exception.h>
00014 #include <dlrLinearAlgebra/linearAlgebra.h>
00015 #include <dlrLinearAlgebra/clapack.h>
00016 #include <dlrNumeric/utilities.h>
00017
00018
00019 namespace dlr {
00020
00025 namespace linearAlgebra {
00026
00027 void
00028 choleskyFactorization(const Array2D<Float64>& inputArray,
00029 Array2D<Float64>& kArray,
00030 bool isUpperTriangular)
00031 {
00032
00033 if(inputArray.size() == 0) {
00034 DLR_THROW3(ValueException,
00035 "choleskyFactorization()",
00036 "Argument inputArray cannot have zero size.");
00037 }
00038 if(inputArray.rows() != inputArray.columns()) {
00039 DLR_THROW3(ValueException,
00040 "choleskyFactorization()",
00041 "Argument inputArray must be square.");
00042 }
00043
00044
00045
00046
00047
00048
00049 size_t dimension = inputArray.rows();
00050 Array2D<Float64> aColumnMajor(dimension, dimension);
00051 aColumnMajor = 0.0;
00052 {
00053 Array2D<Float64>::const_iterator inPtr = inputArray.begin();
00054 Array2D<Float64>::iterator outPtr = aColumnMajor.begin();
00055 if(isUpperTriangular) {
00056 for(size_t index0 = 0; index0 < dimension; ++index0) {
00057 inPtr += index0;
00058 outPtr += index0;
00059 for(size_t index1 = index0; index1 < dimension; ++index1) {
00060 *(outPtr++) = *(inPtr++);
00061 }
00062 }
00063 } else {
00064 for(size_t index0 = 0; index0 < dimension; ++index0) {
00065 for(size_t index1 = 0; index1 <= index0; ++index1) {
00066 *(outPtr++) = *(inPtr++);
00067 }
00068 inPtr += (dimension - index0 - 1);
00069 outPtr += (dimension - index0 - 1);
00070 }
00071 }
00072 }
00073
00074
00075
00076
00077
00078
00079 char UPLO = isUpperTriangular ? 'L' : 'U';
00080 Int32 N = static_cast<Int32>(dimension);
00081 Int32 LDA = static_cast<Int32>(dimension);
00082 Int32 INFO;
00083
00084
00085
00086 dpotrf_(&UPLO, &N, aColumnMajor.data(), &LDA, &INFO);
00087
00088
00089 if(INFO < 0L) {
00090 std::ostringstream message;
00091 message << "Call to dpotrf_ returns " << INFO
00092 << ". Something is wrong.";
00093 DLR_THROW3(ValueException, "choleskyFactorization()",
00094 message.str().c_str());
00095 } else if(INFO > 0L) {
00096 std::ostringstream message;
00097 DLR_THROW3(ValueException, "choleskyFactorization()",
00098 "Input matrix is not positive definite.");
00099 }
00100
00101
00102 kArray = aColumnMajor;
00103 }
00104
00105
00106 Float64
00107 determinant(const Array2D<Float64>& A)
00108 {
00109
00110 if(A.columns() != A.rows()) {
00111 DLR_THROW3(ValueException,
00112 "determinant(const Array2D<Float64>&)",
00113 "Input array is not square.");
00114 }
00115
00116
00117
00118
00119
00120
00121 Array2D<Float64> AColumnMajor = A.transpose();
00122 Int32 M = static_cast<Int32>(A.rows());
00123 Int32 N = static_cast<Int32>(A.columns());
00124 Int32 LDA = static_cast<Int32>(A.rows());
00125 Array1D<Int32> IPIV(M);
00126 Int32 info;
00127 dgetrf_(&M, &N, AColumnMajor.data(), &LDA, IPIV.data(), &info);
00128
00129
00130 if(info != 0L) {
00131 std::ostringstream message;
00132 message << "Call to dgetrf_ returns " << info
00133 << ". Something is wrong.";
00134 DLR_THROW3(ValueException,
00135 "determinant(const Array2D<Float64>&)",
00136 message.str().c_str());
00137 }
00138
00139
00140
00141
00142
00143 Float64 determinant = 1.0;
00144 size_t swapCount = 0;
00145 for(size_t index = 0; index < AColumnMajor.rows(); ++index) {
00146 determinant *= AColumnMajor(index, index);
00147 if(IPIV[index] != static_cast<Int32>(index + 1)) {
00148
00149 ++swapCount;
00150 }
00151 }
00152
00153
00154 if((swapCount % 2) == 1) {
00155 determinant *= -1.0;
00156 }
00157 return determinant;
00158 }
00159
00160
00161 Array1D<Float64>
00162 eigenvaluesSymmetric(const Array2D<Float64>& inputArray)
00163 {
00164
00165 if(inputArray.size() == 0) {
00166 DLR_THROW3(ValueException,
00167 "eigenvaluesSymmetric()",
00168 "Argument inputArray cannot have zero size.");
00169 }
00170 if(inputArray.rows() != inputArray.columns()) {
00171 DLR_THROW3(ValueException,
00172 "eigenvaluesSymmetric()",
00173 "Argument inputArray must be square.");
00174 }
00175
00176
00177
00178
00179 size_t dimension = inputArray.rows();
00180 Array2D<Float64> aColumnMajor(dimension, dimension);
00181 {
00182 Array2D<Float64>::const_iterator inPtr = inputArray.begin();
00183 Array2D<Float64>::iterator outPtr = aColumnMajor.begin();
00184 for(size_t index0 = 0; index0 < dimension; ++index0) {
00185 inPtr += index0;
00186 outPtr += index0;
00187 for(size_t index1 = index0; index1 < dimension; ++index1) {
00188 *(outPtr++) = *(inPtr++);
00189 }
00190 }
00191 }
00192
00193
00194 Array1D<Float64> eigenvalues(dimension);
00195
00196
00197 char JOBZ = 'N';
00198 char UPLO = 'L';
00199 Int32 N = static_cast<Int32>(inputArray.rows());
00200 Int32 LDA = N;
00201 Float64 WORK;
00202 Int32 LWORK = -1;
00203 Int32 INFO;
00204
00205
00206 dsyev_(&JOBZ, &UPLO, &N, aColumnMajor.data(), &LDA,
00207 eigenvalues.data(), &WORK, &LWORK, &INFO);
00208
00209
00210 if(INFO != 0L) {
00211 std::ostringstream message;
00212 message << "First call to dsyev_ returns " << INFO
00213 << ". Something is wrong.";
00214 DLR_THROW3(ValueException,
00215 "eigenvaluesSymmetric()",
00216 message.str().c_str());
00217 }
00218
00219
00220 LWORK = static_cast<Int32>(WORK);
00221 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
00222
00223
00224 dsyev_(&JOBZ, &UPLO, &N, aColumnMajor.data(), &LDA,
00225 eigenvalues.data(), doubleWorkSpace.data(), &LWORK, &INFO);
00226
00227
00228 if(INFO != 0L) {
00229 std::ostringstream message;
00230 message << "Second call to dsyev_ returns " << INFO
00231 << ". Something is wrong.";
00232 DLR_THROW3(ValueException,
00233 "eigenvaluesSymmetric()",
00234 message.str().c_str());
00235 }
00236
00237
00238 std::reverse(eigenvalues.begin(), eigenvalues.end());
00239 return eigenvalues;
00240 }
00241
00242
00243 void
00244 eigenvectors(const Array2D<Float64>& inputArray,
00245 Array1D< std::complex<Float64> >& eigenvalues,
00246 Array2D< std::complex<Float64> >& eigenvectors,
00247 bool isSortRequired)
00248 {
00249
00250 if(inputArray.size() == 0) {
00251 DLR_THROW3(ValueException,
00252 "eigenvectors()",
00253 "Argument inputArray cannot have zero size.");
00254 }
00255 if(inputArray.rows() != inputArray.columns()) {
00256 DLR_THROW3(ValueException,
00257 "eigenvectors()",
00258 "Argument inputArray must be square.");
00259 }
00260
00261
00262 size_t dimension = inputArray.rows();
00263 Array2D<Float64> aTransposeColumnMajor = inputArray.copy();
00264
00265
00266 Array1D<Float64> eigenvaluesReal(dimension);
00267 Array1D<Float64> eigenvaluesImag(dimension);
00268 Array2D<Float64> leftEigenvectorsTranspose(dimension, dimension);
00269 Array2D<Float64> rightEigenvectorsTranspose(dimension, dimension);
00270
00271
00272 char JOBVL = 'V';
00273 char JOBVR = 'N';
00274 Int32 N = static_cast<Int32>(dimension);
00275 Int32 LDA = static_cast<Int32>(dimension);
00276 Int32 LDVL = static_cast<Int32>(dimension);
00277 Int32 LDVR = static_cast<Int32>(dimension);
00278 Float64 WORK;
00279 Int32 LWORK = -1;
00280 Int32 INFO;
00281
00282
00283 dgeev_(&JOBVL, &JOBVR, &N, aTransposeColumnMajor.data(), &LDA,
00284 eigenvaluesReal.data(), eigenvaluesImag.data(),
00285 leftEigenvectorsTranspose.data(), &LDVL,
00286 rightEigenvectorsTranspose.data(), &LDVR,
00287 &WORK, &LWORK, &INFO);
00288
00289
00290 if(INFO != 0L) {
00291 std::ostringstream message;
00292 message << "First call to dgeev_ returns " << INFO
00293 << ". Something is wrong.";
00294 DLR_THROW3(ValueException, "eigenvectors()", message.str().c_str());
00295 }
00296
00297
00298 LWORK = static_cast<Int32>(WORK);
00299 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
00300
00301
00302 dgeev_(&JOBVL, &JOBVR, &N, aTransposeColumnMajor.data(), &LDA,
00303 eigenvaluesReal.data(), eigenvaluesImag.data(),
00304 leftEigenvectorsTranspose.data(), &LDVL,
00305 rightEigenvectorsTranspose.data(), &LDVR,
00306 doubleWorkSpace.data(), &LWORK, &INFO);
00307
00308
00309 if(INFO != 0L) {
00310 std::ostringstream message;
00311 message << "Second call to dgeev_ returns " << INFO
00312 << ". Something is wrong.";
00313 DLR_THROW3(ValueException, "eigenvectors()", message.str().c_str());
00314 }
00315
00316
00317 if(eigenvalues.size() != dimension) {
00318 eigenvalues.reinit(dimension);
00319 }
00320 if(eigenvectors.rows() != dimension
00321 || eigenvectors.columns() != dimension) {
00322 eigenvectors.reinit(dimension, dimension);
00323 }
00324
00325
00326 for(size_t ii = 0; ii < dimension; ++ii) {
00327 eigenvalues[ii].real() = eigenvaluesReal[ii];
00328 eigenvalues[ii].imag() = eigenvaluesImag[ii];
00329 if(eigenvaluesImag[ii] == 0.0) {
00330 for(size_t jj = 0; jj < dimension; ++jj) {
00331 eigenvectors(jj, ii).real() = leftEigenvectorsTranspose(ii, jj);
00332 eigenvectors(jj, ii).imag() = 0.0;
00333 }
00334 } else {
00335 eigenvalues[ii + 1].real() = eigenvaluesReal[ii + 1];
00336 eigenvalues[ii + 1].imag() = eigenvaluesImag[ii + 1];
00337 for(size_t jj = 0; jj < dimension; ++jj) {
00338 eigenvectors(jj, ii).real() =
00339 leftEigenvectorsTranspose(ii, jj);
00340 eigenvectors(jj, ii).imag() =
00341 leftEigenvectorsTranspose(ii + 1, jj);
00342 eigenvectors(jj, ii + 1).real() =
00343 leftEigenvectorsTranspose(ii, jj);
00344 eigenvectors(jj, ii + 1).imag() =
00345 -leftEigenvectorsTranspose(ii + 1, jj);
00346 }
00347 ++ii;
00348 }
00349 }
00350
00351
00352 if(isSortRequired) {
00353 Array1D<double> magnitudes2(eigenvalues.size());
00354 for(size_t ii = 0; ii < eigenvalues.size(); ++ii) {
00355 magnitudes2[ii] = (eigenvalues[ii].real() * eigenvalues[ii].real()
00356 + eigenvalues[ii].imag() * eigenvalues[ii].imag());
00357 }
00358 Array1D<size_t> outputOrder = argsort(magnitudes2);
00359 std::reverse(outputOrder.begin(), outputOrder.end());
00360
00361 Array1D< std::complex<Float64> > sortedEigenvalues(eigenvalues.size());
00362 Array2D< std::complex<Float64> > sortedEigenvectors(
00363 eigenvectors.rows(), eigenvectors.columns());
00364 for(size_t ii = 0; ii < dimension; ++ii) {
00365 sortedEigenvalues[ii] = eigenvalues[outputOrder[ii]];
00366 for(size_t jj = 0; jj < dimension; ++jj) {
00367 sortedEigenvectors(jj, ii) = eigenvectors(jj, outputOrder[ii]);
00368 }
00369 }
00370 eigenvalues = sortedEigenvalues;
00371 eigenvectors = sortedEigenvectors;
00372 }
00373 }
00374
00375
00376 void
00377 eigenvectorsSymmetric(const Array2D<Float64>& inputArray,
00378 Array1D<Float64>& eigenvalues,
00379 Array2D<Float64>& eigenvectors)
00380 {
00381
00382 if(inputArray.size() == 0) {
00383 DLR_THROW3(ValueException,
00384 "eigenvectorsSymmetric()",
00385 "Argument inputArray cannot have zero size.");
00386 }
00387 if(inputArray.rows() != inputArray.columns()) {
00388 DLR_THROW3(ValueException,
00389 "eigenvectorsSymmetric()",
00390 "Argument inputArray must be square.");
00391 }
00392
00393
00394
00395
00396 size_t dimension = inputArray.rows();
00397 Array2D<Float64> aColumnMajor(dimension, dimension);
00398 {
00399 Array2D<Float64>::const_iterator inPtr = inputArray.begin();
00400 Array2D<Float64>::iterator outPtr = aColumnMajor.begin();
00401 for(size_t index0 = 0; index0 < dimension; ++index0) {
00402 inPtr += index0;
00403 outPtr += index0;
00404 for(size_t index1 = index0; index1 < dimension; ++index1) {
00405 *(outPtr++) = *(inPtr++);
00406 }
00407 }
00408 }
00409
00410
00411 Array1D<Float64> eigenvaluesTmp(dimension);
00412
00413
00414 char JOBZ = 'V';
00415 char UPLO = 'L';
00416 Int32 N = static_cast<Int32>(dimension);
00417 Int32 LDA = static_cast<Int32>(dimension);
00418 Float64 WORK;
00419 Int32 LWORK = -1;
00420 Int32 INFO;
00421
00422
00423 dsyev_(&JOBZ, &UPLO, &N, aColumnMajor.data(), &LDA,
00424 eigenvaluesTmp.data(), &WORK, &LWORK, &INFO);
00425
00426
00427 if(INFO != 0L) {
00428 std::ostringstream message;
00429 message << "First call to dsyev_ returns " << INFO
00430 << ". Something is wrong.";
00431 DLR_THROW3(ValueException,
00432 "eigenvectorsSymmetric()",
00433 message.str().c_str());
00434 }
00435
00436
00437 LWORK = static_cast<Int32>(WORK);
00438 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
00439
00440
00441 dsyev_(&JOBZ, &UPLO, &N, aColumnMajor.data(), &LDA,
00442 eigenvaluesTmp.data(), doubleWorkSpace.data(), &LWORK, &INFO);
00443
00444
00445 if(INFO != 0L) {
00446 std::ostringstream message;
00447 message << "Second call to dsyev_ returns " << INFO
00448 << ". Something is wrong.";
00449 DLR_THROW3(ValueException,
00450 "eigenvectorsSymmetric()",
00451 message.str().c_str());
00452 }
00453
00454
00455
00456
00457
00458
00459 if(eigenvalues.size() != dimension) {
00460 eigenvalues.reinit(dimension);
00461 }
00462 if(eigenvectors.rows() != dimension
00463 || eigenvectors.columns() != dimension) {
00464 eigenvectors.reinit(dimension, dimension);
00465 }
00466
00467
00468 {
00469 Array1D<Float64>::iterator outPtr = eigenvalues.end() - 1;
00470 Array1D<Float64>::iterator inPtr0 = eigenvaluesTmp.begin();
00471 Array1D<Float64>::iterator inPtr1 = eigenvaluesTmp.end();
00472 while(inPtr0 != inPtr1) {
00473 *outPtr = *inPtr0;
00474 ++inPtr0;
00475 --outPtr;
00476 }
00477 }
00478
00479
00480 for(size_t index0 = 0; index0 < dimension; ++index0) {
00481 Float64* outPtr = eigenvectors.data(index0);
00482 Float64* inPtr = aColumnMajor.data((dimension - index0 - 1) * dimension);
00483 for(size_t index1 = 0; index1 < dimension; ++index1) {
00484 *outPtr = *inPtr;
00485 ++inPtr;
00486 outPtr += dimension;
00487 }
00488 }
00489 }
00490
00491
00492 Array2D<Float64>
00493 inverse(const Array2D<Float64>& A)
00494 {
00495
00496 if(A.columns() != A.rows()) {
00497 DLR_THROW3(ValueException,
00498 "inverse(const Array2D<Float64>&)",
00499 "Input array is not square.");
00500 }
00501
00502 Array2D<Float64> AInverse =
00503 identity(A.rows(), A.rows(), type_tag<Float64>());
00504 Array2D<Float64> AA = A.transpose();
00505
00506 linearSolveInPlace(AA, AInverse);
00507 return AInverse;
00508 }
00509
00510
00511
00512
00513 std::pair<Float64, Float64>
00514 linearFit(const Array1D<Float64>& array0,
00515 const Array1D<Float64>& array1)
00516 {
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 if(array0.size() != array1.size()) {
00537 std::ostringstream message;
00538 message << "Arguments array0 and array1 must have the same size, "
00539 << "but are of size " << array0.size()
00540 << " and " << array1.size() << " respectively." << std::endl;
00541 DLR_THROW3(ValueException,
00542 "linearFit(const Array1D<Float64>&, const Array1D<Float64>&)",
00543 message.str().c_str());
00544 }
00545 if(array0.size() == 0) {
00546 DLR_THROW3(ValueException,
00547 "linearFit(const Array1D<Float64>&, const Array1D<Float64>&)",
00548 "Arguments cannot have zero size.");
00549 }
00550
00551
00552 Array2D<Float64> AMatrix(2, 2);
00553 AMatrix(0, 0) = dot(array0, array0);
00554 AMatrix(0, 1) = sum(array0);
00555 AMatrix(1, 0) = sum(array0);
00556 AMatrix(1, 1) = array0.size();
00557
00558 Array1D<Float64> bVector(2);
00559 bVector(0) = dot(array0, array1);
00560 bVector(1) = sum(array1);
00561
00562 Array2D<Float64> AInverse = inverse(AMatrix);
00563
00564 Array1D<Float64> result = matrixMultiply(AInverse, bVector);
00565 return std::make_pair(result(0), result(1));
00566 }
00567
00568
00569
00570
00571 Array1D<Float64>
00572 linearLeastSquares(const Array2D<Float64>& A, const Array1D<Float64>& b)
00573 {
00574
00575 if(A.size() == 0) {
00576 DLR_THROW3(
00577 ValueException,
00578 "linearLeastSquares(const Array2D<Float64>&, const Array1D<Float64>&)",
00579 "Input array A must have nonzero size.");
00580 }
00581 if(A.rows() != b.size()) {
00582 DLR_THROW3(
00583 ValueException,
00584 "linearLeastSquares(const Array2D<Float64>&, const Array1D<Float64>&)",
00585 "The number of rows in input array A must be the same as the number "
00586 "of elements in b.");
00587 }
00588
00589
00590
00591
00592
00593
00594 char trans = 'N';
00595 Int32 rows = static_cast<Int32>(A.rows());
00596 Int32 columns = static_cast<Int32>(A.columns());
00597 Int32 nrhs = static_cast<Int32>(1);
00598 Int32 ldb = static_cast<Int32>(std::max(rows, columns));
00599 Float64 temporaryWorkspace;
00600 Int32 lwork = -1;
00601 Int32 info;
00602
00603
00604 Array2D<Float64> AColumnMajor = A.transpose();
00605 Array1D<Float64> bCopy(ldb);
00606 std::copy(b.begin(), b.end(), bCopy.begin());
00607
00608
00609
00610 dgels_(&trans, &rows, &columns, &nrhs, AColumnMajor.data(), &rows,
00611 bCopy.data(), &ldb, &temporaryWorkspace, &lwork, &info);
00612
00613
00614 if(info != 0L) {
00615 std::ostringstream message;
00616 message << "First call to dgels_ returns " << info
00617 << ". Something is wrong.";
00618 DLR_THROW3(ValueException,
00619 "linearLeastSquares()",
00620 message.str().c_str());
00621 }
00622
00623
00624 lwork = static_cast<Int32>(temporaryWorkspace);
00625 Array1D<Float64> doubleWorkspace(static_cast<size_t>(lwork));
00626
00627
00628 dgels_(&trans, &rows, &columns, &nrhs, AColumnMajor.data(), &rows,
00629 bCopy.data(), &ldb, doubleWorkspace.data(), &lwork, &info);
00630
00631
00632 if(info != 0L) {
00633 std::ostringstream message;
00634 message << "Second call to dgels_ returns " << info
00635 << ". Something is wrong.";
00636 DLR_THROW3(ValueException,
00637 "linearLeastSquares()",
00638 message.str().c_str());
00639 }
00640
00641 if(bCopy.size() == A.columns()) {
00642 return bCopy;
00643 } else {
00644 Array1D<Float64> returnValue(A.columns());
00645 std::copy(bCopy.begin(), bCopy.begin() + A.columns(),
00646 returnValue.begin());
00647 return returnValue;
00648 }
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 void
00658 linearSolveInPlace(Array2D<Float64>& A, Array1D<Float64>& b)
00659 {
00660 Array2D<Float64> bMatrix(b.size(), 1, b.data());
00661 linearSolveInPlace(A, bMatrix);
00662 }
00663
00664
00665
00666
00667
00668 void
00669 linearSolveInPlace(Array2D<Float64> &A, Array2D<Float64> &b)
00670 {
00671
00672 if(A.rows() != b.rows()) {
00673 DLR_THROW3(ValueException,
00674 "linearSolveInPlace(Array2D<Float64>&, Array2D<Float64>&)",
00675 "Input arrays A and b must have the same number of rows.");
00676 }
00677 if(A.rows() != A.columns()) {
00678 DLR_THROW3(ValueException,
00679 "linearSolveInPlace(Array2D<Float64>&, Array2D<Float64>&)",
00680 "Input array A must be square.");
00681 }
00682
00683
00684 Array2D<Float64> AColumnMajor = A.transpose();
00685
00686
00687 Int32 rows = static_cast<Int32>(A.rows());
00688 Int32 xColumns = static_cast<Int32>(b.columns());
00689 Int32 *iPiv = new Int32[rows];
00690 Int32 info;
00691 dgesv_(&rows, &xColumns, AColumnMajor.data(), &rows, iPiv, b.data(), &rows,
00692 &info );
00693
00694 delete[] iPiv;
00695
00696 if(info != 0L) {
00697 std::ostringstream message;
00698 message << "Call to dgesv_ returns " << info << ". Something is wrong."
00699 << " Perhaps the the input equations are poorly conditioned "
00700 << "or perhaps there is no solution.";
00701 DLR_THROW3(ValueException,
00702 "linearSolveInPlace(Array2D<Float64>&, Array2D<Float64>&)",
00703 message.str().c_str());
00704 }
00705 }
00706
00707
00708
00709
00710 Array1D<Float64>
00711 linearSolveTridiagonal(const Array1D<Float64>& subDiagonal,
00712 const Array1D<Float64>& centerDiagonal,
00713 const Array1D<Float64>& superDiagonal,
00714 const Array1D<Float64>& bVector)
00715 {
00716
00717 if(subDiagonal.size() != superDiagonal.size()) {
00718 DLR_THROW3(ValueException,
00719 "linearSolveTridiagonal()",
00720 "Input arguments subDiagonal and superDiagonal "
00721 "must have the same size.");
00722 }
00723 if(centerDiagonal.size() != bVector.size()) {
00724 DLR_THROW3(ValueException,
00725 "linearSolveTridiagonal()",
00726 "Input arguments centerDiagonal and bVector "
00727 "must have the same size.");
00728 }
00729 if(centerDiagonal.size() != subDiagonal.size() + 1) {
00730 DLR_THROW3(ValueException,
00731 "linearSolveTridiagonal()",
00732 "Input argument centerDiagonal must have one more element "
00733 "than input argument subDiagonal.");
00734 }
00735
00736
00737
00738 Int32 N = static_cast<Int32>(centerDiagonal.size());
00739 Int32 NRHS = 1;
00740 Array1D<Float64> subDiagonalCopy = subDiagonal.copy();
00741 Array1D<Float64> centerDiagonalCopy = centerDiagonal.copy();
00742 Array1D<Float64> superDiagonalCopy = superDiagonal.copy();
00743 Array1D<Float64> xVector = bVector.copy();
00744 Int32 INFO;
00745
00746 dgtsv_(&N, &NRHS, subDiagonalCopy.data(), centerDiagonalCopy.data(),
00747 superDiagonalCopy.data(), xVector.data(), &N, &INFO);
00748
00749
00750 if(INFO != 0L) {
00751 std::ostringstream message;
00752 message << "Call to dgtsv_ returns " << INFO << ". Something is wrong."
00753 << " Perhaps the the input equations are poorly conditioned "
00754 << "or perhaps there is no solution.";
00755 DLR_THROW3(ValueException,
00756 "linearSolveTridiagonal()",
00757 message.str().c_str());
00758 }
00759
00760 return xVector;
00761 }
00762
00763
00764
00765
00766 void
00767 qrFactorization(const Array2D<Float64>& inputArray,
00768 Array2D<Float64>& qArray,
00769 Array2D<Float64>& rArray)
00770 {
00771
00772 if(inputArray.size() == 0) {
00773 qArray.clear();
00774 rArray.clear();
00775 return;
00776 }
00777
00778
00779 Int32 rows = static_cast<Int32>(inputArray.rows());
00780 Int32 columns = static_cast<Int32>(inputArray.columns());
00781 Int32 lda = rows;
00782 Float64 temporaryWorkspace;
00783 Int32 lwork = -1;
00784 Int32 info;
00785
00786
00787 Array2D<Float64> AColumnMajor = inputArray.transpose();
00788 Array1D<Float64> tauArray = Array1D<Float64>(std::min(rows, columns));
00789
00790
00791
00792 dgeqrf_(&rows, &columns, AColumnMajor.data(), &lda, tauArray.data(),
00793 &temporaryWorkspace, &lwork, &info);
00794
00795
00796 if(info != 0L) {
00797 std::ostringstream message;
00798 message << "First call to dgeqrf_ returns " << info
00799 << ". Something is wrong.";
00800 DLR_THROW3(ValueException, "qrFactorization()", message.str().c_str());
00801 }
00802
00803
00804 lwork = static_cast<Int32>(temporaryWorkspace);
00805 Array1D<Float64> doubleWorkspace(static_cast<size_t>(lwork));
00806
00807
00808 dgeqrf_(&rows, &columns, AColumnMajor.data(), &lda, tauArray.data(),
00809 doubleWorkspace.data(), &lwork, &info);
00810
00811
00812 if(info != 0L) {
00813 std::ostringstream message;
00814 message << "Second call to dgeqrf_ returns " << info
00815 << ". Something is wrong.";
00816 DLR_THROW3(ValueException, "qrFactorization()", message.str().c_str());
00817 }
00818
00819
00820 if((rArray.rows() != inputArray.rows())
00821 || (rArray.columns() != inputArray.columns())) {
00822 rArray.reinit(inputArray.rows(), inputArray.columns());
00823 }
00824 rArray = 0.0;
00825 if((qArray.rows() != inputArray.rows())
00826 || (qArray.columns() != inputArray.rows())) {
00827 qArray.reinit(inputArray.rows(), inputArray.rows());
00828 }
00829 qArray = 0.0;
00830
00831
00832 size_t numNonzeroRows = std::min(inputArray.rows(), inputArray.columns());
00833 for(size_t row = 0; row < numNonzeroRows; ++row) {
00834 for(size_t column = row; column < rArray.columns(); ++column) {
00835 rArray(row, column) = AColumnMajor(column, row);
00836 }
00837 }
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854 for(size_t row = 0; row < qArray.rows(); ++row) {
00855 qArray(row, row) = static_cast<Float64>(1.0);
00856 }
00857
00858
00859 Array1D<Float64> vArray(qArray.rows());
00860 Array2D<Float64> reflector(qArray.rows(), qArray.rows());
00861 for(size_t ii = 0; ii < numNonzeroRows; ++ii) {
00862
00863
00864 reflector = 0.0;
00865 for(size_t kk = 0; kk < reflector.rows(); ++kk) {
00866 reflector(kk, kk) = 1.0;
00867 }
00868
00869
00870 Float64 tau = tauArray[ii];
00871
00872
00873
00874
00875
00876
00877 if(ii > 0) {
00878 vArray[ii - 1] = 0.0;
00879 }
00880 vArray[ii] = 1.0;
00881 for(size_t jj = ii + 1; jj < qArray.rows(); ++jj) {
00882 vArray[jj] = AColumnMajor(ii, jj);
00883 }
00884
00885
00886 for(size_t row = ii; row < qArray.rows(); ++row) {
00887 for(size_t column = ii; column < qArray.columns(); ++column) {
00888 reflector(row, column) -= tau * vArray[row] * vArray[column];
00889 }
00890 }
00891
00892 qArray = matrixMultiply(qArray, reflector);
00893 }
00894
00895
00896
00897 for(size_t ii = 0; ii < inputArray.rows(); ++ii) {
00898 if(rArray(ii, ii) == 0.0) {
00899 continue;
00900 }
00901 if(rArray(ii, ii) < 0.0) {
00902 rArray *= -1.0;
00903 qArray *= -1.0;
00904 break;
00905 }
00906 }
00907 }
00908
00909
00910
00911
00912
00913 Array2D<Float64>
00914 pseudoinverse(const Array2D<Float64>& A)
00915 {
00916 Array2D<Float64> ATranspose = A.transpose();
00917 Array2D<Float64> ATA = matrixMultiply(ATranspose, A);
00918 return matrixMultiply(inverse(ATA), ATranspose);
00919 }
00920
00921
00922
00923
00924 void
00925 singularValueDecomposition(const Array2D<Float64>& inputArray,
00926 Array2D<Float64>& uArray,
00927 Array1D<Float64>& sigmaArray,
00928 Array2D<Float64>& vTransposeArray,
00929 bool isNullSpaceRequired,
00930 bool isFullRangeRequired)
00931 {
00932
00933 if(inputArray.size() == 0) {
00934 DLR_THROW3(ValueException,
00935 "singularValueDecomposition()",
00936 "Argument inputArray cannot have zero size.");
00937 }
00938
00939
00940 isFullRangeRequired = isNullSpaceRequired;
00941
00942
00943
00944
00945
00946
00947 Array2D<Float64> aColumnMajor = inputArray.copy();
00948
00949
00950 size_t numberOfSingularValues =
00951 std::min(inputArray.rows(), inputArray.columns());
00952
00953 size_t numberOfVRows;
00954 if(isNullSpaceRequired) {
00955 numberOfVRows = inputArray.columns();
00956 } else {
00957 numberOfVRows = numberOfSingularValues;
00958 }
00959 if((vTransposeArray.rows() != numberOfVRows)
00960 || (vTransposeArray.columns() != inputArray.columns())) {
00961 vTransposeArray.reinit(numberOfVRows, inputArray.columns());
00962 }
00963
00964 Array2D<Float64> uColumnMajor = vTransposeArray;
00965
00966 size_t numberOfUColumns;
00967 if(isFullRangeRequired) {
00968 numberOfUColumns = inputArray.rows();
00969 } else {
00970 numberOfUColumns = numberOfSingularValues;
00971 }
00972 if((uArray.rows() != inputArray.rows())
00973 || (uArray.columns() != numberOfUColumns)) {
00974 uArray.reinit(inputArray.rows(), numberOfUColumns);
00975 }
00976
00977 Array2D<Float64> vTColumnMajor = uArray;
00978
00979 if(sigmaArray.size() != numberOfSingularValues) {
00980 sigmaArray.reinit(numberOfSingularValues);
00981 }
00982 Array1D<Int32> integerWorkSpace(8 * numberOfSingularValues);
00983
00984
00985 char JOBZ;
00986 if(isNullSpaceRequired) {
00987 JOBZ = 'A';
00988 } else {
00989 JOBZ = 'S';
00990 }
00991 Int32 M = static_cast<Int32>(inputArray.columns());
00992 Int32 N = static_cast<Int32>(inputArray.rows());
00993 Int32 LDA = M;
00994 Int32 LDU = M;
00995 Int32 LDVT = static_cast<Int32>(numberOfSingularValues);
00996 Float64 WORK;
00997 Int32 LWORK = -1;
00998 Int32 INFO;
00999
01000
01001 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01002 sigmaArray.data(), uColumnMajor.data(), &LDU,
01003 vTColumnMajor.data(), &LDVT,
01004 &WORK, &LWORK,
01005 integerWorkSpace.data(), &INFO);
01006
01007
01008 if(INFO != 0L) {
01009 std::ostringstream message;
01010 message << "First call to dgesdd_ returns " << INFO
01011 << ". Something is wrong.";
01012 DLR_THROW3(ValueException,
01013 "singularValueDecomposition()",
01014 message.str().c_str());
01015 }
01016
01017
01018 LWORK = static_cast<Int32>(WORK);
01019 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
01020
01021
01022 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01023 sigmaArray.data(), uColumnMajor.data(), &LDU,
01024 vTColumnMajor.data(), &LDVT,
01025 doubleWorkSpace.data(), &LWORK,
01026 integerWorkSpace.data(), &INFO);
01027
01028
01029 if(INFO != 0L) {
01030 std::ostringstream message;
01031 message << "Second call to dgesdd_ returns " << INFO
01032 << ". Something is wrong.";
01033 DLR_THROW3(ValueException,
01034 "singularValueDecomposition()",
01035 message.str().c_str());
01036 }
01037 }
01038
01039
01040
01041 void
01042 singularValueDecompositionSimple(const Array2D<Float64>& inputArray,
01043 Array2D<Float64>& uArray,
01044 Array1D<Float64>& sigmaArray,
01045 Array2D<Float64>& vTransposeArray)
01046 {
01047
01048 if(inputArray.size() == 0) {
01049 DLR_THROW3(ValueException,
01050 "singularValueDecomposition()",
01051 "Argument inputArray cannot have zero size.");
01052 }
01053
01054
01055
01056
01057
01058 Array2D<Float64> aColumnMajor = inputArray.copy();
01059
01060
01061 size_t numberOfSingularValues =
01062 std::min(inputArray.rows(), inputArray.columns());
01063
01064
01065 if((vTransposeArray.rows() != numberOfSingularValues)
01066 || (vTransposeArray.columns() != inputArray.columns())) {
01067 vTransposeArray.reinit(numberOfSingularValues, inputArray.columns());
01068 }
01069
01070
01071 Array2D<Float64> uColumnMajor = vTransposeArray;
01072
01073
01074 if((uArray.rows() != inputArray.rows())
01075 || (uArray.columns() != numberOfSingularValues)) {
01076 uArray.reinit(inputArray.rows(), numberOfSingularValues);
01077 }
01078
01079
01080 Array2D<Float64> vTColumnMajor = uArray;
01081
01082 if(sigmaArray.size() != numberOfSingularValues) {
01083 sigmaArray.reinit(numberOfSingularValues);
01084 }
01085
01086
01087 Array1D<Int32> integerWorkspace(8 * numberOfSingularValues);
01088
01089
01090 char JOBZ = 'S';
01091 Int32 M = static_cast<Int32>(inputArray.columns());
01092 Int32 N = static_cast<Int32>(inputArray.rows());
01093 Int32 LDA = M;
01094 Int32 LDU = M;
01095 Int32 LDVT = static_cast<Int32>(numberOfSingularValues);
01096 Float64 WORK;
01097 Int32 LWORK = -1;
01098 Int32 INFO;
01099
01100
01101 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01102 sigmaArray.data(), uColumnMajor.data(), &LDU,
01103 vTColumnMajor.data(), &LDVT,
01104 &WORK, &LWORK, integerWorkspace.data(), &INFO);
01105
01106
01107 if(INFO != 0L) {
01108 std::ostringstream message;
01109 message << "First call to dgesdd_ returns " << INFO
01110 << ". Something is wrong.";
01111 DLR_THROW3(ValueException,
01112 "singularValueDecomposition()",
01113 message.str().c_str());
01114 }
01115
01116
01117 LWORK = static_cast<Int32>(WORK);
01118 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
01119
01120
01121 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01122 sigmaArray.data(), uColumnMajor.data(), &LDU,
01123 vTColumnMajor.data(), &LDVT,
01124 doubleWorkSpace.data(), &LWORK, integerWorkspace.data(), &INFO);
01125
01126
01127 if(INFO != 0L) {
01128 std::ostringstream message;
01129 message << "Second call to dgesdd_ returns " << INFO
01130 << ". Something is wrong.";
01131 DLR_THROW3(ValueException,
01132 "singularValueDecomposition()",
01133 message.str().c_str());
01134 }
01135 }
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226 Array1D<Float64>
01227 singularValues(const Array2D<Float64>& inputArray)
01228 {
01229
01230 if(inputArray.size() == 0) {
01231 DLR_THROW3(ValueException,
01232 "singularValues()",
01233 "Argument inputArray cannot have zero size.");
01234 }
01235
01236
01237
01238
01239
01240
01241
01242 Array2D<Float64> aColumnMajor = inputArray.copy();
01243
01244
01245 size_t numberOfSingularValues =
01246 std::min(inputArray.rows(), inputArray.columns());
01247 Array1D<Float64> sigmaArray(numberOfSingularValues);
01248 Array1D<Int32> integerWorkSpace(8 * numberOfSingularValues);
01249
01250
01251 char JOBZ = 'N';
01252
01253
01254
01255 Int32 M = static_cast<Int32>(inputArray.columns());
01256 Int32 N = static_cast<Int32>(inputArray.rows());
01257 Int32 LDA = M;
01258 Float64 U;
01259 Int32 LDU = 1;
01260 Float64 VT;
01261 Int32 LDVT = 1;
01262 Float64 WORK;
01263 Int32 LWORK = -1;
01264 Int32 INFO;
01265
01266
01267 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01268 sigmaArray.data(), &U, &LDU, &VT, &LDVT,
01269 &WORK, &LWORK,
01270 integerWorkSpace.data(), &INFO);
01271
01272
01273 if(INFO != 0L) {
01274 std::ostringstream message;
01275 message << "First call to dgesdd_ returns " << INFO
01276 << ". Something is wrong.";
01277 DLR_THROW3(ValueException,
01278 "singularValues()",
01279 message.str().c_str());
01280 }
01281
01282
01283 LWORK = static_cast<Int32>(WORK);
01284
01285
01286 Int32 minimumLWORK =
01287 3 * std::min(M,N) + std::max(std::max(M, N), 6 * std::min(M, N));
01288 if(LWORK < minimumLWORK) {
01289
01290
01291 LWORK = minimumLWORK;
01292 }
01293 Array1D<Float64> doubleWorkSpace(static_cast<size_t>(LWORK));
01294
01295
01296 dgesdd_(&JOBZ, &M, &N, aColumnMajor.data(), &LDA,
01297 sigmaArray.data(), &U, &LDU, &VT, &LDVT,
01298 doubleWorkSpace.data(), &LWORK,
01299 integerWorkSpace.data(), &INFO);
01300
01301
01302 if(INFO != 0L) {
01303 std::ostringstream message;
01304 message << "Second call to dgesdd_ returns " << INFO
01305 << ". Something is wrong.";
01306 DLR_THROW3(ValueException,
01307 "singularValues()",
01308 message.str().c_str());
01309 }
01310
01311
01312 return sigmaArray;
01313 }
01314
01315 }
01316
01317 }