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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #ifndef LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_NUM_MATRIX_INL
00047
00048 #include "num_common.h"
00049 #include "matrix.h"
00050 #include "impl/matrix_solve.h"
00051 #include "../meta/meta_assert.h"
00052
00053 #define LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(a, b)\
00054 LASS_UTIL_IMPL_MAKE_ENFORCER(\
00055 ::lass::util::impl::TruePredicate,\
00056 ::lass::util::impl::DefaultRaiser,\
00057 (a).rows() == (b).rows() && (a).columns() == (b).columns(),\
00058 int(0), \
00059 "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have different dimensions in '" LASS_HERE "'.")
00060
00061 #define LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(a, b)\
00062 LASS_UTIL_IMPL_MAKE_ENFORCER(\
00063 ::lass::util::impl::EqualPredicate,\
00064 ::lass::util::impl::DefaultRaiser,\
00065 (a).columns(),\
00066 (b).rows(),\
00067 "Matrices '" LASS_STRINGIFY(a) "' and '" LASS_STRINGIFY(b) "' have no matching dimensions for operation at '" LASS_HERE "'.")
00068
00069 namespace lass
00070 {
00071 namespace num
00072 {
00073
00074
00075
00076
00077
00078
00079
00080
00081 template <typename T, typename S>
00082 Matrix<T, S>::Matrix():
00083 storage_()
00084 {
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 template <typename T, typename S>
00104 Matrix<T, S>::Matrix(TSize iRows, TSize iColumns):
00105 storage_(iRows, iColumns)
00106 {
00107 }
00108
00109
00110
00111 template <typename T, typename S>
00112 Matrix<T, S>::Matrix(const TStorage& iStorage):
00113 storage_(iStorage)
00114 {
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 template <typename T, typename S>
00130 template <typename T2, typename S2>
00131 Matrix<T, S>::Matrix(const Matrix<T2, S2>& iOther):
00132 storage_(iOther.rows(), iOther.columns())
00133 {
00134 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00135
00136 const S2& other = iOther.storage();
00137 const TSize m = rows();
00138 const TSize n = columns();
00139 for (TSize i = 0; i < m; ++i)
00140 {
00141 for (TSize j = 0; j < n; ++j)
00142 {
00143 storage_(i, j) = other(i, j);
00144 }
00145 }
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 template <typename T, typename S>
00161 template <typename T2, typename S2>
00162 Matrix<T, S>& Matrix<T, S>::operator=(const Matrix<T2, S2>& iOther)
00163 {
00164 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00165
00166 const S2& other = iOther.storage();
00167 const TSize m = other.rows();
00168 const TSize n = other.columns();
00169 storage_.resize(m, n);
00170 for (TSize i = 0; i < m; ++i)
00171 {
00172 for (TSize j = 0; j < n; ++j)
00173 {
00174 storage_(i, j) = other(i, j);
00175 }
00176 }
00177 return *this;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 template <typename T, typename S> inline
00193 const typename Matrix<T, S>::TSize
00194 Matrix<T, S>::rows() const
00195 {
00196 return storage_.rows();
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 template <typename T, typename S> inline
00212 const typename Matrix<T, S>::TSize
00213 Matrix<T, S>::columns() const
00214 {
00215 return storage_.columns();
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225 template <typename T, typename S> inline
00226 const typename Matrix<T, S>::TValue
00227 Matrix<T, S>::operator()(TSize iRow, TSize iColumn) const
00228 {
00229 LASS_ASSERT(iRow < rows() && iColumn < columns());
00230 return storage_(iRow, iColumn);
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 template <typename T, typename S> inline
00243 typename util::CallTraits<T>::TReference
00244 Matrix<T, S>::operator()(TSize iRow, TSize iColumn)
00245 {
00246 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00247 LASS_ASSERT(iRow < rows() && iColumn < columns());
00248 return storage_(iRow, iColumn);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257 template <typename T, typename S> inline
00258 const typename Matrix<T, S>::TValue
00259 Matrix<T, S>::at(signed iRow, signed iColumn) const
00260 {
00261 return storage_(mod(iRow, rows()), mod(iColumn, columns()));
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 template <typename T, typename S> inline
00273 typename util::CallTraits<T>::TReference
00274 Matrix<T, S>::at(signed iRow, signed iColumn)
00275 {
00276 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00277 return storage_(mod(iRow, rows()), mod(iColumn, columns()));
00278 }
00279
00280
00281
00282
00283
00284
00285 template <typename T, typename S> inline
00286 typename Matrix<T, S>::ConstRow
00287 Matrix<T, S>::row(signed iRow) const
00288 {
00289 return ConstRow(*this, static_cast<size_t>(mod(iRow, static_cast<int>(rows()))));
00290 }
00291
00292
00293
00294
00295
00296
00297
00298 template <typename T, typename S> inline
00299 typename Matrix<T, S>::Row
00300 Matrix<T, S>::row(signed iRow)
00301 {
00302 return Row(*this, static_cast<size_t>(mod(iRow, static_cast<int>(rows()))));
00303 }
00304
00305
00306
00307
00308
00309
00310 template <typename T, typename S> inline
00311 typename Matrix<T, S>::ConstColumn
00312 Matrix<T, S>::column(signed iColumn) const
00313 {
00314 return ConstColumn(*this, static_cast<size_t>(mod(iColumn, static_cast<int>(columns()))));
00315 }
00316
00317
00318
00319
00320
00321
00322
00323 template <typename T, typename S> inline
00324 typename Matrix<T, S>::Column
00325 Matrix<T, S>::column(signed iColumn)
00326 {
00327 return Column(*this, static_cast<size_t>(mod(iColumn, static_cast<int>(columns()))));
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 template <typename T, typename S> inline
00341 const Matrix<T, S>& Matrix<T, S>::operator+() const
00342 {
00343 return *this;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 template <typename T, typename S>
00358 const Matrix<T, impl::MNeg<T, S> >
00359 Matrix<T, S>::operator-() const
00360 {
00361 typedef impl::MNeg<T, S> TExpression;
00362 return Matrix<T, TExpression>(TExpression(storage_));
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 template <typename T, typename S>
00385 template <typename S2>
00386 Matrix<T, S>& Matrix<T, S>::operator+=(const Matrix<T, S2>& iB)
00387 {
00388 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00389 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, iB);
00390 const S2& other = iB.storage();
00391 const TSize m = rows();
00392 const TSize n = columns();
00393 for (TSize i = 0; i < m; ++i)
00394 {
00395 for (TSize j = 0; j < n; ++j)
00396 {
00397 storage_(i, j) += other(i, j);
00398 }
00399 }
00400 return *this;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 template <typename T, typename S>
00418 template <typename S2>
00419 Matrix<T, S>& Matrix<T, S>::operator-=(const Matrix<T, S2>& iB)
00420 {
00421 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00422 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(*this, iB);
00423 const S2& other = iB.storage();
00424 const TSize m = rows();
00425 const TSize n = columns();
00426 for (TSize i = 0; i < m; ++i)
00427 {
00428 for (TSize j = 0; j < n; ++j)
00429 {
00430 storage_(i, j) -= other(i, j);
00431 }
00432 }
00433 return *this;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 template <typename T, typename S>
00446 Matrix<T, S>& Matrix<T, S>::operator*=(TParam iB)
00447 {
00448 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00449 const TSize size = storage_.rows() * storage_.columns();
00450 const TSize m = rows();
00451 const TSize n = columns();
00452 for (TSize i = 0; i < m; ++i)
00453 {
00454 for (TSize j = 0; j < n; ++j)
00455 {
00456 storage_(i, j) *= iB;
00457 }
00458 }
00459 return *this;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468 template <typename T, typename S>
00469 Matrix<T, S>& Matrix<T, S>::operator /=(TParam iB)
00470 {
00471 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00472 const TSize m = rows();
00473 const TSize n = columns();
00474 for (TSize i = 0; i < m; ++i)
00475 {
00476 for (TSize j = 0; j < n; ++j)
00477 {
00478 storage_(i, j) /= iB;
00479 }
00480 }
00481 return *this;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 template <typename T, typename S>
00495 void Matrix<T, S>::setZero(TSize iRows, TSize iColumns)
00496 {
00497 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00498 storage_.resize(iRows, iColumns);
00499 for (TSize i = 0; i < iRows; ++i)
00500 {
00501 for (TSize j = 0; j < iColumns; ++j)
00502 {
00503 storage_(i, j) = TNumTraits::zero;
00504 }
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 template <typename T, typename S>
00519 void Matrix<T, S>::setIdentity(TSize iSize)
00520 {
00521 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00522 storage_.resize(iSize, iSize);
00523 for (TSize i = 0; i < iSize; ++i)
00524 {
00525 for (TSize j = 0; j < iSize; ++j)
00526 {
00527 storage_(i, j) = i == j ? TNumTraits::one : TNumTraits::zero;
00528 }
00529 }
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 template <typename T, typename S>
00543 bool Matrix<T, S>::isEmpty() const
00544 {
00545 return storage_.rows() == 0 || storage_.columns() == 0;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561 template <typename T, typename S>
00562 bool Matrix<T, S>::isZero() const
00563 {
00564 const TSize m = rows();
00565 const TSize n = columns();
00566 for (TSize i = 0; i < m; ++i)
00567 {
00568 for (TSize j = 0; j < n; ++j)
00569 {
00570 if (storage_(i, j) != TNumTraits::zero)
00571 {
00572 return false;
00573 }
00574 }
00575 }
00576 return true;
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 template <typename T, typename S>
00597 bool Matrix<T, S>::isIdentity() const
00598 {
00599 if (!isSquare())
00600 {
00601 return false;
00602 }
00603 const TSize m = rows();
00604 const TSize n = columns();
00605 for (TSize i = 0; i < m; ++i)
00606 {
00607 for (TSize j = 0; j < n; ++j)
00608 {
00609 if (storage_(i, j) != ((i == j) ? TNumTraits::one : TNumTraits::zero))
00610 {
00611 return false;
00612 }
00613 }
00614 }
00615 return true;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 template <typename T, typename S>
00633 bool Matrix<T, S>::isDiagonal() const
00634 {
00635 if (!isSquare())
00636 {
00637 return false;
00638 }
00639 const TSize m = rows();
00640 const TSize n = columns();
00641 for (TSize i = 0; i < m; ++i)
00642 {
00643 for (TSize j = 0; j < n; ++j)
00644 {
00645 if (i != j && storage_(i, j) != TNumTraits::zero)
00646 {
00647 return false;
00648 }
00649 }
00650 }
00651 return true;
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661 template <typename T, typename S>
00662 bool Matrix<T, S>::isSquare() const
00663 {
00664 return storage_.rows() == storage_.columns();
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674 template <typename T, typename S>
00675 const Matrix<T, impl::MTrans<T, S> >
00676 Matrix<T, S>::transpose() const
00677 {
00678 typedef impl::MTrans<T, S> TExpression;
00679 return Matrix<T, TExpression>(TExpression(storage_));
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 template <typename T, typename S>
00695 bool Matrix<T, S>::invert()
00696 {
00697 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00698 LASS_ENFORCE(isSquare());
00699
00700 const TSize n = rows();
00701 Matrix<T> lu(*this);
00702 std::vector<size_t> index(n);
00703 int d;
00704
00705 if (!impl::ludecomp(lu.storage().rowMajor(), index.begin(), n, d))
00706 {
00707 setZero(0, 0);
00708 return false;
00709 }
00710
00711 setIdentity(n);
00712 for (TSize i = 0; i < n; ++i)
00713 {
00714 impl::lusolve(lu.storage().rowMajor(), index.begin(), column(i), n);
00715 }
00716
00717 return true;
00718 }
00719
00720
00721
00722 template <typename T, typename S> inline
00723 const typename Matrix<T, S>::TStorage&
00724 Matrix<T, S>::storage() const
00725 {
00726 return storage_;
00727 }
00728
00729
00730
00731 template <typename T, typename S> inline
00732 typename Matrix<T, S>::TStorage&
00733 Matrix<T, S>::storage()
00734 {
00735 return storage_;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 template <typename T, typename S> inline
00751 void Matrix<T, S>::swap(Matrix<T, S>& iOther)
00752 {
00753 LASS_META_ASSERT(TStorage::lvalue, this_is_not_an_lvalue);
00754 storage_.swap(iOther.storage_);
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 template <typename T, typename S1, typename S2>
00775 bool operator==(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00776 {
00777 if (iA.rows() != iB.rows() || iA.columns() != iB.columns())
00778 {
00779 return false;
00780 }
00781 typedef typename Matrix<T, S1>::TSize TSize;
00782 const TSize m = iA.rows();
00783 const TSize n = iA.columns();
00784 for (TSize i = 0; i < m; ++i)
00785 {
00786 for (TSize j = 0; j < n; ++j)
00787 {
00788 if (iA(i, j) != iB(i, j))
00789 {
00790 return false;
00791 }
00792 }
00793 }
00794 return true;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804 template <typename T, typename S1, typename S2>
00805 bool operator!=(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00806 {
00807 return !(iA == iB);
00808 }
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818 template <typename T, typename S1, typename S2>
00819 const Matrix<T, impl::MAdd<T, S1, S2> >
00820 operator+(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00821 {
00822 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(iA, iB);
00823 typedef impl::MAdd<T, S1, S2> TExpression;
00824 return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835 template <typename T, typename S1, typename S2>
00836 const Matrix<T, impl::MSub<T, S1, S2> >
00837 operator-(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00838 {
00839 LASS_NUM_MATRIX_ENFORCE_EQUAL_DIMENSION(iA, iB);
00840 typedef impl::MSub<T, S1, S2> TExpression;
00841 return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00842 }
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863 template <typename T, typename S1, typename S2>
00864 const Matrix<T, impl::MProd<T, S1, S2> >
00865 operator*(const Matrix<T, S1>& iA, const Matrix<T, S2>& iB)
00866 {
00867 LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(iA, iB);
00868 typedef impl::MProd<T, S1, S2> TExpression;
00869 return Matrix<T, TExpression>(TExpression(iA.storage(), iB.storage()));
00870 }
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880 template <typename T, typename S>
00881 const Matrix<T, impl::MAdd<T, impl::MScalar<T>, S> >
00882 operator+(const T& iA, const Matrix<T, S>& iB)
00883 {
00884 typedef impl::MAdd<T, impl::MScalar<T>, S> TExpression;
00885 return Matrix<T, TExpression>(TExpression(
00886 impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00887 }
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 template <typename T, typename S>
00898 const Matrix<T, impl::MSub<T, impl::MScalar<T>, S> >
00899 operator-(const T& iA, const Matrix<T, S>& iB)
00900 {
00901 typedef impl::MSub<T, impl::MScalar<T>, S> TExpression;
00902 return Matrix<T, TExpression>(TExpression(
00903 impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00904 }
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 template <typename T, typename S>
00915 const Matrix<T, impl::MMul<T, impl::MScalar<T>, S> >
00916 operator*(const T& iA, const Matrix<T, S>& iB)
00917 {
00918 typedef impl::MMul<T, impl::MScalar<T>, S> TExpression;
00919 return Matrix<T, TExpression>(TExpression(
00920 impl::MScalar<T>(iA, iB.rows(), iB.cols()), iB.storage()));
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 template <typename T, typename S>
00932 const Matrix<T, impl::MAdd<T, S, impl::MScalar<T> > >
00933 operator+(const Matrix<T, S>& iA, const T& iB)
00934 {
00935 typedef impl::MAdd<T, S, impl::MScalar<T> > TExpression;
00936 return Matrix<T, TExpression>(TExpression(
00937 iA.storage(), impl::MScalar<T>(iB, iA.rows(), iA.cols())));
00938 }
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 template <typename T, typename S>
00949 const Matrix<T, impl::MAdd<T, S, impl::MScalar<T> > >
00950 operator-(const Matrix<T, S>& iA, const T& iB)
00951 {
00952 typedef impl::MSub<T, S, impl::MScalar<T> > TExpression;
00953 return Matrix<T, TExpression>(TExpression(
00954 iA.storage(), impl::MScalar<T>(-iB, iA.rows(), iA.cols())));
00955 }
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965 template <typename T, typename S>
00966 const Matrix<T, impl::MMul<T, S, impl::MScalar<T> > >
00967 operator*(const Matrix<T, S>& iA, const T& iB)
00968 {
00969 typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
00970 return Matrix<T, TExpression>(TExpression(
00971 iA.storage(), impl::MScalar<T>(iB, iA.rows(), iA.cols())));
00972 }
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 template <typename T, typename S>
00983 const Matrix<T, impl::MMul<T, S, impl::MScalar<T> > >
00984 operator/(const Matrix<T, S>& iA, const T& iB)
00985 {
00986 typedef impl::MMul<T, S, impl::MScalar<T> > TExpression;
00987 return Matrix<T, TExpression>(TExpression(
00988 iA.storage(), impl::MScalar<T>(Matrix<T, S>::TNumTraits::one / iB, iA.rows(), iA.cols())));
00989 }
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 template <typename T, typename S, typename S2>
01003 bool solve(const Matrix<T, S>& iA, Matrix<T, S2>& ioB)
01004 {
01005 LASS_META_ASSERT(S2::lvalue, ioB_isnt_an_lvalue);
01006 LASS_ENFORCE(iA.isSquare());
01007 LASS_NUM_MATRIX_ENFORCE_ADJACENT_DIMENSION(iA, ioB);
01008
01009 size_t n = iA.rows();
01010 Matrix<T> lu(iA);
01011 std::vector<size_t> index(n);
01012 int d;
01013
01014 if (!impl::ludecomp<T>(lu.storage().rowMajor(), index.begin(), n, d))
01015 {
01016 ioB.setZero(0, 0);
01017 return false;
01018 }
01019
01020 for (size_t i = 0; i < ioB.columns(); ++i)
01021 {
01022 LASS_ASSERT(static_cast<int>(i) >= 0);
01023 impl::lusolve<T>(lu.storage().rowMajor(), index.begin(), ioB.column(static_cast<int>(i)), n);
01024 }
01025 return true;
01026 }
01027
01028
01029
01030
01031
01032 template <typename T, typename S, typename Char, typename Traits>
01033 std::basic_ostream<Char, Traits>&
01034 operator<<(std::basic_ostream<Char, Traits>& oOStream, const Matrix<T, S>& iB)
01035 {
01036 typedef typename Matrix<T, S>::TSize TSize;
01037 const TSize m = iB.rows();
01038 const TSize n = iB.columns();
01039
01040 LASS_ENFORCE_STREAM(oOStream) << "(";
01041 for (TSize i = 0; i < m; ++i)
01042 {
01043 if (i != 0)
01044 {
01045 LASS_ENFORCE_STREAM(oOStream) << ", ";
01046 }
01047 LASS_ENFORCE_STREAM(oOStream) << "(";
01048 if (n > 0)
01049 {
01050 LASS_ENFORCE_STREAM(oOStream) << iB(i, 0);
01051 }
01052 for (TSize j = 1; j < n; ++j)
01053 {
01054 LASS_ENFORCE_STREAM(oOStream) << ", " << iB(i, j);
01055 }
01056 LASS_ENFORCE_STREAM(oOStream) << ")";
01057 }
01058 LASS_ENFORCE_STREAM(oOStream) << ")";
01059 return oOStream;
01060 }
01061
01062
01063
01064 }
01065
01066 }
01067
01068 #endif
01069
01070