1 /*
  2  *   Copyright (c) 2011, Michael Lehn
  3  *
  4  *   All rights reserved.
  5  *
  6  *   Redistribution and use in source and binary forms, with or without
  7  *   modification, are permitted provided that the following conditions
  8  *   are met:
  9  *
 10  *   1) Redistributions of source code must retain the above copyright
 11  *      notice, this list of conditions and the following disclaimer.
 12  *   2) Redistributions in binary form must reproduce the above copyright
 13  *      notice, this list of conditions and the following disclaimer in
 14  *      the documentation and/or other materials provided with the
 15  *      distribution.
 16  *   3) Neither the name of the FLENS development group nor the names of
 17  *      its contributors may be used to endorse or promote products derived
 18  *      from this software without specific prior written permission.
 19  *
 20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 31  */
 32 
 33 /* Based on
 34  *
 35        SUBROUTINE DPOCON( UPLO, N, A, LDA, ANORM, RCOND, WORK, IWORK,
 36       $                   INFO )
 37  *
 38  *  -- LAPACK routine (version 3.3.1) --
 39  *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
 40  *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
 41  *  -- April 2011                                                      --
 42  */
 43 
 44 #ifndef FLENS_LAPACK_AUX_POCON_TCC
 45 #define FLENS_LAPACK_AUX_POCON_TCC 1
 46 
 47 #include <flens/blas/blas.h>
 48 #include <flens/lapack/lapack.h>
 49 
 50 namespace flens { namespace lapack {
 51 
 52 //== generic lapack implementation =============================================
 53 template <typename MA, typename NORMA, typename RCOND,
 54           typename VWORK, typename VIWORK>
 55 void
 56 pocon_generic(const SyMatrix<MA>  &A,
 57               const NORMA         &normA,
 58               RCOND               &rCond,
 59               DenseVector<VWORK>  &work,
 60               DenseVector<VIWORK> &iwork)
 61 {
 62     using std::abs;
 63 
 64     typedef typename GeMatrix<MA>::ElementType  ElementType;
 65     typedef typename GeMatrix<MA>::IndexType    IndexType;
 66 
 67     const ElementType Zero(0), One(1);
 68 
 69     const Underscore<IndexType>  _;
 70 
 71     const bool       upper = (A.upLo()==Upper);
 72     const IndexType  n     = A.dim();
 73 
 74 //
 75 //  Local Arrays
 76 //
 77     IndexType iSaveData[3] = {000};
 78     DenseVectorView<IndexType>
 79         iSave = typename DenseVectorView<IndexType>::Engine(3, iSaveData, 1);
 80 //
 81 //  Quick return if possible
 82 //
 83     rCond = Zero;
 84     if (n==0) {
 85         rCond = One;
 86         return;
 87     } else if (normA==Zero) {
 88         return;
 89     }
 90 
 91     const ElementType smallNum = lamch<ElementType>(SafeMin);
 92 //
 93 //  Estimate the norm of inv(A).
 94 //
 95     ElementType  normInvA = Zero;
 96     ElementType  scale, scaleL, scaleU;
 97     IndexType    kase = 0;
 98     bool         normIn = false;
 99 
100     auto x     = work(_(1,n));
101     auto v     = work(_(n+1,2*n));
102     auto _work = work(_(2*n+1,3*n));
103 
104     while (true) {
105         lacn2(v, x, iwork, normInvA, kase, iSave);
106 
107         if (kase==0) {
108             break;
109         }
110 
111         if (upper) {
112 //
113 //          Multiply by inv(U**T).
114 //
115             latrs(Trans, normIn, A.triangular(), x, scaleL, _work);
116             normIn = true;
117 //
118 //          Multiply by inv(U).
119 //
120             latrs(NoTrans, normIn, A.triangular(), x, scaleU, _work);
121         } else {
122 //
123 //          Multiply by inv(L).
124 //
125             latrs(NoTrans, normIn, A.triangular(), x, scaleL, _work);
126             normIn = true;
127 //
128 //          Multiply by inv(L**T).
129 //
130             latrs(Trans, normIn, A.triangular(), x, scaleU, _work);
131         }
132 //
133 //      Multiply by 1/SCALE if doing so will not cause overflow.
134 //
135         scale = scaleL * scaleU;
136         if (scale!=One) {
137             IndexType ix = blas::iamax(x);
138             if (scale<abs(work(ix))*smallNum || scale==Zero) {
139                 break;
140             }
141             rscl(scale, x);
142         }
143     }
144 //
145 //  Compute the estimate of the reciprocal condition number.
146 //
147     if (normInvA!=Zero) {
148         rCond = (One/normInvA) /normA;
149     }
150 }
151 
152 //== interface for native lapack ===============================================
153 
154 #ifdef CHECK_CXXLAPACK
155 
156 template <typename MA, typename NORMA, typename RCOND,
157           typename VWORK, typename VIWORK>
158 void
159 pocon_native(const SyMatrix<MA>  &A,
160              const NORMA         &normA,
161              RCOND               &rCond,
162              DenseVector<VWORK>  &work,
163              DenseVector<VIWORK> &iwork)
164 {
165     typedef typename GeMatrix<MA>::ElementType  T;
166 
167     const char       UPLO   = char(A.upLo());
168     const INTEGER    N      = A.dim();
169     const INTEGER    LDA    = A.leadingDimension();
170     const T          ANORM  = normA;
171     T                _RCOND = rCond;
172     INTEGER          INFO;
173 
174     if (IsSame<T,double>::value) {
175         LAPACK_IMPL(dpocon)(&UPLO,
176                             &N,
177                             A.data(),
178                             &LDA,
179                             &ANORM,
180                             &_RCOND,
181                             work.data(),
182                             iwork.data(),
183                             &INFO);
184         rCond = _RCOND;
185     } else {
186         ASSERT(0);
187     }
188     ASSERT(INFO>=0);
189 }
190 
191 #endif // CHECK_CXXLAPACK
192 
193 //== public interface ==========================================================
194 template <typename MA, typename NORMA, typename RCOND,
195           typename VWORK, typename VIWORK>
196 void
197 pocon(const SyMatrix<MA>  &A,
198       const NORMA         &normA,
199       RCOND               &rCond,
200       DenseVector<VWORK>  &work,
201       DenseVector<VIWORK> &iwork)
202 {
203     typedef typename GeMatrix<MA>::IndexType  IndexType;
204 //
205 //  Test the input parameters
206 //
207 #   ifndef NDEBUG
208     ASSERT(A.firstRow()==1);
209     ASSERT(A.firstCol()==1);
210 
211     const IndexType n = A.dim();
212 
213     ASSERT(work.firstIndex()==1);
214     ASSERT(work.length()==3*n);
215 
216     ASSERT(iwork.firstIndex()==1);
217     ASSERT(iwork.length()==n);
218 #   endif
219 
220 #   ifdef CHECK_CXXLAPACK
221 //
222 //  Make copies of output arguments
223 //
224     RCOND                                rCond_org = rCond;
225     typename DenseVector<VWORK>::NoView  work_org  = work;
226     typename DenseVector<VIWORK>::NoView iwork_org = iwork;
227 #   endif
228 
229 //
230 //  Call implementation
231 //
232     pocon_generic(A, normA, rCond, work, iwork);
233 
234 #   ifdef CHECK_CXXLAPACK
235 //
236 //  Compare results
237 //
238     RCOND                                rCond_generic = rCond;
239     typename DenseVector<VWORK>::NoView  work_generic  = work;
240     typename DenseVector<VIWORK>::NoView iwork_generic = iwork;
241 
242     rCond = rCond_org;
243     work  = work_org;
244     iwork = iwork_org;
245 
246     pocon_native(A, normA, rCond, work, iwork);
247 
248     bool failed = false;
249     if (! isIdentical(rCond_generic, rCond, "rCond_generic""rCond")) {
250         std::cerr << "CXXLAPACK: rCond_generic = "
251                   << rCond_generic << std::endl;
252         std::cerr << "F77LAPACK: rCond = " << rCond << std::endl;
253         failed = true;
254     }
255 
256     if (! isIdentical(work_generic, work, "work_generic""work")) {
257         std::cerr << "CXXLAPACK: work_generic = "
258                   << work_generic << std::endl;
259         std::cerr << "F77LAPACK: work = " << work << std::endl;
260         failed = true;
261     }
262 
263     if (! isIdentical(iwork_generic, iwork, "iwork_generic""iwork")) {
264         std::cerr << "CXXLAPACK: iwork_generic = "
265                   << iwork_generic << std::endl;
266         std::cerr << "F77LAPACK: iwork = " << iwork << std::endl;
267         failed = true;
268     }
269 
270     if (failed) {
271         ASSERT(0);
272     } else {
273         // std::cerr << "passed: con" << std::endl;
274     }
275 #   endif
276 }
277 
278 //-- forwarding ----------------------------------------------------------------
279 template <typename MA, typename NORMA, typename RCOND,
280           typename VWORK, typename VIWORK>
281 void
282 pocon(const MA     &A,
283       const NORMA  &normA,
284       RCOND        &&rCond,
285       VWORK        &&work,
286       VIWORK       &&iwork)
287 {
288     CHECKPOINT_ENTER;
289     pocon(A, normA, rCond, work, iwork);
290     CHECKPOINT_LEAVE;
291 }
292 
293 } } // namespace lapack, flens
294 
295 #endif // FLENS_LAPACK_AUX_LACON_TCC