Commit 983adf00a29da47c81edf5d69cfeda45cb43eb36
1 parent
bf27cf6f
correct bug in cs_transpose as spotted by ISDC guys
Showing
1 changed file
with
129 additions
and
103 deletions
src/linalg/GSparseMatrix.cpp
| @@ -4,19 +4,32 @@ | @@ -4,19 +4,32 @@ | ||
| 4 | * copyright (C) 2006-2011 by Jurgen Knodlseder * | 4 | * copyright (C) 2006-2011 by Jurgen Knodlseder * |
| 5 | * ----------------------------------------------------------------------- * | 5 | * ----------------------------------------------------------------------- * |
| 6 | * * | 6 | * * |
| 7 | - * This program is free software; you can redistribute it and/or modify * | ||
| 8 | - * it under the terms of the GNU General Public License as published by * | ||
| 9 | - * the Free Software Foundation; either version 2 of the License, or * | ||
| 10 | - * (at your option) any later version. * | 7 | + * This program is free software: you can redistribute it and/or modify * |
| 8 | + * it under the terms of the GNU General Public License as published by * | ||
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | ||
| 10 | + * (at your option) any later version. * | ||
| 11 | + * * | ||
| 12 | + * This program is distributed in the hope that it will be useful, * | ||
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
| 15 | + * GNU General Public License for more details. * | ||
| 16 | + * * | ||
| 17 | + * You should have received a copy of the GNU General Public License * | ||
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | ||
| 11 | * * | 19 | * * |
| 12 | * ----------------------------------------------------------------------- * | 20 | * ----------------------------------------------------------------------- * |
| 13 | * This class implements the compressed sparse column format. The * | 21 | * This class implements the compressed sparse column format. The * |
| 14 | * following arrays are allocated: * | 22 | * following arrays are allocated: * |
| 15 | - * m_data : holds all 'elements' non-zero values, in column order (Ax) * | ||
| 16 | - * m_colstart : holds the index of the first element of each column (Ap) * | ||
| 17 | - * m_rowinx : holds the row indices for all elements (Ai) * | 23 | + * * |
| 24 | + * m_rows (n) Number of rows * | ||
| 25 | + * m_cols (m) Number of columns * | ||
| 26 | + * m_data (Ax) Holds all 'elements' non-zero values, in column order * | ||
| 27 | + * m_colstart (Ap) Holds the index of the first element of each column * | ||
| 28 | + * m_rowinx (Ai) Holds the row indices for all elements * | ||
| 29 | + * * | ||
| 18 | * Column 'col' covers therefore [m_colstart[j], ..., m_colstart[j+1]-1] * | 30 | * Column 'col' covers therefore [m_colstart[j], ..., m_colstart[j+1]-1] * |
| 19 | * Note that 'm_colstart' has m_cols+1 elements. * | 31 | * Note that 'm_colstart' has m_cols+1 elements. * |
| 32 | + * * | ||
| 20 | ***************************************************************************/ | 33 | ***************************************************************************/ |
| 21 | /** | 34 | /** |
| 22 | * @file GSparseMatrix.cpp | 35 | * @file GSparseMatrix.cpp |
| @@ -2829,17 +2842,17 @@ GSparseMatrix abs(const GSparseMatrix& m) | @@ -2829,17 +2842,17 @@ GSparseMatrix abs(const GSparseMatrix& m) | ||
| 2829 | ***************************************************************************/ | 2842 | ***************************************************************************/ |
| 2830 | GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv) | 2843 | GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv) |
| 2831 | { | 2844 | { |
| 2832 | - // Declare loop variables | ||
| 2833 | - int i, j, p, q, i2, j2; | 2845 | + // Declare loop variables |
| 2846 | + int i, j, p, q, i2, j2; | ||
| 2834 | 2847 | ||
| 2835 | - // Assign matrix attributes | ||
| 2836 | - int n = m.m_cols; | ||
| 2837 | - int* Ap = m.m_colstart; | ||
| 2838 | - int* Ai = m.m_rowinx; | ||
| 2839 | - double* Ax = m.m_data; | 2848 | + // Assign matrix attributes |
| 2849 | + int n = m.m_cols; | ||
| 2850 | + int* Ap = m.m_colstart; | ||
| 2851 | + int* Ai = m.m_rowinx; | ||
| 2852 | + double* Ax = m.m_data; | ||
| 2840 | 2853 | ||
| 2841 | - // Allocate result matrix | ||
| 2842 | - GSparseMatrix C(n, n, Ap[n]); | 2854 | + // Allocate result matrix |
| 2855 | + GSparseMatrix C(n, n, Ap[n]); | ||
| 2843 | 2856 | ||
| 2844 | // Allocate and initialise workspace | 2857 | // Allocate and initialise workspace |
| 2845 | int wrk_size = n; | 2858 | int wrk_size = n; |
| @@ -2847,66 +2860,69 @@ GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv) | @@ -2847,66 +2860,69 @@ GSparseMatrix cs_symperm(const GSparseMatrix& m, const int* pinv) | ||
| 2847 | for (i = 0; i < wrk_size; ++i) | 2860 | for (i = 0; i < wrk_size; ++i) |
| 2848 | wrk_int[i] = 0; | 2861 | wrk_int[i] = 0; |
| 2849 | 2862 | ||
| 2850 | - // Assign result matrix attributes | ||
| 2851 | - int* Cp = C.m_colstart; | ||
| 2852 | - int* Ci = C.m_rowinx; | ||
| 2853 | - double* Cx = C.m_data; | 2863 | + // Assign result matrix attributes |
| 2864 | + int* Cp = C.m_colstart; | ||
| 2865 | + int* Ci = C.m_rowinx; | ||
| 2866 | + double* Cx = C.m_data; | ||
| 2854 | 2867 | ||
| 2855 | - // Count entries in each column of C | ||
| 2856 | - for (j = 0; j < n; j++) { | 2868 | + // Count entries in each column of C |
| 2869 | + for (j = 0; j < n; j++) { | ||
| 2857 | 2870 | ||
| 2858 | - // Column j of A is column j2 of C | ||
| 2859 | - j2 = pinv ? pinv[j] : j; | 2871 | + // Column j of A is column j2 of C |
| 2872 | + j2 = pinv ? pinv[j] : j; | ||
| 2860 | 2873 | ||
| 2861 | - // Loop over entries in column j | ||
| 2862 | - for (p = Ap[j]; p < Ap[j+1]; p++) { | ||
| 2863 | - i = Ai [p]; | ||
| 2864 | - if (i > j) continue; // skip lower triangular part of A | ||
| 2865 | - i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | ||
| 2866 | - wrk_int[G_MAX(i2, j2)]++; // column count of C | 2874 | + // Loop over entries in column j |
| 2875 | + for (p = Ap[j]; p < Ap[j+1]; p++) { | ||
| 2876 | + i = Ai [p]; | ||
| 2877 | + if (i > j) continue; // skip lower triangular part of A | ||
| 2878 | + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | ||
| 2879 | + wrk_int[G_MAX(i2, j2)]++; // column count of C | ||
| 2880 | + } | ||
| 2867 | } | 2881 | } |
| 2868 | - } | ||
| 2869 | 2882 | ||
| 2870 | - // Compute column pointers of C | ||
| 2871 | - cs_cumsum(Cp, wrk_int, n); | 2883 | + // Compute column pointers of C |
| 2884 | + cs_cumsum(Cp, wrk_int, n); | ||
| 2872 | 2885 | ||
| 2873 | - // Loop over all columns of A | ||
| 2874 | - for (j = 0 ; j < n ; j++) { | 2886 | + // Loop over all columns of A |
| 2887 | + for (j = 0 ; j < n ; j++) { | ||
| 2875 | 2888 | ||
| 2876 | - // Column j of A is column j2 of C | ||
| 2877 | - j2 = pinv ? pinv[j] : j; | 2889 | + // Column j of A is column j2 of C |
| 2890 | + j2 = pinv ? pinv[j] : j; | ||
| 2878 | 2891 | ||
| 2879 | - // Loop over entries in column j | ||
| 2880 | - for (p = Ap[j]; p < Ap[j+1]; p++) { | ||
| 2881 | - i = Ai [p] ; | ||
| 2882 | - if (i > j) continue; // skip lower triangular part of A | ||
| 2883 | - i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | ||
| 2884 | - Ci[q = wrk_int[G_MAX(i2,j2)]++] = G_MIN(i2,j2); | ||
| 2885 | - if (Cx) Cx[q] = Ax[p]; | 2892 | + // Loop over entries in column j |
| 2893 | + for (p = Ap[j]; p < Ap[j+1]; p++) { | ||
| 2894 | + i = Ai [p] ; | ||
| 2895 | + if (i > j) continue; // skip lower triangular part of A | ||
| 2896 | + i2 = pinv ? pinv[i] : i; // row i of A is row i2 of C | ||
| 2897 | + Ci[q = wrk_int[G_MAX(i2,j2)]++] = G_MIN(i2,j2); | ||
| 2898 | + if (Cx) Cx[q] = Ax[p]; | ||
| 2899 | + } | ||
| 2886 | } | 2900 | } |
| 2887 | - } | ||
| 2888 | 2901 | ||
| 2889 | - // Free workspace | ||
| 2890 | - delete [] wrk_int; | 2902 | + // Free workspace |
| 2903 | + delete [] wrk_int; | ||
| 2891 | 2904 | ||
| 2892 | - // Rectify the number of elements in matrix C | ||
| 2893 | - C.free_elements(Cp[n], (C.m_elements-Cp[n])); | 2905 | + // Rectify the number of elements in matrix C |
| 2906 | + C.free_elements(Cp[n], (C.m_elements-Cp[n])); | ||
| 2894 | 2907 | ||
| 2895 | - // Return result | ||
| 2896 | - return C; | 2908 | + // Return result |
| 2909 | + return C; | ||
| 2897 | 2910 | ||
| 2898 | } | 2911 | } |
| 2899 | 2912 | ||
| 2900 | 2913 | ||
| 2901 | /*************************************************************************** | 2914 | /*************************************************************************** |
| 2902 | - * cs_transpose * | ||
| 2903 | - * ----------------------------------------------------------------------- * | ||
| 2904 | - * Transpose matrix. The flag 'values' allows to avoid copying the actual * | ||
| 2905 | - * data values. This allows to perform a logical matrix transposition, as * | ||
| 2906 | - * needed by the symbolic matrix analysis class. * | ||
| 2907 | - * ----------------------------------------------------------------------- * | ||
| 2908 | - * NOTE: This routine DOES NOT support pending elements (they have to be * | ||
| 2909 | - * filled before. * | 2915 | + * @brief Compute transpose matrix |
| 2916 | + * | ||
| 2917 | + * @param[in] m Matrix. | ||
| 2918 | + * @param[in] value Flag that signals if values should be copied. | ||
| 2919 | + * | ||
| 2920 | + * The flag 'values' allows to avoid copying the actual data values. This | ||
| 2921 | + * allows to perform a logical matrix transposition, as needed by the | ||
| 2922 | + * symbolic matrix analysis class. | ||
| 2923 | + * | ||
| 2924 | + * Note that this method does not support pending elements (they have to be | ||
| 2925 | + * filled before). | ||
| 2910 | ***************************************************************************/ | 2926 | ***************************************************************************/ |
| 2911 | GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) | 2927 | GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) |
| 2912 | { | 2928 | { |
| @@ -2916,45 +2932,55 @@ GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) | @@ -2916,45 +2932,55 @@ GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) | ||
| 2916 | // Allocate and initialise workspace | 2932 | // Allocate and initialise workspace |
| 2917 | int wrk_size = m.m_rows; | 2933 | int wrk_size = m.m_rows; |
| 2918 | int* wrk_int = new int[wrk_size]; | 2934 | int* wrk_int = new int[wrk_size]; |
| 2919 | - for (int i = 0; i < wrk_size; i++) | 2935 | + for (int i = 0; i < wrk_size; ++i) { |
| 2920 | wrk_int[i] = 0; | 2936 | wrk_int[i] = 0; |
| 2937 | + } | ||
| 2921 | 2938 | ||
| 2922 | - // Setup the number of non-zero elements in each row | ||
| 2923 | - for (int p = 0; p < m.m_elements; p++) | ||
| 2924 | - wrk_int[m.m_rowinx[p]]++; | ||
| 2925 | - | ||
| 2926 | - // Set row pointers. To use a GSparseSymbolic function we have to | ||
| 2927 | - // allocate and object (but this does not take memory) | ||
| 2928 | - cs_cumsum(result.m_colstart, wrk_int, m.m_rows); | ||
| 2929 | - | ||
| 2930 | - // Case A: Normal transponse, including assignment of values | ||
| 2931 | - if (values) { | ||
| 2932 | - for (int col = 0; col < m.m_cols; col++) { | ||
| 2933 | - for (int p = m.m_colstart[col] ; p < m.m_colstart[col+1] ; p++) { | ||
| 2934 | - int i = wrk_int[m.m_rowinx[p]]++; | ||
| 2935 | - result.m_rowinx[i] = col; | ||
| 2936 | - result.m_data[i] = m.m_data[p] ; | ||
| 2937 | - } | 2939 | + // Setup the number of non-zero elements in each row |
| 2940 | + // for (p = 0 ; p < Ap [n] ; p++) w [Ai [p]]++ ; | ||
| 2941 | + // Ap[n] = m.m_colstart[col] | ||
| 2942 | + // n = m.m_cols | ||
| 2943 | + // Ai[p] = m.m_rowinx[p] | ||
| 2944 | + for (int p = 0; p < m.m_colstart[m.m_cols]; ++p) { | ||
| 2945 | + wrk_int[m.m_rowinx[p]]++; | ||
| 2938 | } | 2946 | } |
| 2939 | - } | ||
| 2940 | 2947 | ||
| 2941 | - // Case B: Logical transponse, no assignment of values is performed | ||
| 2942 | - else { | ||
| 2943 | - for (int col = 0; col < m.m_cols; col++) { | ||
| 2944 | - for (int p = m.m_colstart[col] ; p < m.m_colstart[col+1] ; p++) | ||
| 2945 | - result.m_rowinx[wrk_int[m.m_rowinx[p]]++] = col; | 2948 | + // Set row pointers. To use a GSparseSymbolic function we have to |
| 2949 | + // allocate and object (but this does not take memory) | ||
| 2950 | + cs_cumsum(result.m_colstart, wrk_int, m.m_rows); | ||
| 2951 | + | ||
| 2952 | + // Case A: Normal transponse, including assignment of values | ||
| 2953 | + if (values) { | ||
| 2954 | + for (int col = 0; col < m.m_cols; ++col) { | ||
| 2955 | + for (int p = m.m_colstart[col]; p < m.m_colstart[col+1] ; ++p) { | ||
| 2956 | + int i = wrk_int[m.m_rowinx[p]]++; | ||
| 2957 | + result.m_rowinx[i] = col; | ||
| 2958 | + result.m_data[i] = m.m_data[p] ; | ||
| 2959 | + } | ||
| 2960 | + } | ||
| 2946 | } | 2961 | } |
| 2947 | - } | ||
| 2948 | 2962 | ||
| 2949 | - // Return transponse matrix | ||
| 2950 | - return result; | 2963 | + // Case B: Logical transponse, no assignment of values is performed |
| 2964 | + else { | ||
| 2965 | + for (int col = 0; col < m.m_cols; ++col) { | ||
| 2966 | + for (int p = m.m_colstart[col]; p < m.m_colstart[col+1] ; ++p) { | ||
| 2967 | + result.m_rowinx[wrk_int[m.m_rowinx[p]]++] = col; | ||
| 2968 | + } | ||
| 2969 | + } | ||
| 2970 | + } | ||
| 2971 | + | ||
| 2972 | + // Free workspace | ||
| 2973 | + delete [] wrk_int; | ||
| 2974 | + | ||
| 2975 | + // Return transponse matrix | ||
| 2976 | + return result; | ||
| 2951 | 2977 | ||
| 2952 | } | 2978 | } |
| 2953 | 2979 | ||
| 2954 | 2980 | ||
| 2955 | /*========================================================================== | 2981 | /*========================================================================== |
| 2956 | = = | 2982 | = = |
| 2957 | - = Other functions used by GSparseMatrix = | 2983 | + = Other functions = |
| 2958 | = = | 2984 | = = |
| 2959 | ==========================================================================*/ | 2985 | ==========================================================================*/ |
| 2960 | 2986 | ||
| @@ -2970,22 +2996,22 @@ GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) | @@ -2970,22 +2996,22 @@ GSparseMatrix cs_transpose(const GSparseMatrix& m, int values) | ||
| 2970 | ***************************************************************************/ | 2996 | ***************************************************************************/ |
| 2971 | double cs_cumsum(int* p, int* c, int n) | 2997 | double cs_cumsum(int* p, int* c, int n) |
| 2972 | { | 2998 | { |
| 2973 | - // Signal error if one of the input pointers is NULL | ||
| 2974 | - if (!p || !c) return (-1); | ||
| 2975 | - | ||
| 2976 | - // Initialise sums (integer and double) | ||
| 2977 | - int nz = 0; | ||
| 2978 | - double nz2 = 0.0; | ||
| 2979 | - | ||
| 2980 | - // Evaluate p[0..n] = cumulative sum of c[0..n-1] | ||
| 2981 | - for (int i = 0; i < n; ++i) { | ||
| 2982 | - p[i] = nz ; | ||
| 2983 | - nz += c[i]; | ||
| 2984 | - nz2 += c[i]; // also in double to avoid int overflow | ||
| 2985 | - c[i] = p[i]; // also copy p[0..n-1] back into c[0..n-1] | ||
| 2986 | - } | ||
| 2987 | - p[n] = nz ; | 2999 | + // Signal error if one of the input pointers is NULL |
| 3000 | + if (!p || !c) return (-1); | ||
| 3001 | + | ||
| 3002 | + // Initialise sums (integer and double) | ||
| 3003 | + int nz = 0; | ||
| 3004 | + double nz2 = 0.0; | ||
| 3005 | + | ||
| 3006 | + // Evaluate p[0..n] = cumulative sum of c[0..n-1] | ||
| 3007 | + for (int i = 0; i < n; ++i) { | ||
| 3008 | + p[i] = nz ; | ||
| 3009 | + nz += c[i]; | ||
| 3010 | + nz2 += c[i]; // also in double to avoid int overflow | ||
| 3011 | + c[i] = p[i]; // also copy p[0..n-1] back into c[0..n-1] | ||
| 3012 | + } | ||
| 3013 | + p[n] = nz ; | ||
| 2988 | 3014 | ||
| 2989 | - // Return cumulative sum of c[0..n-1] | ||
| 2990 | - return nz2; | 3015 | + // Return cumulative sum of c[0..n-1] |
| 3016 | + return nz2; | ||
| 2991 | } | 3017 | } |