2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Bernard HUGUENEY
4 * Copyright (C) 2011 - DIGITEO - Cedric DELAMARRE
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
13 /*--------------------------------------------------------------------------*/
15 #include "linear_algebra_gw.hxx"
16 #include "function.hxx"
18 #include "overload.hxx"
19 #include "execvisitor.hxx"
23 #include "localization.h"
27 #include "issymmetric.h"
31 bool isNoZeroImag(types::Double* _pDbl);
32 /*--------------------------------------------------------------------------*/
34 types::Function::ReturnValue sci_spec(types::typed_list &in, int _iRetCount, types::typed_list &out)
36 types::Double* pDblA = NULL;
37 types::Double* pDblB = NULL;
38 double* pDataA = NULL;
39 double* pDataB = NULL;
40 bool symmetric = FALSE;
43 if ((in.size() != 1) && (in.size() != 2))
45 Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "spec", 1, 2);
46 return types::Function::Error;
49 if (_iRetCount > 2 * in.size())
51 Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "spec", 1, 2 * in.size());
52 return types::Function::Error;
55 if ((in[0]->isDouble() == false))
57 std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_spec";
58 return Overload::call(wstFuncName, in, _iRetCount, out, new ExecVisitor());
60 pDblA = in[0]->getAs<types::Double>()->clone()->getAs<types::Double>();
62 if (pDblA->getCols() != pDblA->getRows())
64 Scierror(20, _("%s: Wrong type for input argument #%d: Square matrix expected.\n"), "spec", 1);
65 return types::Function::Error;
68 if ((pDblA->getRows() == -1) || (pDblA->getCols() == -1)) // manage eye case
70 Scierror(271, _("%s: Size varying argument a*eye(), (arg %d) not allowed here.\n"), "spec", 1);
71 return types::Function::Error;
74 if ((pDblA->getCols() == 0) || (pDblA->getRows() == 0)) // size null
76 out.push_back(types::Double::Empty());
77 for (int i = 1; i < _iRetCount; i++)
79 out.push_back(types::Double::Empty());
81 return types::Function::OK;
86 types::Double* pDblEigenValues = NULL;
87 types::Double* pDblEigenVectors = NULL;
89 if (pDblA->isComplex())
91 pDataA = (double*)oGetDoubleComplexFromPointer(pDblA->getReal(), pDblA->getImg(), pDblA->getSize());
94 Scierror(999, _("%s: Cannot allocate more memory.\n"), "spec");
95 return types::Function::Error;
100 pDataA = pDblA->getReal();
103 int totalSize = pDblA->getSize();
104 if ((pDblA->isComplex() ? C2F(vfiniteComplex)(&totalSize, (doublecomplex*)pDataA) : C2F(vfinite)(&totalSize, pDataA)) == false)
106 Scierror(264, _("%s: Wrong value for input argument %d: Must not contain NaN or Inf.\n"), "spec", 1);
107 return types::Function::Error;
110 symmetric = isSymmetric(pDblA->getReal(), pDblA->getImg(), pDblA->isComplex(), pDblA->getRows(), pDblA->getCols()) == 1;
111 int eigenValuesCols = (_iRetCount == 1) ? 1 : pDblA->getCols();
115 pDblEigenValues = new types::Double(pDblA->getCols(), eigenValuesCols);
118 pDblEigenVectors = new types::Double(pDblA->getCols(), pDblA->getCols(), pDblA->isComplex());
123 pDblEigenValues = new types::Double(pDblA->getCols(), eigenValuesCols, true);
126 pDblEigenVectors = new types::Double(pDblA->getCols(), pDblA->getCols(), true);
130 if (pDblA->isComplex())
134 iRet = iEigen1ComplexSymmetricM((doublecomplex*)pDataA, pDblA->getCols(), (_iRetCount == 2), pDblEigenValues->getReal());
138 Scierror(998, _("%s: On entry to ZGEEV parameter number 3 had an illegal value (lapack library problem).\n"), "spec", iRet);
139 return types::Function::Error;
144 Scierror(24, _("%s: Convergence problem, %d off-diagonal elements of an intermediate tridiagonal form did not converge to zero.\n"), "spec", iRet);
145 return types::Function::Error;
150 vGetPointerFromDoubleComplex((doublecomplex*)pDataA, pDblA->getSize() , pDblEigenVectors->getReal(), pDblEigenVectors->getImg());
151 expandToDiagonalOfMatrix(pDblEigenValues->getReal(), pDblA->getCols());
152 out.push_back(pDblEigenVectors);
154 out.push_back(pDblEigenValues);
156 else // not symmetric
158 doublecomplex* pEigenValues = (doublecomplex*)MALLOC(pDblA->getCols() * sizeof(doublecomplex));
159 doublecomplex* pEigenVectors = pDblEigenVectors ? (doublecomplex*)MALLOC(sizeof(doublecomplex) * pDblA->getSize()) : NULL;
160 iRet = iEigen1ComplexM((doublecomplex*)pDataA, pDblA->getCols(), pEigenValues, pEigenVectors);
163 Scierror(998, _("%s: On entry to ZHEEV parameter number 3 had an illegal value (lapack library problem).\n"), "spec", iRet);
164 return types::Function::Error;
169 Scierror(24, _("%s: The QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed. Elements and %d+1:N of W contain eigenvalues which have converged.\n"), "spec", iRet);
170 return types::Function::Error;
175 expandZToDiagonalOfCMatrix(pEigenValues, pDblA->getCols(), pDblEigenValues->getReal(), pDblEigenValues->getImg());
176 vGetPointerFromDoubleComplex(pEigenVectors, pDblA->getSize(), pDblEigenVectors->getReal(), pDblEigenVectors->getImg());
179 out.push_back(pDblEigenVectors);
183 vGetPointerFromDoubleComplex(pEigenValues, pDblA->getCols(), pDblEigenValues->getReal(), pDblEigenValues->getImg());
185 out.push_back(pDblEigenValues);
193 iRet = iEigen1RealSymmetricM(pDataA, pDblA->getCols(), (_iRetCount == 2), pDblEigenValues->getReal());
197 Scierror(998, _("%s: On entry to ZGEEV parameter number 3 had an illegal value (lapack library problem).\n"), "spec", iRet);
198 return types::Function::Error;
203 Scierror(24, _("%s: Convergence problem, %d off-diagonal elements of an intermediate tridiagonal form did not converge to zero.\n"), "spec", iRet);
204 return types::Function::Error;
209 expandToDiagonalOfMatrix(pDblEigenValues->getReal(), pDblA->getCols());
210 out.push_back(pDblA);
212 out.push_back(pDblEigenValues);
214 else // not symmetric
216 iRet = iEigen1RealM(pDataA, pDblA->getCols(), pDblEigenValues->getReal(), pDblEigenValues->getImg(), pDblEigenVectors ? pDblEigenVectors->getReal() : NULL, pDblEigenVectors ? pDblEigenVectors->getImg() : NULL);
220 Scierror(998, _("%s: On entry to ZHEEV parameter number 3 had an illegal value (lapack library problem).\n"), "spec", iRet);
221 return types::Function::Error;
226 Scierror(24, _("%s: The QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed. Elements and %d+1:N of WR and WI contain eigenvalues which have converged.\n"), "spec", iRet);
227 return types::Function::Error;
232 expandToDiagonalOfMatrix(pDblEigenValues->getReal(), pDblA->getCols());
233 expandToDiagonalOfMatrix(pDblEigenValues->getImg(), pDblA->getCols());
234 out.push_back(pDblEigenVectors);
236 out.push_back(pDblEigenValues);
243 types::Double* pDblL = NULL;
244 types::Double* pDblR = NULL;
245 types::Double* pDblBeta = NULL;
246 types::Double* pDblAlpha = NULL;
247 doublecomplex* pL = NULL;
248 doublecomplex* pR = NULL;
249 doublecomplex* pBeta = NULL;
250 doublecomplex* pAlpha = NULL;
251 bool bIsComplex = false;
253 if ((in[1]->isDouble() == false))
255 std::wstring wstFuncName = L"%" + in[1]->getShortTypeStr() + L"_spec";
256 return Overload::call(wstFuncName, in, _iRetCount, out, new ExecVisitor());
258 pDblB = in[1]->getAs<types::Double>()->clone()->getAs<types::Double>();
259 if ((pDblA->getRows() != pDblB->getRows()) && (pDblA->getCols() != pDblB->getCols()))
261 Scierror(999, _("%s: Arguments %d and %d must have equal dimensions.\n"), "spec", 1, 2);
262 return types::Function::Error;
265 //chekc if A and B are real complex or with imag part at 0
266 if (isNoZeroImag(pDblA) == false && isNoZeroImag(pDblB) == false)
268 //view A and B as real matrix
273 bIsComplex = pDblA->isComplex() || pDblB->isComplex();
278 if (pDblA->isComplex() == false)
280 pDblA->setComplex(true);
283 if (pDblB->isComplex() == false)
285 pDblB->setComplex(true);
288 pDataA = (double*)oGetDoubleComplexFromPointer(pDblA->getReal(), pDblA->getImg(), pDblA->getSize());
289 pDataB = (double*)oGetDoubleComplexFromPointer(pDblB->getReal(), pDblB->getImg(), pDblB->getSize());
291 if (!pDblA || !pDblB)
293 Scierror(999, _("%s: Cannot allocate more memory.\n"), "spec");
294 return types::Function::Error;
299 pDataA = pDblA->getReal();
300 pDataB = pDblB->getReal();
303 int totalSize = pDblA->getSize();
305 if ((pDblA->isComplex() ? C2F(vfiniteComplex)(&totalSize, (doublecomplex*)pDataA) : C2F(vfinite)(&totalSize, pDataA)) == false)
307 Scierror(264, _("%s: Wrong value for input argument %d: Must not contain NaN or Inf.\n"), "spec", 1);
308 return types::Function::Error;
311 if ((pDblB->isComplex() ? C2F(vfiniteComplex)(&totalSize, (doublecomplex*)pDataB) : C2F(vfinite)(&totalSize, pDataB)) == false)
313 Scierror(264, _("%s: Wrong value for input argument %d: Must not contain NaN or Inf.\n"), "spec", 2);
314 return types::Function::Error;
321 pDblL = new types::Double(pDblA->getRows(), pDblA->getCols(), true);
324 pL = (doublecomplex*)MALLOC(pDblA->getSize() * sizeof(doublecomplex));
329 pDblR = new types::Double(pDblA->getRows(), pDblA->getCols(), true);
332 pR = (doublecomplex*)MALLOC(pDblA->getSize() * sizeof(doublecomplex));
339 pBeta = (doublecomplex*)MALLOC(pDblA->getCols() * sizeof(doublecomplex));
341 pDblBeta = new types::Double(pDblA->getCols(), 1, pBeta ? true : false);
347 pAlpha = (doublecomplex*)MALLOC(pDblA->getCols() * sizeof(doublecomplex));
349 pDblAlpha = new types::Double(pDblA->getCols(), 1, true);
355 iRet = iEigen2ComplexM((doublecomplex*)pDataA, (doublecomplex*)pDataB, pDblA->getCols(), pAlpha, pBeta, pR, pL);
359 iRet = iEigen2RealM( pDataA, pDataB, pDblA->getCols(),
360 pDblAlpha->getReal(), pDblAlpha->getImg(),
361 pDblBeta ? pDblBeta->getReal() : NULL,
362 pDblR ? pDblR->getReal() : NULL,
363 pDblR ? pDblR->getImg() : NULL,
364 pDblL ? pDblL->getReal() : NULL,
365 pDblL ? pDblL->getImg() : NULL);
370 sciprint(_("Warning :\n"));
371 sciprint(_("Non convergence in the QZ algorithm.\n"));
372 sciprint(_("The top %d x %d blocks may not be in generalized Schur form.\n"), iRet);
377 Scierror(998, _("%s: On entry to ZHEEV parameter number 3 had an illegal value (lapack library problem).\n"), "spec", iRet);
378 return types::Function::Error;
385 if (iRet <= pDblA->getCols())
387 Scierror(24, _("%s: The QZ iteration failed in DGGEV.\n"), "spec");
391 if (iRet == pDblA->getCols() + 1)
393 Scierror(999, _("%s: Other than QZ iteration failed in DHGEQZ.\n"), "spec");
395 if (iRet == pDblA->getCols() + 2)
397 Scierror(999, _("%s: Error return from DTGEVC.\n"), "spec");
403 Scierror(24, _("%s: The QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed. Elements and %d+1:N of W contain eigenvalues which have converged.\n"), "spec", iRet);
405 return types::Function::Error;
413 vGetPointerFromDoubleComplex(pL, pDblA->getSize(), pDblL->getReal(), pDblL->getImg());
415 vGetPointerFromDoubleComplex(pR, pDblA->getSize(), pDblR->getReal(), pDblR->getImg());
417 vGetPointerFromDoubleComplex(pBeta, pDblA->getCols(), pDblBeta->getReal(), pDblBeta->getImg());
419 vGetPointerFromDoubleComplex(pAlpha, pDblA->getCols(), pDblAlpha->getReal(), pDblAlpha->getImg());
427 out.push_back(pDblAlpha);
432 out.push_back(pDblAlpha);
433 out.push_back(pDblBeta);
438 out.push_back(pDblAlpha);
439 out.push_back(pDblBeta);
440 out.push_back(pDblR);
445 out.push_back(pDblAlpha);
446 out.push_back(pDblBeta);
447 out.push_back(pDblL);
448 out.push_back(pDblR);
454 vFreeDoubleComplexFromPointer(pAlpha);
458 vFreeDoubleComplexFromPointer(pBeta);
462 vFreeDoubleComplexFromPointer(pL);
466 vFreeDoubleComplexFromPointer(pR);
468 if (pDblB->isComplex())
470 vFreeDoubleComplexFromPointer((doublecomplex*)pDataB);
473 } // if(in.size() == 2)
475 if (pDblA->isComplex())
477 vFreeDoubleComplexFromPointer((doublecomplex*)pDataA);
480 return types::Function::OK;
482 /*--------------------------------------------------------------------------*/
483 bool isNoZeroImag(types::Double* _pDbl)
485 double* pdbl = _pDbl->getImg();
488 for (int i = 0 ; i < _pDbl->getSize() ; i++)
498 /*--------------------------------------------------------------------------*/