xpow.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2009-2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <cassert>
00029 #include <climits>
00030 
00031 #include "Array-util.h"
00032 #include "CColVector.h"
00033 #include "CDiagMatrix.h"
00034 #include "fCDiagMatrix.h"
00035 #include "CMatrix.h"
00036 #include "EIG.h"
00037 #include "fEIG.h"
00038 #include "dDiagMatrix.h"
00039 #include "fDiagMatrix.h"
00040 #include "dMatrix.h"
00041 #include "PermMatrix.h"
00042 #include "mx-cm-cdm.h"
00043 #include "oct-cmplx.h"
00044 #include "Range.h"
00045 #include "quit.h"
00046 
00047 #include "error.h"
00048 #include "oct-obj.h"
00049 #include "utils.h"
00050 #include "xpow.h"
00051 
00052 #include "bsxfun.h"
00053 
00054 #ifdef _OPENMP
00055 #include <omp.h>
00056 #endif
00057 
00058 static inline int
00059 xisint (double x)
00060 {
00061   return (D_NINT (x) == x
00062           && ((x >= 0 && x < INT_MAX)
00063               || (x <= 0 && x > INT_MIN)));
00064 }
00065 
00066 // Safer pow functions.
00067 //
00068 //       op2 \ op1:   s   m   cs   cm
00069 //            +--   +---+---+----+----+
00070 //   scalar   |     | 1 | 5 |  7 | 11 |
00071 //                  +---+---+----+----+
00072 //   matrix         | 2 | * |  8 |  * |
00073 //                  +---+---+----+----+
00074 //   complex_scalar | 3 | 6 |  9 | 12 |
00075 //                  +---+---+----+----+
00076 //   complex_matrix | 4 | * | 10 |  * |
00077 //                  +---+---+----+----+
00078 
00079 // -*- 1 -*-
00080 octave_value
00081 xpow (double a, double b)
00082 {
00083   double retval;
00084 
00085   if (a < 0.0 && ! xisint (b))
00086     {
00087       Complex atmp (a);
00088 
00089       return std::pow (atmp, b);
00090     }
00091   else
00092     retval = std::pow (a, b);
00093 
00094   return retval;
00095 }
00096 
00097 // -*- 2 -*-
00098 octave_value
00099 xpow (double a, const Matrix& b)
00100 {
00101   octave_value retval;
00102 
00103   octave_idx_type nr = b.rows ();
00104   octave_idx_type nc = b.cols ();
00105 
00106   if (nr == 0 || nc == 0 || nr != nc)
00107     error ("for x^A, A must be a square matrix");
00108   else
00109     {
00110       EIG b_eig (b);
00111 
00112       if (! error_state)
00113         {
00114           ComplexColumnVector lambda (b_eig.eigenvalues ());
00115           ComplexMatrix Q (b_eig.eigenvectors ());
00116 
00117           for (octave_idx_type i = 0; i < nr; i++)
00118             {
00119               Complex elt = lambda(i);
00120               if (std::imag (elt) == 0.0)
00121                 lambda(i) = std::pow (a, std::real (elt));
00122               else
00123                 lambda(i) = std::pow (a, elt);
00124             }
00125           ComplexDiagMatrix D (lambda);
00126 
00127           ComplexMatrix C = Q * D * Q.inverse ();
00128           if (a > 0)
00129             retval = real (C);
00130           else
00131             retval = C;
00132         }
00133       else
00134         error ("xpow: matrix diagonalization failed");
00135     }
00136 
00137   return retval;
00138 }
00139 
00140 // -*- 3 -*-
00141 octave_value
00142 xpow (double a, const Complex& b)
00143 {
00144   Complex result = std::pow (a, b);
00145   return result;
00146 }
00147 
00148 // -*- 4 -*-
00149 octave_value
00150 xpow (double a, const ComplexMatrix& b)
00151 {
00152   octave_value retval;
00153 
00154   octave_idx_type nr = b.rows ();
00155   octave_idx_type nc = b.cols ();
00156 
00157   if (nr == 0 || nc == 0 || nr != nc)
00158     error ("for x^A, A must be a square matrix");
00159   else
00160     {
00161       EIG b_eig (b);
00162 
00163       if (! error_state)
00164         {
00165           ComplexColumnVector lambda (b_eig.eigenvalues ());
00166           ComplexMatrix Q (b_eig.eigenvectors ());
00167 
00168           for (octave_idx_type i = 0; i < nr; i++)
00169             {
00170               Complex elt = lambda(i);
00171               if (std::imag (elt) == 0.0)
00172                 lambda(i) = std::pow (a, std::real (elt));
00173               else
00174                 lambda(i) = std::pow (a, elt);
00175             }
00176           ComplexDiagMatrix D (lambda);
00177 
00178           retval = ComplexMatrix (Q * D * Q.inverse ());
00179         }
00180       else
00181         error ("xpow: matrix diagonalization failed");
00182     }
00183 
00184   return retval;
00185 }
00186 
00187 // -*- 5 -*-
00188 octave_value
00189 xpow (const Matrix& a, double b)
00190 {
00191   octave_value retval;
00192 
00193   octave_idx_type nr = a.rows ();
00194   octave_idx_type nc = a.cols ();
00195 
00196   if (nr == 0 || nc == 0 || nr != nc)
00197     error ("for A^b, A must be a square matrix");
00198   else
00199     {
00200       if (static_cast<int> (b) == b)
00201         {
00202           int btmp = static_cast<int> (b);
00203           if (btmp == 0)
00204             {
00205               retval = DiagMatrix (nr, nr, 1.0);
00206             }
00207           else
00208             {
00209               // Too much copying?
00210               // FIXME -- we shouldn't do this if the exponent is
00211               // large...
00212 
00213               Matrix atmp;
00214               if (btmp < 0)
00215                 {
00216                   btmp = -btmp;
00217 
00218                   octave_idx_type info;
00219                   double rcond = 0.0;
00220                   MatrixType mattype (a);
00221 
00222                   atmp = a.inverse (mattype, info, rcond, 1);
00223 
00224                   if (info == -1)
00225                     warning ("inverse: matrix singular to machine\
00226  precision, rcond = %g", rcond);
00227                 }
00228               else
00229                 atmp = a;
00230 
00231               Matrix result (atmp);
00232 
00233               btmp--;
00234 
00235               while (btmp > 0)
00236                 {
00237                   if (btmp & 1)
00238                     result = result * atmp;
00239 
00240                   btmp >>= 1;
00241 
00242                   if (btmp > 0)
00243                     atmp = atmp * atmp;
00244                 }
00245 
00246               retval = result;
00247             }
00248         }
00249       else
00250         {
00251           EIG a_eig (a);
00252 
00253           if (! error_state)
00254             {
00255               ComplexColumnVector lambda (a_eig.eigenvalues ());
00256               ComplexMatrix Q (a_eig.eigenvectors ());
00257 
00258               for (octave_idx_type i = 0; i < nr; i++)
00259                 lambda(i) = std::pow (lambda(i), b);
00260 
00261               ComplexDiagMatrix D (lambda);
00262 
00263               retval = ComplexMatrix (Q * D * Q.inverse ());
00264             }
00265           else
00266             error ("xpow: matrix diagonalization failed");
00267         }
00268     }
00269 
00270   return retval;
00271 }
00272 
00273 // -*- 5d -*-
00274 octave_value
00275 xpow (const DiagMatrix& a, double b)
00276 {
00277   octave_value retval;
00278 
00279   octave_idx_type nr = a.rows ();
00280   octave_idx_type nc = a.cols ();
00281 
00282   if (nr == 0 || nc == 0 || nr != nc)
00283     error ("for A^b, A must be a square matrix");
00284   else
00285     {
00286       if (static_cast<int> (b) == b)
00287         {
00288           DiagMatrix r (nr, nc);
00289           for (octave_idx_type i = 0; i < nc; i++)
00290             r.dgelem (i) = std::pow (a.dgelem (i), b);
00291           retval = r;
00292         }
00293       else
00294         {
00295           ComplexDiagMatrix r (nr, nc);
00296           for (octave_idx_type i = 0; i < nc; i++)
00297             r.dgelem (i) = std::pow (static_cast<Complex> (a.dgelem (i)), b);
00298           retval = r;
00299         }
00300     }
00301 
00302   return retval;
00303 }
00304 
00305 // -*- 5p -*-
00306 octave_value
00307 xpow (const PermMatrix& a, double b)
00308 {
00309   octave_value retval;
00310   int btmp = static_cast<int> (b);
00311   if (btmp == b)
00312     return a.power (btmp);
00313   else
00314     return xpow (Matrix (a), b);
00315 }
00316 
00317 // -*- 6 -*-
00318 octave_value
00319 xpow (const Matrix& a, const Complex& b)
00320 {
00321   octave_value retval;
00322 
00323   octave_idx_type nr = a.rows ();
00324   octave_idx_type nc = a.cols ();
00325 
00326   if (nr == 0 || nc == 0 || nr != nc)
00327     error ("for A^b, A must be a square matrix");
00328   else
00329     {
00330       EIG a_eig (a);
00331 
00332       if (! error_state)
00333         {
00334           ComplexColumnVector lambda (a_eig.eigenvalues ());
00335           ComplexMatrix Q (a_eig.eigenvectors ());
00336 
00337           for (octave_idx_type i = 0; i < nr; i++)
00338             lambda(i) = std::pow (lambda(i), b);
00339 
00340           ComplexDiagMatrix D (lambda);
00341 
00342           retval = ComplexMatrix (Q * D * Q.inverse ());
00343         }
00344       else
00345         error ("xpow: matrix diagonalization failed");
00346     }
00347 
00348   return retval;
00349 }
00350 
00351 // -*- 7 -*-
00352 octave_value
00353 xpow (const Complex& a, double b)
00354 {
00355   Complex result;
00356 
00357   if (xisint (b))
00358     result = std::pow (a, static_cast<int> (b));
00359   else
00360     result = std::pow (a, b);
00361 
00362   return result;
00363 }
00364 
00365 // -*- 8 -*-
00366 octave_value
00367 xpow (const Complex& a, const Matrix& b)
00368 {
00369   octave_value retval;
00370 
00371   octave_idx_type nr = b.rows ();
00372   octave_idx_type nc = b.cols ();
00373 
00374   if (nr == 0 || nc == 0 || nr != nc)
00375     error ("for x^A, A must be a square matrix");
00376   else
00377     {
00378       EIG b_eig (b);
00379 
00380       if (! error_state)
00381         {
00382           ComplexColumnVector lambda (b_eig.eigenvalues ());
00383           ComplexMatrix Q (b_eig.eigenvectors ());
00384 
00385           for (octave_idx_type i = 0; i < nr; i++)
00386             {
00387               Complex elt = lambda(i);
00388               if (std::imag (elt) == 0.0)
00389                 lambda(i) = std::pow (a, std::real (elt));
00390               else
00391                 lambda(i) = std::pow (a, elt);
00392             }
00393           ComplexDiagMatrix D (lambda);
00394 
00395           retval = ComplexMatrix (Q * D * Q.inverse ());
00396         }
00397       else
00398         error ("xpow: matrix diagonalization failed");
00399     }
00400 
00401   return retval;
00402 }
00403 
00404 // -*- 9 -*-
00405 octave_value
00406 xpow (const Complex& a, const Complex& b)
00407 {
00408   Complex result;
00409   result = std::pow (a, b);
00410   return result;
00411 }
00412 
00413 // -*- 10 -*-
00414 octave_value
00415 xpow (const Complex& a, const ComplexMatrix& b)
00416 {
00417   octave_value retval;
00418 
00419   octave_idx_type nr = b.rows ();
00420   octave_idx_type nc = b.cols ();
00421 
00422   if (nr == 0 || nc == 0 || nr != nc)
00423     error ("for x^A, A must be a square matrix");
00424   else
00425     {
00426       EIG b_eig (b);
00427 
00428       if (! error_state)
00429         {
00430           ComplexColumnVector lambda (b_eig.eigenvalues ());
00431           ComplexMatrix Q (b_eig.eigenvectors ());
00432 
00433           for (octave_idx_type i = 0; i < nr; i++)
00434             {
00435               Complex elt = lambda(i);
00436               if (std::imag (elt) == 0.0)
00437                 lambda(i) = std::pow (a, std::real (elt));
00438               else
00439                 lambda(i) = std::pow (a, elt);
00440             }
00441           ComplexDiagMatrix D (lambda);
00442 
00443           retval = ComplexMatrix (Q * D * Q.inverse ());
00444         }
00445       else
00446         error ("xpow: matrix diagonalization failed");
00447     }
00448 
00449   return retval;
00450 }
00451 
00452 // -*- 11 -*-
00453 octave_value
00454 xpow (const ComplexMatrix& a, double b)
00455 {
00456   octave_value retval;
00457 
00458   octave_idx_type nr = a.rows ();
00459   octave_idx_type nc = a.cols ();
00460 
00461   if (nr == 0 || nc == 0 || nr != nc)
00462     error ("for A^b, A must be a square matrix");
00463   else
00464     {
00465       if (static_cast<int> (b) == b)
00466         {
00467           int btmp = static_cast<int> (b);
00468           if (btmp == 0)
00469             {
00470               retval = DiagMatrix (nr, nr, 1.0);
00471             }
00472           else
00473             {
00474               // Too much copying?
00475               // FIXME -- we shouldn't do this if the exponent is
00476               // large...
00477 
00478               ComplexMatrix atmp;
00479               if (btmp < 0)
00480                 {
00481                   btmp = -btmp;
00482 
00483                   octave_idx_type info;
00484                   double rcond = 0.0;
00485                   MatrixType mattype (a);
00486 
00487                   atmp = a.inverse (mattype, info, rcond, 1);
00488 
00489                   if (info == -1)
00490                     warning ("inverse: matrix singular to machine\
00491  precision, rcond = %g", rcond);
00492                 }
00493               else
00494                 atmp = a;
00495 
00496               ComplexMatrix result (atmp);
00497 
00498               btmp--;
00499 
00500               while (btmp > 0)
00501                 {
00502                   if (btmp & 1)
00503                     result = result * atmp;
00504 
00505                   btmp >>= 1;
00506 
00507                   if (btmp > 0)
00508                     atmp = atmp * atmp;
00509                 }
00510 
00511               retval = result;
00512             }
00513         }
00514       else
00515         {
00516           EIG a_eig (a);
00517 
00518           if (! error_state)
00519             {
00520               ComplexColumnVector lambda (a_eig.eigenvalues ());
00521               ComplexMatrix Q (a_eig.eigenvectors ());
00522 
00523               for (octave_idx_type i = 0; i < nr; i++)
00524                 lambda(i) = std::pow (lambda(i), b);
00525 
00526               ComplexDiagMatrix D (lambda);
00527 
00528               retval = ComplexMatrix (Q * D * Q.inverse ());
00529             }
00530           else
00531             error ("xpow: matrix diagonalization failed");
00532         }
00533     }
00534 
00535   return retval;
00536 }
00537 
00538 // -*- 12 -*-
00539 octave_value
00540 xpow (const ComplexMatrix& a, const Complex& b)
00541 {
00542   octave_value retval;
00543 
00544   octave_idx_type nr = a.rows ();
00545   octave_idx_type nc = a.cols ();
00546 
00547   if (nr == 0 || nc == 0 || nr != nc)
00548     error ("for A^b, A must be a square matrix");
00549   else
00550     {
00551       EIG a_eig (a);
00552 
00553       if (! error_state)
00554         {
00555           ComplexColumnVector lambda (a_eig.eigenvalues ());
00556           ComplexMatrix Q (a_eig.eigenvectors ());
00557 
00558           for (octave_idx_type i = 0; i < nr; i++)
00559             lambda(i) = std::pow (lambda(i), b);
00560 
00561           ComplexDiagMatrix D (lambda);
00562 
00563           retval = ComplexMatrix (Q * D * Q.inverse ());
00564         }
00565       else
00566         error ("xpow: matrix diagonalization failed");
00567     }
00568 
00569   return retval;
00570 }
00571 
00572 // -*- 12d -*-
00573 octave_value
00574 xpow (const ComplexDiagMatrix& a, const Complex& b)
00575 {
00576   octave_value retval;
00577 
00578   octave_idx_type nr = a.rows ();
00579   octave_idx_type nc = a.cols ();
00580 
00581   if (nr == 0 || nc == 0 || nr != nc)
00582     error ("for A^b, A must be a square matrix");
00583   else
00584     {
00585       ComplexDiagMatrix r (nr, nc);
00586       for (octave_idx_type i = 0; i < nc; i++)
00587         r(i, i) = std::pow (a(i, i), b);
00588       retval = r;
00589     }
00590 
00591   return retval;
00592 }
00593 
00594 // mixed
00595 octave_value
00596 xpow (const ComplexDiagMatrix& a, double b)
00597 {
00598   return xpow (a, static_cast<Complex> (b));
00599 }
00600 
00601 octave_value
00602 xpow (const DiagMatrix& a, const Complex& b)
00603 {
00604   return xpow (ComplexDiagMatrix (a), b);
00605 }
00606 
00607 
00608 // Safer pow functions that work elementwise for matrices.
00609 //
00610 //       op2 \ op1:   s   m   cs   cm
00611 //            +--   +---+---+----+----+
00612 //   scalar   |     | * | 3 |  * |  9 |
00613 //                  +---+---+----+----+
00614 //   matrix         | 1 | 4 |  7 | 10 |
00615 //                  +---+---+----+----+
00616 //   complex_scalar | * | 5 |  * | 11 |
00617 //                  +---+---+----+----+
00618 //   complex_matrix | 2 | 6 |  8 | 12 |
00619 //                  +---+---+----+----+
00620 //
00621 //   * -> not needed.
00622 
00623 // FIXME -- these functions need to be fixed so that things
00624 // like
00625 //
00626 //   a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b
00627 //
00628 // and
00629 //
00630 //   a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end
00631 //
00632 // produce identical results.  Also, it would be nice if -1^0.5
00633 // produced a pure imaginary result instead of a complex number with a
00634 // small real part.  But perhaps that's really a problem with the math
00635 // library...
00636 
00637 // -*- 1 -*-
00638 octave_value
00639 elem_xpow (double a, const Matrix& b)
00640 {
00641   octave_value retval;
00642 
00643   octave_idx_type nr = b.rows ();
00644   octave_idx_type nc = b.cols ();
00645 
00646   double d1, d2;
00647 
00648   if (a < 0.0 && ! b.all_integers (d1, d2))
00649     {
00650       Complex atmp (a);
00651       ComplexMatrix result (nr, nc);
00652 
00653       for (octave_idx_type j = 0; j < nc; j++)
00654         for (octave_idx_type i = 0; i < nr; i++)
00655           {
00656             octave_quit ();
00657             result (i, j) = std::pow (atmp, b (i, j));
00658           }
00659 
00660       retval = result;
00661     }
00662   else
00663     {
00664       Matrix result (nr, nc);
00665 
00666       for (octave_idx_type j = 0; j < nc; j++)
00667         for (octave_idx_type i = 0; i < nr; i++)
00668           {
00669             octave_quit ();
00670             result (i, j) = std::pow (a, b (i, j));
00671           }
00672 
00673       retval = result;
00674     }
00675 
00676   return retval;
00677 }
00678 
00679 // -*- 2 -*-
00680 octave_value
00681 elem_xpow (double a, const ComplexMatrix& b)
00682 {
00683   octave_idx_type nr = b.rows ();
00684   octave_idx_type nc = b.cols ();
00685 
00686   ComplexMatrix result (nr, nc);
00687   Complex atmp (a);
00688 
00689   for (octave_idx_type j = 0; j < nc; j++)
00690     for (octave_idx_type i = 0; i < nr; i++)
00691       {
00692         octave_quit ();
00693         result (i, j) = std::pow (atmp, b (i, j));
00694       }
00695 
00696   return result;
00697 }
00698 
00699 static inline bool
00700 same_sign (double a, double b)
00701 {
00702   return (a >= 0 && b >= 0) || (a <= 0 && b <= 0);
00703 }
00704 
00705 octave_value
00706 elem_xpow (double a, const Range& r)
00707 {
00708   octave_value retval;
00709 
00710   // Only optimize powers with ranges that are integer and monotonic in
00711   // magnitude.
00712   if (r.nelem () > 1 && r.all_elements_are_ints ()
00713       && same_sign (r.base (), r.limit ()))
00714     {
00715       octave_idx_type n = r.nelem ();
00716       Matrix result (1, n);
00717       if (same_sign (r.base (), r.inc ()))
00718         {
00719           double base = std::pow (a, r.base ());
00720           double inc = std::pow (a, r.inc ());
00721           result(0) = base;
00722           for (octave_idx_type i = 1; i < n; i++)
00723             result(i) = (base *= inc);
00724         }
00725       else
00726         {
00727           // Don't use Range::limit () here.
00728           double limit = std::pow (a, r.base () + (n-1) * r.inc ());
00729           double inc = std::pow (a, -r.inc ());
00730           result(n-1) = limit;
00731           for (octave_idx_type i = n-2; i >= 0; i--)
00732             result(i) = (limit *= inc);
00733         }
00734 
00735       retval = result;
00736     }
00737   else
00738     retval = elem_xpow (a, r.matrix_value ());
00739 
00740   return retval;
00741 }
00742 
00743 // -*- 3 -*-
00744 octave_value
00745 elem_xpow (const Matrix& a, double b)
00746 {
00747   octave_value retval;
00748 
00749   octave_idx_type nr = a.rows ();
00750   octave_idx_type nc = a.cols ();
00751 
00752   if (! xisint (b) && a.any_element_is_negative ())
00753     {
00754       ComplexMatrix result (nr, nc);
00755 
00756       for (octave_idx_type j = 0; j < nc; j++)
00757         for (octave_idx_type i = 0; i < nr; i++)
00758           {
00759             octave_quit ();
00760 
00761             Complex atmp (a (i, j));
00762 
00763             result (i, j) = std::pow (atmp, b);
00764           }
00765 
00766       retval = result;
00767     }
00768   else
00769     {
00770       Matrix result (nr, nc);
00771 
00772       for (octave_idx_type j = 0; j < nc; j++)
00773         for (octave_idx_type i = 0; i < nr; i++)
00774           {
00775             octave_quit ();
00776             result (i, j) = std::pow (a (i, j), b);
00777           }
00778 
00779       retval = result;
00780     }
00781 
00782   return retval;
00783 }
00784 
00785 // -*- 4 -*-
00786 octave_value
00787 elem_xpow (const Matrix& a, const Matrix& b)
00788 {
00789   octave_value retval;
00790 
00791   octave_idx_type nr = a.rows ();
00792   octave_idx_type nc = a.cols ();
00793 
00794   octave_idx_type b_nr = b.rows ();
00795   octave_idx_type b_nc = b.cols ();
00796 
00797   if (nr != b_nr || nc != b_nc)
00798     {
00799       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
00800       return octave_value ();
00801     }
00802 
00803   int convert_to_complex = 0;
00804   for (octave_idx_type j = 0; j < nc; j++)
00805     for (octave_idx_type i = 0; i < nr; i++)
00806       {
00807         octave_quit ();
00808         double atmp = a (i, j);
00809         double btmp = b (i, j);
00810         if (atmp < 0.0 && static_cast<int> (btmp) != btmp)
00811           {
00812             convert_to_complex = 1;
00813             goto done;
00814           }
00815       }
00816 
00817 done:
00818 
00819   if (convert_to_complex)
00820     {
00821       ComplexMatrix complex_result (nr, nc);
00822 
00823       for (octave_idx_type j = 0; j < nc; j++)
00824         for (octave_idx_type i = 0; i < nr; i++)
00825           {
00826             octave_quit ();
00827             Complex atmp (a (i, j));
00828             Complex btmp (b (i, j));
00829             complex_result (i, j) = std::pow (atmp, btmp);
00830           }
00831 
00832       retval = complex_result;
00833     }
00834   else
00835     {
00836       Matrix result (nr, nc);
00837 
00838       for (octave_idx_type j = 0; j < nc; j++)
00839         for (octave_idx_type i = 0; i < nr; i++)
00840           {
00841             octave_quit ();
00842             result (i, j) = std::pow (a (i, j), b (i, j));
00843           }
00844 
00845       retval = result;
00846     }
00847 
00848   return retval;
00849 }
00850 
00851 // -*- 5 -*-
00852 octave_value
00853 elem_xpow (const Matrix& a, const Complex& b)
00854 {
00855   octave_idx_type nr = a.rows ();
00856   octave_idx_type nc = a.cols ();
00857 
00858   ComplexMatrix result (nr, nc);
00859 
00860   for (octave_idx_type j = 0; j < nc; j++)
00861     for (octave_idx_type i = 0; i < nr; i++)
00862       {
00863         octave_quit ();
00864         result (i, j) = std::pow (Complex (a (i, j)), b);
00865       }
00866 
00867   return result;
00868 }
00869 
00870 // -*- 6 -*-
00871 octave_value
00872 elem_xpow (const Matrix& a, const ComplexMatrix& b)
00873 {
00874   octave_idx_type nr = a.rows ();
00875   octave_idx_type nc = a.cols ();
00876 
00877   octave_idx_type b_nr = b.rows ();
00878   octave_idx_type b_nc = b.cols ();
00879 
00880   if (nr != b_nr || nc != b_nc)
00881     {
00882       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
00883       return octave_value ();
00884     }
00885 
00886   ComplexMatrix result (nr, nc);
00887 
00888   for (octave_idx_type j = 0; j < nc; j++)
00889     for (octave_idx_type i = 0; i < nr; i++)
00890       {
00891         octave_quit ();
00892         result (i, j) = std::pow (Complex (a (i, j)), b (i, j));
00893       }
00894 
00895   return result;
00896 }
00897 
00898 // -*- 7 -*-
00899 octave_value
00900 elem_xpow (const Complex& a, const Matrix& b)
00901 {
00902   octave_idx_type nr = b.rows ();
00903   octave_idx_type nc = b.cols ();
00904 
00905   ComplexMatrix result (nr, nc);
00906 
00907   for (octave_idx_type j = 0; j < nc; j++)
00908     for (octave_idx_type i = 0; i < nr; i++)
00909       {
00910         octave_quit ();
00911         double btmp = b (i, j);
00912         if (xisint (btmp))
00913           result (i, j) = std::pow (a, static_cast<int> (btmp));
00914         else
00915           result (i, j) = std::pow (a, btmp);
00916       }
00917 
00918   return result;
00919 }
00920 
00921 // -*- 8 -*-
00922 octave_value
00923 elem_xpow (const Complex& a, const ComplexMatrix& b)
00924 {
00925   octave_idx_type nr = b.rows ();
00926   octave_idx_type nc = b.cols ();
00927 
00928   ComplexMatrix result (nr, nc);
00929 
00930   for (octave_idx_type j = 0; j < nc; j++)
00931     for (octave_idx_type i = 0; i < nr; i++)
00932       {
00933         octave_quit ();
00934         result (i, j) = std::pow (a, b (i, j));
00935       }
00936 
00937   return result;
00938 }
00939 
00940 octave_value
00941 elem_xpow (const Complex& a, const Range& r)
00942 {
00943   octave_value retval;
00944 
00945   // Only optimize powers with ranges that are integer and monotonic in
00946   // magnitude.
00947   if (r.nelem () > 1 && r.all_elements_are_ints ()
00948       && same_sign (r.base (), r.limit ()))
00949     {
00950       octave_idx_type n = r.nelem ();
00951       ComplexMatrix result (1, n);
00952 
00953       if (same_sign (r.base (), r.inc ()))
00954         {
00955           Complex base = std::pow (a, r.base ());
00956           Complex inc = std::pow (a, r.inc ());
00957           result(0) = base;
00958           for (octave_idx_type i = 1; i < n; i++)
00959             result(i) = (base *= inc);
00960         }
00961       else
00962         {
00963           // Don't use Range::limit () here.
00964           Complex limit = std::pow (a, r.base () + (n-1) * r.inc ());
00965           Complex inc = std::pow (a, -r.inc ());
00966           result(n-1) = limit;
00967           for (octave_idx_type i = n-2; i >= 0; i--)
00968             result(i) = (limit *= inc);
00969         }
00970 
00971       retval = result;
00972     }
00973   else
00974     retval = elem_xpow (a, r.matrix_value ());
00975 
00976 
00977   return retval;
00978 }
00979 
00980 // -*- 9 -*-
00981 octave_value
00982 elem_xpow (const ComplexMatrix& a, double b)
00983 {
00984   octave_idx_type nr = a.rows ();
00985   octave_idx_type nc = a.cols ();
00986 
00987   ComplexMatrix result (nr, nc);
00988 
00989   if (xisint (b))
00990     {
00991       for (octave_idx_type j = 0; j < nc; j++)
00992         for (octave_idx_type i = 0; i < nr; i++)
00993           {
00994             octave_quit ();
00995             result (i, j) = std::pow (a (i, j), static_cast<int> (b));
00996           }
00997     }
00998   else
00999     {
01000       for (octave_idx_type j = 0; j < nc; j++)
01001         for (octave_idx_type i = 0; i < nr; i++)
01002           {
01003             octave_quit ();
01004             result (i, j) = std::pow (a (i, j), b);
01005           }
01006     }
01007 
01008   return result;
01009 }
01010 
01011 // -*- 10 -*-
01012 octave_value
01013 elem_xpow (const ComplexMatrix& a, const Matrix& b)
01014 {
01015   octave_idx_type nr = a.rows ();
01016   octave_idx_type nc = a.cols ();
01017 
01018   octave_idx_type b_nr = b.rows ();
01019   octave_idx_type b_nc = b.cols ();
01020 
01021   if (nr != b_nr || nc != b_nc)
01022     {
01023       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
01024       return octave_value ();
01025     }
01026 
01027   ComplexMatrix result (nr, nc);
01028 
01029   for (octave_idx_type j = 0; j < nc; j++)
01030     for (octave_idx_type i = 0; i < nr; i++)
01031       {
01032         octave_quit ();
01033         double btmp = b (i, j);
01034         if (xisint (btmp))
01035           result (i, j) = std::pow (a (i, j), static_cast<int> (btmp));
01036         else
01037           result (i, j) = std::pow (a (i, j), btmp);
01038       }
01039 
01040   return result;
01041 }
01042 
01043 // -*- 11 -*-
01044 octave_value
01045 elem_xpow (const ComplexMatrix& a, const Complex& b)
01046 {
01047   octave_idx_type nr = a.rows ();
01048   octave_idx_type nc = a.cols ();
01049 
01050   ComplexMatrix result (nr, nc);
01051 
01052   for (octave_idx_type j = 0; j < nc; j++)
01053     for (octave_idx_type i = 0; i < nr; i++)
01054       {
01055         octave_quit ();
01056         result (i, j) = std::pow (a (i, j), b);
01057       }
01058 
01059   return result;
01060 }
01061 
01062 // -*- 12 -*-
01063 octave_value
01064 elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b)
01065 {
01066   octave_idx_type nr = a.rows ();
01067   octave_idx_type nc = a.cols ();
01068 
01069   octave_idx_type b_nr = b.rows ();
01070   octave_idx_type b_nc = b.cols ();
01071 
01072   if (nr != b_nr || nc != b_nc)
01073     {
01074       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
01075       return octave_value ();
01076     }
01077 
01078   ComplexMatrix result (nr, nc);
01079 
01080   for (octave_idx_type j = 0; j < nc; j++)
01081     for (octave_idx_type i = 0; i < nr; i++)
01082       {
01083         octave_quit ();
01084         result (i, j) = std::pow (a (i, j), b (i, j));
01085       }
01086 
01087   return result;
01088 }
01089 
01090 // Safer pow functions that work elementwise for N-d arrays.
01091 //
01092 //       op2 \ op1:   s   nd  cs   cnd
01093 //            +--   +---+---+----+----+
01094 //   scalar   |     | * | 3 |  * |  9 |
01095 //                  +---+---+----+----+
01096 //   N_d            | 1 | 4 |  7 | 10 |
01097 //                  +---+---+----+----+
01098 //   complex_scalar | * | 5 |  * | 11 |
01099 //                  +---+---+----+----+
01100 //   complex_N_d    | 2 | 6 |  8 | 12 |
01101 //                  +---+---+----+----+
01102 //
01103 //   * -> not needed.
01104 
01105 // FIXME -- these functions need to be fixed so that things
01106 // like
01107 //
01108 //   a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b
01109 //
01110 // and
01111 //
01112 //   a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end
01113 //
01114 // produce identical results.  Also, it would be nice if -1^0.5
01115 // produced a pure imaginary result instead of a complex number with a
01116 // small real part.  But perhaps that's really a problem with the math
01117 // library...
01118 
01119 // -*- 1 -*-
01120 octave_value
01121 elem_xpow (double a, const NDArray& b)
01122 {
01123   octave_value retval;
01124 
01125   if (a < 0.0 && ! b.all_integers ())
01126     {
01127       Complex atmp (a);
01128       ComplexNDArray result (b.dims ());
01129       for (octave_idx_type i = 0; i < b.length (); i++)
01130         {
01131           octave_quit ();
01132           result(i) = std::pow (atmp, b(i));
01133         }
01134 
01135       retval = result;
01136     }
01137   else
01138     {
01139       NDArray result (b.dims ());
01140       for (octave_idx_type i = 0; i < b.length (); i++)
01141         {
01142           octave_quit ();
01143           result (i) = std::pow (a, b(i));
01144         }
01145 
01146       retval = result;
01147     }
01148 
01149   return retval;
01150 }
01151 
01152 // -*- 2 -*-
01153 octave_value
01154 elem_xpow (double a, const ComplexNDArray& b)
01155 {
01156   ComplexNDArray result (b.dims ());
01157 
01158   for (octave_idx_type i = 0; i < b.length (); i++)
01159     {
01160       octave_quit ();
01161       result(i) = std::pow (a, b(i));
01162     }
01163 
01164   return result;
01165 }
01166 
01167 // -*- 3 -*-
01168 octave_value
01169 elem_xpow (const NDArray& a, double b)
01170 {
01171   octave_value retval;
01172 
01173   if (! xisint (b))
01174     {
01175       if (a.any_element_is_negative ())
01176         {
01177           ComplexNDArray result (a.dims ());
01178 
01179           for (octave_idx_type i = 0; i < a.length (); i++)
01180             {
01181               octave_quit ();
01182 
01183               Complex atmp (a (i));
01184 
01185               result(i) = std::pow (atmp, b);
01186             }
01187 
01188           retval = result;
01189         }
01190       else
01191         {
01192           NDArray result (a.dims ());
01193           for (octave_idx_type i = 0; i < a.length (); i++)
01194             {
01195               octave_quit ();
01196               result(i) = std::pow (a(i), b);
01197             }
01198 
01199           retval = result;
01200         }
01201     }
01202   else
01203     {
01204       NoAlias<NDArray> result (a.dims ());
01205 
01206       int ib = static_cast<int> (b);
01207       if (ib == 2)
01208         {
01209           for (octave_idx_type i = 0; i < a.length (); i++)
01210             result(i) = a(i) * a(i);
01211         }
01212       else if (ib == 3)
01213         {
01214           for (octave_idx_type i = 0; i < a.length (); i++)
01215             result(i) = a(i) * a(i) * a(i);
01216         }
01217       else if (ib == -1)
01218         {
01219           for (octave_idx_type i = 0; i < a.length (); i++)
01220             result(i) = 1.0 / a(i);
01221         }
01222       else
01223         {
01224           for (octave_idx_type i = 0; i < a.length (); i++)
01225             {
01226               octave_quit ();
01227               result(i) = std::pow (a(i), ib);
01228             }
01229         }
01230 
01231       retval = result;
01232     }
01233 
01234   return retval;
01235 }
01236 
01237 // -*- 4 -*-
01238 octave_value
01239 elem_xpow (const NDArray& a, const NDArray& b)
01240 {
01241   octave_value retval;
01242 
01243   dim_vector a_dims = a.dims ();
01244   dim_vector b_dims = b.dims ();
01245 
01246   if (a_dims != b_dims)
01247     {
01248       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
01249         {
01250           //Potentially complex results
01251           NDArray xa = octave_value_extract<NDArray> (a);
01252           NDArray xb = octave_value_extract<NDArray> (b);
01253           if (! xb.all_integers () && xa.any_element_is_negative ())
01254             return octave_value (bsxfun_pow (ComplexNDArray (xa), xb));
01255           else
01256             return octave_value (bsxfun_pow (xa, xb));
01257         }
01258       else
01259         {
01260           gripe_nonconformant ("operator .^", a_dims, b_dims);
01261           return octave_value ();
01262         }
01263     }
01264 
01265   int len = a.length ();
01266 
01267   bool convert_to_complex = false;
01268 
01269   for (octave_idx_type i = 0; i < len; i++)
01270     {
01271       octave_quit ();
01272       double atmp = a(i);
01273       double btmp = b(i);
01274       if (atmp < 0.0 && static_cast<int> (btmp) != btmp)
01275         {
01276           convert_to_complex = true;
01277           goto done;
01278         }
01279     }
01280 
01281 done:
01282 
01283   if (convert_to_complex)
01284     {
01285       ComplexNDArray complex_result (a_dims);
01286 
01287       for (octave_idx_type i = 0; i < len; i++)
01288         {
01289           octave_quit ();
01290           Complex atmp (a(i));
01291           complex_result(i) = std::pow (atmp, b(i));
01292         }
01293 
01294       retval = complex_result;
01295     }
01296   else
01297     {
01298       NDArray result (a_dims);
01299 
01300       for (octave_idx_type i = 0; i < len; i++)
01301         {
01302           octave_quit ();
01303           result(i) = std::pow (a(i), b(i));
01304         }
01305 
01306       retval = result;
01307     }
01308 
01309   return retval;
01310 }
01311 
01312 // -*- 5 -*-
01313 octave_value
01314 elem_xpow (const NDArray& a, const Complex& b)
01315 {
01316   ComplexNDArray result (a.dims ());
01317 
01318   for (octave_idx_type i = 0; i < a.length (); i++)
01319     {
01320       octave_quit ();
01321       result(i) = std::pow (a(i), b);
01322     }
01323 
01324   return result;
01325 }
01326 
01327 // -*- 6 -*-
01328 octave_value
01329 elem_xpow (const NDArray& a, const ComplexNDArray& b)
01330 {
01331   dim_vector a_dims = a.dims ();
01332   dim_vector b_dims = b.dims ();
01333 
01334   if (a_dims != b_dims)
01335     {
01336       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
01337         {
01338           return bsxfun_pow (a, b);
01339         }
01340       else
01341         {
01342           gripe_nonconformant ("operator .^", a_dims, b_dims);
01343           return octave_value ();
01344         }
01345     }
01346 
01347   ComplexNDArray result (a_dims);
01348 
01349   for (octave_idx_type i = 0; i < a.length (); i++)
01350     {
01351       octave_quit ();
01352       result(i) = std::pow (a(i), b(i));
01353     }
01354 
01355   return result;
01356 }
01357 
01358 // -*- 7 -*-
01359 octave_value
01360 elem_xpow (const Complex& a, const NDArray& b)
01361 {
01362   ComplexNDArray result (b.dims ());
01363 
01364   for (octave_idx_type i = 0; i < b.length (); i++)
01365     {
01366       octave_quit ();
01367       double btmp = b(i);
01368       if (xisint (btmp))
01369         result(i) = std::pow (a, static_cast<int> (btmp));
01370       else
01371         result(i) = std::pow (a, btmp);
01372     }
01373 
01374   return result;
01375 }
01376 
01377 // -*- 8 -*-
01378 octave_value
01379 elem_xpow (const Complex& a, const ComplexNDArray& b)
01380 {
01381   ComplexNDArray result (b.dims ());
01382 
01383   for (octave_idx_type i = 0; i < b.length (); i++)
01384     {
01385       octave_quit ();
01386       result(i) = std::pow (a, b(i));
01387     }
01388 
01389   return result;
01390 }
01391 
01392 // -*- 9 -*-
01393 octave_value
01394 elem_xpow (const ComplexNDArray& a, double b)
01395 {
01396   ComplexNDArray result (a.dims ());
01397 
01398   if (xisint (b))
01399     {
01400       if (b == -1)
01401         {
01402           for (octave_idx_type i = 0; i < a.length (); i++)
01403             result.xelem (i) = 1.0 / a(i);
01404         }
01405       else
01406         {
01407           for (octave_idx_type i = 0; i < a.length (); i++)
01408             {
01409               octave_quit ();
01410               result(i) = std::pow (a(i), static_cast<int> (b));
01411             }
01412         }
01413     }
01414   else
01415     {
01416       for (octave_idx_type i = 0; i < a.length (); i++)
01417         {
01418           octave_quit ();
01419           result(i) = std::pow (a(i), b);
01420         }
01421     }
01422 
01423   return result;
01424 }
01425 
01426 // -*- 10 -*-
01427 octave_value
01428 elem_xpow (const ComplexNDArray& a, const NDArray& b)
01429 {
01430   dim_vector a_dims = a.dims ();
01431   dim_vector b_dims = b.dims ();
01432 
01433   if (a_dims != b_dims)
01434     {
01435       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
01436         {
01437           return bsxfun_pow (a, b);
01438         }
01439       else
01440         {
01441           gripe_nonconformant ("operator .^", a_dims, b_dims);
01442           return octave_value ();
01443         }
01444     }
01445 
01446   ComplexNDArray result (a_dims);
01447 
01448   for (octave_idx_type i = 0; i < a.length (); i++)
01449     {
01450       octave_quit ();
01451       double btmp = b(i);
01452       if (xisint (btmp))
01453         result(i) = std::pow (a(i), static_cast<int> (btmp));
01454       else
01455         result(i) = std::pow (a(i), btmp);
01456     }
01457 
01458   return result;
01459 }
01460 
01461 // -*- 11 -*-
01462 octave_value
01463 elem_xpow (const ComplexNDArray& a, const Complex& b)
01464 {
01465   ComplexNDArray result (a.dims ());
01466 
01467   for (octave_idx_type i = 0; i < a.length (); i++)
01468     {
01469       octave_quit ();
01470       result(i) = std::pow (a(i), b);
01471     }
01472 
01473   return result;
01474 }
01475 
01476 // -*- 12 -*-
01477 octave_value
01478 elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b)
01479 {
01480   dim_vector a_dims = a.dims ();
01481   dim_vector b_dims = b.dims ();
01482 
01483   if (a_dims != b_dims)
01484     {
01485       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
01486         {
01487           return bsxfun_pow (a, b);
01488         }
01489       else
01490         {
01491           gripe_nonconformant ("operator .^", a_dims, b_dims);
01492           return octave_value ();
01493         }
01494     }
01495 
01496   ComplexNDArray result (a_dims);
01497 
01498   for (octave_idx_type i = 0; i < a.length (); i++)
01499     {
01500       octave_quit ();
01501       result(i) = std::pow (a(i), b(i));
01502     }
01503 
01504   return result;
01505 }
01506 
01507 static inline int
01508 xisint (float x)
01509 {
01510   return (D_NINT (x) == x
01511           && ((x >= 0 && x < INT_MAX)
01512               || (x <= 0 && x > INT_MIN)));
01513 }
01514 
01515 // Safer pow functions.
01516 //
01517 //       op2 \ op1:   s   m   cs   cm
01518 //            +--   +---+---+----+----+
01519 //   scalar   |     | 1 | 5 |  7 | 11 |
01520 //                  +---+---+----+----+
01521 //   matrix         | 2 | * |  8 |  * |
01522 //                  +---+---+----+----+
01523 //   complex_scalar | 3 | 6 |  9 | 12 |
01524 //                  +---+---+----+----+
01525 //   complex_matrix | 4 | * | 10 |  * |
01526 //                  +---+---+----+----+
01527 
01528 // -*- 1 -*-
01529 octave_value
01530 xpow (float a, float b)
01531 {
01532   float retval;
01533 
01534   if (a < 0.0 && ! xisint (b))
01535     {
01536       FloatComplex atmp (a);
01537 
01538       return std::pow (atmp, b);
01539     }
01540   else
01541     retval = std::pow (a, b);
01542 
01543   return retval;
01544 }
01545 
01546 // -*- 2 -*-
01547 octave_value
01548 xpow (float a, const FloatMatrix& b)
01549 {
01550   octave_value retval;
01551 
01552   octave_idx_type nr = b.rows ();
01553   octave_idx_type nc = b.cols ();
01554 
01555   if (nr == 0 || nc == 0 || nr != nc)
01556     error ("for x^A, A must be a square matrix");
01557   else
01558     {
01559       FloatEIG b_eig (b);
01560 
01561       if (! error_state)
01562         {
01563           FloatComplexColumnVector lambda (b_eig.eigenvalues ());
01564           FloatComplexMatrix Q (b_eig.eigenvectors ());
01565 
01566           for (octave_idx_type i = 0; i < nr; i++)
01567             {
01568               FloatComplex elt = lambda(i);
01569               if (std::imag (elt) == 0.0)
01570                 lambda(i) = std::pow (a, std::real (elt));
01571               else
01572                 lambda(i) = std::pow (a, elt);
01573             }
01574           FloatComplexDiagMatrix D (lambda);
01575 
01576           FloatComplexMatrix C = Q * D * Q.inverse ();
01577 
01578           if (a > 0)
01579             retval = real (C);
01580           else
01581             retval = C;
01582         }
01583       else
01584         error ("xpow: matrix diagonalization failed");
01585     }
01586 
01587   return retval;
01588 }
01589 
01590 // -*- 3 -*-
01591 octave_value
01592 xpow (float a, const FloatComplex& b)
01593 {
01594   FloatComplex result = std::pow (a, b);
01595   return result;
01596 }
01597 
01598 // -*- 4 -*-
01599 octave_value
01600 xpow (float a, const FloatComplexMatrix& b)
01601 {
01602   octave_value retval;
01603 
01604   octave_idx_type nr = b.rows ();
01605   octave_idx_type nc = b.cols ();
01606 
01607   if (nr == 0 || nc == 0 || nr != nc)
01608     error ("for x^A, A must be a square matrix");
01609   else
01610     {
01611       FloatEIG b_eig (b);
01612 
01613       if (! error_state)
01614         {
01615           FloatComplexColumnVector lambda (b_eig.eigenvalues ());
01616           FloatComplexMatrix Q (b_eig.eigenvectors ());
01617 
01618           for (octave_idx_type i = 0; i < nr; i++)
01619             {
01620               FloatComplex elt = lambda(i);
01621               if (std::imag (elt) == 0.0)
01622                 lambda(i) = std::pow (a, std::real (elt));
01623               else
01624                 lambda(i) = std::pow (a, elt);
01625             }
01626           FloatComplexDiagMatrix D (lambda);
01627 
01628           retval = FloatComplexMatrix (Q * D * Q.inverse ());
01629         }
01630       else
01631         error ("xpow: matrix diagonalization failed");
01632     }
01633 
01634   return retval;
01635 }
01636 
01637 // -*- 5 -*-
01638 octave_value
01639 xpow (const FloatMatrix& a, float b)
01640 {
01641   octave_value retval;
01642 
01643   octave_idx_type nr = a.rows ();
01644   octave_idx_type nc = a.cols ();
01645 
01646   if (nr == 0 || nc == 0 || nr != nc)
01647     error ("for A^b, A must be a square matrix");
01648   else
01649     {
01650       if (static_cast<int> (b) == b)
01651         {
01652           int btmp = static_cast<int> (b);
01653           if (btmp == 0)
01654             {
01655               retval = FloatDiagMatrix (nr, nr, 1.0);
01656             }
01657           else
01658             {
01659               // Too much copying?
01660               // FIXME -- we shouldn't do this if the exponent is
01661               // large...
01662 
01663               FloatMatrix atmp;
01664               if (btmp < 0)
01665                 {
01666                   btmp = -btmp;
01667 
01668                   octave_idx_type info;
01669                   float rcond = 0.0;
01670                   MatrixType mattype (a);
01671 
01672                   atmp = a.inverse (mattype, info, rcond, 1);
01673 
01674                   if (info == -1)
01675                     warning ("inverse: matrix singular to machine\
01676  precision, rcond = %g", rcond);
01677                 }
01678               else
01679                 atmp = a;
01680 
01681               FloatMatrix result (atmp);
01682 
01683               btmp--;
01684 
01685               while (btmp > 0)
01686                 {
01687                   if (btmp & 1)
01688                     result = result * atmp;
01689 
01690                   btmp >>= 1;
01691 
01692                   if (btmp > 0)
01693                     atmp = atmp * atmp;
01694                 }
01695 
01696               retval = result;
01697             }
01698         }
01699       else
01700         {
01701           FloatEIG a_eig (a);
01702 
01703           if (! error_state)
01704             {
01705               FloatComplexColumnVector lambda (a_eig.eigenvalues ());
01706               FloatComplexMatrix Q (a_eig.eigenvectors ());
01707 
01708               for (octave_idx_type i = 0; i < nr; i++)
01709                 lambda(i) = std::pow (lambda(i), b);
01710 
01711               FloatComplexDiagMatrix D (lambda);
01712 
01713               retval = FloatComplexMatrix (Q * D * Q.inverse ());
01714             }
01715           else
01716             error ("xpow: matrix diagonalization failed");
01717         }
01718     }
01719 
01720   return retval;
01721 }
01722 
01723 // -*- 5d -*-
01724 octave_value
01725 xpow (const FloatDiagMatrix& a, float b)
01726 {
01727   octave_value retval;
01728 
01729   octave_idx_type nr = a.rows ();
01730   octave_idx_type nc = a.cols ();
01731 
01732   if (nr == 0 || nc == 0 || nr != nc)
01733     error ("for A^b, A must be a square matrix");
01734   else
01735     {
01736       if (static_cast<int> (b) == b)
01737         {
01738           FloatDiagMatrix r (nr, nc);
01739           for (octave_idx_type i = 0; i < nc; i++)
01740             r.dgelem (i) = std::pow (a.dgelem (i), b);
01741           retval = r;
01742         }
01743       else
01744         {
01745           FloatComplexDiagMatrix r (nr, nc);
01746           for (octave_idx_type i = 0; i < nc; i++)
01747             r.dgelem (i) = std::pow (static_cast<FloatComplex> (a.dgelem (i)), b);
01748           retval = r;
01749         }
01750     }
01751 
01752   return retval;
01753 }
01754 
01755 // -*- 6 -*-
01756 octave_value
01757 xpow (const FloatMatrix& a, const FloatComplex& b)
01758 {
01759   octave_value retval;
01760 
01761   octave_idx_type nr = a.rows ();
01762   octave_idx_type nc = a.cols ();
01763 
01764   if (nr == 0 || nc == 0 || nr != nc)
01765     error ("for A^b, A must be a square matrix");
01766   else
01767     {
01768       FloatEIG a_eig (a);
01769 
01770       if (! error_state)
01771         {
01772           FloatComplexColumnVector lambda (a_eig.eigenvalues ());
01773           FloatComplexMatrix Q (a_eig.eigenvectors ());
01774 
01775           for (octave_idx_type i = 0; i < nr; i++)
01776             lambda(i) = std::pow (lambda(i), b);
01777 
01778           FloatComplexDiagMatrix D (lambda);
01779 
01780           retval = FloatComplexMatrix (Q * D * Q.inverse ());
01781         }
01782       else
01783         error ("xpow: matrix diagonalization failed");
01784     }
01785 
01786   return retval;
01787 }
01788 
01789 // -*- 7 -*-
01790 octave_value
01791 xpow (const FloatComplex& a, float b)
01792 {
01793   FloatComplex result;
01794 
01795   if (xisint (b))
01796     result = std::pow (a, static_cast<int> (b));
01797   else
01798     result = std::pow (a, b);
01799 
01800   return result;
01801 }
01802 
01803 // -*- 8 -*-
01804 octave_value
01805 xpow (const FloatComplex& a, const FloatMatrix& b)
01806 {
01807   octave_value retval;
01808 
01809   octave_idx_type nr = b.rows ();
01810   octave_idx_type nc = b.cols ();
01811 
01812   if (nr == 0 || nc == 0 || nr != nc)
01813     error ("for x^A, A must be a square matrix");
01814   else
01815     {
01816       FloatEIG b_eig (b);
01817 
01818       if (! error_state)
01819         {
01820           FloatComplexColumnVector lambda (b_eig.eigenvalues ());
01821           FloatComplexMatrix Q (b_eig.eigenvectors ());
01822 
01823           for (octave_idx_type i = 0; i < nr; i++)
01824             {
01825               FloatComplex elt = lambda(i);
01826               if (std::imag (elt) == 0.0)
01827                 lambda(i) = std::pow (a, std::real (elt));
01828               else
01829                 lambda(i) = std::pow (a, elt);
01830             }
01831           FloatComplexDiagMatrix D (lambda);
01832 
01833           retval = FloatComplexMatrix (Q * D * Q.inverse ());
01834         }
01835       else
01836         error ("xpow: matrix diagonalization failed");
01837     }
01838 
01839   return retval;
01840 }
01841 
01842 // -*- 9 -*-
01843 octave_value
01844 xpow (const FloatComplex& a, const FloatComplex& b)
01845 {
01846   FloatComplex result;
01847   result = std::pow (a, b);
01848   return result;
01849 }
01850 
01851 // -*- 10 -*-
01852 octave_value
01853 xpow (const FloatComplex& a, const FloatComplexMatrix& b)
01854 {
01855   octave_value retval;
01856 
01857   octave_idx_type nr = b.rows ();
01858   octave_idx_type nc = b.cols ();
01859 
01860   if (nr == 0 || nc == 0 || nr != nc)
01861     error ("for x^A, A must be a square matrix");
01862   else
01863     {
01864       FloatEIG b_eig (b);
01865 
01866       if (! error_state)
01867         {
01868           FloatComplexColumnVector lambda (b_eig.eigenvalues ());
01869           FloatComplexMatrix Q (b_eig.eigenvectors ());
01870 
01871           for (octave_idx_type i = 0; i < nr; i++)
01872             {
01873               FloatComplex elt = lambda(i);
01874               if (std::imag (elt) == 0.0)
01875                 lambda(i) = std::pow (a, std::real (elt));
01876               else
01877                 lambda(i) = std::pow (a, elt);
01878             }
01879           FloatComplexDiagMatrix D (lambda);
01880 
01881           retval = FloatComplexMatrix (Q * D * Q.inverse ());
01882         }
01883       else
01884         error ("xpow: matrix diagonalization failed");
01885     }
01886 
01887   return retval;
01888 }
01889 
01890 // -*- 11 -*-
01891 octave_value
01892 xpow (const FloatComplexMatrix& a, float b)
01893 {
01894   octave_value retval;
01895 
01896   octave_idx_type nr = a.rows ();
01897   octave_idx_type nc = a.cols ();
01898 
01899   if (nr == 0 || nc == 0 || nr != nc)
01900     error ("for A^b, A must be a square matrix");
01901   else
01902     {
01903       if (static_cast<int> (b) == b)
01904         {
01905           int btmp = static_cast<int> (b);
01906           if (btmp == 0)
01907             {
01908               retval = FloatDiagMatrix (nr, nr, 1.0);
01909             }
01910           else
01911             {
01912               // Too much copying?
01913               // FIXME -- we shouldn't do this if the exponent is
01914               // large...
01915 
01916               FloatComplexMatrix atmp;
01917               if (btmp < 0)
01918                 {
01919                   btmp = -btmp;
01920 
01921                   octave_idx_type info;
01922                   float rcond = 0.0;
01923                   MatrixType mattype (a);
01924 
01925                   atmp = a.inverse (mattype, info, rcond, 1);
01926 
01927                   if (info == -1)
01928                     warning ("inverse: matrix singular to machine\
01929  precision, rcond = %g", rcond);
01930                 }
01931               else
01932                 atmp = a;
01933 
01934               FloatComplexMatrix result (atmp);
01935 
01936               btmp--;
01937 
01938               while (btmp > 0)
01939                 {
01940                   if (btmp & 1)
01941                     result = result * atmp;
01942 
01943                   btmp >>= 1;
01944 
01945                   if (btmp > 0)
01946                     atmp = atmp * atmp;
01947                 }
01948 
01949               retval = result;
01950             }
01951         }
01952       else
01953         {
01954           FloatEIG a_eig (a);
01955 
01956           if (! error_state)
01957             {
01958               FloatComplexColumnVector lambda (a_eig.eigenvalues ());
01959               FloatComplexMatrix Q (a_eig.eigenvectors ());
01960 
01961               for (octave_idx_type i = 0; i < nr; i++)
01962                 lambda(i) = std::pow (lambda(i), b);
01963 
01964               FloatComplexDiagMatrix D (lambda);
01965 
01966               retval = FloatComplexMatrix (Q * D * Q.inverse ());
01967             }
01968           else
01969             error ("xpow: matrix diagonalization failed");
01970         }
01971     }
01972 
01973   return retval;
01974 }
01975 
01976 // -*- 12 -*-
01977 octave_value
01978 xpow (const FloatComplexMatrix& a, const FloatComplex& b)
01979 {
01980   octave_value retval;
01981 
01982   octave_idx_type nr = a.rows ();
01983   octave_idx_type nc = a.cols ();
01984 
01985   if (nr == 0 || nc == 0 || nr != nc)
01986     error ("for A^b, A must be a square matrix");
01987   else
01988     {
01989       FloatEIG a_eig (a);
01990 
01991       if (! error_state)
01992         {
01993           FloatComplexColumnVector lambda (a_eig.eigenvalues ());
01994           FloatComplexMatrix Q (a_eig.eigenvectors ());
01995 
01996           for (octave_idx_type i = 0; i < nr; i++)
01997             lambda(i) = std::pow (lambda(i), b);
01998 
01999           FloatComplexDiagMatrix D (lambda);
02000 
02001           retval = FloatComplexMatrix (Q * D * Q.inverse ());
02002         }
02003       else
02004         error ("xpow: matrix diagonalization failed");
02005     }
02006 
02007   return retval;
02008 }
02009 
02010 // -*- 12d -*-
02011 octave_value
02012 xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b)
02013 {
02014   octave_value retval;
02015 
02016   octave_idx_type nr = a.rows ();
02017   octave_idx_type nc = a.cols ();
02018 
02019   if (nr == 0 || nc == 0 || nr != nc)
02020     error ("for A^b, A must be a square matrix");
02021   else
02022     {
02023       FloatComplexDiagMatrix r (nr, nc);
02024       for (octave_idx_type i = 0; i < nc; i++)
02025         r(i, i) = std::pow (a(i, i), b);
02026       retval = r;
02027     }
02028 
02029   return retval;
02030 }
02031 
02032 // mixed
02033 octave_value
02034 xpow (const FloatComplexDiagMatrix& a, float b)
02035 {
02036   return xpow (a, static_cast<FloatComplex> (b));
02037 }
02038 
02039 octave_value
02040 xpow (const FloatDiagMatrix& a, const FloatComplex& b)
02041 {
02042   return xpow (FloatComplexDiagMatrix (a), b);
02043 }
02044 
02045 // Safer pow functions that work elementwise for matrices.
02046 //
02047 //       op2 \ op1:   s   m   cs   cm
02048 //            +--   +---+---+----+----+
02049 //   scalar   |     | * | 3 |  * |  9 |
02050 //                  +---+---+----+----+
02051 //   matrix         | 1 | 4 |  7 | 10 |
02052 //                  +---+---+----+----+
02053 //   complex_scalar | * | 5 |  * | 11 |
02054 //                  +---+---+----+----+
02055 //   complex_matrix | 2 | 6 |  8 | 12 |
02056 //                  +---+---+----+----+
02057 //
02058 //   * -> not needed.
02059 
02060 // FIXME -- these functions need to be fixed so that things
02061 // like
02062 //
02063 //   a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b
02064 //
02065 // and
02066 //
02067 //   a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end
02068 //
02069 // produce identical results.  Also, it would be nice if -1^0.5
02070 // produced a pure imaginary result instead of a complex number with a
02071 // small real part.  But perhaps that's really a problem with the math
02072 // library...
02073 
02074 // -*- 1 -*-
02075 octave_value
02076 elem_xpow (float a, const FloatMatrix& b)
02077 {
02078   octave_value retval;
02079 
02080   octave_idx_type nr = b.rows ();
02081   octave_idx_type nc = b.cols ();
02082 
02083   float d1, d2;
02084 
02085   if (a < 0.0 && ! b.all_integers (d1, d2))
02086     {
02087       FloatComplex atmp (a);
02088       FloatComplexMatrix result (nr, nc);
02089 
02090       for (octave_idx_type j = 0; j < nc; j++)
02091         for (octave_idx_type i = 0; i < nr; i++)
02092           {
02093             octave_quit ();
02094             result (i, j) = std::pow (atmp, b (i, j));
02095           }
02096 
02097       retval = result;
02098     }
02099   else
02100     {
02101       FloatMatrix result (nr, nc);
02102 
02103       for (octave_idx_type j = 0; j < nc; j++)
02104         for (octave_idx_type i = 0; i < nr; i++)
02105           {
02106             octave_quit ();
02107             result (i, j) = std::pow (a, b (i, j));
02108           }
02109 
02110       retval = result;
02111     }
02112 
02113   return retval;
02114 }
02115 
02116 // -*- 2 -*-
02117 octave_value
02118 elem_xpow (float a, const FloatComplexMatrix& b)
02119 {
02120   octave_idx_type nr = b.rows ();
02121   octave_idx_type nc = b.cols ();
02122 
02123   FloatComplexMatrix result (nr, nc);
02124   FloatComplex atmp (a);
02125 
02126   for (octave_idx_type j = 0; j < nc; j++)
02127     for (octave_idx_type i = 0; i < nr; i++)
02128       {
02129         octave_quit ();
02130         result (i, j) = std::pow (atmp, b (i, j));
02131       }
02132 
02133   return result;
02134 }
02135 
02136 // -*- 3 -*-
02137 octave_value
02138 elem_xpow (const FloatMatrix& a, float b)
02139 {
02140   octave_value retval;
02141 
02142   octave_idx_type nr = a.rows ();
02143   octave_idx_type nc = a.cols ();
02144 
02145   if (! xisint (b) && a.any_element_is_negative ())
02146     {
02147       FloatComplexMatrix result (nr, nc);
02148 
02149       for (octave_idx_type j = 0; j < nc; j++)
02150         for (octave_idx_type i = 0; i < nr; i++)
02151           {
02152             octave_quit ();
02153 
02154             FloatComplex atmp (a (i, j));
02155 
02156             result (i, j) = std::pow (atmp, b);
02157           }
02158 
02159       retval = result;
02160     }
02161   else
02162     {
02163       FloatMatrix result (nr, nc);
02164 
02165       for (octave_idx_type j = 0; j < nc; j++)
02166         for (octave_idx_type i = 0; i < nr; i++)
02167           {
02168             octave_quit ();
02169             result (i, j) = std::pow (a (i, j), b);
02170           }
02171 
02172       retval = result;
02173     }
02174 
02175   return retval;
02176 }
02177 
02178 // -*- 4 -*-
02179 octave_value
02180 elem_xpow (const FloatMatrix& a, const FloatMatrix& b)
02181 {
02182   octave_value retval;
02183 
02184   octave_idx_type nr = a.rows ();
02185   octave_idx_type nc = a.cols ();
02186 
02187   octave_idx_type b_nr = b.rows ();
02188   octave_idx_type b_nc = b.cols ();
02189 
02190   if (nr != b_nr || nc != b_nc)
02191     {
02192       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
02193       return octave_value ();
02194     }
02195 
02196   int convert_to_complex = 0;
02197   for (octave_idx_type j = 0; j < nc; j++)
02198     for (octave_idx_type i = 0; i < nr; i++)
02199       {
02200         octave_quit ();
02201         float atmp = a (i, j);
02202         float btmp = b (i, j);
02203         if (atmp < 0.0 && static_cast<int> (btmp) != btmp)
02204           {
02205             convert_to_complex = 1;
02206             goto done;
02207           }
02208       }
02209 
02210 done:
02211 
02212   if (convert_to_complex)
02213     {
02214       FloatComplexMatrix complex_result (nr, nc);
02215 
02216       for (octave_idx_type j = 0; j < nc; j++)
02217         for (octave_idx_type i = 0; i < nr; i++)
02218           {
02219             octave_quit ();
02220             FloatComplex atmp (a (i, j));
02221             FloatComplex btmp (b (i, j));
02222             complex_result (i, j) = std::pow (atmp, btmp);
02223           }
02224 
02225       retval = complex_result;
02226     }
02227   else
02228     {
02229       FloatMatrix result (nr, nc);
02230 
02231       for (octave_idx_type j = 0; j < nc; j++)
02232         for (octave_idx_type i = 0; i < nr; i++)
02233           {
02234             octave_quit ();
02235             result (i, j) = std::pow (a (i, j), b (i, j));
02236           }
02237 
02238       retval = result;
02239     }
02240 
02241   return retval;
02242 }
02243 
02244 // -*- 5 -*-
02245 octave_value
02246 elem_xpow (const FloatMatrix& a, const FloatComplex& b)
02247 {
02248   octave_idx_type nr = a.rows ();
02249   octave_idx_type nc = a.cols ();
02250 
02251   FloatComplexMatrix result (nr, nc);
02252 
02253   for (octave_idx_type j = 0; j < nc; j++)
02254     for (octave_idx_type i = 0; i < nr; i++)
02255       {
02256         octave_quit ();
02257         result (i, j) = std::pow (FloatComplex (a (i, j)), b);
02258       }
02259 
02260   return result;
02261 }
02262 
02263 // -*- 6 -*-
02264 octave_value
02265 elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b)
02266 {
02267   octave_idx_type nr = a.rows ();
02268   octave_idx_type nc = a.cols ();
02269 
02270   octave_idx_type b_nr = b.rows ();
02271   octave_idx_type b_nc = b.cols ();
02272 
02273   if (nr != b_nr || nc != b_nc)
02274     {
02275       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
02276       return octave_value ();
02277     }
02278 
02279   FloatComplexMatrix result (nr, nc);
02280 
02281   for (octave_idx_type j = 0; j < nc; j++)
02282     for (octave_idx_type i = 0; i < nr; i++)
02283       {
02284         octave_quit ();
02285         result (i, j) = std::pow (FloatComplex (a (i, j)), b (i, j));
02286       }
02287 
02288   return result;
02289 }
02290 
02291 // -*- 7 -*-
02292 octave_value
02293 elem_xpow (const FloatComplex& a, const FloatMatrix& b)
02294 {
02295   octave_idx_type nr = b.rows ();
02296   octave_idx_type nc = b.cols ();
02297 
02298   FloatComplexMatrix result (nr, nc);
02299 
02300   for (octave_idx_type j = 0; j < nc; j++)
02301     for (octave_idx_type i = 0; i < nr; i++)
02302       {
02303         octave_quit ();
02304         float btmp = b (i, j);
02305         if (xisint (btmp))
02306           result (i, j) = std::pow (a, static_cast<int> (btmp));
02307         else
02308           result (i, j) = std::pow (a, btmp);
02309       }
02310 
02311   return result;
02312 }
02313 
02314 // -*- 8 -*-
02315 octave_value
02316 elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b)
02317 {
02318   octave_idx_type nr = b.rows ();
02319   octave_idx_type nc = b.cols ();
02320 
02321   FloatComplexMatrix result (nr, nc);
02322 
02323   for (octave_idx_type j = 0; j < nc; j++)
02324     for (octave_idx_type i = 0; i < nr; i++)
02325       {
02326         octave_quit ();
02327         result (i, j) = std::pow (a, b (i, j));
02328       }
02329 
02330   return result;
02331 }
02332 
02333 // -*- 9 -*-
02334 octave_value
02335 elem_xpow (const FloatComplexMatrix& a, float b)
02336 {
02337   octave_idx_type nr = a.rows ();
02338   octave_idx_type nc = a.cols ();
02339 
02340   FloatComplexMatrix result (nr, nc);
02341 
02342   if (xisint (b))
02343     {
02344       for (octave_idx_type j = 0; j < nc; j++)
02345         for (octave_idx_type i = 0; i < nr; i++)
02346           {
02347             octave_quit ();
02348             result (i, j) = std::pow (a (i, j), static_cast<int> (b));
02349           }
02350     }
02351   else
02352     {
02353       for (octave_idx_type j = 0; j < nc; j++)
02354         for (octave_idx_type i = 0; i < nr; i++)
02355           {
02356             octave_quit ();
02357             result (i, j) = std::pow (a (i, j), b);
02358           }
02359     }
02360 
02361   return result;
02362 }
02363 
02364 // -*- 10 -*-
02365 octave_value
02366 elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b)
02367 {
02368   octave_idx_type nr = a.rows ();
02369   octave_idx_type nc = a.cols ();
02370 
02371   octave_idx_type b_nr = b.rows ();
02372   octave_idx_type b_nc = b.cols ();
02373 
02374   if (nr != b_nr || nc != b_nc)
02375     {
02376       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
02377       return octave_value ();
02378     }
02379 
02380   FloatComplexMatrix result (nr, nc);
02381 
02382   for (octave_idx_type j = 0; j < nc; j++)
02383     for (octave_idx_type i = 0; i < nr; i++)
02384       {
02385         octave_quit ();
02386         float btmp = b (i, j);
02387         if (xisint (btmp))
02388           result (i, j) = std::pow (a (i, j), static_cast<int> (btmp));
02389         else
02390           result (i, j) = std::pow (a (i, j), btmp);
02391       }
02392 
02393   return result;
02394 }
02395 
02396 // -*- 11 -*-
02397 octave_value
02398 elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b)
02399 {
02400   octave_idx_type nr = a.rows ();
02401   octave_idx_type nc = a.cols ();
02402 
02403   FloatComplexMatrix result (nr, nc);
02404 
02405   for (octave_idx_type j = 0; j < nc; j++)
02406     for (octave_idx_type i = 0; i < nr; i++)
02407       {
02408         octave_quit ();
02409         result (i, j) = std::pow (a (i, j), b);
02410       }
02411 
02412   return result;
02413 }
02414 
02415 // -*- 12 -*-
02416 octave_value
02417 elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b)
02418 {
02419   octave_idx_type nr = a.rows ();
02420   octave_idx_type nc = a.cols ();
02421 
02422   octave_idx_type b_nr = b.rows ();
02423   octave_idx_type b_nc = b.cols ();
02424 
02425   if (nr != b_nr || nc != b_nc)
02426     {
02427       gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc);
02428       return octave_value ();
02429     }
02430 
02431   FloatComplexMatrix result (nr, nc);
02432 
02433   for (octave_idx_type j = 0; j < nc; j++)
02434     for (octave_idx_type i = 0; i < nr; i++)
02435       {
02436         octave_quit ();
02437         result (i, j) = std::pow (a (i, j), b (i, j));
02438       }
02439 
02440   return result;
02441 }
02442 
02443 // Safer pow functions that work elementwise for N-d arrays.
02444 //
02445 //       op2 \ op1:   s   nd  cs   cnd
02446 //            +--   +---+---+----+----+
02447 //   scalar   |     | * | 3 |  * |  9 |
02448 //                  +---+---+----+----+
02449 //   N_d            | 1 | 4 |  7 | 10 |
02450 //                  +---+---+----+----+
02451 //   complex_scalar | * | 5 |  * | 11 |
02452 //                  +---+---+----+----+
02453 //   complex_N_d    | 2 | 6 |  8 | 12 |
02454 //                  +---+---+----+----+
02455 //
02456 //   * -> not needed.
02457 
02458 // FIXME -- these functions need to be fixed so that things
02459 // like
02460 //
02461 //   a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b
02462 //
02463 // and
02464 //
02465 //   a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end
02466 //
02467 // produce identical results.  Also, it would be nice if -1^0.5
02468 // produced a pure imaginary result instead of a complex number with a
02469 // small real part.  But perhaps that's really a problem with the math
02470 // library...
02471 
02472 // -*- 1 -*-
02473 octave_value
02474 elem_xpow (float a, const FloatNDArray& b)
02475 {
02476   octave_value retval;
02477 
02478   if (a < 0.0 && ! b.all_integers ())
02479     {
02480       FloatComplex atmp (a);
02481       FloatComplexNDArray result (b.dims ());
02482       for (octave_idx_type i = 0; i < b.length (); i++)
02483         {
02484           octave_quit ();
02485           result(i) = std::pow (atmp, b(i));
02486         }
02487 
02488       retval = result;
02489     }
02490   else
02491     {
02492       FloatNDArray result (b.dims ());
02493       for (octave_idx_type i = 0; i < b.length (); i++)
02494         {
02495           octave_quit ();
02496           result (i) = std::pow (a, b(i));
02497         }
02498 
02499       retval = result;
02500     }
02501 
02502   return retval;
02503 }
02504 
02505 // -*- 2 -*-
02506 octave_value
02507 elem_xpow (float a, const FloatComplexNDArray& b)
02508 {
02509   FloatComplexNDArray result (b.dims ());
02510 
02511   for (octave_idx_type i = 0; i < b.length (); i++)
02512     {
02513       octave_quit ();
02514       result(i) = std::pow (a, b(i));
02515     }
02516 
02517   return result;
02518 }
02519 
02520 // -*- 3 -*-
02521 octave_value
02522 elem_xpow (const FloatNDArray& a, float b)
02523 {
02524   octave_value retval;
02525 
02526   if (! xisint (b))
02527     {
02528       if (a.any_element_is_negative ())
02529         {
02530           FloatComplexNDArray result (a.dims ());
02531 
02532           for (octave_idx_type i = 0; i < a.length (); i++)
02533             {
02534               octave_quit ();
02535 
02536               FloatComplex atmp (a (i));
02537 
02538               result(i) = std::pow (atmp, b);
02539             }
02540 
02541           retval = result;
02542         }
02543       else
02544         {
02545           FloatNDArray result (a.dims ());
02546           for (octave_idx_type i = 0; i < a.length (); i++)
02547             {
02548               octave_quit ();
02549               result(i) = std::pow (a(i), b);
02550             }
02551 
02552           retval = result;
02553         }
02554     }
02555   else
02556     {
02557       NoAlias<FloatNDArray> result (a.dims ());
02558 
02559       int ib = static_cast<int> (b);
02560       if (ib == 2)
02561         {
02562           for (octave_idx_type i = 0; i < a.length (); i++)
02563             result(i) = a(i) * a(i);
02564         }
02565       else if (ib == 3)
02566         {
02567           for (octave_idx_type i = 0; i < a.length (); i++)
02568             result(i) = a(i) * a(i) * a(i);
02569         }
02570       else if (ib == -1)
02571         {
02572           for (octave_idx_type i = 0; i < a.length (); i++)
02573             result(i) = 1.0f / a(i);
02574         }
02575       else
02576         {
02577           for (octave_idx_type i = 0; i < a.length (); i++)
02578             {
02579               octave_quit ();
02580               result(i) = std::pow (a(i), ib);
02581             }
02582         }
02583 
02584       retval = result;
02585     }
02586 
02587   return retval;
02588 }
02589 
02590 // -*- 4 -*-
02591 octave_value
02592 elem_xpow (const FloatNDArray& a, const FloatNDArray& b)
02593 {
02594   octave_value retval;
02595 
02596   dim_vector a_dims = a.dims ();
02597   dim_vector b_dims = b.dims ();
02598 
02599   if (a_dims != b_dims)
02600     {
02601       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
02602         {
02603           //Potentially complex results
02604           FloatNDArray xa = octave_value_extract<FloatNDArray> (a);
02605           FloatNDArray xb = octave_value_extract<FloatNDArray> (b);
02606           if (! xb.all_integers () && xa.any_element_is_negative ())
02607             return octave_value (bsxfun_pow (FloatComplexNDArray (xa), xb));
02608           else
02609             return octave_value (bsxfun_pow (xa, xb));
02610         }
02611       else
02612         {
02613           gripe_nonconformant ("operator .^", a_dims, b_dims);
02614           return octave_value ();
02615         }
02616     }
02617 
02618   int len = a.length ();
02619 
02620   bool convert_to_complex = false;
02621 
02622   for (octave_idx_type i = 0; i < len; i++)
02623     {
02624       octave_quit ();
02625       float atmp = a(i);
02626       float btmp = b(i);
02627       if (atmp < 0.0 && static_cast<int> (btmp) != btmp)
02628         {
02629           convert_to_complex = true;
02630           goto done;
02631         }
02632     }
02633 
02634 done:
02635 
02636   if (convert_to_complex)
02637     {
02638       FloatComplexNDArray complex_result (a_dims);
02639 
02640       for (octave_idx_type i = 0; i < len; i++)
02641         {
02642           octave_quit ();
02643           FloatComplex atmp (a(i));
02644           complex_result(i) = std::pow (atmp, b(i));
02645         }
02646 
02647       retval = complex_result;
02648     }
02649   else
02650     {
02651       FloatNDArray result (a_dims);
02652 
02653       for (octave_idx_type i = 0; i < len; i++)
02654         {
02655           octave_quit ();
02656           result(i) = std::pow (a(i), b(i));
02657         }
02658 
02659       retval = result;
02660     }
02661 
02662   return retval;
02663 }
02664 
02665 // -*- 5 -*-
02666 octave_value
02667 elem_xpow (const FloatNDArray& a, const FloatComplex& b)
02668 {
02669   FloatComplexNDArray result (a.dims ());
02670 
02671   for (octave_idx_type i = 0; i < a.length (); i++)
02672     {
02673       octave_quit ();
02674       result(i) = std::pow (a(i), b);
02675     }
02676 
02677   return result;
02678 }
02679 
02680 // -*- 6 -*-
02681 octave_value
02682 elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b)
02683 {
02684   dim_vector a_dims = a.dims ();
02685   dim_vector b_dims = b.dims ();
02686 
02687   if (a_dims != b_dims)
02688     {
02689       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
02690         {
02691           return bsxfun_pow (a, b);
02692         }
02693       else
02694         {
02695           gripe_nonconformant ("operator .^", a_dims, b_dims);
02696           return octave_value ();
02697         }
02698     }
02699 
02700   FloatComplexNDArray result (a_dims);
02701 
02702   for (octave_idx_type i = 0; i < a.length (); i++)
02703     {
02704       octave_quit ();
02705       result(i) = std::pow (a(i), b(i));
02706     }
02707 
02708   return result;
02709 }
02710 
02711 // -*- 7 -*-
02712 octave_value
02713 elem_xpow (const FloatComplex& a, const FloatNDArray& b)
02714 {
02715   FloatComplexNDArray result (b.dims ());
02716 
02717   for (octave_idx_type i = 0; i < b.length (); i++)
02718     {
02719       octave_quit ();
02720       float btmp = b(i);
02721       if (xisint (btmp))
02722         result(i) = std::pow (a, static_cast<int> (btmp));
02723       else
02724         result(i) = std::pow (a, btmp);
02725     }
02726 
02727   return result;
02728 }
02729 
02730 // -*- 8 -*-
02731 octave_value
02732 elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b)
02733 {
02734   FloatComplexNDArray result (b.dims ());
02735 
02736   for (octave_idx_type i = 0; i < b.length (); i++)
02737     {
02738       octave_quit ();
02739       result(i) = std::pow (a, b(i));
02740     }
02741 
02742   return result;
02743 }
02744 
02745 // -*- 9 -*-
02746 octave_value
02747 elem_xpow (const FloatComplexNDArray& a, float b)
02748 {
02749   FloatComplexNDArray result (a.dims ());
02750 
02751   if (xisint (b))
02752     {
02753       if (b == -1)
02754         {
02755           for (octave_idx_type i = 0; i < a.length (); i++)
02756             result.xelem (i) = 1.0f / a(i);
02757         }
02758       else
02759         {
02760           for (octave_idx_type i = 0; i < a.length (); i++)
02761             {
02762               octave_quit ();
02763               result(i) = std::pow (a(i), static_cast<int> (b));
02764             }
02765         }
02766     }
02767   else
02768     {
02769       for (octave_idx_type i = 0; i < a.length (); i++)
02770         {
02771           octave_quit ();
02772           result(i) = std::pow (a(i), b);
02773         }
02774     }
02775 
02776   return result;
02777 }
02778 
02779 // -*- 10 -*-
02780 octave_value
02781 elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b)
02782 {
02783   dim_vector a_dims = a.dims ();
02784   dim_vector b_dims = b.dims ();
02785 
02786   if (a_dims != b_dims)
02787     {
02788       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
02789         {
02790           return bsxfun_pow (a, b);
02791         }
02792       else
02793         {
02794           gripe_nonconformant ("operator .^", a_dims, b_dims);
02795           return octave_value ();
02796         }
02797     }
02798 
02799   FloatComplexNDArray result (a_dims);
02800 
02801   for (octave_idx_type i = 0; i < a.length (); i++)
02802     {
02803       octave_quit ();
02804       float btmp = b(i);
02805       if (xisint (btmp))
02806         result(i) = std::pow (a(i), static_cast<int> (btmp));
02807       else
02808         result(i) = std::pow (a(i), btmp);
02809     }
02810 
02811   return result;
02812 }
02813 
02814 // -*- 11 -*-
02815 octave_value
02816 elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b)
02817 {
02818   FloatComplexNDArray result (a.dims ());
02819 
02820   for (octave_idx_type i = 0; i < a.length (); i++)
02821     {
02822       octave_quit ();
02823       result(i) = std::pow (a(i), b);
02824     }
02825 
02826   return result;
02827 }
02828 
02829 // -*- 12 -*-
02830 octave_value
02831 elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b)
02832 {
02833   dim_vector a_dims = a.dims ();
02834   dim_vector b_dims = b.dims ();
02835 
02836   if (a_dims != b_dims)
02837     {
02838       if (is_valid_bsxfun ("operator .^", a_dims, b_dims))
02839         {
02840           return bsxfun_pow (a, b);
02841         }
02842       else
02843         {
02844           gripe_nonconformant ("operator .^", a_dims, b_dims);
02845           return octave_value ();
02846         }
02847     }
02848 
02849   FloatComplexNDArray result (a_dims);
02850 
02851   for (octave_idx_type i = 0; i < a.length (); i++)
02852     {
02853       octave_quit ();
02854       result(i) = std::pow (a(i), b(i));
02855     }
02856 
02857   return result;
02858 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines