Mercurial > octave
diff libinterp/dldfcn/__ichol__.cc @ 19055:38937efbee21
Incorporate new functions ichol and ilu into Octave.
* NEWS: Announce new functions.
* aspell-octave.en.pws: Add new functions names to custom Octave dictionary.
* sparse.txi: Add functions to Octave manual.
* __unimplemented__.m: Remove functions from unimplemented list.
* lu.cc (Flu), luinc.cc (Fluinc), chol.cc (Fchol): Add seealso links in
docstrings.
* __ichol__.cc: Wrap long lines to less than 80 chars. Remove trailing
whitespace. Don't repeat input validation done in ichol.m for internal
functions. Avoid resizing retval vector.
* __ilu__.cc: Wrap long lines to less than 80 chars. Remove trailing
whitespace. Don't repeat input validation done in ichol.m for internal
functions. Avoid resizing retval vector.
* ichol.m: Rewrite docstring. Use Octave coding conventions (double quotes
hash for comments, ! instead of ~). Replace %!error tests not being run
with fail().
* ilu.m: Rewrite docstring. Use Octave coding conventions (double quotes
hash for comments, ! instead of ~). Replace %!error tests not being run
with fail().
author | Rik <rik@octave.org> |
---|---|
date | Tue, 26 Aug 2014 15:27:21 -0700 |
parents | df64071e538c |
children | af9c22e20a57 |
line wrap: on
line diff
--- a/libinterp/dldfcn/__ichol__.cc Mon Aug 18 12:32:16 2014 +0100 +++ b/libinterp/dldfcn/__ichol__.cc Tue Aug 26 15:27:21 2014 -0700 @@ -1,22 +1,25 @@ -/** - * Copyright (C) 2013 Kai T. Ohlhus <k.ohlhus@gmail.com> - * Copyright (C) 2014 Eduardo Ramos Fernández <eduradical951@gmail.com> - * - * This file is part of Octave. - * - * Octave is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 3 of the License, or (at your option) any later - * version. - * - * Octave is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. - */ +/* + +Copyright (C) 2014 Eduardo Ramos Fernández <eduradical951@gmail.com> +Copyright (C) 2013 Kai T. Ohlhus <k.ohlhus@gmail.com> + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ #ifdef HAVE_CONFIG_H #include <config.h> @@ -25,49 +28,46 @@ #include "defun-dld.h" #include "parse.h" -// Secondary functions for complex and real case used -// in ichol algorithms. +// Secondary functions for complex and real case used in ichol algorithms. Complex ichol_mult_complex (Complex a, Complex b) { b.imag (-std::imag (b)); return a * b; } +double ichol_mult_real (double a, double b) +{ + return a * b; +} + bool ichol_checkpivot_complex (Complex pivot) { if (pivot.imag () != 0) { - error ("ichol: Non-real pivot encountered. \ - The matrix must be hermitian."); + error ("ichol: non-real pivot encountered. The matrix must be hermitian."); return false; } else if (pivot.real () < 0) { - error ("ichol: Non-positive pivot encountered."); + error ("ichol: negative pivot encountered"); return false; } return true; - } bool ichol_checkpivot_real (double pivot) { if (pivot < 0) { - error ("ichol: Non-positive pivot encountered."); + error ("ichol: negative pivot encountered"); return false; } return true; } -double ichol_mult_real (double a, double b) -{ - return a * b; -} - -template <typename octave_matrix_t, typename T, T (*ichol_mult) (T, T), +template <typename octave_matrix_t, typename T, T (*ichol_mult) (T, T), bool (*ichol_checkpivot) (T)> -void ichol_0 (octave_matrix_t& sm, const std::string michol = "off") +void ichol_0 (octave_matrix_t& sm, const std::string michol = "off") { const octave_idx_type n = sm.cols (); @@ -100,7 +100,7 @@ dropsums[i] = 0; } - // Main loop + // Main loop for (k = 0; k < n; k++) { j1 = cidx[k]; @@ -110,7 +110,7 @@ jrow = Llist [k]; // Iterate over each non-zero element in the actual row. - while (jrow != -1) + while (jrow != -1) { jjrow = Lfirst[jrow]; jend = cidx[jrow+1]; @@ -122,16 +122,15 @@ if (jw != -1) data[jw] -= tl; else - // Because the simetry of the matrix we know the drops - // in the column r are also in the column k. + // Because of the symmetry of the matrix, we know + // the drops in the column r are also in the column k. if (opt == ON) { dropsums[r] -= tl; dropsums[k] -= tl; } } - // Update the linked list and the first entry of the - // actual column. + // Update the linked list and the first entry of the actual column. if ((jjrow + 1) < jend) { Lfirst[jrow]++; @@ -149,7 +148,7 @@ if (ridx[j1] != k) { - error ("ichol: There is a pivot equal to zero."); + error ("ichol: encountered a pivot equal to 0"); break; } @@ -158,13 +157,12 @@ data[cidx[k]] = std::sqrt (data[j1]); - // Update Llist and Lfirst with the k-column information. - // Also scale the column elements by the pivot and reset - // the working array iw. - if (k < (n - 1)) + // Update Llist and Lfirst with the k-column information. Also, + // scale the column elements by the pivot and reset the working array iw. + if (k < (n - 1)) { iw[ridx[j1]] = -1; - for(i = j1 + 1; i < j2; i++) + for (i = j1 + 1; i < j2; i++) { iw[ridx[i]] = -1; data[i] /= data[j1]; @@ -182,8 +180,8 @@ } DEFUN_DLD (__ichol0__, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{L} =} __ichol0__ (@var{A})\n\ -@deftypefnx {Loadable Function} {@var{L} =} __ichol0__ (@var{A}, @var{michol})\n\ +@deftypefn {Loadable Function} {@var{L} =} __ichol0__ (@var{A})\n\ +@deftypefnx {Loadable Function} {@var{L} =} __ichol0__ (@var{A}, @var{michol})\n\ Undocumented internal function.\n\ @end deftypefn") @@ -192,7 +190,6 @@ int nargin = args.length (); std::string michol = "off"; - if (nargout > 1 || nargin < 1 || nargin > 2) { @@ -200,65 +197,47 @@ return retval; } - if (args(0).is_scalar_type () || ! args(0).is_sparse_type ()) - error ("__ichol0__: 1. parameter must be a sparse square matrix."); - - if (args(0).is_empty ()) - { - retval(0) = octave_value (SparseMatrix ()); - return retval; - } - + if (nargin == 2) + michol = args(1).string_value (); - if (nargin == 2) - { - michol = args(1).string_value (); - if (error_state || ! (michol == "on" || michol == "off")) - error ("__ichol0__: 2. parameter must be 'on' or 'off' character string."); - } - - - if (!error_state) + // In ICHOL0 algorithm the zero-pattern of the input matrix is preserved + // so it's structure does not change during the algorithm. The same input + // matrix is used to build the output matrix due to that fact. + octave_value_list param_list; + if (!args(0).is_complex_type ()) { - // In ICHOL0 algorithm the zero-pattern of the input matrix is preserved so - // it's structure does not change during the algorithm. The same input - // matrix is used to build the output matrix due to that fact. - octave_value_list param_list; - if (!args(0).is_complex_type ()) - { - SparseMatrix sm = args(0).sparse_matrix_value (); - param_list.append (sm); - sm = feval ("tril", param_list)(0).sparse_matrix_value (); - ichol_0 <SparseMatrix, double, ichol_mult_real, ichol_checkpivot_real> (sm, michol); - if (! error_state) - retval(0) = octave_value (sm); - } - else - { - SparseComplexMatrix sm = args(0).sparse_complex_matrix_value (); - param_list.append (sm); - sm = feval ("tril", param_list)(0).sparse_complex_matrix_value (); - ichol_0 <SparseComplexMatrix, Complex, ichol_mult_complex, ichol_checkpivot_complex> (sm, michol); - if (! error_state) - retval(0) = octave_value (sm); - } - + SparseMatrix sm = args(0).sparse_matrix_value (); + param_list.append (sm); + sm = feval ("tril", param_list)(0).sparse_matrix_value (); + ichol_0 <SparseMatrix, double, ichol_mult_real, + ichol_checkpivot_real> (sm, michol); + if (! error_state) + retval(0) = sm; + } + else + { + SparseComplexMatrix sm = args(0).sparse_complex_matrix_value (); + param_list.append (sm); + sm = feval ("tril", param_list)(0).sparse_complex_matrix_value (); + ichol_0 <SparseComplexMatrix, Complex, ichol_mult_complex, + ichol_checkpivot_complex> (sm, michol); + if (! error_state) + retval(0) = sm; } return retval; } -template <typename octave_matrix_t, typename T, T (*ichol_mult) (T, T), +template <typename octave_matrix_t, typename T, T (*ichol_mult) (T, T), bool (*ichol_checkpivot) (T)> void ichol_t (const octave_matrix_t& sm, octave_matrix_t& L, const T* cols_norm, const T droptol, const std::string michol = "off") - + { const octave_idx_type n = sm.cols (); - octave_idx_type j, jrow, jend, jjrow, jw, i, k, jj, Llist_len, total_len, w_len, - max_len, ind; - + octave_idx_type j, jrow, jend, jjrow, jw, i, k, jj, Llist_len, total_len, + w_len, max_len, ind; char opt; enum {OFF, ON}; if (michol == "on") @@ -271,13 +250,13 @@ octave_idx_type* ridx = sm.ridx (); T* data = sm.data (); - // Output matrix data structures. Because it is not known the - // final zero pattern of the output matrix due to fill-in elements, - // an heuristic approach has been adopted for memory allocation. The - // size of ridx_out_l and data_out_l is incremented 10% of their actual - // size (nnz(A) in the beginning). If that amount is less than n, their - // size is just incremented in n elements. This way the number of - // reallocations decrease throughout the process, obtaining a good performance. + // Output matrix data structures. Because the final zero pattern pattern of + // the output matrix is not known due to fill-in elements, a heuristic + // approach has been adopted for memory allocation. The size of ridx_out_l + // and data_out_l is incremented 10% of their actual size (nnz (A) in the + // beginning). If that amount is less than n, their size is just incremented + // in n elements. This way the number of reallocations decreases throughout + // the process, obtaining a good performance. max_len = sm.nnz (); max_len += (0.1 * max_len) > n ? 0.1 * max_len : n; Array <octave_idx_type> cidx_out_l (dim_vector (n + 1, 1)); @@ -295,7 +274,6 @@ std::vector <octave_idx_type> vec; vec.resize (n); - T zero = T (0); cidx_l[0] = cidx[0]; for (i = 0; i < n; i++) @@ -321,7 +299,7 @@ } } jrow = Llist[k]; - while (jrow != -1) + while (jrow != -1) { jjrow = Lfirst[jrow]; jend = cidx_l[jrow+1]; @@ -329,18 +307,17 @@ { j = ridx_l[jj]; // If the element in the j position of the row is zero, - // then it will become non-zero, so we add it to the - // vector that keeps track of non-zero elements in the working row. + // then it will become non-zero, so we add it to the + // vector that tracks non-zero elements in the working row. if (w_data[j] == zero) { - vec[ind] = j; + vec[ind] = j; ind++; } w_data[j] -= ichol_mult (data_l[jj], data_l[jjrow]); - } - // Update the actual column first element and update the - // linked list of the jrow row. + // Update the actual column first element and + // update the linked list of the jrow row. if ((jjrow + 1) < jend) { Lfirst[jrow]++; @@ -362,21 +339,20 @@ ridx_out_l.resize (dim_vector (max_len, 1)); ridx_l = ridx_out_l.fortran_vec (); } - + // The sorting of the non-zero elements of the working column can be - // handled in a couple of ways. The most efficient two I found, are - // keeping the elements in an ordered binary search tree dinamically - // or keep them unsorted in a vector and at the end of the outer - // iteration order them. The last approach exhibit lower execution - // times. + // handled in a couple of ways. The most efficient two I found, are + // keeping the elements in an ordered binary search tree dynamically or + // keep them unsorted in a vector and at the end of the outer iteration + // order them. The last approach exhibits lower execution times. std::sort (vec.begin (), vec.begin () + ind); data_l[total_len] = w_data[k]; ridx_l[total_len] = k; w_len = 1; - // Extract then non-zero elements of working column and drop the - // elements that are lower than droptol * cols_norm[k]. + // Extract the non-zero elements of working column and + // drop the elements that are lower than droptol * cols_norm[k]. for (i = 0; i < ind ; i++) { jrow = vec[i]; @@ -407,29 +383,29 @@ if (data_l[total_len] == zero) { - error ("ichol: There is a pivot equal to zero."); + error ("ichol: encountered a pivot equal to 0"); break; } else if (! ichol_checkpivot (data_l[total_len])) break; - // Once the elements are dropped and compensation of columns - // sums are done, scale the elements by the pivot. + // Once elements are dropped and compensation of column sums are done, + // scale the elements by the pivot. data_l[total_len] = std::sqrt (data_l[total_len]); for (jj = total_len + 1; jj < (total_len + w_len); jj++) data_l[jj] /= data_l[total_len]; total_len += w_len; - // Check if there are too many elements to be indexed with octave_idx_type - // type due to fill-in during the process. + // Check if there are too many elements to be indexed with + // octave_idx_type type due to fill-in during the process. if (total_len < 0) { - error ("ichol: Integer overflow. Too many fill-in elements in L"); + error ("ichol: integer overflow. Too many fill-in elements in L"); break; } cidx_l[k+1] = cidx_l[k] - cidx_l[0] + w_len; // Update Llist and Lfirst with the k-column information. - if (k < (n - 1)) + if (k < (n - 1)) { Lfirst[k] = cidx_l[k]; if ((Lfirst[k] + 1) < cidx_l[k+1]) @@ -440,8 +416,7 @@ Llist[jjrow] = k; } } - - } + } if (! error_state) { @@ -455,13 +430,12 @@ L.data (i) = data_l[i]; } } - } DEFUN_DLD (__icholt__, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{L} =} __icholt__ (@var{A})\n\ -@deftypefnx {Loadable Function} {@var{L} =} __icholt__ (@var{A}, @var{droptol})\n\ -@deftypefnx {Loadable Function} {@var{L} =} __icholt__ (@var{A}, @var{droptol}, @var{michol})\n\ +@deftypefn {Loadable Function} {@var{L} =} __icholt__ (@var{A})\n\ +@deftypefnx {Loadable Function} {@var{L} =} __icholt__ (@var{A}, @var{droptol})\n\ +@deftypefnx {Loadable Function} {@var{L} =} __icholt__ (@var{A}, @var{droptol}, @var{michol})\n\ Undocumented internal function.\n\ @end deftypefn") { @@ -470,7 +444,6 @@ // Default values of parameters std::string michol = "off"; double droptol = 0; - if (nargout > 1 || nargin < 1 || nargin > 3) { @@ -478,69 +451,51 @@ return retval; } - if (args(0).is_scalar_type () || ! args(0).is_sparse_type ()) - error ("__icholt__: 1. parameter must be a sparse square matrix."); + // Don't repeat input validation of arguments done in ichol.m - if (args(0).is_empty ()) - { - retval(0) = octave_value (SparseMatrix ()); - return retval; - } + if (nargin >= 2) + droptol = args(1).double_value (); - if (! error_state && (nargin >= 2)) - { - droptol = args(1).double_value (); - if (error_state || (droptol < 0) || ! args(1).is_real_scalar ()) - error ("__icholt__: 2. parameter must be a positive real scalar."); - } + if (nargin == 3) + michol = args(2).string_value (); - if (! error_state && (nargin == 3)) - { - michol = args(2).string_value (); - if (error_state || !(michol == "on" || michol == "off")) - error ("__icholt__: 3. parameter must be 'on' or 'off' character string."); - } - - if (!error_state) + octave_value_list param_list; + if (! args(0).is_complex_type ()) { - octave_value_list param_list; - if (! args(0).is_complex_type ()) - { - Array <double> cols_norm; - SparseMatrix L; - param_list.append (args(0).sparse_matrix_value ()); - SparseMatrix sm_l = feval ("tril", - param_list)(0).sparse_matrix_value (); - param_list(0) = sm_l; - param_list(1) = 1; - param_list(2) = "cols"; - cols_norm = feval ("norm", param_list)(0).vector_value (); - param_list.clear (); - ichol_t <SparseMatrix, - double, ichol_mult_real, ichol_checkpivot_real> - (sm_l, L, cols_norm.fortran_vec (), droptol, michol); - if (! error_state) - retval(0) = octave_value (L); - } - else - { - Array <Complex> cols_norm; - SparseComplexMatrix L; - param_list.append (args(0).sparse_complex_matrix_value ()); - SparseComplexMatrix sm_l = feval ("tril", - param_list)(0).sparse_complex_matrix_value (); - param_list(0) = sm_l; - param_list(1) = 1; - param_list(2) = "cols"; - cols_norm = feval ("norm", param_list)(0).complex_vector_value (); - param_list.clear (); - ichol_t <SparseComplexMatrix, - Complex, ichol_mult_complex, ichol_checkpivot_complex> - (sm_l, L, cols_norm.fortran_vec (), Complex (droptol), michol); - if (! error_state) - retval(0) = octave_value (L); - } - + Array <double> cols_norm; + SparseMatrix L; + param_list.append (args(0).sparse_matrix_value ()); + SparseMatrix sm_l = + feval ("tril", param_list)(0).sparse_matrix_value (); + param_list(0) = sm_l; + param_list(1) = 1; + param_list(2) = "cols"; + cols_norm = feval ("norm", param_list)(0).vector_value (); + param_list.clear (); + ichol_t <SparseMatrix, + double, ichol_mult_real, ichol_checkpivot_real> + (sm_l, L, cols_norm.fortran_vec (), droptol, michol); + if (! error_state) + retval(0) = L; + } + else + { + Array <Complex> cols_norm; + SparseComplexMatrix L; + param_list.append (args(0).sparse_complex_matrix_value ()); + SparseComplexMatrix sm_l = + feval ("tril", param_list)(0).sparse_complex_matrix_value (); + param_list(0) = sm_l; + param_list(1) = 1; + param_list(2) = "cols"; + cols_norm = feval ("norm", param_list)(0).complex_vector_value (); + param_list.clear (); + ichol_t <SparseComplexMatrix, + Complex, ichol_mult_complex, ichol_checkpivot_complex> + (sm_l, L, cols_norm.fortran_vec (), + Complex (droptol), michol); + if (! error_state) + retval(0) = L; } return retval; @@ -550,3 +505,4 @@ ## No test needed for internal helper function. %!assert (1) */ +