Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

robot/control/kinematics/IKORFullSpaceSolver.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008 
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013 
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   $Id: IKORFullSpaceSolver.cpp 1080 2004-07-28 19:51:26Z jungd $
00019   $Revision: 1.20 $
00020   $Date: 2004-07-28 15:51:26 -0400 (Wed, 28 Jul 2004) $
00021   $Author: jungd $
00022 
00023 ****************************************************************************/
00024 
00025 #include <robot/control/kinematics/IKORFullSpaceSolver>
00026 
00027 using robot::control::kinematics::IKORFullSpaceSolver;
00028 
00029 //
00030 // This file started as a 'transliteration' of the Full-Space-Parameterization
00031 //  (FSP) solution code from the IKORv2.0 FSP.c file
00032 //
00033 //
00034 // WARNING: This implementation isn't fully debugged and may not work
00035 //  correctly.  Use FullSpaceSolver2.
00036 //
00037 
00038 using base::IVector;
00039 using base::zeroIVector;
00040 using base::equals;
00041 
00042 const Real small = 5.0e-05; // (=def.SMALL)
00043 
00044 
00045 IKORFullSpaceSolver::IKORFullSpaceSolver()
00046   : status(Unknown)
00047 {
00048   Logln("Warning: This implementation doesn't work correctly, consider using FullSpaceSolver2 instead.");
00049 }
00050 
00051 
00052 // debugging convenience
00053 #define dump_A() { \
00054                 printf("A=\n"); \
00055                 for(Int r=0; r<Nred; r++) { \
00056                   for(Int c=0; c<Mred; c++) { \
00057                     printf("%9.6f ",A(slRow[r], slCol[c])); \
00058                   } \
00059                   printf("\n"); \
00060                 } \
00061                 printf("\n"); \
00062               }
00063 
00064 #define dump_Acol(c) { \
00065                 printf("A[:,%d(%d)]=",(c),slCol[c]); \
00066                 for(Int r=0; r<Nred; r++) { \
00067                   printf("%9.6f ",A(slRow[r], slCol[c])); \
00068                 } \
00069                 printf("\n"); \
00070               }
00071 
00072 #define dump_btemp() { \
00073                        printf("btemp=["); \
00074                        for(Int r=0; r<Nred; r++) { \
00075                          printf("%9.6f",btemp[slRow[r]]); \
00076                          if (r!=Nred-1) printf(","); \
00077                        } \
00078                        printf("]\n"); \
00079                      }
00080 
00081 
00082 base::Matrix IKORFullSpaceSolver::solve(const Matrix& A_in, const Vector& b_in,
00083                                         array<Int>& dependentRowsEliminated)
00084 {
00085   // Note:
00086   //  Variables that correspond to variables from the original IKORv2.0
00087   //  code are marked with (=<correspinding-name>); (=id) if the
00088   //  names are identical.
00089 
00090   //
00091   // Initialization/Setup
00092   //
00093 
00094   // make a local copy so we can modify
00095   Matrix A(A_in); // (=Aorig)
00096   Vector b(b_in); // (=borig)
00097 Debugln(Tmp,"\nSOLVE: A=\n" << A << "b=" << b);
00098   const Int N = A.size1(); // (=global N)
00099   const Int M = A.size2(); // (=global M)
00100 
00101   Assert(b.size()==N);
00102 
00103   Matrix Ared(N,M); // reduced A (=id)
00104   Vector bred(N);   // reduced b (=id)
00105 
00106   // array that corresponds to the values in the first soln:
00107   //  !0 ==> non-zero value, 0 ==> zero value
00108   IVector firstOK(N); // (=id)
00109   firstOK = zeroIVector(N);
00110 
00111   IVector rowElim(N); // indicates if a row of A has been eliminated (and why - see consts) (=RowElim)
00112   IVector colElim(M); // indicated if a column of A has been eliminated (and why - see consts) (=ColElim)
00113   rowElim = zeroIVector(N); // init to NotEleminated==0
00114   colElim = zeroIVector(M);
00115 
00116   systemComplete = false;
00117 
00118   //
00119   // Solve
00120   //
00121 
00122   bool bIsZero = equals(b,zeroVector(N),small); // is b completely zero? (=bcheck)
00123 
00124 
00125 
00126   //
00127   // Reduce A
00128   Int Nred = N; // reduced N (=FSP_data.Nred)
00129   Int Mred = M; // reduced M (=FSP_data.Mred)
00130   Matrix specialg(M-1,M); // null vectors created by specialCase1 (=Specialg)
00131   Int numSpecialgs; // number of g vectors created by specialCase1 (=NumSpg)
00132 
00133   // Eliminate all the nonredundancies from the A and B
00134   reduceA(A, Ared, b, bred, M, N, Mred, Nred, colElim, rowElim, specialg, numSpecialgs);
00135 
00136   Matrix g(Mred-Nred+1+numSpecialgs, M); // array of gi solution vectors (=id)
00137   g = zeroMatrix(g.size1(), g.size2()); // init to all 0s
00138 
00139   // Debugging output
00140   Debugln(FSP,"\n\n-------------- FSP ---------------");
00141   Debugcln(FSP," Ared:\n" << Ared);
00142   Debugcln(FSP," bred: " << bred);
00143   Debugcln(FSP,"M:" << M << " Mred:" << Mred << " N:" << N << " Nred:" << Nred);
00144   Debugcln(FSP,"rowElim:" << rowElim);
00145   Debugcln(FSP,"colElim:" << colElim);
00146   //Debugcln(FSP,"xElim");
00147 
00148 
00149   Int nullity;  // dim of null-space  (=id)
00150   Real K2;      // condition number   (=id)
00151 
00152   bIsZero = equals(Vector(vectorRange(bred,Range(0,Nred))),zeroVector(Nred),small); // is bred completely zero? (=bcheck)
00153   if (bIsZero) {
00154     Debugcln(FSP,"A is completely restricted");
00155     Matrix Asub(Nred, Mred); // submatrix of Ared (=id)
00156     Asub = matrixRange(Ared,Range(0,Nred), Range(0,Mred) );
00157 Debugcln(Tmp,"Nred=" << Nred << " Mred=" << Mred << " Asub=\n" << Asub);
00158 
00159     Matrix n( Math::nullSpace(Asub, nullity, K2) ); // null-space vectors (=id)
00160 
00161     // set solution vectors for a completely restricted system (cols of g from rows of n)
00162     const Int Span2 = g.size1()-numSpecialgs; // (=SPAN2)
00163     for(Int gc=0; gc < Mred; gc++) {
00164       for(Int gr=0; gr < Span2-1; gr++)
00165         g(gr,gc) = n(gc,gr);
00166       g(Nred,gc) = 0;
00167     }
00168 
00169     systemComplete=true;
00170     status = Restricted;
00171 
00172   }
00173   else { // !bIsZero
00174 
00175     if (Nred != N) {
00176       Debugcln(FSP,"A is restricted for " << Nred << " out of " << N << " vector components");
00177     }
00178 
00179     const Int Span2 = g.size1()-numSpecialgs; // (=SPAN2)
00180     Matrix block(Span2, Nred); // location of blocked columns for each soln (=id)
00181     block = zeroMatrix(Span2,Nred);
00182     Matrix Asqr(Nred, Nred); // (=id)
00183 
00184     Int nextToFind = 0; // vector being searched for (=NextToFind)
00185 
00186     //
00187     // find first block pattern
00188     //
00189 
00190     // initialize the blocking positions for the first solution vector
00191     for(Int c=0; c<Nred; c++) block(0,c) = c;
00192 Debugcln(DJ,"initialized block=" << matrixRow(block,0) << " Mred=" << Mred << " Nred=" << Nred);
00193     // The IKORv2.0 code didn't test for k<Nred here, which caused tests for block(0,k) with k out of range
00194     //  - which probably (by luck) didn't == i, hence didn't cause any further writing into Asqr
00195     for(Int k=0, i=0; (i<Mred) && (k<Nred); i++) {
00196       if (block(0,k) == i) {
00197         for(Int r=0; r<Nred; r++)
00198           Asqr(r,k) = Ared(r,i);
00199         k++;
00200       }
00201     }
00202     Matrix n( Math::nullSpace(Asqr, nullity, K2) ); // null-space vectors (=id)
00203 
00204     //Debugcln(FSP,"block:\n" << block << "Asqr:\n" << Asqr);
00205     //Debugcln(FSP,"n:\n" << n);
00206     //Debugcln(FSP,"nullity=" << nullity << " K2=" << K2);
00207 
00208 
00209     //Debugcln(FSP,"block:\n" << block << "Asqr:\n" << Asqr);
00210     //Debugcln(FSP,"n:\n" << n);
00211     // loop until an acceptable well-conditioned first solution found
00212     while ( (nullity!=0) && (block(0,0) < N) ) {
00213 
00214       SInt pos = SInt(Nred)-1;
00215       Assert(pos < SInt(block.size2()) );
00216       while (block(0,pos) == Span2-1+pos) { pos--; Assert(pos>0); }
00217       block(0,pos)++;
00218       Int move=pos+1;
00219       while (move < Nred) {
00220         block(0,move) = block(0,move-1)+1;
00221         move++;
00222       }
00223 
00224       // The IKORv2.0 code didn't test for k<Nred here, which caused tests for block(0,k) with k out of range
00225       //  - which probably (by luck) didn't == i, hence didn't cause any further writing into Asqr
00226       for(Int k=0, i=0; (i<Mred) && (k<Nred); i++) {
00227         if (block(0,k) == i) {
00228           for(Int r=0; r<Nred; r++)
00229             Asqr(r,k) = Ared(r,i);
00230           k++;
00231         }
00232       }
00233 Debugcln(FSP,"trying initial block=" << matrixRow(block,0) );
00234       if (block(0,0) <= Nred)
00235         n.reset( Math::nullSpace(Asqr, nullity, K2) ); // calc n, nullity, K2
00236 
00237       //Debugcln(FSP,"block:\n" << block << "Asqr:\n" << Asqr);
00238       //Debugcln(FSP,"nullity=" << nullity << " K2=" << K2);
00239     }
00240 Debugcln(DJ,"found suitable first block=" << matrixRow(block,0) );
00241 
00242 
00243 
00244 
00245     IVector tackon = zeroIVector(Mred-Nred); // columns are indexed for effic, soln finding (=Tackon)  //!!! changed tackon[] to Mred-Nred from M-N
00246     for(Int k=0, I=0, i=0; i<Mred; i++) {
00247       bool colIncluded = false;
00248       if (k<Nred)
00249         if (block(0,k)==i)
00250           colIncluded=true;
00251       if (!colIncluded) { // not in block, add it to tackon
00252         tackon[I]=i;
00253         I++;
00254       }
00255       else
00256         k++; // otherwise skip to next
00257     }
00258 Debugcln(DJ,"tackon=" << tackon);
00259 
00260     // calculate a new g vector for a given square blocking pattern
00261     Vector gRow(matrixRow(g,nextToFind)); // select out rows[nextToFind]
00262     Vector blockRow(matrixRow(block,nextToFind));
00263     blockColFindX(gRow, tackon, blockRow, bred, Ared, Mred, Nred);
00264     matrixRow(g,nextToFind) = gRow;       // copy them back
00265     matrixRow(block,nextToFind) = blockRow;
00266 
00267 
00268     Debugcln(FSP,"first solution\nblock:\n" << matrixRow(block,0) << "\nAsqr:\n" << Asqr);
00269     if (Nred==Mred)
00270       systemComplete=true;
00271     else
00272       restOfSoln(M, N, Mred, Nred, nextToFind, block, g, bred, Ared, tackon, firstOK);
00273 
00274     Debugcln(FSP,"block:\n" << block << "solutions:\n" << g);
00275 
00276   } // end else !bIsZero
00277 
00278 
00279   // check if the eliminated b elements in bred can be
00280   //  produced from the g vectors and the reduced A matrix
00281   //   i.e. check that b is in the range of A
00282   bool binRange=false; // is b in range of A? (=binrange)
00283   if (!systemComplete) {
00284     Debugln(FSP,"System did not complete.  Non-fatal; continuing.");
00285   }
00286   else
00287     binRange = checkRange(A,b,g,rowElim);
00288 
00289 
00290   // check that the original b was not all zeros (special case)
00291   String reason;
00292   Assert(b.size()==N);
00293   bIsZero = equals(b,zeroVector(N),small);
00294 
00295   if (binRange && (!bIsZero) && (status != Restricted)) {
00296 
00297     rebuildgs(g, M, N, Mred, Nred, colElim, rowElim, specialg, numSpecialgs); // modifies g
00298     status = Complete;
00299 
00300     // the original IKOR2.0 code generated the beta constraints for rows eleminated due
00301     //  to dependency here.  That has been seperated out into the InverseKinematicsSolver
00302     //  (e.g. IKOR)
00303   }
00304   else {
00305     if (status != Restricted) {
00306       status = NotComplete;
00307       if (!bIsZero)
00308         reason += ": b is not in the range of A";
00309       else
00310         reason += ": special case - b is the zero vector; constrained optimization must be used";
00311     }
00312   }
00313 
00314 
00315   if (status == NotComplete)
00316     throw std::invalid_argument(Exception(String("FSP method unable to complete solution")+reason));
00317 
00318   // return the indices of rows that were eliminated due to dependency
00319   dependentRowsEliminated.clear();
00320   for(Int r=0; r<N; r++)
00321     if (rowElim[r] == RowEliminated_Dependent)
00322       dependentRowsEliminated.push_back(r);
00323 
00324   // return a M x span matrix of column vectors. (transpose it)
00325   Matrix gs(M,Mred-Nred+1+numSpecialgs);
00326   for(Int r=0; r<gs.size1(); r++)
00327     for(Int c=0; c<gs.size2(); c++)
00328       gs(r,c) = g(c,r);
00329 
00330   return gs;
00331 }
00332 
00333 
00334 
00335 
00336 bool IKORFullSpaceSolver::dependency(const Matrix& A, const base::IVector& slRow, Int Nred, Int first, Int second) const
00337 {
00338   bool stop=false;
00339   Real devidor = 0;
00340   Int i=0;
00341   while ((i<Nred) && !stop) {
00342     if ( isSmall(A(slRow[i], first)) && isSmall(A(slRow[i], second)) )
00343       i++;
00344     else if ( (!isSmall(A(slRow[i], first))) && (!isSmall(A(slRow[i], second))) ) {
00345       if (devidor==0) {
00346         devidor = ( A(slRow[i],first) / A(slRow[i],second) );
00347         i++;
00348       }
00349       else if (isSmall(A(slRow[i], first) - (A(slRow[i],second)*devidor)))
00350         i++;
00351       else
00352         stop = true;
00353     }
00354     else
00355       stop = true;
00356 
00357   } // end while
00358 
00359   return !stop;
00360 }
00361 
00362 
00363 
00364 bool IKORFullSpaceSolver::checkRange(const Matrix& A, const Vector& b, const Matrix& g, const base::IVector& rowElim)
00365 {
00366   for(Int i=0; i<A.size1(); i++) {
00367     if (rowElim[i] == RowEliminated_Dependent) {
00368       for(Int j=0; j<g.size1();j++) {
00369         Real checkValue = 0.0;
00370         for(Int k=0; k<A.size2();k++) checkValue += A(i,k) * g(j,k);
00371         if ( Math::abs(b[i] - checkValue) > 0.01) return false;
00372       }
00373     }
00374   }
00375   return true;
00376 }
00377 
00378 
00379 
00380 
00381 
00382 
00383 void IKORFullSpaceSolver::reduceA(const Matrix& A, Matrix& Ared,
00384                                   const Vector& b, Vector& bred,
00385                                   const Int M, const Int N,
00386                                   Int& Mred, Int& Nred,
00387                                   IVector& colElim, IVector& rowElim,
00388                                   Matrix& specialg, Int& numSpecialgs)
00389 {
00390   // initialize
00391   Nred = N; // number of rows in the reduced A
00392   Mred = M; // number of columns in the reduced A
00393   numSpecialgs = 0;
00394   rowElim = zeroIVector(N);
00395   colElim = zeroIVector(M);
00396 
00397   IVector slRow(N); // Still-Left-Row    - stores remaining non eliminated rows in sequence (=SLRow)
00398   IVector slCol(M); // Still-Left-Column - stores remaining non eliminated columns in sequence (=SLCol)
00399   for(Int i=0; i<N; i++) slRow[i]=i;
00400   for(Int i=0; i<M; i++) slCol[i]=i;
00401 
00402   Vector xElim(M); // Contains strict values for reduced dq's (=Xelim)
00403   xElim = zeroVector(M);
00404 
00405   Vector btemp(b);
00406 
00407   bool doneRed = false; // Keeps track if reduction is done, loop has executed without any reduction (=DoneRed)
00408 
00409   // start reduction
00410   while (!doneRed) {
00411 
00412     doneRed = true;
00413     bool stillChecking = true; // flag to mark when all nonredundancies are gone (=StillChecking)
00414 
00415     // Check each row for the number of nonzero elements.  If only one
00416     // element is nonzero, solve for the joint space motion, and
00417     // modify the b vector so that the appropriate row and column
00418     // can be eliminated from the A.  After a row is eliminated
00419     // the remaining A must be rechecked for any new restrictions
00420 
00421     while (stillChecking) {
00422 
00423       Int lastNred = Nred;
00424       for(Int i=0; i<Nred; i++) {
00425         SInt j=-1;
00426         Int restriction = 0; // num of joints which contrib to a work space d.o.f.!!! (=Restriction)
00427 
00428         // check for non-zero row elements
00429         Int nonZeroCol=0; // Column which has nonzero element for given row (=NonZeroCol)
00430         while ( (j < SInt(Mred-1)) && (restriction < 2) ) {
00431           j++;
00432           if (!isSmall(A(slRow[i],slCol[j])) ) {
00433             restriction++;
00434             nonZeroCol = j;
00435           }
00436         }
00437 
00438         // if a row only has one nonzero element, eliminate it from the A
00439         if ( (restriction==1) && (rowElim[slRow[i]] != Eliminated_ZeroOrRestriction) ) {
00440 
00441           xElim[slCol[nonZeroCol]] = btemp[slRow[i]]/A(slRow[i],slCol[nonZeroCol]);
00442 
00443           for(Int k=0; k<Nred; k++)
00444             btemp[slRow[k]] -= A(slRow[k],slCol[nonZeroCol]) * xElim[slCol[nonZeroCol]];
00445 
00446 
00447           colElim[slCol[nonZeroCol]] = Eliminated_ZeroOrRestriction;
00448 Debugln(DJ,"Eliminating column " <<  slCol[nonZeroCol] << " due to restriction");
00449 //Debugln(DJ,"1: reducing Mred from " << Mred+1 << " to " << Mred << " (zero or restriction)");
00450           for(Int j=nonZeroCol; j<(Mred-1); j++) slCol[j] = slCol[j+1];
00451           Mred--;
00452 
00453           rowElim[slRow[i]] = Eliminated_ZeroOrRestriction;
00454 Debugln(DJ,"eliminated row " << slRow[i] << " due to restriction");
00455           for(Int j=i; j<(Nred-1); j++) slRow[j] = slRow[j+1];
00456           Nred--;
00457 //Debugln(DJ,"2: reducing Nred from " << Nred+1 << " to " << Nred << " (zero or restriction)");
00458 
00459         }
00460         else
00461           if ( (restriction==0) && (rowElim[slRow[i]] != Eliminated_ZeroOrRestriction) ) {
00462             // row of all zeros also eliminated
00463             rowElim[slRow[i]] = Eliminated_ZeroOrRestriction;
00464 Debugln(DJ,"row " << slRow[i] << " eliminated (all zeros)");
00465             for(Int j=i; j<(Nred-1); j++) slRow[j] = slRow[j+1];
00466             Nred--;
00467 //Debugln(DJ,"3: reducing Nred from " << Nred+1 << " to " << Nred << " (row of all zeros)");
00468           }
00469 
00470       } // for
00471 
00472       if (Nred == lastNred)
00473         stillChecking = false;
00474 
00475     } // end while (stillChecking)
00476 
00477 
00478     // check for columns of zeros
00479     for (Int i=0; i<Mred; i++) {
00480       Int j=0;
00481       while ( (j<Nred) && isSmall(A(slRow[j],slCol[i])) ) j++;
00482 
00483       if (j == Nred) {
00484         colElim[slCol[i]] = Eliminated_ZeroOrRestriction;
00485 Debugln(DJ,"4: reducing Mred from " << Mred+1 << " to " << Mred << " (column " << slCol[i] << " of all zeros)");
00486         for(Int j=i; j<(Mred-1); j++) slCol[j] = slCol[j+1];
00487         Mred--;
00488         i--;
00489       }
00490     } // end for
00491 
00492 
00493     // check for dependent rows
00494     if (Mred != 0) {
00495 
00496       Matrix n;
00497       Matrix Atrans(Mred,Mred);
00498 
00499       for(Int i=0; i<Nred; i++)
00500         for(Int j=0; j<Mred; j++)
00501           Atrans(j,i) = A(slRow[i], slCol[j]);
00502       for(Int i=Nred; i<Mred; i++)
00503         for(Int j=0; j<Mred; j++)
00504           Atrans(j,i) = 0;
00505 //Debugln(FSP,"Atrans:" << Atrans.size1() << "x" << Atrans.size2());
00506       Int nullity;
00507       Real K2;
00508       n.reset( Math::nullSpace(Atrans, nullity, K2) );
00509       nullity += Nred-Mred;
00510 //Debugln(FSP,"nullity=" << nullity);
00511       // !!! IKORv2.0 says:
00512       // This is where the b's should be checked and determined if they
00513       // are dependent as well.  If they are not, an error message
00514       // should be displayed and the system should stop.
00515       // This is probably the best place to do this, instead of at the
00516       // bottom of solution_generator(), since it has the information.
00517 
00518 //Debugln(FSP,"slRow.size()=" << slRow.size());//!!!
00519       Int nullCount=0; // (=nul_count)
00520       while (nullCount < nullity) {
00521         Int i=Mred-Nred + nullCount;
00522         Int j=0;
00523         while ( (j!=n.size1()) && isSmall(n(j,i)) ) j++;
00524 
00525         if ( (rowElim[slRow[j]] != Eliminated_ZeroOrRestriction) && (j != n.size1()) ) {
00526           rowElim[slRow[j]] = RowEliminated_Dependent;
00527           for(Int k=j; j<(Nred-1); k++) {
00528 //Debugcln(FSP,"k=" << k);
00529             slRow[k] = slRow[k+1]; //!!! potential index oob here
00530           }
00531           Nred--;
00532 Debugln(DJ,"5: reducing Nred from " << Nred+1 << " to " << Nred << " (dependent row)");
00533         }
00534 
00535         nullCount++;
00536 
00537       } // end while
00538 
00539     } //  end if (Mred!=0) // check for dependent rows
00540 
00541 
00542 
00543     // check for Special Case 1
00544     bool stop;
00545     {
00546       IVector nonZero(M); // stores values of nonzero col (=Nonzero)
00547       nonZero = zeroIVector(M);
00548       Int nonZeroCol;
00549 
00550       stop=false;
00551       for(SInt i=0; i< SInt(Nred); i++) { // for each row (& corresponding elt of btemp)
00552 
00553         if (isSmall(btemp[slRow[i]])) {
00554           nonZeroCol = 0;
00555           SInt j=0;
00556           stop = false;
00557 
00558           while ( (j < (SInt(Mred)-1)) && !stop) {
00559             if (!isSmall(A(slRow[i], slCol[j]))) {
00560               Int k=j+1;
00561               while (!stop && (k<Mred)) {
00562                 if (!isSmall(A(slRow[i], slCol[k]))) {
00563                   if (dependency(A, slRow, Nred, slCol[j], slCol[k]))
00564                     k++;
00565                   else
00566                     stop=true;
00567                 }
00568                 else
00569                   k++;
00570 
00571               } // end while (!stop...)
00572               nonZero[nonZeroCol] = slCol[j];
00573               nonZeroCol++;
00574               j++;
00575             } // end if (!isSmall.. )
00576             else
00577               j++;
00578 
00579           } // end while ( j < ...)
00580 
00581           if (!isSmall(A(slRow[i], slCol[Mred-1]))) {
00582             nonZero[nonZeroCol] = slCol[Mred-1];
00583             nonZeroCol++;
00584           }
00585 
00586           if (nonZeroCol==1)
00587             stop = true;
00588 
00589           if (!stop) { // discovered a special-case 1
00590             doneRed = false;
00591 Debug(DJ,"Discovered specialCase 1 in row " << i << " eliminating cols:");
00592             for(Int r=0; r<nonZeroCol; r++) {
00593               colElim[nonZero[r]] = ColEliminated_SpecialCase1;
00594 Debugc(DJ," " << nonZero[r]);
00595             }
00596 Debugcln(DJ,"");
00597 
00598             for(Int count=0, count2=0, position=0; position<Mred; position++) {
00599               if (slCol[position] != nonZero[count2]) {
00600                 slCol[count] = slCol[position];
00601                 count++;
00602               }
00603               else
00604                 count2++;
00605             }
00606 
00607 
00608             // Construct new g Matrix
00609             Assert(nonZeroCol > 0);
00610             Matrix Aelim(1,nonZeroCol);
00611             for(Int r=0; r<nonZeroCol; r++)
00612               Aelim(0,r) = A(slRow[i], nonZero[r]);
00613             Int nullity;
00614             Real K2;
00615 //          Matrix n; //(nonZeroCol, nonZeroCol-1/*?*/);
00616 
00617 
00618 
00619 //Debugln(FSP,"b n dim " << n.size1() << "x" << n.size2());//!!!
00620             Matrix n = Math::nullSpace(Aelim, nullity, K2);
00621 /* added by DJ (perhaps should be nonZeroCol, not nzc-1)
00622             // pad n with 0s in case it is smaller than expected
00623             Matrix newn(nonZeroCol,nonZeroCol-1);
00624             newn = zeroMatrix(nonZeroCol,nonZeroCol-1);
00625             matrixRange(newn,Range(0,n.size1()),Range(0,n.size2())) = n;
00626             n.reset(newn);
00627 */
00628             Mred -= nonZeroCol;
00629 Debugln(DJ,"6: SC1: reducing Mred from " << Mred+nonZeroCol << " to " << Mred);
00630 
00631             //!!! appropriate
00632             if (Mred == 0)
00633               throw std::invalid_argument(Exception("FSP method unable to complete solution: A reduced to 0 columns (Mred==0)"));
00634 
00635 
00636             rowElim[slRow[i]] = RowEliminated_Special;
00637             for(Int r=i; r<(Nred-1); r++) slRow[r] = slRow[r+1];
00638             Nred--;
00639 Debugln(DJ,"7: SC1: reducing Nred from " << Nred+1 << " to " << Nred);
00640 
00641             //!!! appropriate?
00642             if (Nred == 0)
00643               throw std::invalid_argument(Exception("FSP method unable to complete solution: A reduced to 0 rows (Nred==0)"));
00644 
00645 //Debugln(FSP,"specialg dim " << specialg.size1() << "x" << specialg.size2());//!!!
00646 //Debugcln(FSP,"numSpecialgs=" << numSpecialgs << " M=" << M << " nonZeroCol=" << nonZeroCol);
00647 //Debugcln(FSP,"nonZero.size()=" << nonZero.size());
00648 //Debugln(FSP,"n dim " << n.size1() << "x" << n.size2());//!!!
00649             for(Int m=0; m<(nonZeroCol-1); m++) {
00650 
00651               for(Int r=0; r<M; r++)
00652                 specialg(numSpecialgs, r) = 0;
00653 
00654               for(Int r=0; r<nonZeroCol; r++) {
00655 //Debugcln(FSP,"numSpecialgs=" << numSpecialgs << " nonZero[r]=" << nonZero[r]); //!!!
00656                 specialg(numSpecialgs, nonZero[r]) = n(r,m);
00657               }
00658               numSpecialgs++;
00659             }
00660 
00661           }
00662 
00663         } // end if (.. < small)
00664 
00665       } // end for each row
00666 dump_A();
00667 dump_btemp();
00668     } // end Special Case 1
00669 
00670 
00671 
00672     // check for Special Case 2
00673     {
00674       bool stop2=false;
00675       Vector constant(N);
00676       constant = zeroVector(N);
00677       Int reference=0; // reference position for row
00678       IVector classA(M); // classificationA columns
00679       classA = zeroIVector(M);
00680       Int classANum=0; // number of ClassificationA columns (=ClassANum)
00681 
00682       SInt i=0;
00683       while ( (i<SInt(Nred)-1) && !stop2 ) {
00684 
00685         SInt j=i+1;
00686         while ( (j < SInt(Nred)) && !stop2) {
00687 
00688           stop=false;
00689           bool flag=false; // beta undefined flag (=Flag)
00690           Real beta=0; // (=beta)
00691 
00692           if (!isSmall(btemp[slRow[i]]))
00693             beta = btemp[slRow[j]] / btemp[slRow[i]];
00694           else
00695             flag = true;
00696 
00697           classANum=0;
00698           Int k=0;
00699           reference=i;
00700 
00701           while ( !stop && (k<Mred) ) {
00702             bool goIn = false; // "Go in" for entance into ClassA (=Goin)
00703 
00704             if (isSmall(A(slRow[i], slCol[k]))) {
00705               if (!flag) goIn = true;
00706             }
00707             else {
00708               if (!isSmall( A(slRow[j],slCol[k]) / A(slRow[i],slCol[k]) - beta ) )
00709                 goIn=true;
00710               if (flag) goIn=true;
00711             }
00712 
00713             if (goIn) {
00714 
00715               classA[classANum] = slCol[k];
00716               if (classANum==0) {
00717 
00718                 if (isSmall(A(slRow[reference],classA[0]))) {
00719                   reference=j;
00720                   if (isSmall(A(slRow[reference],classA[0]))) //!!! redundant test?
00721                     stop = true;
00722                 }
00723 
00724                 if (!stop)
00725                   for(Int r=0; r<Nred; r++)
00726                     constant[r] = A(slRow[r],classA[0]) / A(slRow[reference],classA[0]);
00727 
00728               } // end if (classANum==0)
00729               else { // i.e. classANum != 0
00730                 if (isSmall(A(slRow[reference],classA[classANum])))
00731                   stop = true;
00732                 else {
00733                   Int r=0;
00734                   while ( (r<Nred) && !stop) {
00735                     if (!isSmall( (A(slRow[r],classA[classANum]) / A(slRow[reference],classA[classANum]) ) - constant[r]))
00736                       stop=true;
00737                     r++;
00738                   } // end while
00739                 }
00740               } // end else (classANum != 0)
00741 
00742               classANum++;
00743 
00744             } // end if (goIn)
00745             k++;
00746 
00747           } // end while (!stop && (k<Mred)
00748           if (!stop) stop2=true;
00749           j++;
00750 
00751         } // end while (j < Nred) && !stop2
00752         i++;
00753 
00754       } // end while (i < Nred-1) && !stop2
00755 
00756 
00757       if (stop2) {
00758 Debugln(DJ,"Discovered specialCase 2");
00759 
00760         doneRed=false;
00761 
00762         // construct new g matrix
00763         Matrix Aelim(1,classANum);
00764         Matrix n(classANum, classANum-1);
00765         for(Int p=0; p<classANum; p++)
00766           Aelim(0,p) = A(slRow[reference], classA[p]);
00767         Int nullity;
00768         Real K2;
00769         n = Math::nullSpace(Aelim, nullity, K2);
00770 
00771         for(Int p=0; p<(classANum-1); p++) {
00772           for(Int r=0; r<M; r++)
00773             specialg(numSpecialgs,r)=0;
00774           for(Int r=0; r<classANum; r++)
00775             specialg(numSpecialgs, classA[r]) = n(r,p);
00776           numSpecialgs++;
00777 Debugcln(DJ,"new soln: " << Vector(matrixRow(specialg, numSpecialgs-1)) );
00778         } // end for p
00779 
00780         Nred--;
00781 //Debugcln(DJ,"8: SC2: reducing Nred from " << Nred+1 << " to " << Nred);
00782         //!!! appropriate?
00783         if (Nred == 0)
00784           throw std::invalid_argument(Exception("FSP method unable to complete solution: A reduced to 0 rows (Nred==0)"));
00785 
00786         rowElim[slRow[reference]] =  RowEliminated_Special;
00787 Debugc(DJ,"eliminated row " << slRow[reference] << " and cols:");
00788         for(Int r=0; r<classANum; r++) {
00789           colElim[classA[r]] = ColEliminated_SpecialCase2;
00790 Debugc(DJ," " << classA[r]);
00791         }
00792 Debugcln(DJ,"");
00793         for(Int r=reference; r<Nred; r++) slRow[r] = slRow[r+1];
00794 
00795         for(Int count=0, count2=0, position=0; position<Mred; position++)
00796           if (slCol[position] != classA[count2]) {
00797             slCol[count] = slCol[position];
00798             count++;
00799           }
00800           else
00801             count2++;
00802 
00803         //!!! appropriate?
00804         if ((SInt(Mred) - SInt(classANum)) <= 0)
00805           throw std::invalid_argument(Exception("FSP method unable to complete solution: A reduced to 0 columns (Mred==0)"));
00806 
00807         Mred -= classANum;
00808 //Debugln(DJ,"9: SC2: reducing Mred from " << Mred+classANum << " to " << Mred);
00809       } // end if (stop2)
00810 
00811     } // end Special Case 2
00812 
00813 
00814   } // end while (!doneRed)
00815 
00816 
00817 
00818 
00819   // store the reduced A in the variable Ared, and the modified b in bred
00820   if ((Nred > 0) && (Mred > 0)) {
00821     Ared.resize(Nred, Mred);
00822     bred.resize(Nred);
00823     SInt j=-1;
00824     for(Int i=0; i<N; i++)
00825       if (rowElim[i] == NotEleminated) {
00826         j++;
00827         bred[j] = btemp[i];
00828         SInt m=-1;
00829         for(Int k=0; k<M; k++)
00830           if (colElim[k] == NotEleminated) {
00831             m++;
00832             Ared(j,m) = A(i,k);
00833           }
00834       }
00835   }
00836   else
00837     throw std::runtime_error(Exception("FSP method error: The A matrix has been reduced to nothing"));
00838 
00839 }
00840 
00841 
00842 
00843 ///  calculates a g vector for a given square blocking pattern.
00844 void IKORFullSpaceSolver::blockColFindX(Vector& g,
00845                                         const IVector& tackon, const Vector& block,
00846                                         const Vector& b, const Matrix& A,
00847                                         const Int Mred, const Int Nred)
00848 {
00849   Matrix Atemp(Nred, Nred);
00850   Vector btemp(Nred);
00851   Vector blocktemp(Nred);
00852 
00853   // the columns blocked need to be listed from smallest to largest
00854   btemp=b;
00855   blocktemp=block;
00856 
00857   for(Int i=(Nred-1); i>0; i--)
00858     for(SInt j=i-1; j>=0; j--)
00859       if (blocktemp[i] < blocktemp[j])
00860         base::swap(blocktemp[i], blocktemp[j]);
00861 Debugln(DJ,"blocktemp=" << blocktemp);
00862   // !!! IKORv2 has an I var in this loop, it doesn't appear to be used (??)
00863   for(Int k=0, i=0; (i<Mred) && (k<Nred); i++) { //!!! added k<Nred
00864     if (blocktemp[k] == i) {
00865       matrixColumn(Atemp,k) = matrixColumn(A,i);
00866       k++;
00867     }
00868   }
00869 Debugln(DJ,"Atemp=\n" << Atemp);
00870   //Debugcln(FSP,"asqr=\n" << Atemp);
00871 
00872   Vector gtemp( Math::inverse(Atemp)*btemp );
00873 
00874   Debugcln(FSP,"gvector=\n" << gtemp);
00875 
00876   // Now add a zero to where column was blocked
00877   for (Int i=0; i<Nred; i++)
00878     g[Int(blocktemp[i])] = gtemp[i];
00879 
00880   Assert(Mred-Nred <= tackon.size());
00881   for(Int j=0; j<Mred-Nred; j++) {
00882     if (tackon[j] < g.size()) g[tackon[j]]=0; //!!! added if (..<..)
00883   }
00884 
00885 }
00886 
00887 
00888 
00889 
00890 
00891 
00892 void IKORFullSpaceSolver::restOfSoln(const Int M, const Int N, const Int Mred, const Int Nred,
00893                                      Int nextToFind,
00894                                      Matrix& block, Matrix& g,
00895                                      const Vector& bred, const Matrix& Ared,
00896                                      const base::IVector& tackon, base::IVector& firstOK)
00897 {
00898   Debugln(FSP,"Entering RestOfSoln()");
00899   nextToFind++; // looking for next soln
00900 
00901   Int X, Y; // Position markers, keeping track of the current column to be subbed in for and which one to sub in (=id)
00902 
00903   X = nextToFind-1;
00904 Debugcln(FSP,"g=\n" << g);
00905 
00906   // Change firstOK if a previously 0 value of g for a column in first
00907   // blocking pattern has become nonzero
00908   for(Int i=0; i<Nred; i++)
00909     if ( (!firstOK[i]) && (!isSmall(g(nextToFind-1, Int(block(nextToFind-1,i))))) )
00910       firstOK[i] = Int(true);
00911 
00912   IVector changed(Nred); // temp vector for firstOK, passed to recursive call (=Changed)
00913   changed = vectorRange(firstOK,Range(0,Nred));
00914   Debugcln(FSP,"changed=" << changed);
00915 
00916   while ( (X < Mred-Nred) && (!systemComplete) ) {
00917 
00918     Debugcln(FSP,"X=" << X << " next soln to find is " << nextToFind);
00919 
00920     // Set up next Asub comparing the next remaining column to be subbed
00921     // in with the blocking pattern for that level of recursion
00922     Matrix Asub(Nred,Nred+1);
00923     for(Int i=0; i<Nred; i++)
00924       for(Int r=0; r<Nred; r++)
00925         Asub(r,i) = Ared(r, Int(block(nextToFind-1,i)) );
00926     for(Int r=0; r<Nred; r++)
00927       Asub(r,Nred) = Ared(r,tackon[X]);
00928 
00929     Int nullity; // dim of null-space  (=id)
00930     Real K2;     // condition number   (=id)
00931     Matrix n( Math::nullSpace(Asub, nullity, K2) ); // null-space vectors (=id)
00932 
00933     Y=0;
00934     // Loop which compares column to be subbed in with current blocking
00935     // pattern for dependency, if dependent it completes swap and valid
00936     while ( (Y < Nred) && (!systemComplete) ) {
00937 
00938       Debugcln(FSP,"Y=" << Y << " X=" << X);
00939       Debugcln(FSP, "compare column " << tackon[X] << " with " << Int(block(nextToFind-1,Y)) );
00940       Debugcln(FSP, " it is " << Math::abs(n(Y,0)) << " and firstOK[Y]=" << firstOK[Y]);
00941 
00942       if ( (!isSmall(n(Y,0))) && (firstOK[Y]) ) {
00943 
00944         Debugcln(FSP,"*************** " << nextToFind << " ****************");
00945 
00946         Debugcln(FSP,"** block=\n" << block);
00947         Debugcln(FSP,"** tackon=" << tackon);
00948         Debugcln(DJ, "** X=" << X << " Y=" << Y);
00949 
00950         IVector newTack(M-N); // temp vector for tackon, passed in recursive call
00951         for(Int i=0; i<Nred; i++) block(nextToFind,i) = block(nextToFind-1,i);
00952         newTack[0] = Int(block(nextToFind,Y));
00953         block(nextToFind,Y) = tackon[X];
00954         for(Int i=0; i<X; i++) newTack[i+1] = tackon[i];
00955         for(Int j=X+1; j<Mred-Nred; j++)
00956           newTack[j] = tackon[j];
00957 
00958         Debugcln(FSP,"** newTack=" << newTack);
00959         Debugcln(FSP,"** block=\n" << block);
00960         Debugcln(FSP,"** g=\n" << g);
00961 
00962         Vector gRow(matrixRow(g,nextToFind)); // select out rows[nextToFind]
00963         Vector blockRow(matrixRow(block,nextToFind));
00964         blockColFindX(gRow, newTack, blockRow, bred, Ared, Mred, Nred);
00965         matrixRow(g,nextToFind) = gRow;       // copy them back
00966         matrixRow(block,nextToFind) = blockRow;
00967 
00968         Debugln(FSP,"** block=\n" << block);
00969         Debugcln(FSP,"** g=\n" << g);
00970 
00971         Debugcln(FSP," it will be g(nextToFind,block(nextToFind,Y)=" << Math::abs(g(nextToFind,Int(block(nextToFind,Y)))));
00972 
00973 
00974         // Check to ensure the newly created g vector is independent
00975         // of previously created ones in branch
00976         if ( !isSmall(g(nextToFind,Int(block(nextToFind,Y)))) ) {
00977           if (nextToFind < (Mred-Nred)) {
00978             //Debugcln(FSP,"block:\n" << block);
00979             Debugcln(FSP,"solutions:\n" << g);
00980 
00981             // recursive call
00982             restOfSoln(M, N, Mred, Nred, nextToFind, block, g, bred, Ared, newTack, changed);
00983           }
00984           else {
00985             systemComplete=true;
00986           }
00987         } // endif abs(g...) > small
00988 
00989 
00990         if (!systemComplete)
00991           block(nextToFind,Y) = newTack[0];
00992 
00993       } // endif Y > small && ...
00994 
00995       Y++;
00996 
00997     } // while
00998 
00999     X++;
01000 
01001   } // while
01002 
01003 
01004 }
01005 
01006 
01007 
01008 
01009 void IKORFullSpaceSolver::rebuildgs(Matrix& g,
01010                                     const Int M, const Int N, const Int Mred, const Int Nred,
01011                                     const IVector& colElim, const IVector& rowElim,
01012                                     const Matrix& specialg, const Int numSpecialgs)
01013 {
01014   Matrix gtemp(g);
01015 
01016   for(Int k=0, j=0; j<M; j++) {
01017 
01018     if (colElim[j] != NotEleminated) {
01019       for(Int i=0; i<g.size1(); i++) g(i,j) = 0;
01020     }
01021     else {
01022       for(Int i=0; i<g.size1(); i++) g(i,j) = gtemp(i,k);
01023       k++;
01024     }
01025   }
01026 
01027   // Addition of null vectors created by SpecialCase1
01028   for(Int i=(Mred-Nred+1); i<(Mred-Nred+1+numSpecialgs); i++)
01029     for(Int j=0; j<M; j++) {
01030       if (colElim[j] != NotEleminated)
01031         g(i,j) = specialg(i-Mred+Nred-1,j);
01032       else
01033         g(i,j) = g(0,j);
01034     }
01035 
01036 }
01037 
01038 
01039 

Generated on Thu Jul 29 15:56:33 2004 for OpenSim by doxygen 1.3.6