Commit cb738b250bd32e8d741c8ebe4928cf70a0175c3a

Authored by knodlseder
1 parent 9dc93639

Correct small bugs and make spi_toolslib compliant

src/GMatrix.cpp
@@ -170,9 +170,9 @@ GMatrix::GMatrix(const GMatrix& m) @@ -170,9 +170,9 @@ GMatrix::GMatrix(const GMatrix& m)
170 GMatrix::~GMatrix() 170 GMatrix::~GMatrix()
171 { 171 {
172 // De-allocate only if memory has indeed been allocated 172 // De-allocate only if memory has indeed been allocated
173 - if (m_colstart != NULL) delete [] m_colstart;  
174 if (m_rowsel != NULL) delete [] m_rowsel; 173 if (m_rowsel != NULL) delete [] m_rowsel;
175 if (m_colsel != NULL) delete [] m_colsel; 174 if (m_colsel != NULL) delete [] m_colsel;
  175 + if (m_colstart != NULL) delete [] m_colstart;
176 if (m_data != NULL) delete [] m_data; 176 if (m_data != NULL) delete [] m_data;
177 177
178 // Return 178 // Return
src/GSparseMatrix.cpp
@@ -48,8 +48,8 @@ GSparseMatrix::GSparseMatrix(int rows, int cols, int elements) : GMatrix() @@ -48,8 +48,8 @@ GSparseMatrix::GSparseMatrix(int rows, int cols, int elements) : GMatrix()
48 // Initialise private members for clean destruction 48 // Initialise private members for clean destruction
49 m_rows = 0; 49 m_rows = 0;
50 m_cols = 0; 50 m_cols = 0;
51 - m_elements = 0;  
52 - m_alloc = 0; 51 + m_elements = 0; // Logically used # of elements
  52 + m_alloc = 0; // Allocated # of elements (>= m_elements)
53 m_data = NULL; 53 m_data = NULL;
54 m_colstart = NULL; 54 m_colstart = NULL;
55 m_rowinx = NULL; 55 m_rowinx = NULL;
@@ -537,7 +537,14 @@ double GSparseMatrix::sum() const @@ -537,7 +537,14 @@ double GSparseMatrix::sum() const
537 ***************************************************************************/ 537 ***************************************************************************/
538 void GSparseMatrix::transpose() 538 void GSparseMatrix::transpose()
539 { 539 {
540 - *this = cs_transpose(this, 1); 540 + // Fill pending value in input matrix
  541 + fill_pending();
  542 +
  543 + // Transpose matrix
  544 + *this = cs_transpose(*this, 1);
  545 +
  546 + // Return
  547 + return;
541 } 548 }
542 549
543 550
@@ -803,8 +810,12 @@ void GSparseMatrix::cholesky_decompose(int compress) @@ -803,8 +810,12 @@ void GSparseMatrix::cholesky_decompose(int compress)
803 int matrix_rows = m_rows; 810 int matrix_rows = m_rows;
804 int matrix_cols = m_cols; 811 int matrix_cols = m_cols;
805 812
806 - // Delete any existing symbolic analysis object 813 + // Delete any existing symbolic and numeric analysis object and reset
  814 + // pointers
807 if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic; 815 if (m_symbolic != NULL) delete (GSparseSymbolic*)m_symbolic;
  816 + if (m_numeric != NULL) delete (GSparseNumeric*)m_numeric;
  817 + m_symbolic = NULL;
  818 + m_numeric = NULL;
808 819
809 // Allocate symbolic analysis object 820 // Allocate symbolic analysis object
810 GSparseSymbolic* symbolic = new GSparseSymbolic(); 821 GSparseSymbolic* symbolic = new GSparseSymbolic();
@@ -827,44 +838,26 @@ void GSparseMatrix::cholesky_decompose(int compress) @@ -827,44 +838,26 @@ void GSparseMatrix::cholesky_decompose(int compress)
827 // Ordering an symbolic analysis of matrix. This sets up an array 'pinv' 838 // Ordering an symbolic analysis of matrix. This sets up an array 'pinv'
828 // which contains the fill-in reducing permutations 839 // which contains the fill-in reducing permutations
829 symbolic->cholesky_symbolic_analysis(1, *this); 840 symbolic->cholesky_symbolic_analysis(1, *this);
  841 +
  842 + // Store symbolic pointer in sparse matrix object
  843 + m_symbolic = (void*)symbolic;
830 844
831 // Perform numeric Cholesky decomposition 845 // Perform numeric Cholesky decomposition
832 numeric.cholesky_numeric_analysis(*this, *symbolic); 846 numeric.cholesky_numeric_analysis(*this, *symbolic);
833 -  
834 - // Insert zero rows and columns if they have been removed previously.  
835 - // Since no selection information is present in numeric.m_L we have to  
836 - // copy it from this in order to allow for insertion.  
837 - if (compress) {  
838 -  
839 - // If there is a row selection then copy it  
840 - if (m_rowsel != NULL && m_num_rowsel > 0) {  
841 - numeric.m_L->m_rowsel = new int[m_num_rowsel];  
842 - if (numeric.m_L->m_rowsel == NULL)  
843 - throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_rowsel);  
844 - for (int i = 0; i < m_num_rowsel; ++i)  
845 - numeric.m_L->m_rowsel[i] = m_rowsel[i];  
846 - numeric.m_L->m_num_rowsel = m_num_rowsel;  
847 - }  
848 -  
849 - // If there is a column selection then copy it  
850 - if (m_colsel != NULL && m_num_colsel > 0) {  
851 - numeric.m_L->m_colsel = new int[m_num_colsel];  
852 - if (numeric.m_L->m_colsel == NULL)  
853 - throw mem_alloc("GSparseMatrix::cholesky_decompose(int)", m_num_colsel);  
854 - for (int i = 0; i < m_num_colsel; ++i)  
855 - numeric.m_L->m_colsel[i] = m_colsel[i];  
856 - numeric.m_L->m_num_colsel = m_num_colsel;  
857 - }  
858 -  
859 - // Now we can insert zero rows and columns  
860 - numeric.m_L->insert_zero_row_col(matrix_rows, matrix_cols); 847 +
  848 + // Copy L matrix into this object
  849 + free_elements(0, m_elements);
  850 + alloc_elements(0, numeric.m_L->m_elements);
  851 + for (int i = 0; i < m_elements; ++i) {
  852 + m_data[i] = numeric.m_L->m_data[i];
  853 + m_rowinx[i] = numeric.m_L->m_rowinx[i];
861 } 854 }
  855 + for (int col = 0; col <= m_cols; ++col)
  856 + m_colstart[col] = numeric.m_L->m_colstart[col];
862 857
863 - // Store Cholesky decomposition in matrix  
864 - *this = *(numeric.m_L);  
865 -  
866 - // Store symbolic pointer in sparse matrix object  
867 - m_symbolic = (void*)symbolic; 858 + // Insert zero rows and columns if they have been removed previously.
  859 + if (compress)
  860 + insert_zero_row_col(matrix_rows, matrix_cols);
868 861
869 // Return 862 // Return
870 return; 863 return;
@@ -1534,7 +1527,7 @@ void GSparseMatrix::remove_zero_row_col(void) @@ -1534,7 +1527,7 @@ void GSparseMatrix::remove_zero_row_col(void)
1534 1527
1535 // Dump column start array 1528 // Dump column start array
1536 #if defined(G_DEBUG_SPARSE_COMPRESSION) 1529 #if defined(G_DEBUG_SPARSE_COMPRESSION)
1537 - cout << " before compression:"; 1530 + cout << " before compression (" << m_colstart[m_cols] << "):";
1538 for (int col = 0; col <= m_cols; ++col) 1531 for (int col = 0; col <= m_cols; ++col)
1539 cout << " " << m_colstart[col]; 1532 cout << " " << m_colstart[col];
1540 cout << endl; 1533 cout << endl;
@@ -1567,7 +1560,7 @@ void GSparseMatrix::remove_zero_row_col(void) @@ -1567,7 +1560,7 @@ void GSparseMatrix::remove_zero_row_col(void)
1567 1560
1568 // Dump column start array 1561 // Dump column start array
1569 #if defined(G_DEBUG_SPARSE_COMPRESSION) 1562 #if defined(G_DEBUG_SPARSE_COMPRESSION)
1570 - cout << " after compression :"; 1563 + cout << " after compression (" << m_colstart[m_num_colsel] << ") :";
1571 for (int c_col = 0; c_col <= m_num_colsel; ++c_col) 1564 for (int c_col = 0; c_col <= m_num_colsel; ++c_col)
1572 cout << " " << m_colstart[c_col]; 1565 cout << " " << m_colstart[c_col];
1573 cout << endl; 1566 cout << endl;
@@ -1576,10 +1569,9 @@ void GSparseMatrix::remove_zero_row_col(void) @@ -1576,10 +1569,9 @@ void GSparseMatrix::remove_zero_row_col(void)
1576 // Free row mapping array 1569 // Free row mapping array
1577 delete [] row_map; 1570 delete [] row_map;
1578 1571
1579 - // Update matrix attributes  
1580 - m_rows = m_num_rowsel;  
1581 - m_cols = m_num_colsel;  
1582 - m_elements = m_colstart[m_num_colsel]; 1572 + // Update matrix size
  1573 + m_rows = m_num_rowsel;
  1574 + m_cols = m_num_colsel;
1583 1575
1584 // Return 1576 // Return
1585 return; 1577 return;
@@ -1616,7 +1608,7 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols) @@ -1616,7 +1608,7 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols)
1616 1608
1617 // Dump column start array 1609 // Dump column start array
1618 #if defined(G_DEBUG_SPARSE_COMPRESSION) 1610 #if defined(G_DEBUG_SPARSE_COMPRESSION)
1619 - cout << " before restoration:"; 1611 + cout << " before restoration (" << m_colstart[m_num_colsel] << "):";
1620 for (int c_col = 0; c_col <= m_num_colsel; ++c_col) 1612 for (int c_col = 0; c_col <= m_num_colsel; ++c_col)
1621 cout << " " << m_colstart[c_col]; 1613 cout << " " << m_colstart[c_col];
1622 cout << endl; 1614 cout << endl;
@@ -1624,7 +1616,11 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols) @@ -1624,7 +1616,11 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols)
1624 1616
1625 // If column selection exists then restore column counters 1617 // If column selection exists then restore column counters
1626 if (m_colsel != NULL) { 1618 if (m_colsel != NULL) {
  1619 +
  1620 + // Start insertion from the last original column
1627 int col_stop = cols - 1; 1621 int col_stop = cols - 1;
  1622 +
  1623 + // Loop over all compressed columns
1628 for (int c_col = m_num_colsel-1; c_col > 0; --c_col) { 1624 for (int c_col = m_num_colsel-1; c_col > 0; --c_col) {
1629 int col_start = m_colsel[c_col-1] + 1; 1625 int col_start = m_colsel[c_col-1] + 1;
1630 int col_value = m_colstart[c_col]; 1626 int col_value = m_colstart[c_col];
@@ -1632,18 +1628,24 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols) @@ -1632,18 +1628,24 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols)
1632 m_colstart[col] = col_value; 1628 m_colstart[col] = col_value;
1633 col_stop = col_start - 1; 1629 col_stop = col_start - 1;
1634 } 1630 }
  1631 +
  1632 + // Set first columns if they are not yet set
  1633 + for (int col = 0; col <= col_stop; ++col)
  1634 + m_colstart[col] = 0;
  1635 +
  1636 + // Restore the number of elements
1635 m_colstart[cols] = m_elements; 1637 m_colstart[cols] = m_elements;
1636 } 1638 }
1637 1639
1638 // Dump column start array 1640 // Dump column start array
1639 #if defined(G_DEBUG_SPARSE_COMPRESSION) 1641 #if defined(G_DEBUG_SPARSE_COMPRESSION)
1640 - cout << " after restoration :"; 1642 + cout << " after restoration (" << m_colstart[cols] << ") :";
1641 for (int col = 0; col <= cols; ++col) 1643 for (int col = 0; col <= cols; ++col)
1642 cout << " " << m_colstart[col]; 1644 cout << " " << m_colstart[col];
1643 cout << endl; 1645 cout << endl;
1644 #endif 1646 #endif
1645 1647
1646 - // Update matrix attributes 1648 + // Update matrix size
1647 m_rows = rows; 1649 m_rows = rows;
1648 m_cols = cols; 1650 m_cols = cols;
1649 1651
@@ -1652,63 +1654,6 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols) @@ -1652,63 +1654,6 @@ void GSparseMatrix::insert_zero_row_col(int rows, int cols)
1652 } 1654 }
1653 1655
1654 1656
1655 -/***************************************************************************  
1656 - * cs_transpose *  
1657 - * ----------------------------------------------------------------------- *  
1658 - * Transpose matrix. The flag 'values' allows to avoid copying the actual *  
1659 - * data values. This allows to perform a logical matrix transposition, as *  
1660 - * needed by the symbolic matrix analysis class. *  
1661 - ***************************************************************************/  
1662 -GSparseMatrix GSparseMatrix::cs_transpose(GSparseMatrix* m, int values)  
1663 -{  
1664 - // Fill pending value in input matrix  
1665 - m->fill_pending();  
1666 -  
1667 - // Declare and allocate result matrix  
1668 - GSparseMatrix result(m->m_cols, m->m_rows, m->m_elements);  
1669 -  
1670 - // Allocate and initialise workspace  
1671 - int wrk_size = m->m_rows;  
1672 - int* wrk_int = new int[wrk_size];  
1673 - if (wrk_int == NULL)  
1674 - throw mem_alloc("GSparseMatrix::cs_transpose(GSparseMatrix*, int)",  
1675 - wrk_size);  
1676 - for (int i = 0; i < wrk_size; i++)  
1677 - wrk_int[i] = 0;  
1678 -  
1679 - // Setup the number of non-zero elements in each row  
1680 - for (int p = 0; p < m->m_elements; p++)  
1681 - wrk_int[m->m_rowinx[p]]++;  
1682 -  
1683 - // Set row pointers. To use a GSparseSymbolic function we have to  
1684 - // allocate and object (but this does not take memory)  
1685 - cs_cumsum(result.m_colstart, wrk_int, m->m_rows);  
1686 -  
1687 - // Case A: Normal transponse, including assignment of values  
1688 - if (values) {  
1689 - for (int col = 0; col < m->m_cols; col++) {  
1690 - for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++) {  
1691 - int i = wrk_int[m->m_rowinx[p]]++;  
1692 - result.m_rowinx[i] = col;  
1693 - result.m_data[i] = m->m_data[p] ;  
1694 - }  
1695 - }  
1696 - }  
1697 -  
1698 - // Case B: Logical transponse, no assignment of values is performed  
1699 - else {  
1700 - for (int col = 0; col < m->m_cols; col++) {  
1701 - for (int p = m->m_colstart[col] ; p < m->m_colstart[col+1] ; p++)  
1702 - result.m_rowinx[wrk_int[m->m_rowinx[p]]++] = col;  
1703 - }  
1704 - }  
1705 -  
1706 - // Return transponse matrix  
1707 - return result;  
1708 -  
1709 -}  
1710 -  
1711 -  
1712 /*========================================================================== 1657 /*==========================================================================
1713 = = 1658 = =
1714 = GSparseMatrix friends = 1659 = GSparseMatrix friends =
@@ -1732,42 +1677,36 @@ ostream&amp; operator&lt;&lt; (ostream&amp; os, const GSparseMatrix&amp; m) @@ -1732,42 +1677,36 @@ ostream&amp; operator&lt;&lt; (ostream&amp; os, const GSparseMatrix&amp; m)
1732 m.m_num_colsel << ")" << endl; 1677 m.m_num_colsel << ")" << endl;
1733 else 1678 else
1734 os << " Number of columns .........: " << m.m_cols << endl; 1679 os << " Number of columns .........: " << m.m_cols << endl;
1735 - os << " Number of non-zero elements: " << m.m_elements << endl; 1680 + os << " Number of non-zero elements: " << m.m_colstart[m.m_cols] << " (" <<
  1681 + m.m_elements << ")" << endl;
1736 os << " Number of allocated cells .: " << m.m_alloc << endl; 1682 os << " Number of allocated cells .: " << m.m_alloc << endl;
1737 os << " Memory block size .........: " << m.m_mem_block << endl; 1683 os << " Memory block size .........: " << m.m_mem_block << endl;
1738 os << " Sparse matrix fill ........: " << m.fill() << endl; 1684 os << " Sparse matrix fill ........: " << m.fill() << endl;
1739 1685
1740 - // Loop over all matrix elements and put them into the stream (only if  
1741 - // their number is not too large)  
1742 - if (m.m_rows < 20 && m.m_cols < 20) {  
1743 - for (int row = 0; row < m.m_rows; ++row) {  
1744 - os << " ";  
1745 - for (int col = 0; col < m.m_cols; ++col) {  
1746 - os << m(row,col);  
1747 - if (col != m.m_cols-1)  
1748 - os << ", ";  
1749 - }  
1750 - if (row != m.m_rows-1)  
1751 - os << endl;  
1752 - } 1686 + // Loop over all matrix elements and put them into the stream
  1687 + for (int row = 0; row < m.m_rows; ++row) {
  1688 + os << " ";
  1689 + for (int col = 0; col < m.m_cols; ++col) {
  1690 + os << m(row,col);
  1691 + if (col != m.m_cols-1)
  1692 + os << ", ";
  1693 + }
  1694 + if (row != m.m_rows-1)
  1695 + os << endl;
1753 } 1696 }
1754 1697
1755 // If there is a row compression the show scheme 1698 // If there is a row compression the show scheme
1756 if (m.m_rowsel != NULL) { 1699 if (m.m_rowsel != NULL) {
1757 os << endl << " Row selection ..:"; 1700 os << endl << " Row selection ..:";
1758 - if (m.m_num_rowsel < 20) {  
1759 - for (int row = 0; row < m.m_num_rowsel; ++row)  
1760 - os << " " << m.m_rowsel[row];  
1761 - } 1701 + for (int row = 0; row < m.m_num_rowsel; ++row)
  1702 + os << " " << m.m_rowsel[row];
1762 } 1703 }
1763 1704
1764 // If there is a column compression the show scheme 1705 // If there is a column compression the show scheme
1765 if (m.m_colsel != NULL) { 1706 if (m.m_colsel != NULL) {
1766 os << endl << " Column selection:"; 1707 os << endl << " Column selection:";
1767 - if (m.m_num_colsel < 20) {  
1768 - for (int col = 0; col < m.m_num_colsel; ++col)  
1769 - os << " " << m.m_colsel[col];  
1770 - } 1708 + for (int col = 0; col < m.m_num_colsel; ++col)
  1709 + os << " " << m.m_colsel[col];
1771 } 1710 }
1772 1711
1773 // If there is a symbolic decomposition then put it also in the stream 1712 // If there is a symbolic decomposition then put it also in the stream
@@ -1805,6 +1744,145 @@ GSparseMatrix fabs(const GSparseMatrix&amp; m) @@ -1805,6 +1744,145 @@ GSparseMatrix fabs(const GSparseMatrix&amp; m)
1805 } 1744 }
1806 1745
1807 1746
  1747 +/***************************************************************************
  1748 + * cs_symperm *
  1749 + * ----------------------------------------------------------------------- *
  1750 + * C = A(p,p) where A and C are symmetric the upper part stored. *
  1751 + * ----------------------------------------------------------------------- *
  1752 + * Input: A Sparse matrix *
  1753 + * pinv pinv[0..n-1] *
  1754 + * Output: C Sparse matrix *
  1755 + ***************************************************************************/
  1756 +GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv)
  1757 +{
  1758 + // Declare loop variables
  1759 + int i, j, p, q, i2, j2;
  1760 +
  1761 + // Assign matrix attributes
  1762 + int n = m.m_cols;
  1763 + int* Ap = m.m_colstart;
  1764 + int* Ai = m.m_rowinx;
  1765 + double* Ax = m.m_data;
  1766 +
  1767 + // Allocate result matrix
  1768 + GSparseMatrix C(n, n, Ap[n]);
  1769 +
  1770 + // Allocate and initialise workspace
  1771 + int wrk_size = n;
  1772 + int* wrk_int = new int[wrk_size];
  1773 + if (wrk_int == NULL)
  1774 + throw mem_alloc("cs_symperm(GSparseMatrix*, const int*, int", wrk_size);
  1775 + for (i = 0; i < wrk_size; ++i)
  1776 + wrk_int[i] = 0;
  1777 +
  1778 + // Assign result matrix attributes
  1779 + int* Cp = C.m_colstart;
  1780 + int* Ci = C.m_rowinx;
  1781 + double* Cx = C.m_data;
  1782 +
  1783 + // Count entries in each column of C
  1784 + for (j = 0; j < n; j++) {
  1785 +
  1786 + // Column j of A is column j2 of C
  1787 + j2 = pinv ? pinv[j] : j;
  1788 +
  1789 + // Loop over entries in column j
  1790 + for (p = Ap[j]; p < Ap[j+1]; p++) {
  1791 + i = Ai [p];
  1792 + if (i > j) continue; // skip lower triangular part of A
  1793 + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C
  1794 + wrk_int[G_MAX(i2, j2)]++; // column count of C
  1795 + }
  1796 + }
  1797 +
  1798 + // Compute column pointers of C
  1799 + cs_cumsum(Cp, wrk_int, n);
  1800 +
  1801 + // Loop over all columns of A
  1802 + for (j = 0 ; j < n ; j++) {
  1803 +
  1804 + // Column j of A is column j2 of C
  1805 + j2 = pinv ? pinv[j] : j;
  1806 +
  1807 + // Loop over entries in column j
  1808 + for (p = Ap[j]; p < Ap[j+1]; p++) {
  1809 + i = Ai [p] ;
  1810 + if (i > j) continue; // skip lower triangular part of A
  1811 + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C
  1812 + Ci[q = wrk_int[G_MAX(i2,j2)]++] = G_MIN(i2,j2);
  1813 + if (Cx) Cx[q] = Ax[p];
  1814 + }
  1815 + }
  1816 +
  1817 + // Free workspace
  1818 + delete [] wrk_int;
  1819 +
  1820 + // Rectify the number of elements in matrix C
  1821 + C.free_elements(Cp[n], (C.m_elements-Cp[n]));
  1822 +
  1823 + // Return result
  1824 + return C;
  1825 +
  1826 +}
  1827 +
  1828 +
  1829 +/***************************************************************************
  1830 + * cs_transpose *
  1831 + * ----------------------------------------------------------------------- *
  1832 + * Transpose matrix. The flag 'values' allows to avoid copying the actual *
  1833 + * data values. This allows to perform a logical matrix transposition, as *
  1834 + * needed by the symbolic matrix analysis class. *
  1835 + * ----------------------------------------------------------------------- *
  1836 + * NOTE: This routine DOES NOT support pending elements (they have to be *
  1837 + * filled before. *
  1838 + ***************************************************************************/
  1839 +GSparseMatrix cs_transpose(const GSparseMatrix& m, int values)
  1840 +{
  1841 + // Declare and allocate result matrix
  1842 + GSparseMatrix result(m.m_cols, m.m_rows, m.m_elements);
  1843 +
  1844 + // Allocate and initialise workspace
  1845 + int wrk_size = m.m_rows;
  1846 + int* wrk_int = new int[wrk_size];
  1847 + if (wrk_int == NULL)
  1848 + throw mem_alloc("GSparseMatrix::cs_transpose(GSparseMatrix*, int)",
  1849 + wrk_size);
  1850 + for (int i = 0; i < wrk_size; i++)
  1851 + wrk_int[i] = 0;
  1852 +
  1853 + // Setup the number of non-zero elements in each row
  1854 + for (int p = 0; p < m.m_elements; p++)
  1855 + wrk_int[m.m_rowinx[p]]++;
  1856 +
  1857 + // Set row pointers. To use a GSparseSymbolic function we have to
  1858 + // allocate and object (but this does not take memory)
  1859 + cs_cumsum(result.m_colstart, wrk_int, m.m_rows);
  1860 +
  1861 + // Case A: Normal transponse, including assignment of values
  1862 + if (values) {
  1863 + for (int col = 0; col < m.m_cols; col++) {
  1864 + for (int p = m.m_colstart[col] ; p < m.m_colstart[col+1] ; p++) {
  1865 + int i = wrk_int[m.m_rowinx[p]]++;
  1866 + result.m_rowinx[i] = col;
  1867 + result.m_data[i] = m.m_data[p] ;
  1868 + }
  1869 + }
  1870 + }
  1871 +
  1872 + // Case B: Logical transponse, no assignment of values is performed
  1873 + else {
  1874 + for (int col = 0; col < m.m_cols; col++) {
  1875 + for (int p = m.m_colstart[col] ; p < m.m_colstart[col+1] ; p++)
  1876 + result.m_rowinx[wrk_int[m.m_rowinx[p]]++] = col;
  1877 + }
  1878 + }
  1879 +
  1880 + // Return transponse matrix
  1881 + return result;
  1882 +
  1883 +}
  1884 +
  1885 +
1808 /*========================================================================== 1886 /*==========================================================================
1809 = = 1887 = =
1810 = GSparseMatrix exception classes = 1888 = GSparseMatrix exception classes =
@@ -1849,4 +1927,3 @@ double cs_cumsum(int* p, int* c, int n) @@ -1849,4 +1927,3 @@ double cs_cumsum(int* p, int* c, int n)
1849 // Return cumulative sum of c[0..n-1] 1927 // Return cumulative sum of c[0..n-1]
1850 return nz2; 1928 return nz2;
1851 } 1929 }
1852 -  
src/GSparseMatrix.hpp
@@ -25,12 +25,9 @@ using namespace std; @@ -25,12 +25,9 @@ using namespace std;
25 /* __ Definitions ________________________________________________________ */ 25 /* __ Definitions ________________________________________________________ */
26 #define G_SPARSE_MATRIX_DEFAULT_MEM_BLOCK 512 // Default Memory block size 26 #define G_SPARSE_MATRIX_DEFAULT_MEM_BLOCK 512 // Default Memory block size
27 27
28 -/* __ Enumerators ________________________________________________________ */  
29 -  
30 -/* __ Structures _________________________________________________________ */  
31 -  
32 -/* __ Prototypes _________________________________________________________ */  
33 -double cs_cumsum(int* p, int* c, int n); 28 +/* __ Macros (to be moved to GammaLib general header) ____________________ */
  29 +#define G_MIN(a,b) (((a) < (b)) ? (a) : (b))
  30 +#define G_MAX(a,b) (((a) > (b)) ? (a) : (b))
34 31
35 32
36 /*************************************************************************** 33 /***************************************************************************
@@ -54,6 +51,9 @@ class GSparseMatrix : public GMatrix { @@ -54,6 +51,9 @@ class GSparseMatrix : public GMatrix {
54 friend GSparseMatrix fabs(const GSparseMatrix& m); 51 friend GSparseMatrix fabs(const GSparseMatrix& m);
55 friend GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress = 1); 52 friend GSparseMatrix cholesky_decompose(const GSparseMatrix& m, int compress = 1);
56 friend GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress = 1); 53 friend GSparseMatrix cholesky_invert(const GSparseMatrix& m, int compress = 1);
  54 + //
  55 + friend GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv);
  56 + friend GSparseMatrix cs_transpose(const GSparseMatrix& m, int values);
57 57
58 public: 58 public:
59 // Constructors and destructors (not inherited) 59 // Constructors and destructors (not inherited)
@@ -113,7 +113,6 @@ private: @@ -113,7 +113,6 @@ private:
113 void free_elements(int start, int num); 113 void free_elements(int start, int num);
114 void remove_zero_row_col(void); 114 void remove_zero_row_col(void);
115 void insert_zero_row_col(int rows, int cols); 115 void insert_zero_row_col(int rows, int cols);
116 - GSparseMatrix cs_transpose(GSparseMatrix *m, int values);  
117 116
118 // Private data members 117 // Private data members
119 int* m_rowinx; // Row-indices of all elements 118 int* m_rowinx; // Row-indices of all elements
@@ -292,4 +291,10 @@ GSparseMatrix cholesky_invert(const GSparseMatrix&amp; m, int compress) @@ -292,4 +291,10 @@ GSparseMatrix cholesky_invert(const GSparseMatrix&amp; m, int compress)
292 return result; 291 return result;
293 } 292 }
294 293
  294 +
  295 +/***************************************************************************
  296 + * Prototypes for other functions *
  297 + ***************************************************************************/
  298 +double cs_cumsum(int* p, int* c, int n);
  299 +
295 #endif /* GSPARSEMATRIX_HPP */ 300 #endif /* GSPARSEMATRIX_HPP */
src/GSparseNumeric.cpp
@@ -78,6 +78,12 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n) @@ -78,6 +78,12 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n)
78 // Execute only if object is not identical 78 // Execute only if object is not identical
79 if (this != &n) { 79 if (this != &n) {
80 80
  81 + // De-allocate only if memory has indeed been allocated
  82 + if (m_L != NULL) delete m_L;
  83 + if (m_U != NULL) delete m_U;
  84 + if (m_pinv != NULL) delete [] m_pinv;
  85 + if (m_B != NULL) delete [] m_B;
  86 +
81 // Initialise private members for clean destruction 87 // Initialise private members for clean destruction
82 m_L = NULL; 88 m_L = NULL;
83 m_U = NULL; 89 m_U = NULL;
@@ -87,15 +93,23 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n) @@ -87,15 +93,23 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n)
87 m_n_B = 0; 93 m_n_B = 0;
88 94
89 // Copy m_L if it exists 95 // Copy m_L if it exists
90 - if (n.m_L != NULL)  
91 - m_L = new GSparseMatrix(*n.m_L); 96 + if (n.m_L != NULL) {
  97 + m_L = new GSparseMatrix(*n.m_L);
  98 + if (m_L == NULL)
  99 + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)",
  100 + 1);
  101 + }
92 102
93 // Copy m_U if it exists 103 // Copy m_U if it exists
94 - if (n.m_U != NULL)  
95 - m_U = new GSparseMatrix(*n.m_U); 104 + if (n.m_U != NULL) {
  105 + m_U = new GSparseMatrix(*n.m_U);
  106 + if (m_U == NULL)
  107 + throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)",
  108 + 1);
  109 + }
96 110
97 // Copy m_pinv array if it exists 111 // Copy m_pinv array if it exists
98 - if (n.m_pinv != NULL) { 112 + if (n.m_pinv != NULL && n.m_n_pinv > 0) {
99 m_pinv = new int[n.m_n_pinv]; 113 m_pinv = new int[n.m_n_pinv];
100 if (m_pinv == NULL) 114 if (m_pinv == NULL)
101 throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", 115 throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)",
@@ -106,7 +120,7 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n) @@ -106,7 +120,7 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n)
106 } 120 }
107 121
108 // Copy m_B array if it exists 122 // Copy m_B array if it exists
109 - if (n.m_B != NULL) { 123 + if (n.m_B != NULL && n.m_n_B > 0) {
110 m_B = new double[n.m_n_B]; 124 m_B = new double[n.m_n_B];
111 if (m_B == NULL) 125 if (m_B == NULL)
112 throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)", 126 throw mem_alloc("GSparseNumeric::operator= (const GSparseNumeric&)",
@@ -138,9 +152,23 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n) @@ -138,9 +152,23 @@ GSparseNumeric&amp; GSparseNumeric::operator= (const GSparseNumeric&amp; n)
138 * Input: A Sparse matrix * 152 * Input: A Sparse matrix *
139 * S Symbolic analysis of sparse matrix * 153 * S Symbolic analysis of sparse matrix *
140 ***************************************************************************/ 154 ***************************************************************************/
141 -void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix& A, 155 +void GSparseNumeric::cholesky_numeric_analysis(const GSparseMatrix& A,
142 const GSparseSymbolic& S) 156 const GSparseSymbolic& S)
143 { 157 {
  158 + // De-allocate memory that has indeed been previously allocated
  159 + if (m_L != NULL) delete m_L;
  160 + if (m_U != NULL) delete m_U;
  161 + if (m_pinv != NULL) delete [] m_pinv;
  162 + if (m_B != NULL) delete [] m_B;
  163 +
  164 + // Initialise members
  165 + m_L = NULL;
  166 + m_U = NULL;
  167 + m_pinv = NULL;
  168 + m_B = NULL;
  169 + m_n_pinv = 0;
  170 + m_n_B = 0;
  171 +
144 // Return if arrays in the symbolic analysis have not been allocated 172 // Return if arrays in the symbolic analysis have not been allocated
145 if (!S.m_cp || !S.m_parent) return; 173 if (!S.m_cp || !S.m_parent) return;
146 174
@@ -173,7 +201,7 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A, @@ -173,7 +201,7 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A,
173 int* parent = S.m_parent; 201 int* parent = S.m_parent;
174 202
175 // Assign C = A(p,p) where A and C are symmetric and the upper part stored 203 // Assign C = A(p,p) where A and C are symmetric and the upper part stored
176 - GSparseMatrix C = (pinv) ? S.cs_symperm(&A, pinv, 1) : (A); 204 + GSparseMatrix C = (pinv) ? cs_symperm(A, pinv) : (A);
177 205
178 // Assign workspace pointer 206 // Assign workspace pointer
179 int* c = wrk_int; 207 int* c = wrk_int;
@@ -186,7 +214,7 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A, @@ -186,7 +214,7 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A,
186 double* Cx = C.m_data; 214 double* Cx = C.m_data;
187 215
188 // Allocate L matrix 216 // Allocate L matrix
189 - m_L = new GSparseMatrix(n,n,cp[n]); 217 + m_L = new GSparseMatrix(n, n, cp[n]);
190 if (m_L == NULL) 218 if (m_L == NULL)
191 throw mem_alloc( 219 throw mem_alloc(
192 "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)", 220 "GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&, const GSparseSymbolic&)",
@@ -204,7 +232,8 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A, @@ -204,7 +232,8 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A,
204 // Compute L(:,k) for L*L' = C 232 // Compute L(:,k) for L*L' = C
205 for (k = 0; k < n; k++) { 233 for (k = 0; k < n; k++) {
206 234
207 - // Nonzero pattern of L(k,:) 235 + // Nonzero pattern of L(k,:).
  236 + // Returns -1 if parent = NULL, s = NULL or c = NULL
208 top = cs_ereach(&C, k, parent, s, c); // find pattern of L(k,:) 237 top = cs_ereach(&C, k, parent, s, c); // find pattern of L(k,:)
209 x[k] = 0; // x (0:k) is now zero 238 x[k] = 0; // x (0:k) is now zero
210 239
@@ -222,14 +251,14 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A, @@ -222,14 +251,14 @@ void GSparseNumeric::cholesky_numeric_analysis(GSparseMatrix&amp; A,
222 251
223 // Triangular solve: Solve L(0:k-1,0:k-1) * x = C(:,k) 252 // Triangular solve: Solve L(0:k-1,0:k-1) * x = C(:,k)
224 for ( ; top < n; top++) { 253 for ( ; top < n; top++) {
225 - i = s[top]; // s [top..n-1] is pattern of L(k,:)  
226 - lki = x[i]/Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i)  
227 - x[i] = 0; // clear x for k+1st iteration 254 + i = s[top]; // s [top..n-1] is pattern of L(k,:)
  255 + lki = x[i]/Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i)
  256 + x[i] = 0; // clear x for k+1st iteration
228 for (p = Lp[i]+1; p < c[i]; p++) 257 for (p = Lp[i]+1; p < c[i]; p++)
229 x[Li[p]] -= Lx[p] * lki; 258 x[Li[p]] -= Lx[p] * lki;
230 - d -= lki * lki; // d = d - L(k,i)*L(k,i)  
231 - p = c [i]++ ;  
232 - Li[p] = k; // store L(k,i) in column i 259 + d -= lki * lki; // d = d - L(k,i)*L(k,i)
  260 + p = c[i]++;
  261 + Li[p] = k; // store L(k,i) in column i
233 Lx[p] = lki; 262 Lx[p] = lki;
234 } 263 }
235 264
@@ -319,7 +348,7 @@ int GSparseNumeric::cs_ereach(const GSparseMatrix* A, int k, @@ -319,7 +348,7 @@ int GSparseNumeric::cs_ereach(const GSparseMatrix* A, int k,
319 CS_MARK(w, k); 348 CS_MARK(w, k);
320 349
321 // Return index top, where s[top..n-1] contains pattern of L(k,:) 350 // Return index top, where s[top..n-1] contains pattern of L(k,:)
322 - return (top); 351 + return top;
323 } 352 }
324 353
325 354
src/GSparseNumeric.hpp
@@ -51,7 +51,7 @@ public: @@ -51,7 +51,7 @@ public:
51 GSparseNumeric& operator= (const GSparseNumeric& n); 51 GSparseNumeric& operator= (const GSparseNumeric& n);
52 52
53 // Functions 53 // Functions
54 - void cholesky_numeric_analysis(GSparseMatrix& m, const GSparseSymbolic& s); 54 + void cholesky_numeric_analysis(const GSparseMatrix& m, const GSparseSymbolic& s);
55 55
56 private: 56 private:
57 // Functions 57 // Functions
src/GSparseSymbolic.cpp
@@ -24,6 +24,7 @@ using namespace std; @@ -24,6 +24,7 @@ using namespace std;
24 24
25 /* __ Definitions ________________________________________________________ */ 25 /* __ Definitions ________________________________________________________ */
26 //#define G_DEBUG_SPARSE_SYM_AMD_ORDERING // Debug AMD ordering 26 //#define G_DEBUG_SPARSE_SYM_AMD_ORDERING // Debug AMD ordering
  27 +//#define G_DEBUG_SPARSE_CHOLESKY // Analyse Cholesky decomposition
27 28
28 29
29 /*========================================================================== 30 /*==========================================================================
@@ -63,11 +64,11 @@ GSparseSymbolic::GSparseSymbolic() @@ -63,11 +64,11 @@ GSparseSymbolic::GSparseSymbolic()
63 GSparseSymbolic::~GSparseSymbolic() 64 GSparseSymbolic::~GSparseSymbolic()
64 { 65 {
65 // De-allocate only if memory has indeed been allocated 66 // De-allocate only if memory has indeed been allocated
66 - if (m_pinv != NULL) delete[] m_pinv;  
67 - if (m_q != NULL) delete[] m_q;  
68 - if (m_parent != NULL) delete[] m_parent;  
69 - if (m_cp != NULL) delete[] m_cp;  
70 - if (m_leftmost != NULL) delete[] m_leftmost; 67 + if (m_pinv != NULL) delete [] m_pinv;
  68 + if (m_q != NULL) delete [] m_q;
  69 + if (m_parent != NULL) delete [] m_parent;
  70 + if (m_cp != NULL) delete [] m_cp;
  71 + if (m_leftmost != NULL) delete [] m_leftmost;
71 72
72 // Return 73 // Return
73 return; 74 return;
@@ -88,6 +89,13 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -88,6 +89,13 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
88 // Execute only if object is not identical 89 // Execute only if object is not identical
89 if (this != &s) { 90 if (this != &s) {
90 91
  92 + // De-allocate only if memory has indeed been allocated
  93 + if (m_pinv != NULL) delete [] m_pinv;
  94 + if (m_q != NULL) delete [] m_q;
  95 + if (m_parent != NULL) delete [] m_parent;
  96 + if (m_cp != NULL) delete [] m_cp;
  97 + if (m_leftmost != NULL) delete [] m_leftmost;
  98 +
91 // Initialise private members for clean destruction 99 // Initialise private members for clean destruction
92 m_n_pinv = 0; 100 m_n_pinv = 0;
93 m_n_q = 0; 101 m_n_q = 0;
@@ -109,7 +117,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -109,7 +117,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
109 m_unz = s.m_unz; 117 m_unz = s.m_unz;
110 118
111 // Copy m_pinv array if it exists 119 // Copy m_pinv array if it exists
112 - if (s.m_pinv != NULL) { 120 + if (s.m_pinv != NULL && s.m_n_pinv > 0) {
113 m_pinv = new int[s.m_n_pinv]; 121 m_pinv = new int[s.m_n_pinv];
114 if (m_pinv == NULL) 122 if (m_pinv == NULL)
115 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", 123 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)",
@@ -120,7 +128,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -120,7 +128,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
120 } 128 }
121 129
122 // Copy m_q array if it exists 130 // Copy m_q array if it exists
123 - if (s.m_q != NULL) { 131 + if (s.m_q != NULL && s.m_n_q > 0) {
124 m_q = new int[s.m_n_q]; 132 m_q = new int[s.m_n_q];
125 if (m_q == NULL) 133 if (m_q == NULL)
126 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", 134 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)",
@@ -131,7 +139,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -131,7 +139,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
131 } 139 }
132 140
133 // Copy m_parent array if it exists 141 // Copy m_parent array if it exists
134 - if (s.m_parent != NULL) { 142 + if (s.m_parent != NULL && s.m_n_parent > 0) {
135 m_parent = new int[s.m_n_parent]; 143 m_parent = new int[s.m_n_parent];
136 if (m_parent == NULL) 144 if (m_parent == NULL)
137 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", 145 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)",
@@ -142,7 +150,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -142,7 +150,7 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
142 } 150 }
143 151
144 // Copy m_cp array if it exists 152 // Copy m_cp array if it exists
145 - if (s.m_cp != NULL) { 153 + if (s.m_cp != NULL && s.m_n_cp > 0) {
146 m_cp = new int[s.m_n_cp]; 154 m_cp = new int[s.m_n_cp];
147 if (m_cp == NULL) 155 if (m_cp == NULL)
148 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", 156 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)",
@@ -153,20 +161,20 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -153,20 +161,20 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
153 } 161 }
154 162
155 // Copy m_leftmost array if it exists 163 // Copy m_leftmost array if it exists
156 - if (s.m_leftmost != NULL) { 164 + if (s.m_leftmost != NULL && s.m_n_leftmost > 0) {
157 m_leftmost = new int[s.m_n_leftmost]; 165 m_leftmost = new int[s.m_n_leftmost];
158 if (m_leftmost == NULL) 166 if (m_leftmost == NULL)
159 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)", 167 throw mem_alloc("GSparseSymbolic::operator= (const GSparseSymbolic&)",
160 s.m_n_leftmost); 168 s.m_n_leftmost);
161 for (int i = 0; i < s.m_n_leftmost; ++i) 169 for (int i = 0; i < s.m_n_leftmost; ++i)
162 m_leftmost[i] = s.m_leftmost[i]; 170 m_leftmost[i] = s.m_leftmost[i];
163 - m_leftmost = s.m_leftmost; 171 + m_n_leftmost = s.m_n_leftmost;
164 } 172 }
165 173
166 } // endif: object was not identical 174 } // endif: object was not identical
167 175
168 // Return 176 // Return
169 - return (*this); 177 + return *this;
170 } 178 }
171 179
172 180
@@ -186,44 +194,120 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s) @@ -186,44 +194,120 @@ GSparseSymbolic&amp; GSparseSymbolic::operator= (const GSparseSymbolic&amp; s)
186 * 1: Cholesky decomposition * 194 * 1: Cholesky decomposition *
187 * m Sparse matrix * 195 * m Sparse matrix *
188 ***************************************************************************/ 196 ***************************************************************************/
189 -void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix& m) 197 +void GSparseSymbolic::cholesky_symbolic_analysis(int order,
  198 + const GSparseMatrix& m)
190 { 199 {
  200 + // Debug
  201 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  202 + cout << endl << "GSparseSymbolic::cholesky_symbolic_analysis entered" << endl;
  203 + cout << " order ......................: " << order << endl;
  204 + cout << " number of rows .............: " << m.m_rows << endl;
  205 + cout << " number of columns ..........: " << m.m_cols << endl;
  206 + cout << " number of non-zero elements : " << m.m_elements << endl;
  207 + #endif
  208 +
  209 + // De-allocate memory that has indeed been previously allocated
  210 + if (m_pinv != NULL) delete [] m_pinv;
  211 + if (m_q != NULL) delete [] m_q;
  212 + if (m_parent != NULL) delete [] m_parent;
  213 + if (m_cp != NULL) delete [] m_cp;
  214 + if (m_leftmost != NULL) delete [] m_leftmost;
  215 +
  216 + // Initialise members
  217 + m_n_pinv = 0;
  218 + m_n_q = 0;
  219 + m_n_parent = 0;
  220 + m_n_cp = 0;
  221 + m_n_leftmost = 0;
  222 + m_pinv = NULL;
  223 + m_q = NULL;
  224 + m_parent = NULL;
  225 + m_cp = NULL;
  226 + m_leftmost = NULL;
  227 + m_m2 = 0;
  228 + m_lnz = 0.0;
  229 + m_unz = 0.0;
  230 +
191 // Check if order type is valid 231 // Check if order type is valid
192 if (order < 0 || order > 1) 232 if (order < 0 || order > 1)
193 - throw invalid_order("GSparseSymbolic::cholesky_symbolic_analysis(int, GSparseMatrix*)",  
194 - order, 0, 1); 233 + throw invalid_order(
  234 + "GSparseSymbolic::cholesky_symbolic_analysis(int, GSparseMatrix*)",
  235 + order, 0, 1);
195 236
196 - // Fill pending element  
197 - m.fill_pending();  
198 -  
199 // Assign input matrix attributes 237 // Assign input matrix attributes
200 int n = m.m_cols; 238 int n = m.m_cols;
201 239
202 // P = amd(A+A'), or natural 240 // P = amd(A+A'), or natural
203 int* P = cs_amd(order, &m); 241 int* P = cs_amd(order, &m);
  242 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  243 + cout << " AMD ordering permutation (" << P << ")" << endl;
  244 + if (P != NULL) {
  245 + for (int i = 0; i < n; ++i)
  246 + cout << " " << P[i];
  247 + cout << endl;
  248 + }
  249 + #endif
204 250
205 - // Find inverse permutation and store it in class member 'm_pinv' 251 + // Find inverse permutation and store it in class member 'm_pinv'.
  252 + // Note that if P = NULL or n < 1 this function returns NULL.
206 m_pinv = cs_pinv(P, n); 253 m_pinv = cs_pinv(P, n);
207 m_n_pinv = n; 254 m_n_pinv = n;
  255 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  256 + cout << " Inverse permutation (" << m_pinv << ")" << endl;
  257 + if (m_pinv != NULL) {
  258 + for (int i = 0; i < n; ++i)
  259 + cout << " " << m_pinv[i];
  260 + cout << endl;
  261 + }
  262 + #endif
208 263
209 // Delete workspace 264 // Delete workspace
210 - delete [] P; 265 + if (P != NULL) delete [] P;
211 266
212 // C = spones(triu(A(P,P))) 267 // C = spones(triu(A(P,P)))
213 - GSparseMatrix C = cs_symperm(&m, m_pinv, 0); 268 + GSparseMatrix C = cs_symperm(m, m_pinv);
  269 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  270 + cout << " C = spones(triu(A(P,P))) " << C << endl;
  271 + #endif
214 272
215 // Find etree of C and store it in class member 'm_parent' 273 // Find etree of C and store it in class member 'm_parent'
216 m_parent = cs_etree(&C, 0); 274 m_parent = cs_etree(&C, 0);
217 m_n_parent = n; 275 m_n_parent = n;
  276 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  277 + cout << " Elimination tree (" << m_parent << ")" << endl;
  278 + if (m_parent != NULL) {
  279 + for (int i = 0; i < n; ++i)
  280 + cout << " " << m_parent[i];
  281 + cout << endl;
  282 + }
  283 + #endif
218 284
219 // Post order the etree 285 // Post order the etree
  286 + // Note that if m_parent = NULL or n < 1 this function returns NULL.
220 int* post = cs_post(m_parent, n); 287 int* post = cs_post(m_parent, n);
  288 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  289 + cout << " Post ordered elimination tree (" << post << ")" << endl;
  290 + if (post != NULL) {
  291 + for (int i = 0; i < n; ++i)
  292 + cout << " " << post[i];
  293 + cout << endl;
  294 + }
  295 + #endif
221 296
222 // Find column counts of chol(C) 297 // Find column counts of chol(C)
  298 + // Note that if m_parent = NULL or post = NULL this function returns NULL.
223 int* c = cs_counts(&C, m_parent, post, 0); 299 int* c = cs_counts(&C, m_parent, post, 0);
  300 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  301 + cout << " Column counts (" << c << ")" << endl;
  302 + if (c != NULL) {
  303 + for (int i = 0; i < n; ++i)
  304 + cout << " " << c[i];
  305 + cout << endl;
  306 + }
  307 + #endif
224 308
225 // Delete workspace 309 // Delete workspace
226 - delete [] post; 310 + if (post != NULL) delete [] post;
227 311
228 // Allocate column pointers for Cholesky decomposition 312 // Allocate column pointers for Cholesky decomposition
229 m_n_cp = n+1; 313 m_n_cp = n+1;
@@ -233,11 +317,52 @@ void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix&amp; m) @@ -233,11 +317,52 @@ void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix&amp; m)
233 317
234 // Find column pointers for L 318 // Find column pointers for L
235 m_unz = m_lnz = cs_cumsum(m_cp, c, n); 319 m_unz = m_lnz = cs_cumsum(m_cp, c, n);
  320 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  321 + cout << " Column pointers for L (" << m_cp << ")" << endl;
  322 + if (m_cp != NULL) {
  323 + for (int i = 0; i < m_n_cp; ++i)
  324 + cout << " " << m_cp[i];
  325 + cout << endl;
  326 + }
  327 + cout << " Number of non-zero elements in L: " << m_lnz << endl;
  328 + #endif
236 329
237 // Delete workspace 330 // Delete workspace
238 - delete [] c; 331 + if (c != NULL) delete [] c;
  332 +
  333 + // Delete symbolic analysis if it is not valid
  334 + if (m_lnz < 0) {
  335 +
  336 + // De-allocate memory that has indeed been previously allocated
  337 + if (m_pinv != NULL) delete [] m_pinv;
  338 + if (m_q != NULL) delete [] m_q;
  339 + if (m_parent != NULL) delete [] m_parent;
  340 + if (m_cp != NULL) delete [] m_cp;
  341 + if (m_leftmost != NULL) delete [] m_leftmost;
239 342
240 -// return ((S->lnz >= 0) ? S : cs_sfree (S)) ; 343 + // Initialise members
  344 + m_n_pinv = 0;
  345 + m_n_q = 0;
  346 + m_n_parent = 0;
  347 + m_n_cp = 0;
  348 + m_n_leftmost = 0;
  349 + m_pinv = NULL;
  350 + m_q = NULL;
  351 + m_parent = NULL;
  352 + m_cp = NULL;
  353 + m_leftmost = NULL;
  354 + m_m2 = 0;
  355 + m_lnz = 0.0;
  356 + m_unz = 0.0;
  357 + }
  358 +
  359 + // Debug
  360 + #if defined(G_DEBUG_SPARSE_CHOLESKY)
  361 + cout << "GSparseSymbolic::cholesky_symbolic_analysis finished" << endl;
  362 + #endif
  363 +
  364 + // Return
  365 + return;
241 } 366 }
242 367
243 368
@@ -261,11 +386,11 @@ void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix&amp; m) @@ -261,11 +386,11 @@ void GSparseSymbolic::cholesky_symbolic_analysis(int order, GSparseMatrix&amp; m)
261 * A Sparse matrix * 386 * A Sparse matrix *
262 * Output: p[0..n] integer array of n+1 elements * 387 * Output: p[0..n] integer array of n+1 elements *
263 ***************************************************************************/ 388 ***************************************************************************/
264 -int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) 389 +int* GSparseSymbolic::cs_amd(int order, const GSparseMatrix* A)
265 { 390 {
266 // Throw exception if order is not a decomposition 391 // Throw exception if order is not a decomposition
267 if (order < 0 || order > 3) 392 if (order < 0 || order > 3)
268 - throw invalid_order("GSparseSymbolic::cs_amd(int, GSparseMatrix*)", 393 + throw invalid_order("GSparseSymbolic::cs_amd(int, const GSparseMatrix*)",
269 order, 0, 3); 394 order, 0, 3);
270 395
271 // Debug 396 // Debug
@@ -305,17 +430,20 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -305,17 +430,20 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
305 GSparseMatrix C(m,n); 430 GSparseMatrix C(m,n);
306 431
307 // Get (logical) transpose of A: AT = A' 432 // Get (logical) transpose of A: AT = A'
308 - GSparseMatrix AT = A->cs_transpose(A,0); 433 +// NOTE: WE ONLY NEED THE LOGICAL TRANSPOSE HERE. HOWEVER, WE HAVE NO
  434 +// LOGICAL ADDITION SO FAR ...
  435 +// GSparseMatrix AT = cs_transpose(*A, 0);
  436 + GSparseMatrix AT = cs_transpose(*A, 1);
309 437
310 // Find dense threshold 438 // Find dense threshold
311 dense = (int)CS_MAX(16, 10 * sqrt((double)n)); 439 dense = (int)CS_MAX(16, 10 * sqrt((double)n));
312 dense = CS_MIN(n-2, dense); 440 dense = CS_MIN(n-2, dense);
313 441
314 // Case A: Cholesky decomposition of a symmetric matrix: C = A + A' 442 // Case A: Cholesky decomposition of a symmetric matrix: C = A + A'
315 - if (order == 1 && n == m) { 443 + if (order == 1 && n == m)
  444 +// NOTE: HERE WE ONLY NEED LOGICAL ADDITION
316 // C = cs_add (A, AT, 0, 0); 445 // C = cs_add (A, AT, 0, 0);
317 C = *A + AT; 446 C = *A + AT;
318 - }  
319 447
320 // Case B: LU decomposition: C = A' * A with no dense rows 448 // Case B: LU decomposition: C = A' * A with no dense rows
321 else if (order == 2) { 449 else if (order == 2) {
@@ -337,24 +465,35 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -337,24 +465,35 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
337 ATp[m] = p2; 465 ATp[m] = p2;
338 466
339 // Get (logical) transpose of AT: A2 = AT' 467 // Get (logical) transpose of AT: A2 = AT'
340 - GSparseMatrix A2 = AT.cs_transpose(&AT,0); 468 +// NOTE: WE ONLY NEED THE LOGICAL TRANSPOSE HERE. HOWEVER, WE HAVE NO
  469 +// LOGICAL MULTIPLICATION SO FAR ...
  470 +// GSparseMatrix A2 = cs_transpose(AT, 0);
  471 + GSparseMatrix A2 = cs_transpose(AT, 1);
341 472
342 // C = A' * A with no dense rows 473 // C = A' * A with no dense rows
  474 +// NOTE: cs_multiply NOT YET IMPLEMENTED
343 // C = A2 ? cs_multiply(AT, A2) : NULL; 475 // C = A2 ? cs_multiply(AT, A2) : NULL;
344 C = AT * A2; 476 C = AT * A2;
345 } 477 }
346 478
347 // Case C: QR decomposition: C = A' * A 479 // Case C: QR decomposition: C = A' * A
348 - else { 480 + else
  481 +// NOTE: cs_multiply NOT YET IMPLEMENTED
349 // C = cs_multiply(AT, A); 482 // C = cs_multiply(AT, A);
350 C = AT * *A; 483 C = AT * *A;
351 - }  
352 -  
353 - // Stop in case of an error  
354 -// if (!C) return (NULL) ;  
355 484
  485 + // Debug
  486 + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
  487 + cout << " Matrix C " << C << endl;
  488 + #endif
  489 +
356 // Drop diagonal entries from C 490 // Drop diagonal entries from C
357 - cs_fkeep(&C, &cs_diag, NULL); 491 + int cnz_diag = cs_fkeep(&C, &cs_diag, NULL);
  492 +
  493 + // Debug
  494 + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
  495 + cout << " Dropped diagonal entries from matrix C " << C << endl;
  496 + #endif
358 497
359 // Assign C matrix attributes 498 // Assign C matrix attributes
360 int* Cp = C.m_colstart; 499 int* Cp = C.m_colstart;
@@ -372,10 +511,19 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -372,10 +511,19 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
372 throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", wrk_size); 511 throw mem_alloc("GSparseSymbolic::cs_amd (int, GSparseMatrix*)", wrk_size);
373 512
374 // Add elbow room to C 513 // Add elbow room to C
375 -// t = cnz + cnz/5 + 2*n;  
376 -// if (!P || !W || !cs_sprealloc (C, t)) return (cs_idone (P, C, W, 0)) ;  
377 - int t = cnz/5 + 2*n;  
378 - C.alloc_elements(cnz, t); 514 + int elbow_room = cnz/5 + 2*n; // Request additional # of elements
  515 + C.alloc_elements(cnz, elbow_room); // Appand elements
  516 + int nzmax = C.m_elements; // Save the maximum # of entries for garbage coll.
  517 + C.m_elements -= elbow_room; // Reverse element increase of alloc_elements
  518 +
  519 + // (Re-)assign C matrix attributes
  520 + Cp = C.m_colstart;
  521 + int* Ci = C.m_rowinx;
  522 +
  523 + // Debug
  524 + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
  525 + cout << " Added elbow room to matrix C " << C << endl;
  526 + #endif
379 527
380 // Set workspace pointers 528 // Set workspace pointers
381 int* len = wrk_int; 529 int* len = wrk_int;
@@ -386,7 +534,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -386,7 +534,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
386 int* degree = wrk_int + 5*(n+1); 534 int* degree = wrk_int + 5*(n+1);
387 int* w = wrk_int + 6*(n+1); 535 int* w = wrk_int + 6*(n+1);
388 int* hhead = wrk_int + 7*(n+1); 536 int* hhead = wrk_int + 7*(n+1);
389 - int* last = P; // use P as workspace for last 537 + int* last = P; // use P as workspace for last
390 538
391 539
392 // ====================================================================== 540 // ======================================================================
@@ -398,35 +546,38 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -398,35 +546,38 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
398 cout << " Step 2: Initialize quotient graph" << endl; 546 cout << " Step 2: Initialize quotient graph" << endl;
399 #endif 547 #endif
400 548
401 - // (Re-)assign C matrix attributes  
402 - int nzmax = C.m_elements; // Maximum number of entries  
403 - Cp = C.m_colstart;  
404 - int* Ci = C.m_rowinx;  
405 -  
406 // Setup array that contains for each column the number of non-zero elements 549 // Setup array that contains for each column the number of non-zero elements
407 for (k = 0 ; k < n ; k++) 550 for (k = 0 ; k < n ; k++)
408 len[k] = Cp[k+1] - Cp[k]; 551 len[k] = Cp[k+1] - Cp[k];
409 len[n] = 0; 552 len[n] = 0;
  553 +
  554 + // Debug
  555 + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
  556 + cout << " Non-zero elements per column: ";
  557 + for (k = 0 ; k <= n ; k++)
  558 + cout << " " << len[k];
  559 + cout << endl;
  560 + #endif
410 561
411 - // Loop over all columns 562 + // Loop over all nodes (i.e. matrix columns)
412 for (i = 0 ; i <= n ; i++) { 563 for (i = 0 ; i <= n ; i++) {
413 - head[i] = -1; // degree list i is empty 564 + head[i] = -1; // degree list i is empty
414 last[i] = -1; 565 last[i] = -1;
415 next[i] = -1; 566 next[i] = -1;
416 - hhead[i] = -1; // hash list i is empty  
417 - nv[i] = 1; // node i is just one node  
418 - w[i] = 1; // node i is alive  
419 - elen[i] = 0; // Ek of node i is empty  
420 - degree[i] = len[i]; // degree of node i 567 + hhead[i] = -1; // hash list i is empty
  568 + nv[i] = 1; // node i is just one node
  569 + w[i] = 1; // node i is alive
  570 + elen[i] = 0; // Ek of node i is empty
  571 + degree[i] = len[i]; // degree of node i
421 } 572 }
422 573
423 // Clear w 574 // Clear w
424 mark = cs_wclear(0, 0, w, n); 575 mark = cs_wclear(0, 0, w, n);
425 576
426 // End-point initialisations 577 // End-point initialisations
427 - elen[n] = -2; // n is a dead element  
428 - Cp[n] = -1; // n is a root of assembly tree  
429 - w[n] = 0; // n is a dead element 578 + elen[n] = -2; // n is a dead element
  579 + Cp[n] = -1; // n is a root of assembly tree
  580 + w[n] = 0; // n is a dead element
430 581
431 582
432 // ====================================================================== 583 // ======================================================================
@@ -438,7 +589,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -438,7 +589,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
438 cout << " Step 3: Initialize degree lists" << endl; 589 cout << " Step 3: Initialize degree lists" << endl;
439 #endif 590 #endif
440 591
441 - // Loop over all columns 592 + // Loop over all nodes
442 for (i = 0 ; i < n ; i++) { 593 for (i = 0 ; i < n ; i++) {
443 594
444 // Get degree of node 595 // Get degree of node
@@ -446,25 +597,25 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -446,25 +597,25 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
446 597
447 // Case A: Node i is empty 598 // Case A: Node i is empty
448 if (d == 0) { 599 if (d == 0) {
449 - elen[i] = -2; // element i is dead 600 + elen[i] = -2; // element i is dead
450 nel++ ; 601 nel++ ;
451 - Cp[i] = -1; // i is a root of assembly tree  
452 - w[i] = 0; // i is a dead element 602 + Cp[i] = -1; // i is a root of assembly tree
  603 + w[i] = 0; // i is a dead element
453 } 604 }
454 605
455 // Case B: Node is dense 606 // Case B: Node is dense
456 else if (d > dense) { 607 else if (d > dense) {
457 - nv[i] = 0; // absorb i into element n  
458 - elen[i] = -1; // node i is dead  
459 - nel++ ;  
460 - Cp[i] = CS_FLIP(n);  
461 - nv[n]++ ; 608 + nv[i] = 0; // absorb i into element n
  609 + elen[i] = -1; // node i is dead
  610 + nel++;
  611 + Cp[i] = CS_FLIP(n);
  612 + nv[n]++;
462 } 613 }
463 614
464 // Case C: Node is sparse 615 // Case C: Node is sparse
465 else { 616 else {
466 if (head[d] != -1) last[head[d]] = i; 617 if (head[d] != -1) last[head[d]] = i;
467 - next[i] = head[d]; // put node i in degree list d 618 + next[i] = head[d]; // put node i in degree list d
468 head[d] = i; 619 head[d] = i;
469 } 620 }
470 } // endfor: looped over all columns 621 } // endfor: looped over all columns
@@ -485,65 +636,65 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -485,65 +636,65 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
485 // Select node of minimum approximate degree 636 // Select node of minimum approximate degree
486 for (k = -1; mindeg < n && (k = head [mindeg]) == -1; mindeg++) ; 637 for (k = -1; mindeg < n && (k = head [mindeg]) == -1; mindeg++) ;
487 if (next[k] != -1) last [next[k]] = -1; 638 if (next[k] != -1) last [next[k]] = -1;
488 - head[mindeg] = next[k]; // remove k from degree list  
489 - elenk = elen[k]; // elenk = |Ek|  
490 - nvk = nv[k]; // # of nodes k represents  
491 - nel += nvk; // nv[k] nodes of A eliminated 639 + head[mindeg] = next[k]; // remove k from degree list
  640 + elenk = elen[k]; // elenk = |Ek|
  641 + nvk = nv[k]; // # of nodes k represents
  642 + nel += nvk; // nv[k] nodes of A eliminated
492 643
493 - // Garbage collection 644 + // Garbage collection. This frees the elbow rooms in matrix C
494 if (elenk > 0 && cnz + mindeg >= nzmax) { 645 if (elenk > 0 && cnz + mindeg >= nzmax) {
495 646
496 // Loop over all columns 647 // Loop over all columns
497 - for (j = 0 ; j < n ; j++) { 648 + for (j = 0; j < n; j++) {
498 // If j is a live node or element, then ... 649 // If j is a live node or element, then ...
499 if ((p = Cp[j]) >= 0) { 650 if ((p = Cp[j]) >= 0) {
500 - Cp[j] = Ci[p]; // save first entry of object  
501 - Ci[p] = CS_FLIP(j); // first entry is now CS_FLIP(j) 651 + Cp[j] = Ci[p]; // save first entry of object
  652 + Ci[p] = CS_FLIP(j); // first entry is now CS_FLIP(j)
502 } 653 }
503 } 654 }
504 655
505 // Scan all memory 656 // Scan all memory
506 - for (q = 0, p = 0; p < cnz ; ) { 657 + for (q = 0, p = 0; p < cnz; ) {
507 // If we found object j, then ... 658 // If we found object j, then ...
508 if ((j = CS_FLIP(Ci[p++])) >= 0) { 659 if ((j = CS_FLIP(Ci[p++])) >= 0) {
509 - Ci[q] = Cp[j]; // restore first entry of object  
510 - Cp[j] = q++; // new pointer to object j  
511 - for (k3 = 0; k3 < len [j]-1; k3++) 660 + Ci[q] = Cp[j]; // restore first entry of object
  661 + Cp[j] = q++; // new pointer to object j
  662 + for (k3 = 0; k3 < len[j]-1; k3++)
512 Ci[q++] = Ci[p++]; 663 Ci[q++] = Ci[p++];
513 } 664 }
514 } 665 }
515 - cnz = q; // Ci[cnz...nzmax-1] now free 666 + cnz = q; // Ci[cnz...nzmax-1] now free
516 667
517 } // endif: garbage collection done 668 } // endif: garbage collection done
518 669
519 // Construct new element ---------------------------------------- */ 670 // Construct new element ---------------------------------------- */
520 dk = 0; 671 dk = 0;
521 - nv[k] = -nvk; // flag k as in Lk 672 + nv[k] = -nvk; // flag k as in Lk
522 p = Cp[k]; 673 p = Cp[k];
523 - pk1 = (elenk == 0) ? p : cnz; // do in place if elen[k] == 0 674 + pk1 = (elenk == 0) ? p : cnz; // do in place if elen[k] == 0
524 pk2 = pk1; 675 pk2 = pk1;
525 for (k1 = 1; k1 <= elenk + 1; k1++) { 676 for (k1 = 1; k1 <= elenk + 1; k1++) {
526 677
527 // ... 678 // ...
528 if (k1 > elenk) { 679 if (k1 > elenk) {
529 - e = k; // search the nodes in k  
530 - pj = p; // list of nodes starts at Ci[pj]  
531 - ln = len [k] - elenk; // length of list of nodes in k 680 + e = k; // search the nodes in k
  681 + pj = p; // list of nodes starts at Ci[pj]
  682 + ln = len[k] - elenk; // length of list of nodes in k
532 } 683 }
533 else { 684 else {
534 - e = Ci[p++]; // search the nodes in e 685 + e = Ci[p++]; // search the nodes in e
535 pj = Cp[e]; 686 pj = Cp[e];
536 - ln = len[e]; // length of list of nodes in e 687 + ln = len[e]; // length of list of nodes in e
537 } 688 }
538 689
539 // ... 690 // ...
540 for (k2 = 1 ; k2 <= ln ; k2++) { 691 for (k2 = 1 ; k2 <= ln ; k2++) {
541 i = Ci[pj++]; 692 i = Ci[pj++];
542 - if ((nvi = nv [i]) <= 0) // Skip of node i is dead or seen 693 + if ((nvi = nv [i]) <= 0) // Skip of node i is dead or seen
543 continue; 694 continue;
544 - dk += nvi; // degree[Lk] += size of node i  
545 - nv[i] = -nvi; // negate nv[i] to denote i in Lk  
546 - Ci[pk2++] = i; // place i in Lk 695 + dk += nvi; // degree[Lk] += size of node i
  696 + nv[i] = -nvi; // negate nv[i] to denote i in Lk
  697 + Ci[pk2++] = i; // place i in Lk
547 if (next[i] != -1) 698 if (next[i] != -1)
548 last[next[i]] = last[i]; 699 last[next[i]] = last[i];
549 700
@@ -556,16 +707,16 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -556,16 +707,16 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
556 707
557 // ... 708 // ...
558 if (e != k) { 709 if (e != k) {
559 - Cp[e] = CS_FLIP (k); // absorb e into k  
560 - w[e] = 0; // e is now a dead element 710 + Cp[e] = CS_FLIP(k); // absorb e into k
  711 + w[e] = 0; // e is now a dead element
561 } 712 }
562 } // endfor: k1 713 } // endfor: k1
563 714
564 - if (elenk != 0) cnz = pk2; // Ci [cnz...nzmax] is free  
565 - degree[k] = dk; // external degree of k - |Lk\i|  
566 - Cp[k] = pk1; // element k is in Ci[pk1..pk2-1] 715 + if (elenk != 0) cnz = pk2; // Ci [cnz...nzmax] is free
  716 + degree[k] = dk; // external degree of k - |Lk\i|
  717 + Cp[k] = pk1; // element k is in Ci[pk1..pk2-1]
567 len[k] = pk2 - pk1; 718 len[k] = pk2 - pk1;
568 - elen[k] = -2; // k is now an element 719 + elen[k] = -2; // k is now an element
569 720
570 // Clear w if necessary 721 // Clear w if necessary
571 mark = cs_wclear(mark, lemax, w, n); 722 mark = cs_wclear(mark, lemax, w, n);
@@ -573,85 +724,86 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -573,85 +724,86 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
573 // Scan 1: Find set differences |Le\Lk| 724 // Scan 1: Find set differences |Le\Lk|
574 for (pk = pk1 ; pk < pk2 ; pk++) { 725 for (pk = pk1 ; pk < pk2 ; pk++) {
575 i = Ci [pk]; 726 i = Ci [pk];
576 - if ((eln = elen [i]) <= 0) // skip if elen[i] empty 727 + if ((eln = elen[i]) <= 0) // skip if elen[i] empty
577 continue; 728 continue;
578 - nvi = -nv[i]; // nv [i] was negated 729 + nvi = -nv[i]; // nv [i] was negated
579 wnvi = mark - nvi; 730 wnvi = mark - nvi;
580 731
581 // Scan Ei 732 // Scan Ei
582 for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) { 733 for (p = Cp[i]; p <= Cp[i] + eln - 1; p++) {
583 - e = Ci [p] ; 734 + e = Ci[p];
584 if (w[e] >= mark) 735 if (w[e] >= mark)
585 - w[e] -= nvi; // decrement |Le\Lk|  
586 - else if (w[e] != 0) // ensure e is a live element  
587 - w[e] = degree[e] + wnvi; // 1st time e seen in scan 1 736 + w[e] -= nvi; // decrement |Le\Lk|
  737 + else if (w[e] != 0) // ensure e is a live element
  738 + w[e] = degree[e] + wnvi; // 1st time e seen in scan 1
588 } 739 }
589 } // endfor: scan 1 finished 740 } // endfor: scan 1 finished
590 741
591 // Scan 2: Degree update 742 // Scan 2: Degree update
592 for (pk = pk1; pk < pk2; pk++) { 743 for (pk = pk1; pk < pk2; pk++) {
593 - i = Ci [pk] ; /* consider node i in Lk */  
594 - p1 = Cp [i] ;  
595 - p2 = p1 + elen [i] - 1 ;  
596 - pn = p1 ; 744 + i = Ci[pk]; // consider node i in Lk
  745 + p1 = Cp[i];
  746 + p2 = p1 + elen [i] - 1;
  747 + pn = p1;
597 748
598 // Scan Ei 749 // Scan Ei
599 for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) { 750 for (h = 0, d = 0, p = p1 ; p <= p2 ; p++) {
600 - e = Ci [p] ; 751 + e = Ci[p];
601 // If e is an unabsorbed element, then ... 752 // If e is an unabsorbed element, then ...
602 - if (w [e] != 0) {  
603 - dext = w [e] - mark ; /* dext = |Le\Lk| */ 753 + if (w[e] != 0) {
  754 + dext = w[e] - mark; // dext = |Le\Lk|
604 if (dext > 0) { 755 if (dext > 0) {
605 - d += dext ; /* sum up the set differences */  
606 - Ci [pn++] = e ; /* keep e in Ei */  
607 - h += e ; /* compute the hash of node i */ 756 + d += dext; // sum up the set differences
  757 + Ci[pn++] = e; // keep e in Ei
  758 + h += e; // compute the hash of node i
608 } 759 }
609 else { 760 else {
610 - Cp [e] = CS_FLIP (k) ; /* aggressive absorb. e->k */  
611 - w [e] = 0 ; /* e is a dead element */ 761 + Cp[e] = CS_FLIP(k); // aggressive absorb. e->k
  762 + w[e] = 0; // e is a dead element
612 } 763 }
613 } 764 }
614 } // endfor: scanned Ei 765 } // endfor: scanned Ei
615 766
616 // elen[i] = |Ei| 767 // elen[i] = |Ei|
617 - elen [i] = pn - p1 + 1 ; 768 + elen[i] = pn - p1 + 1;
618 p3 = pn ; 769 p3 = pn ;
619 - p4 = p1 + len [i] ; 770 + p4 = p1 + len[i];
620 771
621 // Prune edges in Ai 772 // Prune edges in Ai
622 for (p = p2 + 1 ; p < p4 ; p++) { 773 for (p = p2 + 1 ; p < p4 ; p++) {
623 - j = Ci [p] ;  
624 - if ((nvj = nv [j]) <= 0) continue ; /* node j dead or in Lk */  
625 - d += nvj ; /* degree(i) += |j| */  
626 - Ci [pn++] = j ; /* place j in node list of i */  
627 - h += j ; /* compute hash for node i */ 774 + j = Ci[p];
  775 + if ((nvj = nv[j]) <= 0) // node j dead or in Lk
  776 + continue;
  777 + d += nvj; // degree(i) += |j|
  778 + Ci[pn++] = j; // place j in node list of i
  779 + h += j; // compute hash for node i
628 } 780 }
629 781
630 // Check for mass elimination 782 // Check for mass elimination
631 if (d == 0) { 783 if (d == 0) {
632 - Cp [i] = CS_FLIP (k) ; /* absorb i into k */  
633 - nvi = -nv [i] ;  
634 - dk -= nvi ; /* |Lk| -= |i| */  
635 - nvk += nvi ; /* |k| += nv[i] */  
636 - nel += nvi ;  
637 - nv [i] = 0 ;  
638 - elen [i] = -1 ; /* node i is dead */ 784 + Cp[i] = CS_FLIP(k); // absorb i into k
  785 + nvi = -nv[i];
  786 + dk -= nvi; // |Lk| -= |i|
  787 + nvk += nvi; // |k| += nv[i]
  788 + nel += nvi;
  789 + nv[i] = 0;
  790 + elen[i] = -1; // node i is dead
639 } 791 }
640 else { 792 else {
641 - degree [i] = CS_MIN (degree [i], d) ; /* update degree(i) */  
642 - Ci [pn] = Ci [p3] ; /* move first node to end */  
643 - Ci [p3] = Ci [p1] ; /* move 1st el. to end of Ei */  
644 - Ci [p1] = k ; /* add k as 1st element in of Ei */  
645 - len [i] = pn - p1 + 1 ; /* new len of adj. list of node i */  
646 - h %= n ; /* finalize hash of i */  
647 - next [i] = hhead [h] ; /* place i in hash bucket */  
648 - hhead [h] = i ;  
649 - last [i] = h ; /* save hash of i in last[i] */ 793 + degree[i] = CS_MIN(degree[i], d); // update degree(i)
  794 + Ci[pn] = Ci[p3]; // move first node to end
  795 + Ci[p3] = Ci[p1]; // move 1st el. to end of Ei
  796 + Ci[p1] = k; // add k as 1st element in of Ei
  797 + len[i] = pn - p1 + 1; // new len of adj. list of node i
  798 + h %= n; // finalize hash of i
  799 + next[i] = hhead[h]; // place i in hash bucket
  800 + hhead[h] = i;
  801 + last[i] = h; // save hash of i in last[i]
650 } 802 }
651 } // endfor: scan 2 is done 803 } // endfor: scan 2 is done
652 804
653 // finalize |Lk| 805 // finalize |Lk|
654 - degree[k] = dk ; 806 + degree[k] = dk;
655 lemax = CS_MAX(lemax, dk); 807 lemax = CS_MAX(lemax, dk);
656 808
657 // Clear w 809 // Clear w
@@ -659,33 +811,35 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -659,33 +811,35 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
659 811
660 // Supernode detection 812 // Supernode detection
661 for (pk = pk1 ; pk < pk2 ; pk++) { 813 for (pk = pk1 ; pk < pk2 ; pk++) {
662 - i = Ci [pk] ;  
663 - if (nv [i] >= 0) continue ; /* skip if i is dead */  
664 - h = last [i] ; /* scan hash bucket of node i */  
665 - i = hhead [h] ;  
666 - hhead [h] = -1 ; /* hash bucket will be empty */ 814 + i = Ci[pk];
  815 + if (nv[i] >= 0) continue; // skip if i is dead
  816 + h = last[i]; // scan hash bucket of node i
  817 + i = hhead[h];
  818 + hhead[h] = -1; // hash bucket will be empty
667 819
668 // ... 820 // ...
669 - for ( ; i != -1 && next [i] != -1 ; i = next [i], mark++) {  
670 - ln = len [i] ;  
671 - eln = elen [i] ;  
672 - for (p = Cp [i]+1 ; p <= Cp [i] + ln-1 ; p++) w [Ci [p]] = mark;  
673 - jlast = i ; 821 + for ( ; i != -1 && next[i] != -1 ; i = next[i], mark++) {
  822 + ln = len[i];
  823 + eln = elen[i];
  824 + for (p = Cp[i]+1 ; p <= Cp[i] + ln-1 ; p++)
  825 + w[Ci[p]] = mark;
  826 + jlast = i;
674 827
675 // Compare i with all j 828 // Compare i with all j
676 - for (j = next [i] ; j != -1 ; ) {  
677 - ok = (len [j] == ln) && (elen [j] == eln) ;  
678 - for (p = Cp [j] + 1 ; ok && p <= Cp [j] + ln - 1 ; p++) {  
679 - if (w [Ci [p]] != mark) ok = 0 ; /* compare i and j*/ 829 + for (j = next[i]; j != -1; ) {
  830 + ok = (len[j] == ln) && (elen[j] == eln) ;
  831 + for (p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++) {
  832 + if (w[Ci[p]] != mark) // compare i and j
  833 + ok = 0;
680 } 834 }
681 835
682 // i and j are identical 836 // i and j are identical
683 if (ok) { 837 if (ok) {
684 - Cp[j] = CS_FLIP(i); /* absorb j into i */ 838 + Cp[j] = CS_FLIP(i); // absorb j into i
685 nv[i] += nv[j]; 839 nv[i] += nv[j];
686 nv[j] = 0; 840 nv[j] = 0;
687 - elen[j] = -1; /* node j is dead */  
688 - j = next[j]; /* delete j from hash bucket */ 841 + elen[j] = -1; // node j is dead
  842 + j = next[j]; // delete j from hash bucket
689 next[jlast] = j; 843 next[jlast] = j;
690 } 844 }
691 // j and i are different 845 // j and i are different
@@ -697,57 +851,75 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -697,57 +851,75 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
697 } // 851 } //
698 } // endfor: supernode detection 852 } // endfor: supernode detection
699 853
700 - // Finalize new element  
701 - for (p = pk1, pk = pk1 ; pk < pk2 ; pk++) /* finalize Lk */  
702 - {  
703 - i = Ci [pk] ;  
704 - if ((nvi = -nv [i]) <= 0) continue ;/* skip if i is dead */  
705 - nv [i] = nvi ; /* restore nv[i] */  
706 - d = degree [i] + dk - nvi ; /* compute external degree(i) */  
707 - d = CS_MIN (d, n - nel - nvi) ;  
708 - if (head [d] != -1) last [head [d]] = i ;  
709 - next [i] = head [d] ; /* put i back in degree list */  
710 - last [i] = -1 ;  
711 - head [d] = i ;  
712 - mindeg = CS_MIN (mindeg, d) ; /* find new minimum degree */  
713 - degree [i] = d ;  
714 - Ci [p++] = i ; /* place i in Lk */ 854 + // Finalize new element Lk
  855 + for (p = pk1, pk = pk1; pk < pk2; pk++) {
  856 + i = Ci[pk];
  857 + if ((nvi = -nv[i]) <= 0) // skip if i is dead
  858 + continue;
  859 + nv[i] = nvi; // restore nv[i]
  860 + d = degree[i] + dk - nvi; // compute external degree(i)
  861 + d = CS_MIN(d, n - nel - nvi);
  862 + if (head[d] != -1) last[head[d]] = i;
  863 + next [i] = head [d]; // put i back in degree list
  864 + last [i] = -1 ;
  865 + head [d] = i ;
  866 + mindeg = CS_MIN (mindeg, d); // find new minimum degree
  867 + degree [i] = d ;
  868 + Ci [p++] = i ; // place i in Lk
715 } 869 }
716 - nv [k] = nvk ; /* # nodes absorbed into k */  
717 - if ((len [k] = p-pk1) == 0) /* length of adj list of element k*/  
718 - {  
719 - Cp [k] = -1 ; /* k is a root of the tree */  
720 - w [k] = 0 ; /* k is now a dead element */ 870 +
  871 + // Number of nodes absorbed into k
  872 + nv[k] = nvk;
  873 +
  874 + // ...
  875 + if ((len [k] = p-pk1) == 0) { // length of adj list of element k
  876 + Cp [k] = -1 ; // k is a root of the tree
  877 + w [k] = 0 ; // k is now a dead element
721 } 878 }
722 - if (elenk != 0) cnz = p ; /* free unused space in Lk */  
723 - } 879 + if (elenk != 0) cnz = p ; // free unused space in Lk
  880 +
  881 + } // endwhile
  882 +
  883 +
  884 + // ======================================================================
  885 + // Step 5: Postordering
  886 + // ======================================================================
  887 +
  888 + // Debug
  889 + #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
  890 + cout << " Step 5: Postordering" << endl;
  891 + #endif
724 892
725 - // Postordering  
726 - for (i = 0 ; i < n ; i++) Cp [i] = CS_FLIP (Cp [i]) ;/* fix assembly tree */  
727 - for (j = 0 ; j <= n ; j++) head [j] = -1 ;  
728 - for (j = n ; j >= 0 ; j--) /* place unordered nodes in lists */  
729 - {  
730 - if (nv [j] > 0) continue ; /* skip if j is an element */  
731 - next [j] = head [Cp [j]] ; /* place j in list of its parent */  
732 - head [Cp [j]] = j ;  
733 - }  
734 - for (e = n ; e >= 0 ; e--) /* place elements in lists */  
735 - {  
736 - if (nv [e] <= 0) continue ; /* skip unless e is an element */  
737 - if (Cp [e] != -1)  
738 - {  
739 - next [e] = head [Cp [e]] ; /* place e in list of its parent */  
740 - head [Cp [e]] = e ; 893 + // Fix assembly tree
  894 + for (i = 0; i < n; i++)
  895 + Cp[i] = CS_FLIP(Cp[i]);
  896 + for (j = 0 ; j <= n ; j++)
  897 + head[j] = -1;
  898 +
  899 + // Place unordered nodes in lists
  900 + for (j = n ; j >= 0 ; j--) {
  901 + if (nv[j] > 0) continue; // skip if j is an element
  902 + next[j] = head [Cp[j]]; // place j in list of its parent
  903 + head[Cp[j]] = j;
  904 + }
  905 +
  906 + // Place elements in lists
  907 + for (e = n ; e >= 0 ; e--) {
  908 + if (nv[e] <= 0) continue; // skip unless e is an element
  909 + if (Cp[e] != -1) {
  910 + next[e] = head[Cp[e]]; // place e in list of its parent
  911 + head[Cp[e]] = e;
741 } 912 }
742 } 913 }
743 914
  915 +
744 // ====================================================================== 916 // ======================================================================
745 - // Step 5: Postorder the assembly tree 917 + // Step 6: Postorder the assembly tree
746 // ====================================================================== 918 // ======================================================================
747 919
748 // Debug 920 // Debug
749 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING) 921 #if defined(G_DEBUG_SPARSE_SYM_AMD_ORDERING)
750 - cout << " Step 5: Postorder the assembly tree" << endl; 922 + cout << " Step 6: Postorder the assembly tree" << endl;
751 #endif 923 #endif
752 924
753 // Postorder the assembly tree 925 // Postorder the assembly tree
@@ -769,7 +941,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -769,7 +941,7 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
769 #endif 941 #endif
770 942
771 // Return result 943 // Return result
772 - return (P); 944 + return P;
773 } 945 }
774 946
775 947
@@ -784,7 +956,9 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A) @@ -784,7 +956,9 @@ int* GSparseSymbolic::cs_amd(int order, GSparseMatrix* A)
784 * ata 0: count LL'=A, 1: count LL'=A'A * 956 * ata 0: count LL'=A, 1: count LL'=A'A *
785 * Output: p[0..n] integer array of n+1 elements * 957 * Output: p[0..n] integer array of n+1 elements *
786 ***************************************************************************/ 958 ***************************************************************************/
787 -int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, 959 +#define HEAD(k,j) (ata ? head [k] : j)
  960 +#define NEXT(J) (ata ? next [J] : -1)
  961 +int* GSparseSymbolic::cs_counts(const GSparseMatrix* A, const int* parent,
788 const int* post, int ata) 962 const int* post, int ata)
789 { 963 {
790 // Declare loop variables 964 // Declare loop variables
@@ -792,7 +966,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -792,7 +966,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
792 966
793 // Return NULL pointer if input arrays are NULL or sparse matrix is 967 // Return NULL pointer if input arrays are NULL or sparse matrix is
794 // empty 968 // empty
795 - if (!parent || !post) return (NULL); 969 + if (!parent || !post) return NULL;
796 970
797 // Assign input matrix attributes 971 // Assign input matrix attributes
798 int m = A->m_rows; 972 int m = A->m_rows;
@@ -801,8 +975,9 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -801,8 +975,9 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
801 // Allocate result 975 // Allocate result
802 int* colcount = new int[n]; 976 int* colcount = new int[n];
803 if (colcount == NULL) 977 if (colcount == NULL)
804 - throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)",  
805 - n); 978 + throw mem_alloc(
  979 + "GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)",
  980 + n);
806 int* delta = colcount; 981 int* delta = colcount;
807 982
808 // Allocate workspace 983 // Allocate workspace
@@ -812,8 +987,8 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -812,8 +987,8 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
812 throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)", 987 throw mem_alloc("GSparseSymbolic::cs_counts(GSparseMatrix*, const int*, const int*, int)",
813 wrk_size); 988 wrk_size);
814 989
815 - // Get transpose of A: AT = A'  
816 - GSparseMatrix AT = A->cs_transpose(A,0); 990 + // Get (logical) transpose of A: AT = A'
  991 + GSparseMatrix AT = cs_transpose(*A, 0);
817 992
818 // Set-up pointers to workspace 993 // Set-up pointers to workspace
819 int* ancestor = wrk_int; 994 int* ancestor = wrk_int;
@@ -836,7 +1011,9 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -836,7 +1011,9 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
836 int* ATp = AT.m_colstart; 1011 int* ATp = AT.m_colstart;
837 int* ATi = AT.m_rowinx; 1012 int* ATi = AT.m_rowinx;
838 1013
839 - // Initialise 1014 + // Initialise. Note that init_ata wires the working array into the *head
  1015 + // and *next pointers, so both arrays are just aliases of the wrk_int
  1016 + // array.
840 int* head = NULL; 1017 int* head = NULL;
841 int* next = NULL; 1018 int* next = NULL;
842 if (ata) init_ata(&AT, post, wrk_int, &head, &next); 1019 if (ata) init_ata(&AT, post, wrk_int, &head, &next);
@@ -845,8 +1022,6 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -845,8 +1022,6 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
845 for (i = 0; i < n; i++) ancestor[i] = i; 1022 for (i = 0; i < n; i++) ancestor[i] = i;
846 1023
847 // Loop over all columns of matrix A (or rows of matrix AT) 1024 // Loop over all columns of matrix A (or rows of matrix AT)
848 - #define HEAD(k,j) (ata ? head [k] : j)  
849 - #define NEXT(J) (ata ? next [J] : -1)  
850 for (k = 0; k < n; k++) { 1025 for (k = 0; k < n; k++) {
851 j = post[k]; // j is the kth node in postordered etree 1026 j = post[k]; // j is the kth node in postordered etree
852 if (parent[j] != -1) delta[parent[j]]--; // j is not a root 1027 if (parent[j] != -1) delta[parent[j]]--; // j is not a root
@@ -872,7 +1047,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -872,7 +1047,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
872 delete [] wrk_int; 1047 delete [] wrk_int;
873 1048
874 // Return result 1049 // Return result
875 - return (colcount); 1050 + return colcount;
876 } 1051 }
877 1052
878 1053
@@ -885,7 +1060,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent, @@ -885,7 +1060,7 @@ int* GSparseSymbolic::cs_counts(GSparseMatrix* A, const int* parent,
885 * ata flag * 1060 * ata flag *
886 * Output: etree(A) Evaluation tree of matrix A * 1061 * Output: etree(A) Evaluation tree of matrix A *
887 ***************************************************************************/ 1062 ***************************************************************************/
888 -int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) 1063 +int* GSparseSymbolic::cs_etree(const GSparseMatrix* A, int ata)
889 { 1064 {
890 // Declare loop variables 1065 // Declare loop variables
891 int i, k, p; 1066 int i, k, p;
@@ -910,7 +1085,10 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) @@ -910,7 +1085,10 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata)
910 int* prev = wrk_int + n; 1085 int* prev = wrk_int + n;
911 1086
912 // If 'prev' is requested, initialise array with -1 1087 // If 'prev' is requested, initialise array with -1
913 - if (ata) for (i = 0; i < m ; ++i) prev[i] = -1; 1088 + if (ata) {
  1089 + for (i = 0; i < m ; ++i)
  1090 + prev[i] = -1;
  1091 + }
914 1092
915 // Loop over all nodes (columns) 1093 // Loop over all nodes (columns)
916 for (k = 0; k < n; ++k) { 1094 for (k = 0; k < n; ++k) {
@@ -940,7 +1118,7 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) @@ -940,7 +1118,7 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata)
940 delete [] wrk_int; 1118 delete [] wrk_int;
941 1119
942 // Return result 1120 // Return result
943 - return (parent); 1121 + return parent;
944 1122
945 } 1123 }
946 1124
@@ -956,7 +1134,8 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata) @@ -956,7 +1134,8 @@ int* GSparseSymbolic::cs_etree(GSparseMatrix* A, int ata)
956 * other Other function * 1134 * other Other function *
957 * Output: result 0..n-1 if ok, -1 in case of error * 1135 * Output: result 0..n-1 if ok, -1 in case of error *
958 ***************************************************************************/ 1136 ***************************************************************************/
959 -int GSparseSymbolic::cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), 1137 +int GSparseSymbolic::cs_fkeep(GSparseMatrix* A,
  1138 + int(*fkeep)(int, int, double, void*),
960 void* other) 1139 void* other)
961 { 1140 {
962 // Return error if some of the input pointers is invalid 1141 // Return error if some of the input pointers is invalid
@@ -984,13 +1163,15 @@ int GSparseSymbolic::cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, vo @@ -984,13 +1163,15 @@ int GSparseSymbolic::cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, vo
984 } 1163 }
985 1164
986 // Finalise A 1165 // Finalise A
987 - Ap[n] = nz; 1166 + Ap[n] = nz;
  1167 + A->m_elements = nz;
988 1168
989 // Remove extra space from A 1169 // Remove extra space from A
990 -// cs_sprealloc (A, 0) ; /* remove extra space from A */ 1170 +// cs_sprealloc(A, 0);
  1171 + A->free_elements(nz, (A->m_elements-nz));
991 1172
992 // Return number of non-zero elements 1173 // Return number of non-zero elements
993 - return (nz) ; 1174 + return nz;
994 } 1175 }
995 1176
996 1177
@@ -1061,7 +1242,7 @@ int GSparseSymbolic::cs_leaf(int i, int j, const int *first, int *maxfirst, @@ -1061,7 +1242,7 @@ int GSparseSymbolic::cs_leaf(int i, int j, const int *first, int *maxfirst,
1061 int* GSparseSymbolic::cs_pinv(int const *p, int n) 1242 int* GSparseSymbolic::cs_pinv(int const *p, int n)
1062 { 1243 {
1063 // Return NULL pointer if input pointer is NULL. This denotes identity 1244 // Return NULL pointer if input pointer is NULL. This denotes identity
1064 - if (!p || n < 1) return (NULL); 1245 + if (!p || n < 1) return NULL;
1065 1246
1066 // Allocate result array 1247 // Allocate result array
1067 int* pinv = new int[n]; 1248 int* pinv = new int[n];
@@ -1073,7 +1254,7 @@ int* GSparseSymbolic::cs_pinv(int const *p, int n) @@ -1073,7 +1254,7 @@ int* GSparseSymbolic::cs_pinv(int const *p, int n)
1073 pinv[p[k]] = k; 1254 pinv[p[k]] = k;
1074 1255
1075 // Return result 1256 // Return result
1076 - return (pinv); 1257 + return pinv;
1077 } 1258 }
1078 1259
1079 1260
@@ -1137,90 +1318,7 @@ int* GSparseSymbolic::cs_post(const int* parent, int n) @@ -1137,90 +1318,7 @@ int* GSparseSymbolic::cs_post(const int* parent, int n)
1137 delete [] wrk_int; 1318 delete [] wrk_int;
1138 1319
1139 // Return result 1320 // Return result
1140 - return (post);  
1141 -  
1142 -}  
1143 -  
1144 -  
1145 -/***************************************************************************  
1146 - * cs_symperm *  
1147 - * ----------------------------------------------------------------------- *  
1148 - * C = A(p,p) where A and C are symmetric the upper part stored. *  
1149 - * pinv not p *  
1150 - * ----------------------------------------------------------------------- *  
1151 - * Input: A Sparse matrix *  
1152 - * pinv pinv[0..n-1] *  
1153 - * values =1 allocate memory for values (NOT USED) *  
1154 - * Output: C Sparse matrix *  
1155 - ***************************************************************************/  
1156 -GSparseMatrix GSparseSymbolic::cs_symperm(GSparseMatrix* A, const int* pinv,  
1157 - int values) const  
1158 -{  
1159 - // Declare loop variables  
1160 - int i, j, p, q, i2, j2;  
1161 -  
1162 - // Assign matrix attributes  
1163 - int n = A->m_cols;  
1164 - int* Ap = A->m_colstart;  
1165 - int* Ai = A->m_rowinx;  
1166 - double* Ax = A->m_data;  
1167 -  
1168 - // Allocate result matrix  
1169 - GSparseMatrix C(n, n, Ap[n]);  
1170 -  
1171 - // Allocate and initialise workspace  
1172 - int wrk_size = n;  
1173 - int* wrk_int = new int[wrk_size];  
1174 - if (wrk_int == NULL)  
1175 - throw mem_alloc("GSparseSymbolic::cs_symperm(GSparseMatrix*, const int*, int",  
1176 - wrk_size);  
1177 - for (i = 0; i < wrk_size; ++i)  
1178 - wrk_int[i] = 0;  
1179 -  
1180 - // Assign result matriix attributes  
1181 - int* Cp = C.m_colstart;  
1182 - int* Ci = C.m_rowinx;  
1183 - double* Cx = C.m_data;  
1184 -  
1185 - // Count entries in each column of C  
1186 - for (j = 0; j < n; j++) {  
1187 -  
1188 - // Column j of A is column j2 of C  
1189 - j2 = pinv ? pinv[j] : j;  
1190 -  
1191 - // Loop over entries in column j  
1192 - for (p = Ap[j]; p < Ap[j+1]; p++) {  
1193 - i = Ai [p];  
1194 - if (i > j) continue; // skip lower triangular part of A  
1195 - i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C  
1196 - wrk_int[CS_MAX(i2, j2)]++; // column count of C  
1197 - }  
1198 - }  
1199 -  
1200 - // Compute column pointers of C  
1201 - cs_cumsum(Cp, wrk_int, n);  
1202 -  
1203 - // Loop over all columns of A  
1204 - for (j = 0 ; j < n ; j++) {  
1205 -  
1206 - // Column j of A is column j2 of C  
1207 - j2 = pinv ? pinv[j] : j;  
1208 -  
1209 - // Loop over entries in column j  
1210 - for (p = Ap[j]; p < Ap[j+1]; p++) {  
1211 - i = Ai [p] ;  
1212 - if (i > j) continue; // skip lower triangular part of A  
1213 - i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C  
1214 - Ci[q = wrk_int[CS_MAX(i2,j2)]++] = CS_MIN(i2,j2);  
1215 - Cx[q] = Ax[p];  
1216 - }  
1217 - }  
1218 -  
1219 - // Free workspace  
1220 - delete [] wrk_int;  
1221 -  
1222 - // Return result  
1223 - return (C); 1321 + return post;
1224 1322
1225 } 1323 }
1226 1324
@@ -1266,7 +1364,7 @@ int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next, @@ -1266,7 +1364,7 @@ int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next,
1266 } 1364 }
1267 1365
1268 // Return result 1366 // Return result
1269 - return (k) ; 1367 + return k;
1270 } 1368 }
1271 1369
1272 1370
@@ -1290,7 +1388,7 @@ int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next, @@ -1290,7 +1388,7 @@ int GSparseSymbolic::cs_tdfs(int j, int k, int* head, const int* next,
1290 * next pointer to next[0..n-1] linked list info * 1388 * next pointer to next[0..n-1] linked list info *
1291 * Output: - - * 1389 * Output: - - *
1292 ***************************************************************************/ 1390 ***************************************************************************/
1293 -void GSparseSymbolic::init_ata(GSparseMatrix* AT, const int* post, 1391 +void GSparseSymbolic::init_ata(const GSparseMatrix* AT, const int* post,
1294 int* wrk_int, int** head, int** next) 1392 int* wrk_int, int** head, int** next)
1295 { 1393 {
1296 // Declare loop variables 1394 // Declare loop variables
@@ -1321,6 +1419,9 @@ void GSparseSymbolic::init_ata(GSparseMatrix* AT, const int* post, @@ -1321,6 +1419,9 @@ void GSparseSymbolic::init_ata(GSparseMatrix* AT, const int* post,
1321 (*next)[i] = (*head)[k]; 1419 (*next)[i] = (*head)[k];
1322 (*head)[k] = i; 1420 (*head)[k] = i;
1323 } 1421 }
  1422 +
  1423 + // Return
  1424 + return;
1324 } 1425 }
1325 1426
1326 1427
src/GSparseSymbolic.hpp
@@ -61,7 +61,7 @@ public: @@ -61,7 +61,7 @@ public:
61 // Unary operators 61 // Unary operators
62 62
63 // Functions 63 // Functions
64 - void cholesky_symbolic_analysis(int order, GSparseMatrix& m); 64 + void cholesky_symbolic_analysis(int order, const GSparseMatrix& m);
65 65
66 // Exception: Invalid ordering scheme 66 // Exception: Invalid ordering scheme
67 class invalid_order : public GException { 67 class invalid_order : public GException {
@@ -71,18 +71,17 @@ public: @@ -71,18 +71,17 @@ public:
71 71
72 private: 72 private:
73 // Functions 73 // Functions
74 - int* cs_amd (int order, GSparseMatrix* A);  
75 - int* cs_counts(GSparseMatrix* A, const int* parent, const int* post, int ata);  
76 - int* cs_etree(GSparseMatrix* A, int ata);  
77 - int cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), void* other);  
78 - int cs_leaf(int i, int j, const int* first, int* maxfirst, int* prevleaf, int* ancestor, int* jleaf);  
79 - int* cs_pinv(int const* p, int n);  
80 - int* cs_post(const int* parent, int n);  
81 - GSparseMatrix cs_symperm(GSparseMatrix* A, const int* pinv, int values) const;  
82 - int cs_tdfs(int j, int k, int* head, const int* next, int* post, int* stack);  
83 - static void init_ata(GSparseMatrix* AT, const int* post, int* wrk_int, int** head, int** next);  
84 - static int cs_diag(int i, int j, double aij, void* other);  
85 - static int cs_wclear(int mark, int lemax, int* w, int n); 74 + int* cs_amd (int order, const GSparseMatrix* A);
  75 + int* cs_counts(const GSparseMatrix* A, const int* parent, const int* post, int ata);
  76 + int* cs_etree(const GSparseMatrix* A, int ata);
  77 + int cs_fkeep(GSparseMatrix* A, int(*fkeep)(int, int, double, void*), void* other);
  78 + int cs_leaf(int i, int j, const int* first, int* maxfirst, int* prevleaf, int* ancestor, int* jleaf);
  79 + int* cs_pinv(int const* p, int n);
  80 + int* cs_post(const int* parent, int n);
  81 + int cs_tdfs(int j, int k, int* head, const int* next, int* post, int* stack);
  82 + static void init_ata(const GSparseMatrix* AT, const int* post, int* wrk_int, int** head, int** next);
  83 + static int cs_diag(int i, int j, double aij, void* other);
  84 + static int cs_wclear(int mark, int lemax, int* w, int n);
86 85
87 // Data 86 // Data
88 int* m_pinv; // Inverse row permutation for QR, fill reduce permutation for Cholesky 87 int* m_pinv; // Inverse row permutation for QR, fill reduce permutation for Cholesky
src/GVector.cpp
@@ -46,15 +46,32 @@ GVector::GVector(int num) @@ -46,15 +46,32 @@ GVector::GVector(int num)
46 46
47 47
48 /*************************************************************************** 48 /***************************************************************************
  49 + * GVector copy constructor *
  50 + ***************************************************************************/
  51 +GVector::GVector(const GVector& v)
  52 +{
  53 + // Allocate vector array. Throw exception if allocation failed
  54 + m_data = new double[v.m_num];
  55 + if (m_data == NULL)
  56 + throw mem_alloc("GVector copy constructor", v.m_num);
  57 +
  58 + // Store vector size and copy elements
  59 + m_num = v.m_num;
  60 + for (int i = 0; i < m_num; ++i)
  61 + m_data[i] = v.m_data[i];
  62 +
  63 + // Return
  64 + return;
  65 +}
  66 +
  67 +
  68 +/***************************************************************************
49 * GVector destructor * 69 * GVector destructor *
50 ***************************************************************************/ 70 ***************************************************************************/
51 GVector::~GVector() 71 GVector::~GVector()
52 { 72 {
53 // Deallocate only if memory has indeed been allocated 73 // Deallocate only if memory has indeed been allocated
54 - if (m_num > 0) {  
55 - m_num = 0;  
56 - delete[] m_data;  
57 - } 74 + if (m_data != NULL) delete[] m_data;
58 75
59 // Return 76 // Return
60 return; 77 return;
@@ -67,6 +84,33 @@ GVector::~GVector() @@ -67,6 +84,33 @@ GVector::~GVector()
67 = = 84 = =
68 ==========================================================================*/ 85 ==========================================================================*/
69 86
  87 +/***************************************************************************
  88 + * GVector assignment operator *
  89 + ***************************************************************************/
  90 +GVector& GVector::operator= (const GVector& v)
  91 +{
  92 + // Assign only if not identical
  93 + if (this != &v) {
  94 +
  95 + // First delete old data if it exists
  96 + if (m_data != NULL) delete [] m_data;
  97 +
  98 + // Allocate vector array. Throw exception if allocation failed
  99 + m_data = new double[v.m_num];
  100 + if (m_data == NULL)
  101 + throw mem_alloc("GVector assignment operator", v.m_num);
  102 +
  103 + // Store vector size and copy elements
  104 + m_num = v.m_num;
  105 + for (int i = 0; i < m_num; ++i)
  106 + m_data[i] = v.m_data[i];
  107 + }
  108 +
  109 + // Return vector
  110 + return *this;
  111 +}
  112 +
  113 +
70 /*========================================================================== 114 /*==========================================================================
71 = = 115 = =
72 = GVector member functions = 116 = GVector member functions =
src/GVector.hpp
@@ -134,18 +134,6 @@ private: @@ -134,18 +134,6 @@ private:
134 * Inline members * 134 * Inline members *
135 ***************************************************************************/ 135 ***************************************************************************/
136 136
137 -// Copy constructor  
138 -inline  
139 -GVector::GVector(const GVector& v)  
140 -{  
141 - m_data = new double[v.m_num];  
142 - if (m_data == NULL)  
143 - throw mem_alloc("GVector copy constructor", v.m_num);  
144 - m_num = v.m_num;  
145 - for (int i = 0; i < m_num; ++i)  
146 - m_data[i] = v.m_data[i];  
147 -}  
148 -  
149 // Vector element access operator 137 // Vector element access operator
150 inline 138 inline
151 double& GVector::operator() (int inx) 139 double& GVector::operator() (int inx)
@@ -168,22 +156,6 @@ const double&amp; GVector::operator() (int inx) const @@ -168,22 +156,6 @@ const double&amp; GVector::operator() (int inx) const
168 return m_data[inx]; 156 return m_data[inx];
169 } 157 }
170 158
171 -// Vector assignment operator  
172 -inline  
173 -GVector& GVector::operator= (const GVector& v)  
174 -{  
175 - if (this != &v) {  
176 - if (m_data != NULL) delete [] m_data;  
177 - m_data = new double[v.m_num];  
178 - if (m_data == NULL)  
179 - throw mem_alloc("GVector assignment operator", v.m_num);  
180 - m_num = v.m_num;  
181 - for (int i = 0; i < m_num; ++i)  
182 - m_data[i] = v.m_data[i];  
183 - }  
184 - return *this;  
185 -}  
186 -  
187 // Vector unary addition operator 159 // Vector unary addition operator
188 inline 160 inline
189 GVector& GVector::operator+= (const GVector& v) 161 GVector& GVector::operator+= (const GVector& v)