Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

mmatrix.cc

Go to the documentation of this file.
00001 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <magic/mmath.h>
00028 #include <magic/mmatrix.h>
00029 #include <magic/mstream.h>
00030 #include <magic/mtextstream.h>
00031 #include <magic/mlist.h>
00032 
00033 BEGIN_NAMESPACE (MagiC);
00034 
00036 //                         |   |               o                             //
00037 //                         |\ /|  ___   |                                    //
00038 //                         | V |  ___| -+- |/\ | \ /                         //
00039 //                         | | | (   |  |  |   |  X                          //
00040 //                         |   |  \__|   \ |   | / \                         //
00042 
00043 /*******************************************************************************
00044  *
00045 **/
00046 Matrix::Matrix (
00047     int       rows,
00048     int       cols,
00049     double*   pData)
00050         : PackTable<double> (rows, cols)
00051 {
00052     memcpy (mData, pData, rows*cols*sizeof(double));
00053 }
00054 
00055 void Matrix::make (int rs, int cs)
00056 {
00057     PackTable<double>::make (rs, cs);
00058     operator= (0.0);
00059 }
00060 
00065 void Matrix::load (const String& filename)
00066 {
00067     FILE* in = fopen (filename, "r");
00068     if (!in)
00069         throw file_not_found (format("Matrix file '%s' not found", (CONSTR)filename));
00070     load (in);
00071     fclose (in);
00072 }
00073 
00078 void Matrix::load (FILE* in) {
00079     List<Vector*> rows;     // Will contain the rows in the input file
00080 
00081     // Read the datafile
00082     String buffer;
00083     String item;        // One numeric or text item
00084     item.reserve (20);
00085 
00086     // Read one line at a time
00087     int rowCnt = 0;
00088     while (fgetS (in, buffer) != -1) {
00089         buffer.chop(); // Remove trailing newline
00090         Vector* prow = new Vector (cols);
00091         int itemIndex=0;    // Index of the above item within the row
00092         for (uint i=0; i<buffer.length()+1; i++) {
00093             if (i==buffer.length() || buffer[i]==' ' || buffer[i]=='\t') {
00094                 if (itemIndex<cols)
00095                     (*prow)[itemIndex++] = (item=="x")? UNDEFINED_FLOAT : item.toDouble();
00096                 item = "";
00097             } else
00098                 item += buffer[i];
00099         }
00100         rows.add (prow);
00101         rowCnt++;
00102     }
00103 
00104     // Adjust our size
00105     make (rowCnt,cols);
00106 
00107     // Put the pattern list into the set
00108     int r=0;
00109     for (ListIter<Vector*> l (rows); !l.exhausted(); l.next(), r++) {
00110         for (int c=0; c<cols; c++)
00111             get(r,c) = (*l.get())[c];
00112     }
00113 }
00114 
00115 /*******************************************************************************
00116  *
00117 **/
00118 void Matrix::save (FILE* out) const {
00119     for (int r=0; r<rows; r++) {
00120         for (int c=0; c<cols; c++)
00121             fprintf (out, "%g ", get(r,c));
00122         fprintf (out, "\n");
00123     }
00124 }
00125 
00126 /*******************************************************************************
00127  *
00128 **/
00129 const Matrix& Matrix::transpose () {
00130     for (int i=0; i<rows; i++)
00131         for (int j=i; j<cols; j++)
00132             swap (get(i,j), get(j,i));
00133     return *this;
00134 }
00135 
00138 const Matrix& Matrix::multiplyToSum (double s) {
00139     double cs = sum ();
00140     ASSERTWITH (fabs(cs)>1E-10, "Tried to normalize a zero matrix");
00141 
00142     operator*= (1.0/cs);
00143     return *this;
00144 }
00145 
00146 /*******************************************************************************
00147  *
00148 **/
00149 double Matrix::sum () const
00150 {
00151     int size=rows*cols;
00152     double res=0.0;
00153     for (int i=0; i<size; i++)
00154         res += mData[i];
00155     return res;
00156 }
00157 
00160 double Matrix::det () const
00161 {
00162     if (rows != cols || rows<2)
00163         return 0;
00164 
00165     if (rows == 2)
00166         return mData[0]*mData[3] - mData[1]*mData[2];
00167 
00168     // Compute determinant of a sub-matrix
00169 
00170     // Find a row with non-zero first column
00171     int rownon0;
00172     for (rownon0=0; rownon0<rows; rownon0++)
00173         if (get(rownon0,0) != 0)
00174             break;
00175 
00176     if (rownon0 == rows)
00177         return 0;
00178 
00179     // Prepare for taking complement by making a column with
00180     // zeroes, except for one row.
00181     Matrix modified (*this);
00182     double scale_to = get(rownon0, 0);
00183     for (int row=0; row<rows; row++)
00184         if (row != rownon0 && get(row,0)!=0)
00185             modified.addRowByScalar (rownon0, row, -get(row,0)/scale_to);
00186 
00187     // Create complement
00188     Matrix cmpl = modified.complement (rownon0, 0);
00189 
00190     // Compute determinant of the complement, and multiply it by the
00191     // nonzero element, and the appropriate sign.
00192     return get(rownon0, 0) * cmpl.det () * (1-(rownon0%2)*2);
00193 }
00194 
00197 Matrix Matrix::complement (int row, int col) const
00198 {
00199     ASSERT (rows>1 && rows==cols);
00200 
00201     Matrix result (rows-1, cols-1);
00202 
00203     for (int i=0, trgrow=0; i<rows; i++)
00204         if (i != row) {
00205             for (int j=0, trgcol=0; j<cols; j++)
00206                 if (j!=col)
00207                     result.get(trgrow, trgcol++) = get (i,j);
00208             trgrow++;
00209         }
00210 
00211     return result;
00212 }
00213 
00216 void Matrix::mulRowByScalar (int row, double scalar)
00217 {
00218     for (int i=0; i<cols; i++)
00219         get(row,i) *= scalar;
00220 }
00221 
00226 void Matrix::addRowByScalar (int srcrow, int dstrow, double scalar)
00227 {
00228     for (int i=0; i<cols; i++) {
00229         get(dstrow,i) += scalar*get(srcrow,i);
00230 
00231         // Round to zero
00232         if (isRoundZero (get(dstrow,i)))
00233             get(dstrow,i) = 0;
00234     }
00235 }
00236 
00239 void Matrix::swaprows (int row1, int row2)
00240 {
00241     double tmp [cols];
00242     int    collen = cols * sizeof(double);
00243     memcpy (&tmp, mData + row1*cols, collen);
00244     memcpy (mData + row1*cols, mData + row2*cols, collen);
00245     memcpy (mData + row2*cols, &tmp, collen);
00246 }
00247 
00250 const Matrix& Matrix::operator= (double x) {
00251     int size=rows*cols;
00252     for (int i=0; i<size; i++)
00253         mData[i] = x;
00254     return *this;
00255 }
00256 
00259 const Matrix& Matrix::operator= (const Matrix& orig) {
00260     make (orig.rows, orig.cols);
00261     int size=rows*cols;
00262     for (int i=0; i<size; i++)
00263         mData[i]= orig.mData[i];
00264     return *this;
00265 }
00266 
00269 const Matrix& Matrix::operator+= (const Matrix& other) {
00270     int size=rows*cols;
00271     for (int i=0; i<size; i++)
00272         mData[i] += other.mData[i];
00273     return *this;
00274 }
00275 
00278 const Matrix& Matrix::operator+= (double x) {
00279     int size=rows*cols;
00280     for (int i=0; i<size; i++)
00281         mData[i] += x;
00282     return *this;
00283 }
00284 
00287 const Matrix& Matrix::operator*= (const Matrix& other) {
00288     int size=rows*cols;
00289     for (int i=0; i<size; i++)
00290         mData[i] *= other.mData[i];
00291     return *this;
00292 }
00293 
00296 const Matrix& Matrix::operator*= (double x) {
00297     int size=rows*cols;
00298     for (int i=0; i<size; i++)
00299         mData[i] *= x;
00300     return *this;
00301 }
00302 
00303 /*******************************************************************************
00304  *
00305 **/
00306 TextOStream& Matrix::operator>> (TextOStream& out) const
00307 {
00308     out << "{";
00309     for (int i=0; i<rows; i++) {
00310         if (i > 0)
00311             out << ' ';
00312         out << '{';
00313         for (int j=0; j < cols; j++) {
00314             out.printf ("%2f", get (i,j));
00315             if (j < cols-1)
00316                 out << ',';
00317         }
00318         out << '}';
00319         if (i < rows-1)
00320             out << '\n';
00321     }
00322     out << "}\n";
00323     return out;
00324 }
00325 
00328 void Matrix::splitVertical (Matrix& a, Matrix& b, int column) const {
00329     a.make (rows, column);
00330     b.make (rows, cols-column);
00331     for (int r=0; r<rows; r++) {
00332         for (int c=0; c<column; c++)
00333             a.get(r,c) = get(r,c);
00334         for (int c=0; c<cols-column; c++)
00335             b.get(r,c) = get(r,c+column);
00336     }
00337 }
00338 
00341 void Matrix::splitHorizontal (Matrix& a, Matrix& b, int row) const {
00342     a.make (row, cols);
00343     b.make (rows-row, cols);
00344     for (int c=0; c<cols; c++) {
00345         for (int r=0; r<row; r++)
00346             a.get(r,c) = get(r,c);
00347         for (int r=0; r<rows-row; r++)
00348             b.get(r,c) = get(r+row,c);
00349     }
00350 }
00351 
00356 void Matrix::joinVertical (const Matrix& a, const Vector& b)
00357 {
00358     ASSERT (a.rows == b.size ());
00359 
00360     make (a.rows, a.cols+1);
00361 
00362     int collen  = cols*sizeof(double);
00363     int acollen = a.cols*sizeof(double);
00364     for (int r=0; r<rows; r++) {
00365         // Copy matrix row
00366         memcpy (mData + r*collen, a.mData + r*acollen, acollen);
00367 
00368         // Copy vector element
00369         mData[r*cols + cols-1] = b[r];
00370     }
00371 }
00372 
00377 void Matrix::joinVertical (const Matrix& a, const Matrix& b) {
00378     ASSERT (a.rows == b.rows);
00379     make (a.rows, a.cols + b.cols);
00380     for (int r=0; r<rows; r++) {
00381         for (int c=0; c<a.cols; c++)
00382             get(r,c) = a.get(r,c);
00383         for (int c=0; c<b.cols; c++)
00384             get(r,c+a.cols) = a.get(r,c);
00385     }
00386 }
00387 
00392 void Matrix::joinHorizontal (const Matrix& a, const Matrix& b) {
00393     ASSERT (a.cols == b.cols);
00394     make (a.rows+b.rows, a.cols);
00395     for (int c=0; c<cols; c++) {
00396         for (int r=0; r<a.rows; r++)
00397             get(r,c) = a.get(r,c);
00398         for (int r=0; r<b.rows; r++)
00399             get(r+a.rows,c) = a.get(r,c);
00400     }
00401 }
00402 
00405 Matrix Matrix::sub (int row0, int row1, int col0, int col1) const {
00406     ASSERT (row0>=0 && row0<rows);
00407     ASSERT ((row1>=-1 && row1<rows) || row1==-1);
00408     ASSERT (col0>=0 && col0<cols);
00409     ASSERT ((col1>=-1 && col1<cols) || col1==-1);
00410 
00411     if (row1==-1)
00412         row1 = rows-1;
00413     if (col1==-1)
00414         col1 = cols-1;
00415 
00416     Matrix result;
00417     result.make (row1-row0+1, col1-col0+1);
00418     for (int r=0; r<result.rows; r++)
00419         for (int c=0; c<result.cols; c++)
00420             result.get(r,c) = (*this).get(r+row0, c+col0);
00421     return result;
00422 }
00423 
00424 /*******************************************************************************
00425  *
00426 **/
00427 void Matrix::insertColumn (int cols) {
00428     
00429 }
00430 
00431 /*
00432 SubMatrix::SubMatrix (Matrix& m, int sr, int sc, int er, int ec) : matrix (m) {
00433     ASSERT (sr>0 && sc>0 && er>0 && ec>0);
00434     ASSERT (sr<m.rows);
00435     ASSERT (sc<m.cols);
00436     ASSERT (er<m.rows);
00437     ASSERT (ec<m.cols);
00438     ASSERT (sr<=er);
00439     ASSERT (sc<=ec);
00440     srow=sr, scol=sc, erow=er, ecol=ec;
00441     rows = erow-srow+1;
00442     cols = ecol-scol+1;
00443 
00444 }
00445 
00446 double& SubMatrix::get (int row, int col) {
00447     return matrix.PackTable<double>::get (row-srow, col-scol);
00448 }
00449 */
00450 
00453 int solveLinear     (const Matrix& mat, const Vector& b, Vector& result)
00454 {
00455     // Create augmented matrix
00456     Matrix augmat (mat);
00457     augmat.joinVertical (mat, b);
00458     
00459     return solveLinear (augmat, result);
00460 }
00461 
00473 int solveLinear (const Matrix& augmat_orig, Vector& result, int* bv_set)
00474 {
00475     int bv_count = 0;
00476     
00477     // Auxiliary augmented matrix which we can manipulate
00478     // with Elementary Row Operations
00479     Matrix augmat (augmat_orig);
00480 
00481     // Perform the actual Gauss-Jordan method
00482     for (int col=0, row=0; col<augmat.cols-1 && row<augmat.rows; col++)
00483         // Work only on basic variables
00484         if (!bv_set || bv_set[col]) {
00485         
00486             // Ensure that the top-left element is not 0
00487             if (augmat.get(row,col) == 0) {
00488                 // Find row with non-zero top-left element
00489                 bool found = false;
00490                 for (int i=row+1; i<augmat.rows; i++)
00491                     if (augmat.get(i,col) != 0) {
00492                         augmat.swaprows (row, i);
00493                         found = true;
00494                     }
00495                 
00496                 if (!found)
00497                     return 1; // Unsolvable
00498             }
00499             
00500             // Scale the top-left element to 1
00501             augmat.mulRowByScalar (row, 1/augmat.get(row,col));
00502             augmat.get(row,col) = 1; // In case of rounding errors
00503             
00504             // Make the column below the position to begin with 0
00505             for (int i=row+1; i<augmat.rows; i++)
00506                 if (augmat.get(i,col) != 0) {
00507                     augmat.addRowByScalar (row, i, -augmat.get(i,col));
00508                     augmat.get(i,col) = 0; // In case of rounding errors
00509                 }
00510 
00511             row++;
00512         }
00513         else
00514             // Count the number of nonbasic variables in the BV set
00515             bv_count++;
00516 
00517     // If rows > cols-1, the bottom columns must be 0
00518     if (augmat.rows > augmat.cols - bv_count - 1)
00519         for (int i=augmat.cols - bv_count - 1; i<augmat.rows; i++)
00520             if (!bv_set || bv_set[i])
00521                 if (!isRoundZero (augmat.get(i,augmat.cols - bv_count - 1)))
00522                     return 2; // Unsolvable
00523 
00524     // Go back up and solve the variables above
00525     for (int col=augmat.cols-2, row=augmat.rows-1; col>=0; col--)
00526         if (!bv_set || bv_set[col]) {
00527             // Use this solution to fix the column above to 0
00528             for (int i=row-1; i>=0; i--)
00529                 if (augmat.get(i,col) != 0)
00530                     augmat.addRowByScalar (row, i, -augmat.get(i,col));
00531 
00532             row--;
00533         }
00534 
00535     // Store the result
00536     result.make (augmat.cols-1);
00537     for (int var=0, row=0; var<result.size(); var++)
00538         if (!bv_set || bv_set[var]) // BV
00539             result[var] = augmat.get (row++, augmat.cols-1);
00540         else // BV
00541             result[var] = 0.0;
00542 
00543     return 0;
00544 }
00545 
00546 END_NAMESPACE;
00547 

Generated on Thu Feb 10 20:06:42 2005 for LibMagiC by doxygen1.2.18