00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #include "floatQR.h"
00030 #include "f77-fcn.h"
00031 #include "lo-error.h"
00032 #include "Range.h"
00033 #include "idx-vector.h"
00034 #include "oct-locbuf.h"
00035
00036 #include "base-qr.cc"
00037
00038 template class base_qr<FloatMatrix>;
00039
00040 extern "C"
00041 {
00042 F77_RET_T
00043 F77_FUNC (sgeqrf, SGEQRF) (const octave_idx_type&, const octave_idx_type&,
00044 float*, const octave_idx_type&, float*, float*,
00045 const octave_idx_type&, octave_idx_type&);
00046
00047 F77_RET_T
00048 F77_FUNC (sorgqr, SORGQR) (const octave_idx_type&, const octave_idx_type&,
00049 const octave_idx_type&, float*,
00050 const octave_idx_type&, float*, float*,
00051 const octave_idx_type&, octave_idx_type&);
00052
00053 #ifdef HAVE_QRUPDATE
00054
00055 F77_RET_T
00056 F77_FUNC (sqr1up, SQR1UP) (const octave_idx_type&, const octave_idx_type&,
00057 const octave_idx_type&, float*,
00058 const octave_idx_type&, float*,
00059 const octave_idx_type&, float*, float*, float*);
00060
00061 F77_RET_T
00062 F77_FUNC (sqrinc, SQRINC) (const octave_idx_type&, const octave_idx_type&,
00063 const octave_idx_type&, float*,
00064 const octave_idx_type&, float*,
00065 const octave_idx_type&,
00066 const octave_idx_type&, const float*, float*);
00067
00068 F77_RET_T
00069 F77_FUNC (sqrdec, SQRDEC) (const octave_idx_type&, const octave_idx_type&,
00070 const octave_idx_type&, float*,
00071 const octave_idx_type&, float*,
00072 const octave_idx_type&,
00073 const octave_idx_type&, float*);
00074
00075 F77_RET_T
00076 F77_FUNC (sqrinr, SQRINR) (const octave_idx_type&, const octave_idx_type&,
00077 float*, const octave_idx_type&,
00078 float*, const octave_idx_type&,
00079 const octave_idx_type&, const float*, float*);
00080
00081 F77_RET_T
00082 F77_FUNC (sqrder, SQRDER) (const octave_idx_type&, const octave_idx_type&,
00083 float*, const octave_idx_type&,
00084 float*, const octave_idx_type&,
00085 const octave_idx_type&, float*);
00086
00087 F77_RET_T
00088 F77_FUNC (sqrshc, SQRSHC) (const octave_idx_type&, const octave_idx_type&,
00089 const octave_idx_type&, float*,
00090 const octave_idx_type&, float*,
00091 const octave_idx_type&,
00092 const octave_idx_type&, const octave_idx_type&,
00093 float*);
00094
00095 #endif
00096 }
00097
00098 FloatQR::FloatQR (const FloatMatrix& a, qr_type_t qr_type)
00099 {
00100 init (a, qr_type);
00101 }
00102
00103 void
00104 FloatQR::init (const FloatMatrix& a, qr_type_t qr_type)
00105 {
00106 octave_idx_type m = a.rows ();
00107 octave_idx_type n = a.cols ();
00108
00109 octave_idx_type min_mn = m < n ? m : n;
00110 OCTAVE_LOCAL_BUFFER (float, tau, min_mn);
00111
00112 octave_idx_type info = 0;
00113
00114 FloatMatrix afact = a;
00115 if (m > n && qr_type == qr_type_std)
00116 afact.resize (m, m);
00117
00118 if (m > 0)
00119 {
00120
00121 float rlwork;
00122 F77_XFCN (sgeqrf, SGEQRF, (m, n, afact.fortran_vec (), m, tau, &rlwork, -1, info));
00123
00124
00125 octave_idx_type lwork = rlwork;
00126 lwork = std::max (lwork, static_cast<octave_idx_type> (1));
00127 OCTAVE_LOCAL_BUFFER (float, work, lwork);
00128 F77_XFCN (sgeqrf, SGEQRF, (m, n, afact.fortran_vec (), m, tau, work, lwork, info));
00129 }
00130
00131 form (n, afact, tau, qr_type);
00132 }
00133
00134 void FloatQR::form (octave_idx_type n, FloatMatrix& afact,
00135 float *tau, qr_type_t qr_type)
00136 {
00137 octave_idx_type m = afact.rows (), min_mn = std::min (m, n);
00138 octave_idx_type info;
00139
00140 if (qr_type == qr_type_raw)
00141 {
00142 for (octave_idx_type j = 0; j < min_mn; j++)
00143 {
00144 octave_idx_type limit = j < min_mn - 1 ? j : min_mn - 1;
00145 for (octave_idx_type i = limit + 1; i < m; i++)
00146 afact.elem (i, j) *= tau[j];
00147 }
00148
00149 r = afact;
00150 }
00151 else
00152 {
00153
00154 if (m >= n)
00155 {
00156
00157 q = afact;
00158 octave_idx_type k = qr_type == qr_type_economy ? n : m;
00159 r = FloatMatrix (k, n);
00160 for (octave_idx_type j = 0; j < n; j++)
00161 {
00162 octave_idx_type i = 0;
00163 for (; i <= j; i++)
00164 r.xelem (i, j) = afact.xelem (i, j);
00165 for (;i < k; i++)
00166 r.xelem (i, j) = 0;
00167 }
00168 afact = FloatMatrix ();
00169 }
00170 else
00171 {
00172
00173 q = FloatMatrix (m, m);
00174 for (octave_idx_type j = 0; j < m; j++)
00175 for (octave_idx_type i = j + 1; i < m; i++)
00176 {
00177 q.xelem (i, j) = afact.xelem (i, j);
00178 afact.xelem (i, j) = 0;
00179 }
00180 r = afact;
00181 }
00182
00183
00184 if (m > 0)
00185 {
00186 octave_idx_type k = q.columns ();
00187
00188 float rlwork;
00189 F77_XFCN (sorgqr, SORGQR, (m, k, min_mn, q.fortran_vec (), m, tau,
00190 &rlwork, -1, info));
00191
00192
00193 octave_idx_type lwork = rlwork;
00194 lwork = std::max (lwork, static_cast<octave_idx_type> (1));
00195 OCTAVE_LOCAL_BUFFER (float, work, lwork);
00196 F77_XFCN (sorgqr, SORGQR, (m, k, min_mn, q.fortran_vec (), m, tau,
00197 work, lwork, info));
00198 }
00199 }
00200 }
00201
00202 #ifdef HAVE_QRUPDATE
00203
00204 void
00205 FloatQR::update (const FloatColumnVector& u, const FloatColumnVector& v)
00206 {
00207 octave_idx_type m = q.rows ();
00208 octave_idx_type n = r.columns ();
00209 octave_idx_type k = q.columns ();
00210
00211 if (u.length () == m && v.length () == n)
00212 {
00213 FloatColumnVector utmp = u, vtmp = v;
00214 OCTAVE_LOCAL_BUFFER (float, w, 2*k);
00215 F77_XFCN (sqr1up, SQR1UP, (m, n, k, q.fortran_vec (), m, r.fortran_vec (), k,
00216 utmp.fortran_vec (), vtmp.fortran_vec (), w));
00217 }
00218 else
00219 (*current_liboctave_error_handler) ("qrupdate: dimensions mismatch");
00220 }
00221
00222 void
00223 FloatQR::update (const FloatMatrix& u, const FloatMatrix& v)
00224 {
00225 octave_idx_type m = q.rows ();
00226 octave_idx_type n = r.columns ();
00227 octave_idx_type k = q.columns ();
00228
00229 if (u.rows () == m && v.rows () == n && u.cols () == v.cols ())
00230 {
00231 OCTAVE_LOCAL_BUFFER (float, w, 2*k);
00232 for (volatile octave_idx_type i = 0; i < u.cols (); i++)
00233 {
00234 FloatColumnVector utmp = u.column (i), vtmp = v.column (i);
00235 F77_XFCN (sqr1up, SQR1UP, (m, n, k, q.fortran_vec (), m, r.fortran_vec (), k,
00236 utmp.fortran_vec (), vtmp.fortran_vec (), w));
00237 }
00238 }
00239 else
00240 (*current_liboctave_error_handler) ("qrupdate: dimensions mismatch");
00241 }
00242
00243 void
00244 FloatQR::insert_col (const FloatColumnVector& u, octave_idx_type j)
00245 {
00246 octave_idx_type m = q.rows ();
00247 octave_idx_type n = r.columns ();
00248 octave_idx_type k = q.columns ();
00249
00250 if (u.length () != m)
00251 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00252 else if (j < 0 || j > n)
00253 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00254 else
00255 {
00256 if (k < m)
00257 {
00258 q.resize (m, k+1);
00259 r.resize (k+1, n+1);
00260 }
00261 else
00262 {
00263 r.resize (k, n+1);
00264 }
00265
00266 FloatColumnVector utmp = u;
00267 OCTAVE_LOCAL_BUFFER (float, w, k);
00268 F77_XFCN (sqrinc, SQRINC, (m, n, k, q.fortran_vec (), q.rows (),
00269 r.fortran_vec (), r.rows (), j + 1,
00270 utmp.data (), w));
00271 }
00272 }
00273
00274 void
00275 FloatQR::insert_col (const FloatMatrix& u, const Array<octave_idx_type>& j)
00276 {
00277 octave_idx_type m = q.rows ();
00278 octave_idx_type n = r.columns ();
00279 octave_idx_type k = q.columns ();
00280
00281 Array<octave_idx_type> jsi;
00282 Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
00283 octave_idx_type nj = js.length ();
00284 bool dups = false;
00285 for (octave_idx_type i = 0; i < nj - 1; i++)
00286 dups = dups && js(i) == js(i+1);
00287
00288 if (dups)
00289 (*current_liboctave_error_handler) ("qrinsert: duplicate index detected");
00290 else if (u.length () != m || u.columns () != nj)
00291 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00292 else if (nj > 0 && (js(0) < 0 || js(nj-1) > n))
00293 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00294 else if (nj > 0)
00295 {
00296 octave_idx_type kmax = std::min (k + nj, m);
00297 if (k < m)
00298 {
00299 q.resize (m, kmax);
00300 r.resize (kmax, n + nj);
00301 }
00302 else
00303 {
00304 r.resize (k, n + nj);
00305 }
00306
00307 OCTAVE_LOCAL_BUFFER (float, w, kmax);
00308 for (volatile octave_idx_type i = 0; i < js.length (); i++)
00309 {
00310 octave_idx_type ii = i;
00311 FloatColumnVector utmp = u.column (jsi(i));
00312 F77_XFCN (sqrinc, SQRINC, (m, n + ii, std::min (kmax, k + ii),
00313 q.fortran_vec (), q.rows (),
00314 r.fortran_vec (), r.rows (), js(ii) + 1,
00315 utmp.data (), w));
00316 }
00317 }
00318 }
00319
00320 void
00321 FloatQR::delete_col (octave_idx_type j)
00322 {
00323 octave_idx_type m = q.rows ();
00324 octave_idx_type k = r.rows ();
00325 octave_idx_type n = r.columns ();
00326
00327 if (j < 0 || j > n-1)
00328 (*current_liboctave_error_handler) ("qrdelete: index out of range");
00329 else
00330 {
00331 OCTAVE_LOCAL_BUFFER (float, w, k);
00332 F77_XFCN (sqrdec, SQRDEC, (m, n, k, q.fortran_vec (), q.rows (),
00333 r.fortran_vec (), r.rows (), j + 1, w));
00334
00335 if (k < m)
00336 {
00337 q.resize (m, k-1);
00338 r.resize (k-1, n-1);
00339 }
00340 else
00341 {
00342 r.resize (k, n-1);
00343 }
00344 }
00345 }
00346
00347 void
00348 FloatQR::delete_col (const Array<octave_idx_type>& j)
00349 {
00350 octave_idx_type m = q.rows ();
00351 octave_idx_type n = r.columns ();
00352 octave_idx_type k = q.columns ();
00353
00354 Array<octave_idx_type> jsi;
00355 Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
00356 octave_idx_type nj = js.length ();
00357 bool dups = false;
00358 for (octave_idx_type i = 0; i < nj - 1; i++)
00359 dups = dups && js(i) == js(i+1);
00360
00361 if (dups)
00362 (*current_liboctave_error_handler) ("qrinsert: duplicate index detected");
00363 else if (nj > 0 && (js(0) > n-1 || js(nj-1) < 0))
00364 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00365 else if (nj > 0)
00366 {
00367 OCTAVE_LOCAL_BUFFER (float, w, k);
00368 for (volatile octave_idx_type i = 0; i < js.length (); i++)
00369 {
00370 octave_idx_type ii = i;
00371 F77_XFCN (sqrdec, SQRDEC, (m, n - ii, k == m ? k : k - ii,
00372 q.fortran_vec (), q.rows (),
00373 r.fortran_vec (), r.rows (), js(ii) + 1, w));
00374 }
00375 if (k < m)
00376 {
00377 q.resize (m, k - nj);
00378 r.resize (k - nj, n - nj);
00379 }
00380 else
00381 {
00382 r.resize (k, n - nj);
00383 }
00384
00385 }
00386 }
00387
00388 void
00389 FloatQR::insert_row (const FloatRowVector& u, octave_idx_type j)
00390 {
00391 octave_idx_type m = r.rows ();
00392 octave_idx_type n = r.columns ();
00393 octave_idx_type k = std::min (m, n);
00394
00395 if (! q.is_square () || u.length () != n)
00396 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00397 else if (j < 0 || j > m)
00398 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00399 else
00400 {
00401 q.resize (m + 1, m + 1);
00402 r.resize (m + 1, n);
00403 FloatRowVector utmp = u;
00404 OCTAVE_LOCAL_BUFFER (float, w, k);
00405 F77_XFCN (sqrinr, SQRINR, (m, n, q.fortran_vec (), q.rows (),
00406 r.fortran_vec (), r.rows (),
00407 j + 1, utmp.fortran_vec (), w));
00408
00409 }
00410 }
00411
00412 void
00413 FloatQR::delete_row (octave_idx_type j)
00414 {
00415 octave_idx_type m = r.rows ();
00416 octave_idx_type n = r.columns ();
00417
00418 if (! q.is_square ())
00419 (*current_liboctave_error_handler) ("qrdelete: dimensions mismatch");
00420 else if (j < 0 || j > m-1)
00421 (*current_liboctave_error_handler) ("qrdelete: index out of range");
00422 else
00423 {
00424 OCTAVE_LOCAL_BUFFER (float, w, 2*m);
00425 F77_XFCN (sqrder, SQRDER, (m, n, q.fortran_vec (), q.rows (),
00426 r.fortran_vec (), r.rows (), j + 1,
00427 w));
00428
00429 q.resize (m - 1, m - 1);
00430 r.resize (m - 1, n);
00431 }
00432 }
00433
00434 void
00435 FloatQR::shift_cols (octave_idx_type i, octave_idx_type j)
00436 {
00437 octave_idx_type m = q.rows ();
00438 octave_idx_type k = r.rows ();
00439 octave_idx_type n = r.columns ();
00440
00441 if (i < 0 || i > n-1 || j < 0 || j > n-1)
00442 (*current_liboctave_error_handler) ("qrshift: index out of range");
00443 else
00444 {
00445 OCTAVE_LOCAL_BUFFER (float, w, 2*k);
00446 F77_XFCN (sqrshc, SQRSHC, (m, n, k,
00447 q.fortran_vec (), q.rows (),
00448 r.fortran_vec (), r.rows (),
00449 i + 1, j + 1, w));
00450 }
00451 }
00452
00453 #else
00454
00455
00456
00457 void
00458 FloatQR::update (const FloatColumnVector& u, const FloatColumnVector& v)
00459 {
00460 warn_qrupdate_once ();
00461
00462 octave_idx_type m = q.rows ();
00463 octave_idx_type n = r.columns ();
00464
00465 if (u.length () == m && v.length () == n)
00466 {
00467 init(q*r + FloatMatrix (u) * FloatMatrix (v).transpose (), get_type ());
00468 }
00469 else
00470 (*current_liboctave_error_handler) ("qrupdate: dimensions mismatch");
00471 }
00472
00473 void
00474 FloatQR::update (const FloatMatrix& u, const FloatMatrix& v)
00475 {
00476 warn_qrupdate_once ();
00477
00478 octave_idx_type m = q.rows ();
00479 octave_idx_type n = r.columns ();
00480
00481 if (u.rows () == m && v.rows () == n && u.cols () == v.cols ())
00482 {
00483 init(q*r + u * v.transpose (), get_type ());
00484 }
00485 else
00486 (*current_liboctave_error_handler) ("qrupdate: dimensions mismatch");
00487 }
00488
00489 static
00490 FloatMatrix insert_col (const FloatMatrix& a, octave_idx_type i,
00491 const FloatColumnVector& x)
00492 {
00493 FloatMatrix retval (a.rows (), a.columns () + 1);
00494 retval.assign (idx_vector::colon, idx_vector (0, i),
00495 a.index (idx_vector::colon, idx_vector (0, i)));
00496 retval.assign (idx_vector::colon, idx_vector (i), x);
00497 retval.assign (idx_vector::colon, idx_vector (i+1, retval.columns ()),
00498 a.index (idx_vector::colon, idx_vector (i, a.columns ())));
00499 return retval;
00500 }
00501
00502 static
00503 FloatMatrix insert_row (const FloatMatrix& a, octave_idx_type i,
00504 const FloatRowVector& x)
00505 {
00506 FloatMatrix retval (a.rows () + 1, a.columns ());
00507 retval.assign (idx_vector (0, i), idx_vector::colon,
00508 a.index (idx_vector (0, i), idx_vector::colon));
00509 retval.assign (idx_vector (i), idx_vector::colon, x);
00510 retval.assign (idx_vector (i+1, retval.rows ()), idx_vector::colon,
00511 a.index (idx_vector (i, a.rows ()), idx_vector::colon));
00512 return retval;
00513 }
00514
00515 static
00516 FloatMatrix delete_col (const FloatMatrix& a, octave_idx_type i)
00517 {
00518 FloatMatrix retval = a;
00519 retval.delete_elements (1, idx_vector (i));
00520 return retval;
00521 }
00522
00523 static
00524 FloatMatrix delete_row (const FloatMatrix& a, octave_idx_type i)
00525 {
00526 FloatMatrix retval = a;
00527 retval.delete_elements (0, idx_vector (i));
00528 return retval;
00529 }
00530
00531 static
00532 FloatMatrix shift_cols (const FloatMatrix& a,
00533 octave_idx_type i, octave_idx_type j)
00534 {
00535 octave_idx_type n = a.columns ();
00536 Array<octave_idx_type> p (n);
00537 for (octave_idx_type k = 0; k < n; k++) p(k) = k;
00538 if (i < j)
00539 {
00540 for (octave_idx_type k = i; k < j; k++) p(k) = k+1;
00541 p(j) = i;
00542 }
00543 else if (j < i)
00544 {
00545 p(j) = i;
00546 for (octave_idx_type k = j+1; k < i+1; k++) p(k) = k-1;
00547 }
00548
00549 return a.index (idx_vector::colon, idx_vector (p));
00550 }
00551
00552 void
00553 FloatQR::insert_col (const FloatColumnVector& u, octave_idx_type j)
00554 {
00555 warn_qrupdate_once ();
00556
00557 octave_idx_type m = q.rows ();
00558 octave_idx_type n = r.columns ();
00559
00560 if (u.length () != m)
00561 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00562 else if (j < 0 || j > n)
00563 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00564 else
00565 {
00566 init (::insert_col (q*r, j, u), get_type ());
00567 }
00568 }
00569
00570 void
00571 FloatQR::insert_col (const FloatMatrix& u, const Array<octave_idx_type>& j)
00572 {
00573 warn_qrupdate_once ();
00574
00575 octave_idx_type m = q.rows ();
00576 octave_idx_type n = r.columns ();
00577
00578 Array<octave_idx_type> jsi;
00579 Array<octave_idx_type> js = j.sort (jsi, 0, ASCENDING);
00580 octave_idx_type nj = js.length ();
00581 bool dups = false;
00582 for (octave_idx_type i = 0; i < nj - 1; i++)
00583 dups = dups && js(i) == js(i+1);
00584
00585 if (dups)
00586 (*current_liboctave_error_handler) ("qrinsert: duplicate index detected");
00587 else if (u.length () != m || u.columns () != nj)
00588 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00589 else if (nj > 0 && (js(0) < 0 || js(nj-1) > n))
00590 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00591 else if (nj > 0)
00592 {
00593 FloatMatrix a = q*r;
00594 for (octave_idx_type i = 0; i < js.length (); i++)
00595 a = ::insert_col (a, js(i), u.column (i));
00596 init (a, get_type ());
00597 }
00598 }
00599
00600 void
00601 FloatQR::delete_col (octave_idx_type j)
00602 {
00603 warn_qrupdate_once ();
00604
00605 octave_idx_type m = q.rows ();
00606 octave_idx_type n = r.columns ();
00607
00608 if (j < 0 || j > n-1)
00609 (*current_liboctave_error_handler) ("qrdelete: index out of range");
00610 else
00611 {
00612 init (::delete_col (q*r, j), get_type ());
00613 }
00614 }
00615
00616 void
00617 FloatQR::delete_col (const Array<octave_idx_type>& j)
00618 {
00619 warn_qrupdate_once ();
00620
00621 octave_idx_type m = q.rows ();
00622 octave_idx_type n = r.columns ();
00623
00624 Array<octave_idx_type> jsi;
00625 Array<octave_idx_type> js = j.sort (jsi, 0, DESCENDING);
00626 octave_idx_type nj = js.length ();
00627 bool dups = false;
00628 for (octave_idx_type i = 0; i < nj - 1; i++)
00629 dups = dups && js(i) == js(i+1);
00630
00631 if (dups)
00632 (*current_liboctave_error_handler) ("qrinsert: duplicate index detected");
00633 else if (nj > 0 && (js(0) > n-1 || js(nj-1) < 0))
00634 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00635 else if (nj > 0)
00636 {
00637 FloatMatrix a = q*r;
00638 for (octave_idx_type i = 0; i < js.length (); i++)
00639 a = ::delete_col (a, js(i));
00640 init (a, get_type ());
00641 }
00642 }
00643
00644 void
00645 FloatQR::insert_row (const FloatRowVector& u, octave_idx_type j)
00646 {
00647 warn_qrupdate_once ();
00648
00649 octave_idx_type m = r.rows ();
00650 octave_idx_type n = r.columns ();
00651
00652 if (! q.is_square () || u.length () != n)
00653 (*current_liboctave_error_handler) ("qrinsert: dimensions mismatch");
00654 else if (j < 0 || j > m)
00655 (*current_liboctave_error_handler) ("qrinsert: index out of range");
00656 else
00657 {
00658 init (::insert_row (q*r, j, u), get_type ());
00659 }
00660 }
00661
00662 void
00663 FloatQR::delete_row (octave_idx_type j)
00664 {
00665 warn_qrupdate_once ();
00666
00667 octave_idx_type m = r.rows ();
00668 octave_idx_type n = r.columns ();
00669
00670 if (! q.is_square ())
00671 (*current_liboctave_error_handler) ("qrdelete: dimensions mismatch");
00672 else if (j < 0 || j > m-1)
00673 (*current_liboctave_error_handler) ("qrdelete: index out of range");
00674 else
00675 {
00676 init (::delete_row (q*r, j), get_type ());
00677 }
00678 }
00679
00680 void
00681 FloatQR::shift_cols (octave_idx_type i, octave_idx_type j)
00682 {
00683 warn_qrupdate_once ();
00684
00685 octave_idx_type m = q.rows ();
00686 octave_idx_type n = r.columns ();
00687
00688 if (i < 0 || i > n-1 || j < 0 || j > n-1)
00689 (*current_liboctave_error_handler) ("qrshift: index out of range");
00690 else
00691 {
00692 init (::shift_cols (q*r, i, j), get_type ());
00693 }
00694 }
00695
00696 #endif