Mercurial > octave-nkf
changeset 15076:000587f92082
rename src/DLD-FUNCTIONS directory to src/dldfcn
* src/dldfcn: Rename from src/DLD-FUNCTIONS.
* autogen.sh, src/Makefile.am, src/dldfcn/config-module.awk,
src/dldfcn/config-module.sh: Change all uses of DLD-FUNCTIONS to be
dldfcn. Change all uses of DLD_FUNCTIONS to be DLDFCN.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 31 Jul 2012 21:57:58 -0400 |
parents | b62b0b85369c |
children | f0b04a20d7cf |
files | autogen.sh src/DLD-FUNCTIONS/__delaunayn__.cc src/DLD-FUNCTIONS/__dsearchn__.cc src/DLD-FUNCTIONS/__fltk_uigetfile__.cc src/DLD-FUNCTIONS/__glpk__.cc src/DLD-FUNCTIONS/__init_fltk__.cc src/DLD-FUNCTIONS/__init_gnuplot__.cc src/DLD-FUNCTIONS/__magick_read__.cc src/DLD-FUNCTIONS/__voronoi__.cc src/DLD-FUNCTIONS/amd.cc src/DLD-FUNCTIONS/ccolamd.cc src/DLD-FUNCTIONS/chol.cc src/DLD-FUNCTIONS/colamd.cc src/DLD-FUNCTIONS/config-module.awk src/DLD-FUNCTIONS/config-module.sh src/DLD-FUNCTIONS/convhulln.cc src/DLD-FUNCTIONS/dmperm.cc src/DLD-FUNCTIONS/eigs.cc src/DLD-FUNCTIONS/fftw.cc src/DLD-FUNCTIONS/module-files src/DLD-FUNCTIONS/oct-qhull.h src/DLD-FUNCTIONS/qr.cc src/DLD-FUNCTIONS/symbfact.cc src/DLD-FUNCTIONS/symrcm.cc src/DLD-FUNCTIONS/tsearch.cc src/DLD-FUNCTIONS/urlwrite.cc src/Makefile.am src/dldfcn/__delaunayn__.cc src/dldfcn/__dsearchn__.cc src/dldfcn/__fltk_uigetfile__.cc src/dldfcn/__glpk__.cc src/dldfcn/__init_fltk__.cc src/dldfcn/__init_gnuplot__.cc src/dldfcn/__magick_read__.cc src/dldfcn/__voronoi__.cc src/dldfcn/amd.cc src/dldfcn/ccolamd.cc src/dldfcn/chol.cc src/dldfcn/colamd.cc src/dldfcn/config-module.awk src/dldfcn/config-module.sh src/dldfcn/convhulln.cc src/dldfcn/dmperm.cc src/dldfcn/eigs.cc src/dldfcn/fftw.cc src/dldfcn/module-files src/dldfcn/oct-qhull.h src/dldfcn/qr.cc src/dldfcn/symbfact.cc src/dldfcn/symrcm.cc src/dldfcn/tsearch.cc src/dldfcn/urlwrite.cc src/link-deps.mk |
diffstat | 53 files changed, 15283 insertions(+), 15283 deletions(-) [+] |
line wrap: on
line diff
--- a/autogen.sh Tue Jul 31 20:46:47 2012 -0400 +++ b/autogen.sh Tue Jul 31 21:57:58 2012 -0400 @@ -30,9 +30,9 @@ (cd doc/interpreter; ./config-images.sh) -echo "generating src/DLD-FUNCTIONS/module.mk..." +echo "generating src/dldfcn/module.mk..." -(cd src/DLD-FUNCTIONS; ./config-module.sh) +(cd src/dldfcn; ./config-module.sh) echo "bootstrapping..."
--- a/src/DLD-FUNCTIONS/__delaunayn__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -/* - -Copyright (C) 2000-2012 Kai Habel - -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/>. - -*/ - -/* - 16. July 2000 - Kai Habel: first release - - 25. September 2002 - Changes by Rafael Laboissiere <rafael@laboissiere.net> - - * Added Qbb option to normalize the input and avoid crashes in Octave. - * delaunayn accepts now a second (optional) argument that must be a string - containing extra options to the qhull command. - * Fixed doc string. The dimension of the result matrix is [m, dim+1], and - not [n, dim-1]. - - 6. June 2006: Changes by Alexander Barth <abarth@marine.usf.edu> - - * triangulate non-simplicial facets - * allow options to be specified as cell array of strings - * change the default options (for compatibility with matlab) -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <iostream> -#include <string> - -#include "Cell.h" -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" -#include "unwind-prot.h" - -#if defined (HAVE_QHULL) -# include "oct-qhull.h" -# if defined (NEED_QHULL_VERSION) -char qh_version[] = "__delaunayn__.oct 2007-08-21"; -# endif -#endif - -static void -close_fcn (FILE *f) -{ - gnulib::fclose (f); -} - -DEFUN_DLD (__delaunayn__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{T} =} __delaunayn__ (@var{pts})\n\ -@deftypefnx {Loadable Function} {@var{T} =} __delaunayn__ (@var{pts}, @var{options})\n\ -Undocumented internal function.\n\ -@end deftypefn") - -{ - octave_value_list retval; - -#if defined (HAVE_QHULL) - - retval(0) = 0.0; - - int nargin = args.length (); - if (nargin < 1 || nargin > 2) - { - print_usage (); - return retval; - } - - Matrix p (args(0).matrix_value ()); - const octave_idx_type dim = p.columns (); - const octave_idx_type n = p.rows (); - - // Default options - std::string options; - if (dim <= 3) - options = "Qt Qbb Qc Qz"; - else - options = "Qt Qbb Qc Qx"; - - if (nargin == 2) - { - if (args(1).is_string ()) - options = args(1).string_value (); - else if (args(1).is_empty ()) - ; // Use default options - else if (args(1).is_cellstr ()) - { - options = ""; - Array<std::string> tmp = args(1).cellstr_value (); - - for (octave_idx_type i = 0; i < tmp.numel (); i++) - options += tmp(i) + " "; - } - else - { - error ("__delaunayn__: OPTIONS argument must be a string, cell array of strings, or empty"); - return retval; - } - } - - if (n > dim + 1) - { - p = p.transpose (); - double *pt_array = p.fortran_vec (); - boolT ismalloc = false; - - // Qhull flags argument is not const char* - OCTAVE_LOCAL_BUFFER (char, flags, 9 + options.length ()); - - sprintf (flags, "qhull d %s", options.c_str ()); - - unwind_protect frame; - - // Replace the outfile pointer with stdout for debugging information. -#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) - FILE *outfile = gnulib::fopen ("NUL", "w"); -#else - FILE *outfile = gnulib::fopen ("/dev/null", "w"); -#endif - FILE *errfile = stderr; - - if (outfile) - frame.add_fcn (close_fcn, outfile); - else - { - error ("__delaunayn__: unable to create temporary file for output"); - return retval; - } - - int exitcode = qh_new_qhull (dim, n, pt_array, - ismalloc, flags, outfile, errfile); - if (! exitcode) - { - // triangulate non-simplicial facets - qh_triangulate (); - - facetT *facet; - vertexT *vertex, **vertexp; - octave_idx_type nf = 0, i = 0; - - FORALLfacets - { - if (! facet->upperdelaunay) - nf++; - - // Double check. Non-simplicial facets will cause segfault below - if (! facet->simplicial) - { - error ("__delaunayn__: Qhull returned non-simplicial facets -- try delaunayn with different options"); - exitcode = 1; - break; - } - } - - if (! exitcode) - { - Matrix simpl (nf, dim+1); - - FORALLfacets - { - if (! facet->upperdelaunay) - { - octave_idx_type j = 0; - - FOREACHvertex_ (facet->vertices) - { - simpl(i, j++) = 1 + qh_pointid(vertex->point); - } - i++; - } - } - - retval(0) = simpl; - } - } - else - error ("__delaunayn__: qhull failed"); - - // Free memory from Qhull - qh_freeqhull (! qh_ALL); - - int curlong, totlong; - qh_memfreeshort (&curlong, &totlong); - - if (curlong || totlong) - warning ("__delaunay__: did not free %d bytes of long memory (%d pieces)", - totlong, curlong); - } - else if (n == dim + 1) - { - // one should check if nx points span a simplex - // I will look at this later. - RowVector vec (n); - for (octave_idx_type i = 0; i < n; i++) - vec(i) = i + 1.0; - - retval(0) = vec; - } - -#else - error ("__delaunayn__: not available in this version of Octave"); -#endif - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/
--- a/src/DLD-FUNCTIONS/__dsearchn__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - -Copyright (C) 2007-2012 David Bateman - -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> -#endif - -#include <iostream> -#include <fstream> -#include <string> - -#include "lo-math.h" - -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" - -DEFUN_DLD (__dsearchn__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{idx}, @var{d}] =} dsearch (@var{x}, @var{xi})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - int nargin = args.length (); - octave_value_list retval; - - if (nargin != 2) - { - print_usage (); - return retval; - } - - Matrix x = args(0).matrix_value ().transpose (); - Matrix xi = args(1).matrix_value ().transpose (); - - if (! error_state) - { - if (x.rows () != xi.rows () || x.columns () < 1) - error ("__dsearch__: number of rows of X and XI must match"); - else - { - octave_idx_type n = x.rows (); - octave_idx_type nx = x.columns (); - octave_idx_type nxi = xi.columns (); - - ColumnVector idx (nxi); - double *pidx = idx.fortran_vec (); - ColumnVector dist (nxi); - double *pdist = dist.fortran_vec (); - -#define DIST(dd, y, yi, m) \ - dd = 0.; \ - for (octave_idx_type k = 0; k < m; k++) \ - { \ - double yd = y[k] - yi[k]; \ - dd += yd * yd; \ - } \ - dd = sqrt (dd); - - const double *pxi = xi.fortran_vec (); - for (octave_idx_type i = 0; i < nxi; i++) - { - double d0; - const double *px = x.fortran_vec (); - DIST(d0, px, pxi, n); - *pidx = 1.; - for (octave_idx_type j = 1; j < nx; j++) - { - px += n; - double d; - DIST (d, px, pxi, n); - if (d < d0) - { - d0 = d; - *pidx = static_cast<double>(j + 1); - } - OCTAVE_QUIT; - } - - *pdist++ = d0; - pidx++; - pxi += n; - } - - retval(1) = dist; - retval(0) = idx; - } - } - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/
--- a/src/DLD-FUNCTIONS/__fltk_uigetfile__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - -Copyright (C) 2010-2012 Kai Habel - -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> -#endif - -#if defined (HAVE_FLTK) - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#endif - -#include <FL/Fl.H> -#include <FL/Fl_File_Chooser.H> - -// FLTK headers may include X11/X.h which defines Complex, and that -// conflicts with Octave's Complex typedef. We don't need the X11 -// Complex definition in this file, so remove it before including Octave -// headers which may require Octave's Complex typedef. -#undef Complex - -#include "defun-dld.h" -#include "file-ops.h" - -DEFUN_DLD (__fltk_uigetfile__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} __fltk_uigetfile__ (@dots{})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - // Expected argument list: - // - // args(0) ... FileFilter in fltk format - // args(1) ... Title - // args(2) ... Default Filename - // args(3) ... PostionValue [x,y] - // args(4) ... SelectValue "on"/"off"/"dir"/"create" - - octave_value_list retval (3, octave_value (0)); - - std::string file_filter = args(0).string_value (); - std::string title = args(1).string_value (); - std::string default_name = args(2).string_value (); - Matrix pos = args(3).matrix_value (); - - int multi_type = Fl_File_Chooser::SINGLE; - std::string flabel = "Filename:"; - - std::string multi = args(4).string_value (); - if (multi == "on") - multi_type = Fl_File_Chooser::MULTI; - else if (multi == "dir") - { - multi_type = Fl_File_Chooser::DIRECTORY; - flabel = "Directory:"; - } - else if (multi == "create") - multi_type = Fl_File_Chooser::CREATE; - - Fl_File_Chooser::filename_label = flabel.c_str (); - - Fl_File_Chooser fc (default_name.c_str (), file_filter.c_str (), - multi_type, title.c_str ()); - - fc.preview (0); - - if (multi_type == Fl_File_Chooser::CREATE) - fc.ok_label ("Save"); - - fc.show (); - - while (fc.shown ()) - Fl::wait (); - - if (fc.value ()) - { - int file_count = fc.count (); - std::string fname; - - //fltk uses forward slash even for windows - std::string sep = "/"; - std::size_t idx; - - if (file_count == 1 && multi_type != Fl_File_Chooser::DIRECTORY) - { - fname = fc.value (); - idx = fname.find_last_of (sep); - retval(0) = fname.substr (idx + 1); - } - else - { - Cell file_cell = Cell (file_count, 1); - for (octave_idx_type n = 1; n <= file_count; n++) - { - fname = fc.value (n); - idx = fname.find_last_of (sep); - file_cell(n - 1) = fname.substr (idx + 1); - } - retval(0) = file_cell; - } - - if (multi_type == Fl_File_Chooser::DIRECTORY) - retval(0) = std::string (fc.value ()); - else - { - retval(1) = std::string (fc.directory ()) + sep; - retval(2) = fc.filter_value () + 1; - } - } - - fc.hide (); - Fl::flush (); - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/ - -#endif
--- a/src/DLD-FUNCTIONS/__glpk__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,861 +0,0 @@ -/* - -Copyright (C) 2005-2012 Nicolo' Giorgetti - -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> -#endif - -#include <cfloat> -#include <csetjmp> -#include <ctime> - -#include "lo-ieee.h" - -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-map.h" -#include "oct-obj.h" -#include "pager.h" - -#if defined (HAVE_GLPK) - -extern "C" -{ -#if defined (HAVE_GLPK_GLPK_H) -#include <glpk/glpk.h> -#else -#include <glpk.h> -#endif - -#if 0 -#ifdef GLPK_PRE_4_14 - -#ifndef _GLPLIB_H -#include <glplib.h> -#endif -#ifndef lib_set_fault_hook -#define lib_set_fault_hook lib_fault_hook -#endif -#ifndef lib_set_print_hook -#define lib_set_print_hook lib_print_hook -#endif - -#else - -void _glp_lib_print_hook (int (*func)(void *info, char *buf), void *info); -void _glp_lib_fault_hook (int (*func)(void *info, char *buf), void *info); - -#endif -#endif -} - -#define NIntP 17 -#define NRealP 10 - -int lpxIntParam[NIntP] = { - 0, - 1, - 0, - 1, - 0, - -1, - 0, - 200, - 1, - 2, - 0, - 1, - 0, - 0, - 2, - 2, - 1 -}; - -int IParam[NIntP] = { - LPX_K_MSGLEV, - LPX_K_SCALE, - LPX_K_DUAL, - LPX_K_PRICE, - LPX_K_ROUND, - LPX_K_ITLIM, - LPX_K_ITCNT, - LPX_K_OUTFRQ, - LPX_K_MPSINFO, - LPX_K_MPSOBJ, - LPX_K_MPSORIG, - LPX_K_MPSWIDE, - LPX_K_MPSFREE, - LPX_K_MPSSKIP, - LPX_K_BRANCH, - LPX_K_BTRACK, - LPX_K_PRESOL -}; - - -double lpxRealParam[NRealP] = { - 0.07, - 1e-7, - 1e-7, - 1e-9, - -DBL_MAX, - DBL_MAX, - -1.0, - 0.0, - 1e-6, - 1e-7 -}; - -int RParam[NRealP] = { - LPX_K_RELAX, - LPX_K_TOLBND, - LPX_K_TOLDJ, - LPX_K_TOLPIV, - LPX_K_OBJLL, - LPX_K_OBJUL, - LPX_K_TMLIM, - LPX_K_OUTDLY, - LPX_K_TOLINT, - LPX_K_TOLOBJ -}; - -static jmp_buf mark; //-- Address for long jump to jump to - -#if 0 -int -glpk_fault_hook (void * /* info */, char *msg) -{ - error ("CRITICAL ERROR in GLPK: %s", msg); - longjmp (mark, -1); -} - -int -glpk_print_hook (void * /* info */, char *msg) -{ - message (0, "%s", msg); - return 1; -} -#endif - -int -glpk (int sense, int n, int m, double *c, int nz, int *rn, int *cn, - double *a, double *b, char *ctype, int *freeLB, double *lb, - int *freeUB, double *ub, int *vartype, int isMIP, int lpsolver, - int save_pb, double *xmin, double *fmin, double *status, - double *lambda, double *redcosts, double *time, double *mem) -{ - int errnum; - int typx = 0; - int method; - - clock_t t_start = clock (); - -#if 0 -#ifdef GLPK_PRE_4_14 - lib_set_fault_hook (0, glpk_fault_hook); -#else - _glp_lib_fault_hook (glpk_fault_hook, 0); -#endif - - if (lpxIntParam[0] > 1) -#ifdef GLPK_PRE_4_14 - lib_set_print_hook (0, glpk_print_hook); -#else - _glp_lib_print_hook (glpk_print_hook, 0); -#endif -#endif - - LPX *lp = lpx_create_prob (); - - - //-- Set the sense of optimization - if (sense == 1) - lpx_set_obj_dir (lp, LPX_MIN); - else - lpx_set_obj_dir (lp, LPX_MAX); - - //-- If the problem has integer structural variables switch to MIP - if (isMIP) - lpx_set_class (lp, LPX_MIP); - - lpx_add_cols (lp, n); - for (int i = 0; i < n; i++) - { - //-- Define type of the structural variables - if (! freeLB[i] && ! freeUB[i]) - { - if (lb[i] != ub[i]) - lpx_set_col_bnds (lp, i+1, LPX_DB, lb[i], ub[i]); - else - lpx_set_col_bnds (lp, i+1, LPX_FX, lb[i], ub[i]); - } - else - { - if (! freeLB[i] && freeUB[i]) - lpx_set_col_bnds (lp, i+1, LPX_LO, lb[i], ub[i]); - else - { - if (freeLB[i] && ! freeUB[i]) - lpx_set_col_bnds (lp, i+1, LPX_UP, lb[i], ub[i]); - else - lpx_set_col_bnds (lp, i+1, LPX_FR, lb[i], ub[i]); - } - } - - // -- Set the objective coefficient of the corresponding - // -- structural variable. No constant term is assumed. - lpx_set_obj_coef(lp,i+1,c[i]); - - if (isMIP) - lpx_set_col_kind (lp, i+1, vartype[i]); - } - - lpx_add_rows (lp, m); - - for (int i = 0; i < m; i++) - { - /* If the i-th row has no lower bound (types F,U), the - corrispondent parameter will be ignored. - If the i-th row has no upper bound (types F,L), the corrispondent - parameter will be ignored. - If the i-th row is of S type, the i-th LB is used, but - the i-th UB is ignored. - */ - - switch (ctype[i]) - { - case 'F': - typx = LPX_FR; - break; - - case 'U': - typx = LPX_UP; - break; - - case 'L': - typx = LPX_LO; - break; - - case 'S': - typx = LPX_FX; - break; - - case 'D': - typx = LPX_DB; - break; - } - - lpx_set_row_bnds (lp, i+1, typx, b[i], b[i]); - - } - - lpx_load_matrix (lp, nz, rn, cn, a); - - if (save_pb) - { - static char tmp[] = "outpb.lp"; - if (lpx_write_cpxlp (lp, tmp) != 0) - { - error ("__glpk__: unable to write problem"); - longjmp (mark, -1); - } - } - - //-- scale the problem data (if required) - //-- if (scale && (!presol || method == 1)) lpx_scale_prob (lp); - //-- LPX_K_SCALE=IParam[1] LPX_K_PRESOL=IParam[16] - if (lpxIntParam[1] && (! lpxIntParam[16] || lpsolver != 1)) - lpx_scale_prob (lp); - - //-- build advanced initial basis (if required) - if (lpsolver == 1 && ! lpxIntParam[16]) - lpx_adv_basis (lp); - - for (int i = 0; i < NIntP; i++) - lpx_set_int_parm (lp, IParam[i], lpxIntParam[i]); - - for (int i = 0; i < NRealP; i++) - lpx_set_real_parm (lp, RParam[i], lpxRealParam[i]); - - if (lpsolver == 1) - method = 'S'; - else - method = 'T'; - - switch (method) - { - case 'S': - { - if (isMIP) - { - method = 'I'; - errnum = lpx_simplex (lp); - errnum = lpx_integer (lp); - } - else - errnum = lpx_simplex (lp); - } - break; - - case 'T': - errnum = lpx_interior (lp); - break; - - default: - break; -#if 0 -#ifdef GLPK_PRE_4_14 - insist (method != method); -#else - static char tmp[] = "method != method"; - glpk_fault_hook (0, tmp); -#endif -#endif - } - - /* errnum assumes the following results: - errnum = 0 <=> No errors - errnum = 1 <=> Iteration limit exceeded. - errnum = 2 <=> Numerical problems with basis matrix. - */ - if (errnum == LPX_E_OK) - { - if (isMIP) - { - *status = lpx_mip_status (lp); - *fmin = lpx_mip_obj_val (lp); - } - else - { - if (lpsolver == 1) - { - *status = lpx_get_status (lp); - *fmin = lpx_get_obj_val (lp); - } - else - { - *status = lpx_ipt_status (lp); - *fmin = lpx_ipt_obj_val (lp); - } - } - - if (isMIP) - { - for (int i = 0; i < n; i++) - xmin[i] = lpx_mip_col_val (lp, i+1); - } - else - { - /* Primal values */ - for (int i = 0; i < n; i++) - { - if (lpsolver == 1) - xmin[i] = lpx_get_col_prim (lp, i+1); - else - xmin[i] = lpx_ipt_col_prim (lp, i+1); - } - - /* Dual values */ - for (int i = 0; i < m; i++) - { - if (lpsolver == 1) - lambda[i] = lpx_get_row_dual (lp, i+1); - else - lambda[i] = lpx_ipt_row_dual (lp, i+1); - } - - /* Reduced costs */ - for (int i = 0; i < lpx_get_num_cols (lp); i++) - { - if (lpsolver == 1) - redcosts[i] = lpx_get_col_dual (lp, i+1); - else - redcosts[i] = lpx_ipt_col_dual (lp, i+1); - } - } - - *time = (clock () - t_start) / CLOCKS_PER_SEC; - -#ifdef GLPK_PRE_4_14 - *mem = (lib_env_ptr () -> mem_tpeak); -#else - *mem = 0; -#endif - - lpx_delete_prob (lp); - return 0; - } - - lpx_delete_prob (lp); - - *status = errnum; - - return errnum; -} - -#endif - -#define OCTAVE_GLPK_GET_REAL_PARAM(NAME, IDX) \ - do \ - { \ - octave_value tmp = PARAM.getfield (NAME); \ - \ - if (tmp.is_defined ()) \ - { \ - if (! tmp.is_empty ()) \ - { \ - lpxRealParam[IDX] = tmp.scalar_value (); \ - \ - if (error_state) \ - { \ - error ("glpk: invalid value in PARAM." NAME); \ - return retval; \ - } \ - } \ - else \ - { \ - error ("glpk: invalid value in PARAM." NAME); \ - return retval; \ - } \ - } \ - } \ - while (0) - -#define OCTAVE_GLPK_GET_INT_PARAM(NAME, VAL) \ - do \ - { \ - octave_value tmp = PARAM.getfield (NAME); \ - \ - if (tmp.is_defined ()) \ - { \ - if (! tmp.is_empty ()) \ - { \ - VAL = tmp.int_value (); \ - \ - if (error_state) \ - { \ - error ("glpk: invalid value in PARAM." NAME); \ - return retval; \ - } \ - } \ - else \ - { \ - error ("glpk: invalid value in PARAM." NAME); \ - return retval; \ - } \ - } \ - } \ - while (0) - -DEFUN_DLD (__glpk__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{values}] =} __glpk__ (@var{args})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - // The list of values to return. See the declaration in oct-obj.h - octave_value_list retval; - -#if defined (HAVE_GLPK) - - int nrhs = args.length (); - - if (nrhs != 9) - { - print_usage (); - return retval; - } - - //-- 1nd Input. A column array containing the objective function - //-- coefficients. - volatile int mrowsc = args(0).rows (); - - Matrix C (args(0).matrix_value ()); - - if (error_state) - { - error ("__glpk__: invalid value of C"); - return retval; - } - - double *c = C.fortran_vec (); - Array<int> rn; - Array<int> cn; - ColumnVector a; - volatile int mrowsA; - volatile int nz = 0; - - //-- 2nd Input. A matrix containing the constraints coefficients. - // If matrix A is NOT a sparse matrix - if (args(1).is_sparse_type ()) - { - SparseMatrix A = args(1).sparse_matrix_value (); // get the sparse matrix - - if (error_state) - { - error ("__glpk__: invalid value of A"); - return retval; - } - - mrowsA = A.rows (); - octave_idx_type Anc = A.cols (); - octave_idx_type Anz = A.nnz (); - rn.resize (dim_vector (Anz+1, 1)); - cn.resize (dim_vector (Anz+1, 1)); - a.resize (Anz+1, 0.0); - - if (Anc != mrowsc) - { - error ("__glpk__: invalid value of A"); - return retval; - } - - for (octave_idx_type j = 0; j < Anc; j++) - for (octave_idx_type i = A.cidx (j); i < A.cidx (j+1); i++) - { - nz++; - rn(nz) = A.ridx (i) + 1; - cn(nz) = j + 1; - a(nz) = A.data(i); - } - } - else - { - Matrix A (args(1).matrix_value ()); // get the matrix - - if (error_state) - { - error ("__glpk__: invalid value of A"); - return retval; - } - - mrowsA = A.rows (); - rn.resize (dim_vector (mrowsA*mrowsc+1, 1)); - cn.resize (dim_vector (mrowsA*mrowsc+1, 1)); - a.resize (mrowsA*mrowsc+1, 0.0); - - for (int i = 0; i < mrowsA; i++) - { - for (int j = 0; j < mrowsc; j++) - { - if (A(i,j) != 0) - { - nz++; - rn(nz) = i + 1; - cn(nz) = j + 1; - a(nz) = A(i,j); - } - } - } - - } - - //-- 3rd Input. A column array containing the right-hand side value - // for each constraint in the constraint matrix. - Matrix B (args(2).matrix_value ()); - - if (error_state) - { - error ("__glpk__: invalid value of B"); - return retval; - } - - double *b = B.fortran_vec (); - - //-- 4th Input. An array of length mrowsc containing the lower - //-- bound on each of the variables. - Matrix LB (args(3).matrix_value ()); - - if (error_state || LB.length () < mrowsc) - { - error ("__glpk__: invalid value of LB"); - return retval; - } - - double *lb = LB.fortran_vec (); - - //-- LB argument, default: Free - Array<int> freeLB (dim_vector (mrowsc, 1)); - for (int i = 0; i < mrowsc; i++) - { - if (xisinf (lb[i])) - { - freeLB(i) = 1; - lb[i] = -octave_Inf; - } - else - freeLB(i) = 0; - } - - //-- 5th Input. An array of at least length numcols containing the upper - //-- bound on each of the variables. - Matrix UB (args(4).matrix_value ()); - - if (error_state || UB.length () < mrowsc) - { - error ("__glpk__: invalid value of UB"); - return retval; - } - - double *ub = UB.fortran_vec (); - - Array<int> freeUB (dim_vector (mrowsc, 1)); - for (int i = 0; i < mrowsc; i++) - { - if (xisinf (ub[i])) - { - freeUB(i) = 1; - ub[i] = octave_Inf; - } - else - freeUB(i) = 0; - } - - //-- 6th Input. A column array containing the sense of each constraint - //-- in the constraint matrix. - charMatrix CTYPE (args(5).char_matrix_value ()); - - if (error_state) - { - error ("__glpk__: invalid value of CTYPE"); - return retval; - } - - char *ctype = CTYPE.fortran_vec (); - - //-- 7th Input. A column array containing the types of the variables. - charMatrix VTYPE (args(6).char_matrix_value ()); - - if (error_state) - { - error ("__glpk__: invalid value of VARTYPE"); - return retval; - } - - Array<int> vartype (dim_vector (mrowsc, 1)); - volatile int isMIP = 0; - for (int i = 0; i < mrowsc ; i++) - { - if (VTYPE(i,0) == 'I') - { - isMIP = 1; - vartype(i) = LPX_IV; - } - else - vartype(i) = LPX_CV; - } - - //-- 8th Input. Sense of optimization. - volatile int sense; - double SENSE = args(7).scalar_value (); - - if (error_state) - { - error ("__glpk__: invalid value of SENSE"); - return retval; - } - - if (SENSE >= 0) - sense = 1; - else - sense = -1; - - //-- 9th Input. A structure containing the control parameters. - octave_scalar_map PARAM = args(8).scalar_map_value (); - - if (error_state) - { - error ("__glpk__: invalid value of PARAM"); - return retval; - } - - //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - //-- Integer parameters - //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - //-- Level of messages output by the solver - OCTAVE_GLPK_GET_INT_PARAM ("msglev", lpxIntParam[0]); - if (lpxIntParam[0] < 0 || lpxIntParam[0] > 3) - { - error ("__glpk__: PARAM.msglev must be 0 (no output [default]) or 1 (error messages only) or 2 (normal output) or 3 (full output)"); - return retval; - } - - //-- scaling option - OCTAVE_GLPK_GET_INT_PARAM ("scale", lpxIntParam[1]); - if (lpxIntParam[1] < 0 || lpxIntParam[1] > 2) - { - error ("__glpk__: PARAM.scale must be 0 (no scaling) or 1 (equilibration scaling [default]) or 2 (geometric mean scaling)"); - return retval; - } - - //-- Dual dimplex option - OCTAVE_GLPK_GET_INT_PARAM ("dual", lpxIntParam[2]); - if (lpxIntParam[2] < 0 || lpxIntParam[2] > 1) - { - error ("__glpk__: PARAM.dual must be 0 (do NOT use dual simplex [default]) or 1 (use dual simplex)"); - return retval; - } - - //-- Pricing option - OCTAVE_GLPK_GET_INT_PARAM ("price", lpxIntParam[3]); - if (lpxIntParam[3] < 0 || lpxIntParam[3] > 1) - { - error ("__glpk__: PARAM.price must be 0 (textbook pricing) or 1 (steepest edge pricing [default])"); - return retval; - } - - //-- Solution rounding option - OCTAVE_GLPK_GET_INT_PARAM ("round", lpxIntParam[4]); - if (lpxIntParam[4] < 0 || lpxIntParam[4] > 1) - { - error ("__glpk__: PARAM.round must be 0 (report all primal and dual values [default]) or 1 (replace tiny primal and dual values by exact zero)"); - return retval; - } - - //-- Simplex iterations limit - OCTAVE_GLPK_GET_INT_PARAM ("itlim", lpxIntParam[5]); - - //-- Simplex iterations count - OCTAVE_GLPK_GET_INT_PARAM ("itcnt", lpxIntParam[6]); - - //-- Output frequency, in iterations - OCTAVE_GLPK_GET_INT_PARAM ("outfrq", lpxIntParam[7]); - - //-- Branching heuristic option - OCTAVE_GLPK_GET_INT_PARAM ("branch", lpxIntParam[14]); - if (lpxIntParam[14] < 0 || lpxIntParam[14] > 2) - { - error ("__glpk__: PARAM.branch must be (MIP only) 0 (branch on first variable) or 1 (branch on last variable) or 2 (branch using a heuristic by Driebeck and Tomlin [default]"); - return retval; - } - - //-- Backtracking heuristic option - OCTAVE_GLPK_GET_INT_PARAM ("btrack", lpxIntParam[15]); - if (lpxIntParam[15] < 0 || lpxIntParam[15] > 2) - { - error ("__glpk__: PARAM.btrack must be (MIP only) 0 (depth first search) or 1 (breadth first search) or 2 (backtrack using the best projection heuristic [default]"); - return retval; - } - - //-- Presolver option - OCTAVE_GLPK_GET_INT_PARAM ("presol", lpxIntParam[16]); - if (lpxIntParam[16] < 0 || lpxIntParam[16] > 1) - { - error ("__glpk__: PARAM.presol must be 0 (do NOT use LP presolver) or 1 (use LP presolver [default])"); - return retval; - } - - //-- LPsolver option - volatile int lpsolver = 1; - OCTAVE_GLPK_GET_INT_PARAM ("lpsolver", lpsolver); - if (lpsolver < 1 || lpsolver > 2) - { - error ("__glpk__: PARAM.lpsolver must be 1 (simplex method) or 2 (interior point method)"); - return retval; - } - - //-- Save option - volatile int save_pb = 0; - OCTAVE_GLPK_GET_INT_PARAM ("save", save_pb); - save_pb = save_pb != 0; - - //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - //-- Real parameters - //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - //-- Ratio test option - OCTAVE_GLPK_GET_REAL_PARAM ("relax", 0); - - //-- Relative tolerance used to check if the current basic solution - //-- is primal feasible - OCTAVE_GLPK_GET_REAL_PARAM ("tolbnd", 1); - - //-- Absolute tolerance used to check if the current basic solution - //-- is dual feasible - OCTAVE_GLPK_GET_REAL_PARAM ("toldj", 2); - - //-- Relative tolerance used to choose eligible pivotal elements of - //-- the simplex table in the ratio test - OCTAVE_GLPK_GET_REAL_PARAM ("tolpiv", 3); - - OCTAVE_GLPK_GET_REAL_PARAM ("objll", 4); - - OCTAVE_GLPK_GET_REAL_PARAM ("objul", 5); - - OCTAVE_GLPK_GET_REAL_PARAM ("tmlim", 6); - - OCTAVE_GLPK_GET_REAL_PARAM ("outdly", 7); - - OCTAVE_GLPK_GET_REAL_PARAM ("tolint", 8); - - OCTAVE_GLPK_GET_REAL_PARAM ("tolobj", 9); - - //-- Assign pointers to the output parameters - ColumnVector xmin (mrowsc, octave_NA); - double fmin = octave_NA; - double status; - ColumnVector lambda (mrowsA, octave_NA); - ColumnVector redcosts (mrowsc, octave_NA); - double time; - double mem; - - int jmpret = setjmp (mark); - - if (jmpret == 0) - glpk (sense, mrowsc, mrowsA, c, nz, rn.fortran_vec (), - cn.fortran_vec (), a.fortran_vec (), b, ctype, - freeLB.fortran_vec (), lb, freeUB.fortran_vec (), ub, - vartype.fortran_vec (), isMIP, lpsolver, save_pb, - xmin.fortran_vec (), &fmin, &status, lambda.fortran_vec (), - redcosts.fortran_vec (), &time, &mem); - - octave_scalar_map extra; - - if (! isMIP) - { - extra.assign ("lambda", lambda); - extra.assign ("redcosts", redcosts); - } - - extra.assign ("time", time); - extra.assign ("mem", mem); - - retval(3) = extra; - retval(2) = status; - retval(1) = fmin; - retval(0) = xmin; - -#else - - gripe_not_supported ("glpk"); - -#endif - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/
--- a/src/DLD-FUNCTIONS/__init_fltk__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2129 +0,0 @@ -/* - -Copyright (C) 2007-2012 Shai Ayal - -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/>. - -*/ - -/* - -To initialize: - - graphics_toolkit ("fltk"); - plot (randn (1e3, 1)); - -*/ - -// PKG_ADD: register_graphics_toolkit ("fltk"); - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "defun-dld.h" -#include "error.h" - -#if defined (HAVE_FLTK) - -#include <map> -#include <set> -#include <sstream> -#include <iostream> - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#endif - -#include <FL/Fl.H> -#include <FL/Fl_Box.H> -#include <FL/Fl_Button.H> -#include <FL/Fl_Choice.H> -#include <FL/Fl_File_Chooser.H> -#include <FL/Fl_Gl_Window.H> -#include <FL/Fl_Menu_Bar.H> -#include <FL/Fl_Menu_Button.H> -#include <FL/Fl_Output.H> -#include <FL/Fl_Window.H> -#include <FL/fl_ask.H> -#include <FL/fl_draw.H> -#include <FL/gl.h> - -// FLTK headers may include X11/X.h which defines Complex, and that -// conflicts with Octave's Complex typedef. We don't need the X11 -// Complex definition in this file, so remove it before including Octave -// headers which may require Octave's Complex typedef. -#undef Complex - -#include "cmd-edit.h" -#include "lo-ieee.h" - -#include "file-ops.h" -#include "gl-render.h" -#include "gl2ps-renderer.h" -#include "graphics.h" -#include "parse.h" -#include "sysdep.h" -#include "toplev.h" -#include "variables.h" - -#define FLTK_GRAPHICS_TOOLKIT_NAME "fltk" - -// Give FLTK no more than 0.01 sec to do its stuff. -static double fltk_maxtime = 1e-2; - -const char* help_text = "\ -Keyboard Shortcuts\n\ -a - autoscale\n\ -p - pan/zoom\n\ -r - rotate\n\ -g - toggle grid\n\ -\n\ -Mouse\n\ -left drag - pan\n\ -mouse wheel - zoom\n\ -right drag - rectangle zoom\n\ -left double click - autoscale\n\ -"; - -class OpenGL_fltk : public Fl_Gl_Window -{ -public: - OpenGL_fltk (int xx, int yy, int ww, int hh, double num) - : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), renderer (), - in_zoom (false), zoom_box (), print_mode (false) - { - // Ask for double buffering and a depth buffer. - mode (FL_DEPTH | FL_DOUBLE); - } - - ~OpenGL_fltk (void) { } - - void zoom (bool z) - { - in_zoom = z; - if (! in_zoom) - hide_overlay (); - } - - bool zoom (void) { return in_zoom; } - void set_zoom_box (const Matrix& zb) { zoom_box = zb; } - - void print (const std::string& cmd, const std::string& term) - { - print_mode = true; - print_cmd = cmd; - print_term = term; - } - - void resize (int xx, int yy, int ww, int hh) - { - Fl_Gl_Window::resize (xx, yy, ww, hh); - setup_viewport (ww, hh); - redraw (); - } - - bool renumber (double new_number) - { - bool retval = false; - - if (number != new_number) - { - number = new_number; - retval = true; - } - - return retval; - } - -private: - double number; - opengl_renderer renderer; - bool in_zoom; - // (x1,y1,x2,y2) - Matrix zoom_box; - - bool print_mode; - std::string print_cmd; - std::string print_term; - - void setup_viewport (int ww, int hh) - { - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glViewport (0, 0, ww, hh); - } - - void draw (void) - { - if (! valid ()) - { - valid (1); - setup_viewport (w (), h ()); - } - - if (print_mode) - { - FILE *fp = octave_popen (print_cmd.c_str (), "w"); - glps_renderer rend (fp, print_term); - - rend.draw (gh_manager::get_object (number)); - - octave_pclose (fp); - print_mode = false; - } - else - { - renderer.draw (gh_manager::get_object (number)); - - if (zoom ()) - overlay (); - } - } - - void zoom_box_vertex (void) - { - glVertex2d (zoom_box(0), h () - zoom_box(1)); - glVertex2d (zoom_box(0), h () - zoom_box(3)); - glVertex2d (zoom_box(2), h () - zoom_box(3)); - glVertex2d (zoom_box(2), h () - zoom_box(1)); - glVertex2d (zoom_box(0), h () - zoom_box(1)); - } - - void overlay (void) - { - glPushMatrix (); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluOrtho2D (0.0, w (), 0.0, h ()); - - glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT); - glDisable (GL_DEPTH_TEST); - - glBegin (GL_POLYGON); - glColor4f (0.45, 0.62, 0.81, 0.1); - zoom_box_vertex (); - glEnd (); - - glBegin (GL_LINE_STRIP); - glLineWidth (1.5); - glColor4f (0.45, 0.62, 0.81, 0.9); - zoom_box_vertex (); - glEnd (); - - glPopAttrib (); - glPopMatrix (); - } - - int handle (int event) - { - int retval = Fl_Gl_Window::handle (event); - - switch (event) - { - case FL_ENTER: - window ()->cursor (FL_CURSOR_CROSS); - return 1; - - case FL_LEAVE: - window ()->cursor (FL_CURSOR_DEFAULT); - return 1; - } - - return retval; - } -}; - -// Parameter controlling how fast we zoom when using the scrool wheel. -static double wheel_zoom_speed = 0.05; -// Parameter controlling the GUI mode. -static enum { pan_zoom, rotate_zoom, none } gui_mode; - -void script_cb (Fl_Widget*, void* data) - { - static_cast<uimenu::properties*> (data)->execute_callback (); - } - - -class fltk_uimenu -{ -public: - fltk_uimenu (int xx, int yy, int ww, int hh) - { - menubar = new - Fl_Menu_Bar (xx, yy, ww, hh); - } - - int items_to_show (void) - { - //returns the number of visible menu items - int len = menubar->size (); - int n = 0; - for (int t = 0; t < len; t++ ) - { - const Fl_Menu_Item *m = static_cast<const Fl_Menu_Item*> (&(menubar->menu ()[t])); - if ((m->label () != NULL) && m->visible ()) - n++; - } - - return n; - } - - void show (void) - { - menubar->show (); - } - - void hide (void) - { - menubar->hide (); - } - - bool is_visible (void) - { - return menubar->visible (); - } - - int find_index_by_name (const std::string& findname) - { - // This function is derived from Greg Ercolano's function - // int GetIndexByName(...), see: - // http://seriss.com/people/erco/fltk/#Menu_ChangeLabel - // He agreed via PM that it can be included in octave using GPLv3 - // Kai Habel (14.10.2010) - - std::string menupath; - for (int t = 0; t < menubar->size (); t++ ) - { - Fl_Menu_Item *m = const_cast<Fl_Menu_Item*> (&(menubar->menu ()[t])); - if (m->submenu ()) - { - // item has submenu - if (!menupath.empty ()) - menupath += "/"; - menupath += m->label (); - - if (menupath.compare (findname) == 0 ) - return (t); - } - else - { - // End of submenu? Pop back one level. - if (m->label () == NULL) - { - std::size_t idx = menupath.find_last_of ("/"); - if (idx != std::string::npos) - menupath.erase (idx); - else - menupath.clear (); - continue; - } - // Menu item? - std::string itempath = menupath; - if (!itempath.empty ()) - itempath += "/"; - itempath += m->label (); - - if (itempath.compare (findname) == 0) - return (t); - } - } - return (-1); - } - - Matrix find_uimenu_children (uimenu::properties& uimenup) const - { - Matrix uimenu_childs = uimenup.get_all_children (); - Matrix retval = do_find_uimenu_children (uimenu_childs); - return retval; - } - - Matrix find_uimenu_children (figure::properties& figp) const - { - Matrix uimenu_childs = figp.get_all_children (); - Matrix retval = do_find_uimenu_children (uimenu_childs); - return retval; - } - - Matrix do_find_uimenu_children (Matrix uimenu_childs) const - { - octave_idx_type k = 0; - - - Matrix pos = Matrix (uimenu_childs.numel (), 1); - - for (octave_idx_type ii = 0; ii < uimenu_childs.numel (); ii++) - { - graphics_object kidgo = gh_manager::get_object (uimenu_childs (ii)); - - if (kidgo.valid_object () && kidgo.isa ("uimenu")) - { - uimenu_childs(k) = uimenu_childs(ii); - pos(k++) = - dynamic_cast<uimenu::properties&> (kidgo.get_properties ()).get_position (); - } - } - - uimenu_childs.resize (k, 1); - pos.resize (k, 1); - Matrix retval = Matrix (k, 1); - // Don't know if this is the best method to sort. - // Can we avoid the for loop? - Array<octave_idx_type> sidx = pos.sort_rows_idx (DESCENDING); - for (octave_idx_type ii = 0; ii < k; ii++) - retval(ii) = uimenu_childs (sidx(ii)); - - return retval; - } - - void delete_entry (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - int idx = find_index_by_name (fltk_label.c_str ()); - - if (idx >= 0) - menubar->remove (idx); - } - - void update_accelerator (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); - if (item != NULL) - { - std::string acc = uimenup.get_accelerator (); - if (acc.length () > 0) - { - int key = FL_CTRL + acc[0]; - item->shortcut (key); - } - } - } - } - - void update_callback (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); - if (item != NULL) - { - if (!uimenup.get_callback ().is_empty ()) - item->callback (static_cast<Fl_Callback*> (script_cb), - static_cast<void*> (&uimenup)); - else - item->callback (NULL, static_cast<void*> (0)); - } - } - } - - void update_enable (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); - if (item != NULL) - { - if (uimenup.is_enable ()) - item->activate (); - else - item->deactivate (); - } - } - } - - void update_foregroundcolor (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); - if (item != NULL) - { - Matrix rgb = uimenup.get_foregroundcolor_rgb (); - - uchar r = static_cast<uchar> (gnulib::floor (rgb (0) * 255)); - uchar g = static_cast<uchar> (gnulib::floor (rgb (1) * 255)); - uchar b = static_cast<uchar> (gnulib::floor (rgb (2) * 255)); - - item->labelcolor (fl_rgb_color (r, g, b)); - } - } - } - - void update_seperator (const uimenu::properties& uimenup) - { - // Matlab places the separator before the current - // menu entry, while fltk places it after. So we need to find - // the previous item in this menu/submenu. (Kai) - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - int itemflags = 0, idx; - int curr_idx = find_index_by_name (fltk_label.c_str ()); - - for (idx = curr_idx - 1; idx >= 0; idx--) - { - Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (&menubar->menu () [idx]); - itemflags = item->flags; - if (item->label () != NULL) - break; - } - - if (idx >= 0 && idx < menubar->size ()) - { - if (uimenup.is_separator ()) - { - if (idx >= 0 && !(itemflags & FL_SUBMENU)) - menubar->mode (idx, itemflags | FL_MENU_DIVIDER); - } - else - menubar->mode (idx, itemflags & (~FL_MENU_DIVIDER)); - } - } - } - - void update_visible (uimenu::properties& uimenup) - { - std::string fltk_label = uimenup.get_fltk_label (); - if (!fltk_label.empty ()) - { - Fl_Menu_Item* item - = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); - if (item != NULL) - { - if (uimenup.is_visible ()) - item->show (); - else - item->hide (); - } - } - } - - void add_entry (uimenu::properties& uimenup) - { - - std::string fltk_label = uimenup.get_fltk_label (); - - if (!fltk_label.empty ()) - { - bool item_added = false; - do - { - const Fl_Menu_Item* item - = menubar->find_item (fltk_label.c_str ()); - - if (item == NULL) - { - Matrix uimenu_ch = find_uimenu_children (uimenup); - int len = uimenu_ch.numel (); - int flags = 0; - if (len > 0) - flags = FL_SUBMENU; - if (len == 0 && uimenup.is_checked ()) - flags += FL_MENU_TOGGLE + FL_MENU_VALUE; - menubar->add (fltk_label.c_str (), 0, 0, 0, flags); - item_added = true; - } - else - { - //avoid duplicate menulabels - std::size_t idx1 = fltk_label.find_last_of ("("); - std::size_t idx2 = fltk_label.find_last_of (")"); - int len = idx2 - idx1; - int val = 1; - if (len > 0) - { - std::string valstr = fltk_label.substr (idx1 + 1, len - 1); - fltk_label.erase (idx1, len + 1); - val = atoi (valstr.c_str ()); - if (val > 0 && val < 99) - val++; - } - std::ostringstream valstream; - valstream << val; - fltk_label += "(" + valstream.str () + ")"; - } - } - while (!item_added); - uimenup.set_fltk_label (fltk_label); - } - } - - void add_to_menu (uimenu::properties& uimenup) - { - Matrix kids = find_uimenu_children (uimenup); - int len = kids.length (); - std::string fltk_label = uimenup.get_fltk_label (); - - add_entry (uimenup); - update_foregroundcolor (uimenup); - update_callback (uimenup); - update_accelerator (uimenup); - update_enable (uimenup); - update_visible (uimenup); - update_seperator (uimenup); - - for (octave_idx_type ii = 0; ii < len; ii++) - { - graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); - if (kgo.valid_object ()) - { - uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); - add_to_menu (kprop); - } - } - } - - void add_to_menu (figure::properties& figp) - { - Matrix kids = find_uimenu_children (figp); - int len = kids.length (); - menubar->clear (); - for (octave_idx_type ii = 0; ii < len; ii++) - { - graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); - - if (kgo.valid_object ()) - { - uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); - add_to_menu (kprop); - } - } - } - - template <class T_prop> - void remove_from_menu (T_prop& prop) - { - Matrix kids; - std::string type = prop.get_type (); - kids = find_uimenu_children (prop); - int len = kids.length (); - - for (octave_idx_type ii = 0; ii < len; ii++) - { - graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); - - if (kgo.valid_object ()) - { - uimenu::properties kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); - remove_from_menu (kprop); - } - } - - if (type.compare ("uimenu") == 0) - delete_entry (dynamic_cast<uimenu::properties&> (prop)); - else if (type.compare ("figure") == 0) - menubar->clear (); - } - - ~fltk_uimenu (void) - { - delete menubar; - } - -private: - - // No copying! - - fltk_uimenu (const fltk_uimenu&); - - fltk_uimenu operator = (const fltk_uimenu&); - - Fl_Menu_Bar* menubar; -}; - -class plot_window : public Fl_Window -{ - friend class fltk_uimenu; -public: - plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp) - : Fl_Window (xx, yy, ww, hh, "octave"), window_label (), shift (0), - ndim (2), fp (xfp), canvas (0), autoscale (0), togglegrid (0), - panzoom (0), rotate (0), help (0), status (0), - ax_obj (), pos_x (0), pos_y (0) - { - callback (window_close, static_cast<void*> (this)); - size_range (4*status_h, 2*status_h); - - // FIXME: The function below is only available in FLTK >= 1.3 - // At some point support for FLTK 1.1 will be dropped in Octave. - // At that point this function should be uncommented. - // The current solution is to call xclass() before show() for each window. - // Set WM_CLASS which allows window managers to properly group related - // windows. Otherwise, the class is just "FLTK" - //default_xclass ("Octave"); - - begin (); - { - - canvas = new OpenGL_fltk (0, 0, ww, hh - status_h, number ()); - - uimenu = new fltk_uimenu (0, 0, ww, menu_h); - uimenu->hide (); - - bottom = new Fl_Box (0, hh - status_h, ww, status_h); - bottom->box (FL_FLAT_BOX); - - ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ())); - - autoscale = new Fl_Button (0, hh - status_h, status_h, status_h, "A"); - autoscale->callback (button_callback, static_cast<void*> (this)); - autoscale->tooltip ("Autoscale"); - - togglegrid = new Fl_Button (status_h, hh - status_h, status_h, - status_h, "G"); - togglegrid->callback (button_callback, static_cast<void*> (this)); - togglegrid->tooltip ("Toggle Grid"); - - panzoom = new Fl_Button (2 * status_h, hh - status_h, status_h, - status_h, "P"); - panzoom->callback (button_callback, static_cast<void*> (this)); - panzoom->tooltip ("Mouse Pan/Zoom"); - - rotate = new Fl_Button (3 * status_h, hh - status_h, status_h, - status_h, "R"); - rotate->callback (button_callback, static_cast<void*> (this)); - rotate->tooltip ("Mouse Rotate"); - - if (ndim == 2) - rotate->deactivate (); - - help = new Fl_Button (4 * status_h, hh - status_h, status_h, - status_h, "?"); - help->callback (button_callback, static_cast<void*> (this)); - help->tooltip ("Help"); - - status = new Fl_Output (5 * status_h, hh - status_h, - ww > 2*status_h ? ww - status_h : 0, - status_h, ""); - - status->textcolor (FL_BLACK); - status->color (FL_GRAY); - status->textfont (FL_COURIER); - status->textsize (10); - status->box (FL_ENGRAVED_BOX); - - // This allows us to have a valid OpenGL context right away. - canvas->mode (FL_DEPTH | FL_DOUBLE ); - if (fp.is_visible ()) - { - // FIXME: This code should be removed when Octave drops support - // for FLTK 1.1. Search for default_xclass in this file to find - // code that should be uncommented to take its place. - // - // Set WM_CLASS which allows window managers to properly group - // related windows. Otherwise, the class is just "FLTK" - xclass ("Octave"); - show (); - if (fp.get_currentaxes ().ok ()) - show_canvas (); - else - hide_canvas (); - } - } - end (); - - status->show (); - autoscale->show (); - togglegrid->show (); - panzoom->show (); - rotate->show (); - - set_name (); - resizable (canvas); - gui_mode = (ndim == 3 ? rotate_zoom : pan_zoom); - uimenu->add_to_menu (fp); - if (uimenu->items_to_show ()) - show_menubar (); - else - hide_menubar (); - } - - ~plot_window (void) - { - canvas->hide (); - status->hide (); - uimenu->hide (); - this->hide (); - } - - double number (void) { return fp.get___myhandle__ ().value (); } - - void renumber (double new_number) - { - if (canvas) - { - if (canvas->renumber (new_number)) - mark_modified (); - } - else - error ("unable to renumber figure"); - } - - void print (const std::string& cmd, const std::string& term) - { - canvas->print (cmd, term); - - // Print immediately so the output file will exist when the drawnow - // command is done. - mark_modified (); - Fl::wait (fltk_maxtime); - } - - void show_menubar (void) - { - if (!uimenu->is_visible ()) - { - canvas->resize (canvas->x (), - canvas->y () + menu_h, - canvas->w (), - canvas->h () - menu_h); - uimenu->show (); - mark_modified (); - } - } - - void hide_menubar (void) - { - if (uimenu->is_visible ()) - { - canvas->resize (canvas->x (), - canvas->y () - menu_h, - canvas->w (), - canvas->h () + menu_h); - uimenu->hide (); - mark_modified (); - } - } - - void uimenu_update (const graphics_handle& gh, int id) - { - graphics_object uimenu_obj = gh_manager::get_object (gh); - - if (uimenu_obj.valid_object () && uimenu_obj.isa ("uimenu")) - { - uimenu::properties& uimenup = - dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ()); - std::string fltk_label = uimenup.get_fltk_label (); - graphics_object fig = uimenu_obj.get_ancestor ("figure"); - figure::properties& figp = - dynamic_cast<figure::properties&> (fig.get_properties ()); - - switch (id) - { - case base_properties::ID_BEINGDELETED: - uimenu->remove_from_menu (uimenup); - break; - - case base_properties::ID_VISIBLE: - uimenu->update_visible (uimenup); - break; - - case uimenu::properties::ID_ACCELERATOR: - uimenu->update_accelerator (uimenup); - break; - - case uimenu::properties::ID_CALLBACK: - uimenu->update_callback (uimenup); - break; - - case uimenu::properties::ID_CHECKED: - uimenu->add_to_menu (figp);//rebuilding entire menu - break; - - case uimenu::properties::ID_ENABLE: - uimenu->update_enable (uimenup); - break; - - case uimenu::properties::ID_FOREGROUNDCOLOR: - uimenu->update_foregroundcolor (uimenup); - break; - - case uimenu::properties::ID_LABEL: - uimenu->add_to_menu (figp);//rebuilding entire menu - break; - - case uimenu::properties::ID_POSITION: - uimenu->add_to_menu (figp);//rebuilding entire menu - break; - - case uimenu::properties::ID_SEPARATOR: - uimenu->update_seperator (uimenup); - break; - } - - if (uimenu->items_to_show ()) - show_menubar (); - else - hide_menubar (); - - mark_modified (); - } - } - - void show_canvas (void) - { - if (fp.is_visible ()) - { - canvas->show (); - canvas->make_current (); - } - } - - void hide_canvas (void) - { - canvas->hide (); - } - - void mark_modified (void) - { - damage (FL_DAMAGE_ALL); - canvas->damage (FL_DAMAGE_ALL); - ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ())); - - if (ndim == 3) - rotate->activate (); - else if (ndim == 2 && gui_mode == rotate_zoom) - { - rotate->deactivate (); - gui_mode = pan_zoom; - } - } - - void set_name (void) - { - window_label = fp.get_title (); - label (window_label.c_str ()); - } - -private: - - // No copying! - - plot_window (const plot_window&); - - plot_window& operator = (const plot_window&); - - // window name -- this must exists for the duration of the window's - // life - std::string window_label; - - // Mod keys status - int shift; - - // Number of dimensions, 2 or 3. - int ndim; - - // Figure properties. - figure::properties& fp; - - // Status area height. - static const int status_h = 20; - - // Menu height - static const int menu_h = 20; - - // Window callback. - static void window_close (Fl_Widget*, void* data) - { - octave_value_list args; - args(0) = static_cast<plot_window*> (data)->number (); - feval ("close", args); - } - - // Button callbacks. - static void button_callback (Fl_Widget* ww, void* data) - { - static_cast<plot_window*> (data)->button_press (ww, data); - } - - void button_press (Fl_Widget* widg, void*) - { - if (widg == autoscale) - axis_auto (); - - if (widg == togglegrid) - toggle_grid (); - - if (widg == panzoom) - gui_mode = pan_zoom; - - if (widg == rotate && ndim == 3) - gui_mode = rotate_zoom; - - if (widg == help) - fl_message ("%s", help_text); - } - - fltk_uimenu* uimenu; - OpenGL_fltk* canvas; - Fl_Box* bottom; - Fl_Button* autoscale; - Fl_Button* togglegrid; - Fl_Button* panzoom; - Fl_Button* rotate; - Fl_Button* help; - Fl_Output* status; - graphics_object ax_obj; - int pos_x; - int pos_y; - - void axis_auto (void) - { - octave_value_list args; - args(0) = fp.get_currentaxes ().as_octave_value (); - args(1) = "auto"; - feval ("axis", args); - mark_modified (); - } - - void toggle_grid (void) - { - octave_value_list args; - if (fp.get_currentaxes ().ok ()) - args(0) = fp.get_currentaxes ().as_octave_value (); - - feval ("grid", args); - mark_modified (); - } - - void pixel2pos (const graphics_handle& ax, int px, int py, double& xx, - double& yy) const - { - pixel2pos ( gh_manager::get_object (ax), px, py, xx, yy); - } - - void pixel2pos (graphics_object ax, int px, int py, double& xx, - double& yy) const - { - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - ColumnVector pp = ap.pixel2coord (px, py); - xx = pp(0); - yy = pp(1); - } - } - - graphics_handle pixel2axes_or_ca (int px, int py ) - { - Matrix kids = fp.get_children (); - int len = kids.length (); - - for (int k = 0; k < len; k++) - { - graphics_handle hnd = gh_manager::lookup (kids(k)); - - if (hnd.ok ()) - { - graphics_object kid = gh_manager::get_object (hnd); - - if (kid.valid_object () && kid.isa ("axes")) - { - Matrix bb = kid.get_properties ().get_boundingbox (true); - - if (bb(0) <= px && px < (bb(0)+bb(2)) - && bb(1) <= py && py < (bb(1)+bb(3))) - { - return hnd; - } - } - } - } - return fp.get_currentaxes (); - } - - void pixel2status (const graphics_handle& ax, int px0, int py0, - int px1 = -1, int py1 = -1) - { - pixel2status (gh_manager::get_object (ax), px0, py0, px1, py1); - } - - void pixel2status (graphics_object ax, int px0, int py0, - int px1 = -1, int py1 = -1) - { - double x0, y0, x1, y1; - std::stringstream cbuf; - cbuf.precision (4); - cbuf.width (6); - pixel2pos (ax, px0, py0, x0, y0); - cbuf << "[" << x0 << ", " << y0 << "]"; - if (px1 >= 0) - { - pixel2pos (ax, px1, py1, x1, y1); - cbuf << " -> ["<< x1 << ", " << y1 << "]"; - } - - status->value (cbuf.str ().c_str ()); - status->redraw (); - } - - void view2status (graphics_object ax) - { - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - std::stringstream cbuf; - cbuf.precision (4); - cbuf.width (6); - Matrix v (1,2,0); - v = ap.get ("view").matrix_value (); - cbuf << "[azimuth: " << v(0) << ", elevation: " << v(1) << "]"; - - status->value (cbuf.str ().c_str ()); - status->redraw (); - } - } - - void set_currentpoint (int px, int py) - { - if (!fp.is_beingdeleted ()) - { - Matrix pos (1,2,0); - pos(0) = px; - pos(1) = h () - status_h - menu_h - py; - fp.set_currentpoint (pos); - } - } - - void set_axes_currentpoint (graphics_object ax, int px, int py) - { - if (ax.valid_object ()) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - - double xx, yy; - pixel2pos (ax, px, py, xx, yy); - - Matrix pos (2,3,0); - pos(0,0) = xx; - pos(1,0) = yy; - pos(0,1) = xx; - pos(1,1) = yy; - - ap.set_currentpoint (pos); - } - } - - int key2shift (int key) - { - if (key == FL_Shift_L || key == FL_Shift_R) - return FL_SHIFT; - - if (key == FL_Control_L || key == FL_Control_R) - return FL_CTRL; - - if (key == FL_Alt_L || key == FL_Alt_R) - return FL_ALT; - - if (key == FL_Meta_L || key == FL_Meta_R) - return FL_META; - - return 0; - } - - int key2ascii (int key) - { - if (key < 256) return key; - if (key == FL_Tab) return '\t'; - if (key == FL_Enter) return 0x0a; - if (key == FL_BackSpace) return 0x08; - if (key == FL_Escape) return 0x1b; - - return 0; - } - - Cell modifier2cell () - { - string_vector mod; - - if (shift & FL_SHIFT) - mod.append (std::string ("shift")); - if (shift & FL_CTRL) - mod.append (std::string ("control")); - if (shift & FL_ALT || shift & FL_META) - mod.append (std::string ("alt")); - - return Cell (mod); - } - - void resize (int xx,int yy,int ww,int hh) - { - Fl_Window::resize (xx, yy, ww, hh); - - Matrix pos (1,4,0); - pos(0) = xx; - pos(1) = yy; - pos(2) = ww; - pos(3) = hh - status_h - menu_h; - - fp.set_boundingbox (pos, true); - } - - void draw (void) - { - Matrix pos = fp.get_boundingbox (true); - Fl_Window::resize (pos(0), pos(1), pos(2), pos(3) + status_h + menu_h); - - return Fl_Window::draw (); - } - - int handle (int event) - { - graphics_handle gh; - - graphics_object fig = gh_manager::get_object (fp.get___myhandle__ ()); - int retval = Fl_Window::handle (event); - - // We only handle events which are in the canvas area. - if (!Fl::event_inside (canvas)) - return retval; - - if (!fp.is_beingdeleted ()) - { - switch (event) - { - case FL_KEYDOWN: - { - int key = Fl::event_key (); - - shift |= key2shift (key); - int key_a = key2ascii (key); - if (key_a && fp.get_keypressfcn ().is_defined ()) - { - Octave_map evt; - evt.assign ("Character", octave_value (key_a)); - evt.assign ("Key", octave_value (std::tolower (key_a))); - evt.assign ("Modifier", octave_value (modifier2cell ())); - fp.execute_keypressfcn (evt); - } - switch (key) - { - case 'a': - case 'A': - axis_auto (); - break; - - case 'g': - case 'G': - toggle_grid (); - break; - - case 'p': - case 'P': - gui_mode = pan_zoom; - break; - - case 'r': - case 'R': - gui_mode = rotate_zoom; - break; - } - } - break; - - case FL_KEYUP: - { - int key = Fl::event_key (); - - shift &= (~key2shift (key)); - int key_a = key2ascii (key); - if (key_a && fp.get_keyreleasefcn ().is_defined ()) - { - Octave_map evt; - evt.assign ("Character", octave_value (key_a)); - evt.assign ("Key", octave_value (std::tolower (key_a))); - evt.assign ("Modifier", octave_value (modifier2cell ())); - fp.execute_keyreleasefcn (evt); - } - } - break; - - case FL_MOVE: - pixel2status (pixel2axes_or_ca (Fl::event_x (), Fl::event_y ()), - Fl::event_x (), Fl::event_y ()); - break; - - case FL_PUSH: - pos_x = Fl::event_x (); - pos_y = Fl::event_y (); - - set_currentpoint (Fl::event_x (), Fl::event_y ()); - - gh = pixel2axes_or_ca (pos_x, pos_y); - - if (gh.ok ()) - { - ax_obj = gh_manager::get_object (gh); - set_axes_currentpoint (ax_obj, pos_x, pos_y); - } - - fp.execute_windowbuttondownfcn (); - - if (Fl::event_button () == 1 || Fl::event_button () == 3) - return 1; - - break; - - case FL_DRAG: - if (fp.get_windowbuttonmotionfcn ().is_defined ()) - { - set_currentpoint (Fl::event_x (), Fl::event_y ()); - fp.execute_windowbuttonmotionfcn (); - } - - if (Fl::event_button () == 1) - { - if (ax_obj && ax_obj.isa ("axes")) - { - if (gui_mode == pan_zoom) - pixel2status (ax_obj, pos_x, pos_y, - Fl::event_x (), Fl::event_y ()); - else - view2status (ax_obj); - axes::properties& ap = - dynamic_cast<axes::properties&> (ax_obj.get_properties ()); - - double x0, y0, x1, y1; - Matrix pos = fp.get_boundingbox (true); - pixel2pos (ax_obj, pos_x, pos_y, x0, y0); - pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (), x1, y1); - - if (gui_mode == pan_zoom) - ap.translate_view (x0, x1, y0, y1); - else if (gui_mode == rotate_zoom) - { - double daz, del; - daz = (Fl::event_x () - pos_x) / pos(2) * 360; - del = (Fl::event_y () - pos_y) / pos(3) * 360; - ap.rotate_view (del, daz); - } - - pos_x = Fl::event_x (); - pos_y = Fl::event_y (); - mark_modified (); - } - return 1; - } - else if (Fl::event_button () == 3) - { - pixel2status (ax_obj, pos_x, pos_y, - Fl::event_x (), Fl::event_y ()); - Matrix zoom_box (1,4,0); - zoom_box (0) = pos_x; - zoom_box (1) = pos_y; - zoom_box (2) = Fl::event_x (); - zoom_box (3) = Fl::event_y (); - canvas->set_zoom_box (zoom_box); - canvas->zoom (true); - canvas->redraw (); - } - - break; - - case FL_MOUSEWHEEL: - { - graphics_object ax = - gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (), - Fl::event_y ())); - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - - // Determine if we're zooming in or out. - const double factor = - (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed; - - // Get the point we're zooming about. - double x1, y1; - pixel2pos (ax, Fl::event_x (), Fl::event_y (), x1, y1); - - ap.zoom_about_point (x1, y1, factor, false); - mark_modified (); - } - } - return 1; - - case FL_RELEASE: - if (fp.get_windowbuttonupfcn ().is_defined ()) - { - set_currentpoint (Fl::event_x (), Fl::event_y ()); - fp.execute_windowbuttonupfcn (); - } - - if (Fl::event_button () == 1) - { - if ( Fl::event_clicks () == 1) - { - if (ax_obj && ax_obj.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax_obj.get_properties ()); - ap.set_xlimmode ("auto"); - ap.set_ylimmode ("auto"); - ap.set_zlimmode ("auto"); - mark_modified (); - } - } - } - if (Fl::event_button () == 3) - { - // End of drag -- zoom. - if (canvas->zoom ()) - { - canvas->zoom (false); - double x0,y0,x1,y1; - if (ax_obj && ax_obj.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax_obj.get_properties ()); - pixel2pos (ax_obj, pos_x, pos_y, x0, y0); - int pos_x1 = Fl::event_x (); - int pos_y1 = Fl::event_y (); - pixel2pos (ax_obj, pos_x1, pos_y1, x1, y1); - Matrix xl (1,2,0); - Matrix yl (1,2,0); - int dx = abs (pos_x - pos_x1); - int dy = abs (pos_y - pos_y1); - // Smallest zoom box must be 4 pixels square - if ((dx > 4) && (dy > 4)) - { - if (x0 < x1) - { - xl(0) = x0; - xl(1) = x1; - } - else - { - xl(0) = x1; - xl(1) = x0; - } - if (y0 < y1) - { - yl(0) = y0; - yl(1) = y1; - } - else - { - yl(0) = y1; - yl(1) = y0; - } - ap.zoom (xl, yl); - } - mark_modified (); - } - } - } - break; - } - } - - return retval; - } -}; - -class figure_manager -{ -public: - - static bool instance_ok (void) - { - bool retval = true; - - if (! instance) - instance = new figure_manager (); - - if (! instance) - { - ::error ("unable to create figure_manager object!"); - - retval = false; - } - - return retval; - } - - ~figure_manager (void) - { - close_all (); - } - - static void close_all (void) - { - if (instance_ok ()) - instance->do_close_all (); - } - - static void new_window (figure::properties& fp) - { - if (instance_ok ()) - instance->do_new_window (fp); - } - - static void delete_window (int idx) - { - if (instance_ok ()) - instance->do_delete_window (idx); - } - - static void delete_window (const std::string& idx_str) - { - delete_window (str2idx (idx_str)); - } - - static void renumber_figure (const std::string& idx_str, double new_number) - { - if (instance_ok ()) - instance->do_renumber_figure (str2idx (idx_str), new_number); - } - - static void toggle_window_visibility (int idx, bool is_visible) - { - if (instance_ok ()) - instance->do_toggle_window_visibility (idx, is_visible); - } - - static void toggle_window_visibility (const std::string& idx_str, - bool is_visible) - { - toggle_window_visibility (str2idx (idx_str), is_visible); - } - - static void mark_modified (int idx) - { - if (instance_ok ()) - instance->do_mark_modified (idx); - } - - static void mark_modified (const graphics_handle& gh) - { - mark_modified (hnd2idx (gh)); - } - - static void set_name (int idx) - { - if (instance_ok ()) - instance->do_set_name (idx); - } - - static void set_name (const std::string& idx_str) - { - set_name (str2idx (idx_str)); - } - - static Matrix get_size (int idx) - { - return instance_ok () ? instance->do_get_size (idx) : Matrix (); - } - - static Matrix get_size (const graphics_handle& gh) - { - return get_size (hnd2idx (gh)); - } - - static void print (const graphics_handle& gh, const std::string& cmd, - const std::string& term) - { - if (instance_ok ()) - instance->do_print (hnd2idx (gh), cmd, term); - } - - static void uimenu_update (const graphics_handle& figh, - const graphics_handle& uimenuh, int id) - { - if (instance_ok ()) - instance->do_uimenu_update (hnd2idx (figh), uimenuh, id); - } - - static void update_canvas (const graphics_handle& gh, - const graphics_handle& ca) - { - if (instance_ok ()) - instance->do_update_canvas (hnd2idx (gh), ca); - } - - static void toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) - { - if (instance_ok ()) - instance->do_toggle_menubar_visibility (fig_idx, menubar_is_figure); - } - - static void toggle_menubar_visibility (const std::string& fig_idx_str, - bool menubar_is_figure) - { - toggle_menubar_visibility (str2idx (fig_idx_str), menubar_is_figure); - } - -private: - - static figure_manager *instance; - - figure_manager (void) { } - - // No copying! - figure_manager (const figure_manager&); - figure_manager& operator = (const figure_manager&); - - // Singelton -- hide all of the above. - - static int curr_index; - typedef std::map<int, plot_window*> window_map; - typedef window_map::iterator wm_iterator;; - window_map windows; - - static std::string fltk_idx_header; - - void do_close_all (void) - { - wm_iterator win; - for (win = windows.begin (); win != windows.end (); win++) - delete win->second; - windows.clear (); - } - - void do_new_window (figure::properties& fp) - { - int idx = figprops2idx (fp); - - if (idx >= 0 && windows.find (idx) == windows.end ()) - { - Matrix pos = fp.get_boundingbox (true); - - int x = pos(0); - int y = pos(1); - int w = pos(2); - int h = pos(3); - - idx2figprops (curr_index, fp); - - windows[curr_index++] = new plot_window (x, y, w, h, fp); - } - } - - void do_delete_window (int idx) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - { - delete win->second; - windows.erase (win); - } - } - - void do_renumber_figure (int idx, double new_number) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - win->second->renumber (new_number); - } - - void do_toggle_window_visibility (int idx, bool is_visible) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - { - if (is_visible) - win->second->show (); - else - win->second->hide (); - - win->second->redraw (); - } - } - - void do_toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) - { - wm_iterator win = windows.find (fig_idx); - - if (win != windows.end ()) - { - if (menubar_is_figure) - win->second->show_menubar (); - else - win->second->hide_menubar (); - - win->second->redraw (); - } - } - - void do_mark_modified (int idx) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - win->second->mark_modified (); - } - - void do_set_name (int idx) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - win->second->set_name (); - } - - Matrix do_get_size (int idx) - { - Matrix sz (1, 2, 0.0); - - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - { - sz(0) = win->second->w (); - sz(1) = win->second->h (); - } - - return sz; - } - - void do_print (int idx, const std::string& cmd, const std::string& term) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - win->second->print (cmd, term); - } - - void do_uimenu_update (int idx, const graphics_handle& gh, int id) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - win->second->uimenu_update (gh, id); - } - - void do_update_canvas (int idx, const graphics_handle& ca) - { - wm_iterator win = windows.find (idx); - - if (win != windows.end ()) - { - if (ca.ok ()) - win->second->show_canvas (); - else - win->second->hide_canvas (); - } - } - - static int str2idx (const caseless_str& clstr) - { - int ind; - if (clstr.find (fltk_idx_header,0) == 0) - { - std::istringstream istr (clstr.substr (fltk_idx_header.size ())); - if (istr >> ind) - return ind; - } - error ("figure_manager: could not recognize fltk index"); - return -1; - } - - void idx2figprops (int idx, figure::properties& fp) - { - std::ostringstream ind_str; - ind_str << fltk_idx_header << idx; - fp.set___plot_stream__ (ind_str.str ()); - } - - static int figprops2idx (const figure::properties& fp) - { - if (fp.get___graphics_toolkit__ () == FLTK_GRAPHICS_TOOLKIT_NAME) - { - octave_value ps = fp.get___plot_stream__ (); - if (ps.is_string ()) - return str2idx (ps.string_value ()); - else - return 0; - } - error ("figure_manager: figure is not fltk"); - return -1; - } - - static int hnd2idx (double h) - { - graphics_object fobj = gh_manager::get_object (h); - if (fobj && fobj.isa ("figure")) - { - figure::properties& fp = - dynamic_cast<figure::properties&> (fobj.get_properties ()); - return figprops2idx (fp); - } - error ("figure_manager: H (= %g) is not a figure", h); - return -1; - } - - static int hnd2idx (const graphics_handle& fh) - { - return hnd2idx (fh.value ()); - } -}; - -figure_manager *figure_manager::instance = 0; - -std::string figure_manager::fltk_idx_header="fltk index="; -int figure_manager::curr_index = 1; - -static bool toolkit_loaded = false; - -static int -__fltk_redraw__ (void) -{ - if (toolkit_loaded) - { - // We scan all figures and add those which use FLTK. - graphics_object obj = gh_manager::get_object (0); - if (obj && obj.isa ("root")) - { - base_properties& props = obj.get_properties (); - Matrix children = props.get_all_children (); - - for (octave_idx_type n = 0; n < children.numel (); n++) - { - graphics_object fobj = gh_manager::get_object (children (n)); - if (fobj && fobj.isa ("figure")) - { - figure::properties& fp = - dynamic_cast<figure::properties&> (fobj.get_properties ()); - if (fp.get___graphics_toolkit__ () - == FLTK_GRAPHICS_TOOLKIT_NAME) - figure_manager::new_window (fp); - } - } - } - - // it seems that we have to call Fl::check twice to get everything drawn - Fl::check (); - Fl::check (); - } - - return 0; -} - -class fltk_graphics_toolkit : public base_graphics_toolkit -{ -public: - fltk_graphics_toolkit (void) - : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME) { } - - ~fltk_graphics_toolkit (void) { } - - bool is_valid (void) const { return true; } - - bool initialize (const graphics_object& go) - { return go.isa ("figure"); } - - void finalize (const graphics_object& go) - { - if (go.isa ("figure")) - { - octave_value ov = go.get (caseless_str ("__plot_stream__")); - - if (! ov.is_empty ()) - figure_manager::delete_window (ov.string_value ()); - } - } - - void uimenu_set_fltk_label (graphics_object uimenu_obj) - { - if (uimenu_obj.valid_object ()) - { - uimenu::properties& uimenup = - dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ()); - std::string fltk_label = uimenup.get_label (); - graphics_object go = gh_manager::get_object (uimenu_obj.get_parent ()); - if (go.isa ("uimenu")) - fltk_label = dynamic_cast<const uimenu::properties&> (go.get_properties ()).get_fltk_label () - + "/" - + fltk_label; - else if (go.isa ("figure")) - ; - else - error ("unexpected parent object\n"); - - uimenup.set_fltk_label (fltk_label); - } - } - - void update (const graphics_object& go, int id) - { - if (go.isa ("figure")) - { - octave_value ov = go.get (caseless_str ("__plot_stream__")); - - if (! ov.is_empty ()) - { - const figure::properties& fp = - dynamic_cast<const figure::properties&> (go.get_properties ()); - - switch (id) - { - case base_properties::ID_VISIBLE: - figure_manager::toggle_window_visibility - (ov.string_value (), fp.is_visible ()); - break; - - case figure::properties::ID_MENUBAR: - figure_manager::toggle_menubar_visibility - (ov.string_value (), fp.menubar_is ("figure")); - break; - - case figure::properties::ID_CURRENTAXES: - figure_manager::update_canvas - (go.get_handle (), fp.get_currentaxes ()); - break; - - case figure::properties::ID_NAME: - case figure::properties::ID_NUMBERTITLE: - figure_manager::set_name (ov.string_value ()); - break; - - case figure::properties::ID_INTEGERHANDLE: - { - std::string tmp = ov.string_value (); - graphics_handle gh = fp.get___myhandle__ (); - figure_manager::renumber_figure (tmp, gh.value ()); - figure_manager::set_name (tmp); - } - break; - } - } - } - else if (go.isa ("uimenu")) - { - if (id == uimenu::properties::ID_LABEL) - uimenu_set_fltk_label (go); - - graphics_object fig = go.get_ancestor ("figure"); - figure_manager::uimenu_update (fig.get_handle (), go.get_handle (), id); - } - } - - void redraw_figure (const graphics_object& go) const - { - figure_manager::mark_modified (go.get_handle ()); - - __fltk_redraw__ (); - } - - void print_figure (const graphics_object& go, - const std::string& term, - const std::string& file_cmd, bool /*mono*/, - const std::string& /*debug_file*/) const - { - figure_manager::print (go.get_handle (), file_cmd, term); - redraw_figure (go); - } - - Matrix get_canvas_size (const graphics_handle& fh) const - { - return figure_manager::get_size (fh); - } - - double get_screen_resolution (void) const - { - // FLTK doesn't give this info. - return 72.0; - } - - Matrix get_screen_size (void) const - { - Matrix sz (1, 2, 0.0); - sz(0) = Fl::w (); - sz(1) = Fl::h (); - return sz; - } - - void close (void) - { - if (toolkit_loaded) - { - munlock ("__init_fltk__"); - - figure_manager::close_all (); - gtk_manager::unload_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME); - toolkit_loaded = false; - - octave_value_list args; - args(0) = "__fltk_redraw__"; - feval ("remove_input_event_hook", args, 0); - - // FIXME ??? - Fl::wait (fltk_maxtime); - } - } -}; - -// Initialize the fltk graphics toolkit. - -DEFUN_DLD (__init_fltk__, , , "") -{ - if (! toolkit_loaded) - { - mlock (); - - graphics_toolkit tk (new fltk_graphics_toolkit ()); - gtk_manager::load_toolkit (tk); - toolkit_loaded = true; - - octave_value_list args; - args(0) = "__fltk_redraw__"; - feval ("add_input_event_hook", args, 0); - } - - octave_value retval; - return retval; -} - -DEFUN_DLD (__fltk_redraw__, , , "") -{ - __fltk_redraw__ (); - - return octave_value (); -} - -DEFUN_DLD (__fltk_maxtime__, args, ,"") -{ - octave_value retval = fltk_maxtime; - - if (args.length () == 1) - { - if (args(0).is_real_scalar ()) - fltk_maxtime = args(0).double_value (); - else - error ("argument must be a real scalar"); - } - - return retval; -} - -#endif - -// FIXME -- This function should be abstracted and made potentially -// available to all graphics toolkits. This suggests putting it in -// graphics.cc as is done for drawnow() and having the master -// mouse_wheel_zoom function call fltk_mouse_wheel_zoom. The same -// should be done for gui_mode and fltk_gui_mode. For now (2011.01.30), -// just changing function names and docstrings. - -DEFUN_DLD (mouse_wheel_zoom, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{speed} =} mouse_wheel_zoom ()\n\ -@deftypefnx {Built-in Function} {} mouse_wheel_zoom (@var{speed})\n\ -Query or set the mouse wheel zoom factor.\n\ -\n\ -This function is currently implemented only for the FLTK graphics toolkit.\n\ -@seealso{gui_mode}\n\ -@end deftypefn") -{ -#if defined (HAVE_FLTK) - octave_value retval = wheel_zoom_speed; - - if (args.length () == 1) - { - if (args(0).is_real_scalar ()) - wheel_zoom_speed = args(0).double_value (); - else - error ("mouse_wheel_zoom: SPEED must be a real scalar"); - } - - return retval; -#else - error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries"); - return octave_value (); -#endif -} - -DEFUN_DLD (gui_mode, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{mode} =} gui_mode ()\n\ -@deftypefnx {Built-in Function} {} gui_mode (@var{mode})\n\ -Query or set the GUI mode for the current graphics toolkit.\n\ -The @var{mode} argument can be one of the following strings:\n\ -\n\ -@table @asis\n\ -@item '2d'\n\ -Allows panning and zooming of current axes.\n\ -\n\ -@item '3d'\n\ -Allows rotating and zooming of current axes.\n\ -\n\ -@item 'none'\n\ -Mouse inputs have no effect.\n\ -@end table\n\ -\n\ -This function is currently implemented only for the FLTK graphics toolkit.\n\ -@seealso{mouse_wheel_zoom}\n\ -@end deftypefn") -{ -#if defined (HAVE_FLTK) - caseless_str mode_str; - - if (gui_mode == pan_zoom) - mode_str = "2d"; - else if (gui_mode == rotate_zoom) - mode_str = "3d"; - else - mode_str = "none"; - - bool failed = false; - - if (args.length () == 1) - { - if (args(0).is_string ()) - { - mode_str = args(0).string_value (); - - if (mode_str.compare ("2d")) - gui_mode = pan_zoom; - else if (mode_str.compare ("3d")) - gui_mode = rotate_zoom; - else if (mode_str.compare ("none")) - gui_mode = none; - else - failed = true; - } - else - failed = true; - } - - if (failed) - error ("MODE must be one of the strings: \"2D\", \"3D\", or \"none\""); - - return octave_value (mode_str); -#else - error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries"); - return octave_value (); -#endif -} -
--- a/src/DLD-FUNCTIONS/__init_gnuplot__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - -Copyright (C) 2007-2012 John W. Eaton - -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/>. - -*/ - -/* - -To initialize: - - graphics_toolkit ("gnuplot"); - plot (randn (1e3, 1)); - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "defun-dld.h" -#include "error.h" -#include "graphics.h" -#include "parse.h" -#include "variables.h" - -// PKG_ADD: register_graphics_toolkit ("gnuplot"); - -static bool toolkit_loaded = false; - -class gnuplot_graphics_toolkit : public base_graphics_toolkit -{ -public: - gnuplot_graphics_toolkit (void) - : base_graphics_toolkit ("gnuplot") { } - - ~gnuplot_graphics_toolkit (void) { } - - bool is_valid (void) const { return true; } - - bool initialize (const graphics_object& go) - { - return go.isa ("figure"); - } - - void finalize (const graphics_object& go) - { - if (go.isa ("figure")) - { - const figure::properties& props = - dynamic_cast<const figure::properties&> (go.get_properties ()); - - send_quit (props.get___plot_stream__ ()); - } - } - - void update (const graphics_object& go, int id) - { - if (go.isa ("figure")) - { - graphics_object obj (go); - - figure::properties& props = - dynamic_cast<figure::properties&> (obj.get_properties ()); - - switch (id) - { - case base_properties::ID_VISIBLE: - if (! props.is_visible ()) - { - send_quit (props.get___plot_stream__ ()); - props.set___plot_stream__ (Matrix ()); - props.set___enhanced__ (false); - } - break; - } - } - } - - void redraw_figure (const graphics_object& go) const - { - octave_value_list args; - args(0) = go.get_handle ().as_octave_value (); - feval ("__gnuplot_drawnow__", args); - } - - void print_figure (const graphics_object& go, const std::string& term, - const std::string& file, bool mono, - const std::string& debug_file) const - { - octave_value_list args; - if (! debug_file.empty ()) - args(4) = debug_file; - args(3) = mono; - args(2) = file; - args(1) = term; - args(0) = go.get_handle ().as_octave_value (); - feval ("__gnuplot_drawnow__", args); - } - - Matrix get_canvas_size (const graphics_handle&) const - { - Matrix sz (1, 2, 0.0); - return sz; - } - - double get_screen_resolution (void) const - { return 72.0; } - - Matrix get_screen_size (void) const - { return Matrix (1, 2, 0.0); } - - void close (void) - { - if (toolkit_loaded) - { - munlock ("__init_gnuplot__"); - - gtk_manager::unload_toolkit ("gnuplot"); - - toolkit_loaded = false; - } - } - -private: - - void send_quit (const octave_value& pstream) const - { - if (! pstream.is_empty ()) - { - octave_value_list args; - Matrix fids = pstream.matrix_value (); - - if (! error_state) - { - args(1) = "\nquit;\n"; - args(0) = fids(0); - feval ("fputs", args); - - args.resize (1); - feval ("fflush", args); - feval ("pclose", args); - - if (fids.numel () > 1) - { - args(0) = fids(1); - feval ("pclose", args); - - if (fids.numel () > 2) - { - args(0) = fids(2); - feval ("waitpid", args); - } - } - } - } - } -}; - -// Initialize the fltk graphics toolkit. - -DEFUN_DLD (__init_gnuplot__, , , "") -{ - octave_value retval; - - if (! toolkit_loaded) - { - mlock (); - - graphics_toolkit tk (new gnuplot_graphics_toolkit ()); - gtk_manager::load_toolkit (tk); - - toolkit_loaded = true; - } - - return retval; -} -
--- a/src/DLD-FUNCTIONS/__magick_read__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1216 +0,0 @@ -/* - -Copyright (C) 2002-2012 Andy Adler -Copyright (C) 2008 Thomas L. Scofield -Copyright (C) 2010 David Grundberg - -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> -#endif - -#include <cmath> - -#include "file-stat.h" -#include "oct-env.h" -#include "oct-time.h" - -#include "defun-dld.h" -#include "error.h" -#include "ov-struct.h" - -#ifdef HAVE_MAGICK - -#include <Magick++.h> -#include <clocale> - -octave_value_list -read_indexed_images (std::vector<Magick::Image>& imvec, - const Array<int>& frameidx, bool wantalpha) -{ - octave_value_list output; - - int rows = imvec[0].baseRows (); - int columns = imvec[0].baseColumns (); - int nframes = frameidx.length (); - - dim_vector idim = dim_vector (); - idim.resize (4); - idim(0) = rows; - idim(1) = columns; - idim(2) = 1; - idim(3) = nframes; - - Array<int> idx (dim_vector (4, 1)); - - Magick::ImageType type = imvec[0].type (); - - unsigned int mapsize = imvec[0].colorMapSize (); - unsigned int i = mapsize; - unsigned int depth = 0; - while (i >>= 1) - depth++; - i = 0; - depth--; - while (depth >>= 1) - i++; - depth = 1 << i; - - switch (depth) - { - case 1: - case 2: - case 4: - case 8: - { - uint8NDArray im = uint8NDArray (idim); - - idx(2) = 0; - for (int frame = 0; frame < nframes; frame++) - { - imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - const Magick::IndexPacket *pix - = imvec[frameidx(frame)].getConstIndexes (); - - i = 0; - idx(3) = frame; - - for (int y = 0; y < rows; y++) - { - idx(0) = y; - for (int x = 0; x < columns; x++) - { - idx(1) = x; - im(idx) = static_cast<octave_uint8> (pix[i++]); - } - } - } - - output(0) = octave_value (im); - } - break; - - case 16: - { - uint16NDArray im = uint16NDArray (idim); - - idx(2) = 0; - for (int frame = 0; frame < nframes; frame++) - { - imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - const Magick::IndexPacket *pix - = imvec[frameidx(frame)].getConstIndexes (); - - i = 0; - idx(3) = frame; - - for (int y = 0; y < rows; y++) - { - idx(0) = y; - for (int x = 0; x < columns; x++) - { - idx(1) = x; - im(idx) = static_cast<octave_uint16> (pix[i++]); - } - } - } - - output(0) = octave_value (im); - } - break; - - default: - error ("__magic_read__: index depths greater than 16-bit are not supported"); - return octave_value_list (); - } - - Matrix map = Matrix (mapsize, 3); - Matrix alpha; - - switch (type) - { - case Magick::PaletteMatteType: -#if 0 - warning ("palettematte"); - Matrix map (mapsize, 3); - Matrix alpha (mapsize, 1); - for (i = 0; i < mapsize; i++) - { - warning ("%d", i); - Magick::ColorRGB c = imvec[0].colorMap (i); - map(i,0) = c.red (); - map(i,1) = c.green (); - map(i,2) = c.blue (); - alpha(i,1) = c.alpha (); - } - break; -#endif - - case Magick::PaletteType: - alpha = Matrix (0, 0); - for (i = 0; i < mapsize; i++) - { - Magick::ColorRGB c = imvec[0].colorMap (i); - map(i,0) = c.red (); - map(i,1) = c.green (); - map(i,2) = c.blue (); - } - break; - - default: - error ("__magick_read__: unsupported indexed image type"); - return octave_value_list (); - } - - if (wantalpha) - output(2) = alpha; - - output(1) = map; - - return output; -} - -template <class T> -octave_value_list -read_images (const std::vector<Magick::Image>& imvec, - const Array<int>& frameidx, unsigned int depth) -{ - typedef typename T::element_type P; - - octave_value_list retval (3, Matrix ()); - - T im; - - int rows = imvec[0].baseRows (); - int columns = imvec[0].baseColumns (); - int nframes = frameidx.length (); - - dim_vector idim = dim_vector (); - idim.resize (4); - idim(0) = rows; - idim(1) = columns; - idim(2) = 1; - idim(3) = nframes; - - Magick::ImageType type = imvec[0].type (); - const int divisor = ((uint64_t (1) << QuantumDepth) - 1) / - ((uint64_t (1) << depth) - 1); - - switch (type) - { - case Magick::BilevelType: - case Magick::GrayscaleType: - { - im = T (idim); - P *vec = im.fortran_vec (); - - for (int frame = 0; frame < nframes; frame++) - { - const Magick::PixelPacket *pix - = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - P *rbuf = vec; - for (int y = 0; y < rows; y++) - { - for (int x = 0; x < columns; x++) - { - *rbuf = pix->red / divisor; - pix++; - rbuf += rows; - } - rbuf -= rows * columns - 1; - } - - // Next frame. - vec += rows * columns * idim(2); - } - } - break; - - case Magick::GrayscaleMatteType: - { - idim(2) = 2; - im = T (idim); - P *vec = im.fortran_vec (); - - for (int frame = 0; frame < nframes; frame++) - { - const Magick::PixelPacket *pix - = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - P *rbuf = vec; - P *obuf = vec + rows * columns; - for (int y = 0; y < rows; y++) - { - for (int x = 0; x < columns; x++) - { - *rbuf = pix->red / divisor; - *obuf = pix->opacity / divisor; - pix++; - rbuf += rows; - obuf += rows; - } - rbuf -= rows * columns - 1; - obuf -= rows * columns - 1; - } - - // Next frame. - vec += rows * columns * idim(2); - } - } - break; - - case Magick::PaletteType: - case Magick::TrueColorType: - { - idim(2) = 3; - im = T (idim); - P *vec = im.fortran_vec (); - - for (int frame = 0; frame < nframes; frame++) - { - const Magick::PixelPacket *pix - = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - P *rbuf = vec; - P *gbuf = vec + rows * columns; - P *bbuf = vec + rows * columns * 2; - for (int y = 0; y < rows; y++) - { - for (int x = 0; x < columns; x++) - { - *rbuf = pix->red / divisor; - *gbuf = pix->green / divisor; - *bbuf = pix->blue / divisor; - pix++; - rbuf += rows; - gbuf += rows; - bbuf += rows; - } - rbuf -= rows * columns - 1; - gbuf -= rows * columns - 1; - bbuf -= rows * columns - 1; - } - - // Next frame. - vec += rows * columns * idim(2); - } - } - break; - - case Magick::PaletteMatteType: - case Magick::TrueColorMatteType: - case Magick::ColorSeparationType: - { - idim(2) = 4; - im = T (idim); - P *vec = im.fortran_vec (); - - for (int frame = 0; frame < nframes; frame++) - { - const Magick::PixelPacket *pix - = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); - - P *rbuf = vec; - P *gbuf = vec + rows * columns; - P *bbuf = vec + rows * columns * 2; - P *obuf = vec + rows * columns * 3; - for (int y = 0; y < rows; y++) - { - for (int x = 0; x < columns; x++) - { - *rbuf = pix->red / divisor; - *gbuf = pix->green / divisor; - *bbuf = pix->blue / divisor; - *obuf = pix->opacity / divisor; - pix++; - rbuf += rows; - gbuf += rows; - bbuf += rows; - obuf += rows; - } - rbuf -= rows * columns - 1; - gbuf -= rows * columns - 1; - bbuf -= rows * columns - 1; - obuf -= rows * columns - 1; - } - - // Next frame. - vec += rows * columns * idim(2); - } - } - break; - - default: - error ("__magick_read__: undefined ImageMagick image type"); - return retval; - } - - retval(0) = im; - - return retval; -} - -#endif - -static void -maybe_initialize_magick (void) -{ -#ifdef HAVE_MAGICK - - static bool initialized = false; - - if (! initialized) - { - // Save the locale as GraphicsMagick might change this (depending on version) - const char *static_locale = setlocale (LC_ALL, NULL); - const std::string locale (static_locale); - - std::string program_name = octave_env::get_program_invocation_name (); - - Magick::InitializeMagick (program_name.c_str ()); - - // Restore locale from before GraphicsMagick initialisation - setlocale (LC_ALL, locale.c_str ()); - - if (QuantumDepth < 32) - warning ("your version of %s limits images to %d bits per pixel", - MagickPackageName, QuantumDepth); - - initialized = true; - } -#endif -} - -DEFUN_DLD (__magick_read__, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Function File} {@var{m} =} __magick_read__ (@var{fname}, @var{index})\n\ -@deftypefnx {Function File} {[@var{m}, @var{colormap}] =} __magick_read__ (@var{fname}, @var{index})\n\ -@deftypefnx {Function File} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__ (@var{fname}, @var{index})\n\ -Read images with ImageMagick++. In general you should not be using this\n\ -function. Instead use @code{imread}.\n\ -@seealso{imread}\n\ -@end deftypefn") -{ - octave_value_list output; - -#ifdef HAVE_MAGICK - - maybe_initialize_magick (); - - if (args.length () > 3 || args.length () < 1 || ! args(0).is_string () - || nargout > 3) - { - print_usage (); - return output; - } - - Array<int> frameidx; - bool all_frames = false; - - if (args.length () == 2 && args(1).is_real_type ()) - frameidx = args(1).int_vector_value (); - else if (args.length () == 3 && args(1).is_string () - && args(1).string_value () == "frames") - { - if (args(2).is_string () && args(2).string_value () == "all") - all_frames = true; - else if (args(2).is_real_type ()) - frameidx = args(2).int_vector_value (); - } - else - { - frameidx = Array<int> (dim_vector (1, 1)); - frameidx(0) = 1; - } - - std::vector<Magick::Image> imvec; - - try - { - // Read a file into vector of image objects - Magick::readImages (&imvec, args(0).string_value ()); - } - catch (Magick::Warning& w) - { - warning ("Magick++ warning: %s", w.what ()); - } - catch (Magick::ErrorCoder& e) - { - warning ("Magick++ coder error: %s", e.what ()); - } - catch (Magick::Exception& e) - { - error ("Magick++ exception: %s", e.what ()); - return output; - } - - int nframes = imvec.size (); - if (all_frames) - { - frameidx = Array<int> (dim_vector (1, nframes)); - for (int i = 0; i < frameidx.length (); i++) - frameidx(i) = i; - } - else - { - for (int i = 0; i < frameidx.length (); i++) - { - frameidx(i) = frameidx(i) - 1; - - if (frameidx(i) >= nframes || frameidx(i) < 0) - { - error ("__magick_read__: invalid INDEX vector"); - return output; - } - } - } - - Magick::ClassType klass = imvec[0].classType (); - - if (klass == Magick::PseudoClass && nargout > 1) - output = read_indexed_images (imvec, frameidx, (nargout == 3)); - else - { - unsigned int depth = imvec[0].modulusDepth (); - if (depth > 1) - { - --depth; - int i = 1; - while (depth >>= 1) - i++; - depth = 1 << i; - } - - switch (depth) - { - case 1: - output = read_images<boolNDArray> (imvec, frameidx, depth); - break; - - case 2: - case 4: - case 8: - output = read_images<uint8NDArray> (imvec, frameidx, depth) ; - break; - - case 16: - output = read_images<uint16NDArray> (imvec, frameidx, depth); - break; - - case 32: - case 64: - default: - error ("__magick_read__: image depths greater than 16-bit are not supported"); - } - } -#else - - error ("imread: image reading capabilities were disabled when Octave was compiled"); - -#endif - - return output; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/ - -#ifdef HAVE_MAGICK - -static void -jpg_settings (std::vector<Magick::Image>& imvec, - const Octave_map& options, - bool) -{ - bool something_set = false; - - // Quality setting - octave_value result; - Octave_map::const_iterator p; - bool found_it = false; - - for (p = options.begin (); p != options.end (); p++) - { - if (options.key (p) == "Quality") - { - found_it = true; - result = options.contents (p).elem (0); - break; - } - } - - if (found_it && (! result.is_empty ())) - { - something_set = true; - - if (result.is_real_type ()) - { - int qlev = result.int_value (); - - if (qlev < 0 || qlev > 100) - warning ("warning: Quality setting invalid--use default of 75"); - else - { - for (size_t fnum = 0; fnum < imvec.size (); fnum++) - imvec[fnum].quality (static_cast<unsigned int>(qlev)); - } - } - else - warning ("warning: Quality setting invalid--use default of 75"); - } - - // Other settings go here - - if (! something_set) - warning ("__magick_write__ warning: all write parameters ignored"); -} - -static void -encode_bool_image (std::vector<Magick::Image>& imvec, const octave_value& img) -{ - unsigned int nframes = 1; - boolNDArray m = img.bool_array_value (); - - dim_vector dsizes = m.dims (); - if (dsizes.length () == 4) - nframes = dsizes(3); - - Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1)); - - octave_idx_type rows = m.rows (); - octave_idx_type columns = m.columns (); - - for (unsigned int ii = 0; ii < nframes; ii++) - { - Magick::Image im (Magick::Geometry (columns, rows), "black"); - im.classType (Magick::DirectClass); - im.depth (1); - - for (int y = 0; y < columns; y++) - { - idx(1) = y; - - for (int x = 0; x < rows; x++) - { - if (nframes > 1) - { - idx(2) = 0; - idx(3) = ii; - } - - idx(0) = x; - - if (m(idx)) - im.pixelColor (y, x, "white"); - } - } - - im.quantizeColorSpace (Magick::GRAYColorspace); - im.quantizeColors (2); - im.quantize (); - - imvec.push_back (im); - } -} - -template <class T> -static void -encode_uint_image (std::vector<Magick::Image>& imvec, - const octave_value& img, - bool has_map) -{ - unsigned int bitdepth = 0; - T m; - - if (img.is_uint8_type ()) - { - bitdepth = 8; - m = img.uint8_array_value (); - } - else if (img.is_uint16_type ()) - { - bitdepth = 16; - m = img.uint16_array_value (); - } - else - error ("__magick_write__: invalid image class"); - - dim_vector dsizes = m.dims (); - unsigned int nframes = 1; - if (dsizes.length () == 4) - nframes = dsizes(3); - - bool is_color = ((dsizes.length () > 2) && (dsizes(2) > 2)); - bool has_alpha = (dsizes.length () > 2 && (dsizes(2) == 2 || dsizes(2) == 4)); - - Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1)); - octave_idx_type rows = m.rows (); - octave_idx_type columns = m.columns (); - - unsigned int div_factor = (1 << bitdepth) - 1; - - for (unsigned int ii = 0; ii < nframes; ii++) - { - Magick::Image im (Magick::Geometry (columns, rows), "black"); - - im.depth (bitdepth); - - if (has_map) - im.classType (Magick::PseudoClass); - else - im.classType (Magick::DirectClass); - - if (is_color) - { - if (has_alpha) - im.type (Magick::TrueColorMatteType); - else - im.type (Magick::TrueColorType); - - Magick::ColorRGB c; - - for (int y = 0; y < columns; y++) - { - idx(1) = y; - - for (int x = 0; x < rows; x++) - { - idx(0) = x; - - if (nframes > 1) - idx(3) = ii; - - idx(2) = 0; - c.red (static_cast<double>(m(idx)) / div_factor); - - idx(2) = 1; - c.green (static_cast<double>(m(idx)) / div_factor); - - idx(2) = 2; - c.blue (static_cast<double>(m(idx)) / div_factor); - - if (has_alpha) - { - idx(2) = 3; - c.alpha (static_cast<double>(m(idx)) / div_factor); - } - - im.pixelColor (y, x, c); - } - } - } - else - { - if (has_alpha) - im.type (Magick::GrayscaleMatteType); - else - im.type (Magick::GrayscaleType); - - Magick::ColorGray c; - - for (int y = 0; y < columns; y++) - { - idx(1) = y; - - for (int x=0; x < rows; x++) - { - idx(0) = x; - - if (nframes > 1) - { - idx(2) = 0; - idx(3) = ii; - } - - if (has_alpha) - { - idx(2) = 1; - c.alpha (static_cast<double>(m(idx)) / div_factor); - idx(2) = 0; - } - - c.shade (static_cast<double>(m(idx)) / div_factor); - - im.pixelColor (y, x, c); - } - } - - im.quantizeColorSpace (Magick::GRAYColorspace); - im.quantizeColors (1 << bitdepth); - im.quantize (); - } - - imvec.push_back (im); - } -} - -static void -encode_map (std::vector<Magick::Image>& imvec, const NDArray& cmap) -{ - unsigned int mapsize = cmap.dim1 (); - - for (size_t fnum = 0; fnum < imvec.size (); fnum++) - { - imvec[fnum].colorMapSize (mapsize); - imvec[fnum].type (Magick::PaletteType); - } - - for (unsigned int ii = 0; ii < mapsize; ii++) - { - Magick::ColorRGB c (cmap(ii,0), cmap(ii,1), cmap(ii,2)); - - // FIXME -- is this case needed? - if (cmap.dim2 () == 4) - c.alpha (cmap(ii,3)); - - try - { - for_each (imvec.begin (), imvec.end (), - Magick::colorMapImage (ii, c)); - } - catch (Magick::Warning& w) - { - warning ("Magick++ warning: %s", w.what ()); - } - catch (Magick::ErrorCoder& e) - { - warning ("Magick++ coder error: %s", e.what ()); - } - catch (Magick::Exception& e) - { - error ("Magick++ exception: %s", e.what ()); - } - } -} - -static void -write_image (const std::string& filename, const std::string& fmt, - const octave_value& img, - const octave_value& map = octave_value (), - const octave_value& params = octave_value ()) -{ - std::vector<Magick::Image> imvec; - - bool has_map = map.is_defined (); - - if (has_map) - { - error ("__magick_write__: direct saving of indexed images not currently supported; use ind2rgb and save converted image"); - return; - } - - if (img.is_bool_type ()) - encode_bool_image (imvec, img); - else if (img.is_uint8_type ()) - encode_uint_image<uint8NDArray> (imvec, img, has_map); - else if (img.is_uint16_type ()) - encode_uint_image<uint16NDArray> (imvec, img, has_map); - else - error ("__magick_write__: image type not supported"); - - if (! error_state && has_map) - { - NDArray cmap = map.array_value (); - - if (! error_state) - encode_map (imvec, cmap); - } - - if (! error_state && params.is_defined ()) - { - Octave_map options = params.map_value (); - - // Insert calls here to handle parameters for various image formats - if (fmt == "jpg" || fmt == "jpeg") - jpg_settings (imvec, options, has_map); - else - warning ("warning: your parameter(s) currently not supported"); - } - - try - { - Magick::writeImages (imvec.begin (), imvec.end (), fmt + ":" + filename); - } - catch (Magick::Warning& w) - { - warning ("Magick++ warning: %s", w.what ()); - } - catch (Magick::ErrorCoder& e) - { - warning ("Magick++ coder error: %s", e.what ()); - } - catch (Magick::Exception& e) - { - error ("Magick++ exception: %s", e.what ()); - } -} - -#endif - -DEFUN_DLD (__magick_write__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img})\n\ -@deftypefnx {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img}, @var{map})\n\ -Write images with ImageMagick++. In general you should not be using this\n\ -function. Instead use @code{imwrite}.\n\ -@seealso{imread}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_MAGICK - maybe_initialize_magick (); - - int nargin = args.length (); - - if (nargin > 2) - { - std::string filename = args(0).string_value (); - - if (! error_state) - { - std::string fmt = args(1).string_value (); - - if (! error_state) - { - if (nargin > 4) - write_image (filename, fmt, args(2), args(3), args(4)); - else if (nargin > 3) - if (args(3).is_real_type ()) - write_image (filename, fmt, args(2), args(3)); - else - write_image (filename, fmt, args(2), octave_value (), args(3)); - else - write_image (filename, fmt, args(2)); - } - else - error ("__magick_write__: FMT must be string"); - } - else - error ("__magick_write__: FNAME must be a string"); - } - else - print_usage (); -#else - - error ("__magick_write__: not available in this version of Octave"); - -#endif - -return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/ - -#ifdef HAVE_MAGICK - -template<class T> -static octave_value -magick_to_octave_value (const T magick) -{ - return octave_value (magick); -} - -static octave_value -magick_to_octave_value (const Magick::EndianType magick) -{ - switch (magick) - { - case Magick::LSBEndian: - return octave_value ("little-endian"); - - case Magick::MSBEndian: - return octave_value ("big-endian"); - - default: - return octave_value ("undefined"); - } -} - -static octave_value -magick_to_octave_value (const Magick::ResolutionType magick) -{ - switch (magick) - { - case Magick::PixelsPerInchResolution: - return octave_value ("pixels per inch"); - - case Magick::PixelsPerCentimeterResolution: - return octave_value ("pixels per centimeter"); - - default: - return octave_value ("undefined"); - } -} - -static octave_value -magick_to_octave_value (const Magick::ImageType magick) -{ - switch (magick) - { - case Magick::BilevelType: - case Magick::GrayscaleType: - case Magick::GrayscaleMatteType: - return octave_value ("grayscale"); - - case Magick::PaletteType: - case Magick::PaletteMatteType: - return octave_value ("indexed"); - - case Magick::TrueColorType: - case Magick::TrueColorMatteType: - case Magick::ColorSeparationType: - return octave_value ("truecolor"); - - default: - return octave_value ("undefined"); - } -} - -// We put this in a try-block because GraphicsMagick will throw -// exceptions if a parameter isn't present in the current image. -#define GET_PARAM(NAME, OUTNAME) \ - try \ - { \ - info.contents (OUTNAME)(frame,0) = magick_to_octave_value (im.NAME ()); \ - } \ - catch (Magick::Warning& w) \ - { \ - } - -#endif - -DEFUN_DLD (__magick_finfo__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __magick_finfo__ (@var{fname})\n\ -Read image information with GraphicsMagick++. In general you should\n\ -not be using this function. Instead use @code{imfinfo}.\n\ -@seealso{imfinfo, imread}\n\ -@end deftypefn") -{ - octave_value retval; - -#ifdef HAVE_MAGICK - - maybe_initialize_magick (); - - if (args.length () < 1 || ! args (0).is_string ()) - { - print_usage (); - return retval; - } - - const std::string filename = args (0).string_value (); - - try - { - // Read the file. - std::vector<Magick::Image> imvec; - Magick::readImages (&imvec, args(0).string_value ()); - int nframes = imvec.size (); - - // Create the right size for the output. - - static const char *fields[] = - { - "Filename", - "FileModDate", - "FileSize", - "Height", - "Width", - "BitDepth", - "Format", - "LongFormat", - "XResolution", - "YResolution", - "TotalColors", - "TileName", - "AnimationDelay", - "AnimationIterations", - "ByteOrder", - "Gamma", - "Matte", - "ModulusDepth", - "Quality", - "QuantizeColors", - "ResolutionUnits", - "ColorType", - "View", - 0 - }; - - Octave_map info (string_vector (fields), dim_vector (nframes, 1)); - - file_stat fs (filename); - - std::string filetime; - - if (fs) - { - octave_localtime mtime = fs.mtime (); - - filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S"); - } - else - { - std::string msg = fs.error (); - - error ("imfinfo: error reading `%s': %s", - filename.c_str (), msg.c_str ()); - - return retval; - } - - // For each frame in the image (some images contain multiple - // layers, each to be treated like a separate image). - for (int frame = 0; frame < nframes; frame++) - { - Magick::Image im = imvec[frame]; - - // Add file name and timestamp. - info.contents ("Filename")(frame,0) = filename; - info.contents ("FileModDate")(frame,0) = filetime; - - // Annoying CamelCase naming is for Matlab compatibility. - GET_PARAM (fileSize, "FileSize") - GET_PARAM (rows, "Height") - GET_PARAM (columns, "Width") - GET_PARAM (depth, "BitDepth") - GET_PARAM (magick, "Format") - GET_PARAM (format, "LongFormat") - GET_PARAM (xResolution, "XResolution") - GET_PARAM (yResolution, "YResolution") - GET_PARAM (totalColors, "TotalColors") - GET_PARAM (tileName, "TileName") - GET_PARAM (animationDelay, "AnimationDelay") - GET_PARAM (animationIterations, "AnimationIterations") - GET_PARAM (endian, "ByteOrder") - GET_PARAM (gamma, "Gamma") - GET_PARAM (matte, "Matte") - GET_PARAM (modulusDepth, "ModulusDepth") - GET_PARAM (quality, "Quality") - GET_PARAM (quantizeColors, "QuantizeColors") - GET_PARAM (resolutionUnits, "ResolutionUnits") - GET_PARAM (type, "ColorType") - GET_PARAM (view, "View") - } - - retval = octave_value (info); - } - catch (Magick::Warning& w) - { - warning ("Magick++ warning: %s", w.what ()); - } - catch (Magick::ErrorCoder& e) - { - warning ("Magick++ coder error: %s", e.what ()); - } - catch (Magick::Exception& e) - { - error ("Magick++ exception: %s", e.what ()); - return retval; - } - -#else - - error ("imfinfo: not available in this version of Octave"); - -#endif - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/ - -#undef GET_PARAM - -// Determine the file formats supported by GraphicsMagick. This is -// called once at the beginning of imread or imwrite to determine -// exactly which file formats are supported, so error messages can be -// displayed properly. - -DEFUN_DLD (__magick_format_list__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Function File} {} __magick_format_list__ (@var{formats})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value retval; - -#ifdef HAVE_MAGICK - maybe_initialize_magick (); - - std::list<std::string> accepted_formats; - - if (args.length () == 1) - { - Cell c = args (0).cell_value (); - - if (! error_state) - { - for (octave_idx_type i = 0; i < c.nelem (); i++) - { - try - { - std::string fmt = c.elem (i).string_value (); - - Magick::CoderInfo info(fmt); - - if (info.isReadable () && info.isWritable ()) - accepted_formats.push_back (fmt); - } - catch (Magick::Exception& e) - { - // Do nothing: exception here are simply missing formats. - } - } - } - else - error ("__magick_format_list__: expecting a cell array of image format names"); - } - else - print_usage (); - - retval = Cell (accepted_formats); - -#else - - error ("__magick_format_list__: not available in this version of Octave"); - -#endif - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/
--- a/src/DLD-FUNCTIONS/__voronoi__.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,334 +0,0 @@ -/* - -Copyright (C) 2000-2012 Kai Habel - -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/>. - -*/ - -/* -20. Augiust 2000 - Kai Habel: first release -*/ - -/* -2003-12-14 Rafael Laboissiere <rafael@laboissiere.net> -Added optional second argument to pass options to the underlying -qhull command -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <cstdio> - -#include <list> - -#include "lo-ieee.h" - -#include "Cell.h" -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" -#include "unwind-prot.h" - -#if defined (HAVE_QHULL) -# include "oct-qhull.h" -# if defined (NEED_QHULL_VERSION) -char qh_version[] = "__voronoi__.oct 2007-07-24"; -# endif -#endif - -static void -close_fcn (FILE *f) -{ - gnulib::fclose (f); -} - -DEFUN_DLD (__voronoi__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts})\n\ -@deftypefnx {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts}, @var{options})\n\ -@deftypefnx {Loadable Function} {@var{C}, @var{F}, @var{Inf_Pts} =} __voronoi__ (@dots{})\n\ -Undocumented internal function.\n\ -@end deftypefn") -{ - octave_value_list retval; - - std::string caller = args(0).string_value (); - -#if defined (HAVE_QHULL) - - retval(0) = 0.0; - - int nargin = args.length (); - if (nargin < 2 || nargin > 3) - { - print_usage (); - return retval; - } - - Matrix points = args(1).matrix_value (); - const octave_idx_type dim = points.columns (); - const octave_idx_type num_points = points.rows (); - - points = points.transpose (); - - std::string options; - - if (dim <= 4) - options = " Qbb"; - else - options = " Qbb Qx"; - - if (nargin == 3) - { - octave_value opt_arg = args(2); - - if (opt_arg.is_string ()) - options = " " + opt_arg.string_value (); - else if (opt_arg.is_empty ()) - ; // Use default options. - else if (opt_arg.is_cellstr ()) - { - options = ""; - - Array<std::string> tmp = opt_arg.cellstr_value (); - - for (octave_idx_type i = 0; i < tmp.numel (); i++) - options += " " + tmp(i); - } - else - { - error ("%s: OPTIONS must be a string, cell array of strings, or empty", - caller.c_str ()); - return retval; - } - } - - boolT ismalloc = false; - - unwind_protect frame; - - // Replace the outfile pointer with stdout for debugging information. -#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) - FILE *outfile = gnulib::fopen ("NUL", "w"); -#else - FILE *outfile = gnulib::fopen ("/dev/null", "w"); -#endif - FILE *errfile = stderr; - - if (outfile) - frame.add_fcn (close_fcn, outfile); - else - { - error ("__voronoi__: unable to create temporary file for output"); - return retval; - } - - // qh_new_qhull command and points arguments are not const... - - std::string cmd = "qhull v" + options; - - OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); - - strcpy (cmd_str, cmd.c_str ()); - - int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), - ismalloc, cmd_str, outfile, errfile); - if (! exitcode) - { - // Calling findgood_all provides the number of Voronoi vertices - // (sets qh num_good). - - qh_findgood_all (qh facet_list); - - octave_idx_type num_voronoi_regions - = qh num_vertices - qh_setsize (qh del_vertices); - - octave_idx_type num_voronoi_vertices = qh num_good; - - // Find the voronoi centers for all facets. - - qh_setvoronoi_all (); - - facetT *facet; - vertexT *vertex; - octave_idx_type k; - - // Find the number of Voronoi vertices for each Voronoi cell and - // store them in NI so we can use them later to set the dimensions - // of the RowVector objects used to collect them. - - FORALLfacets - { - facet->seen = false; - } - - OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions); - for (octave_idx_type i = 0; i < num_voronoi_regions; i++) - ni[i] = 0; - - k = 0; - - FORALLvertices - { - if (qh hull_dim == 3) - qh_order_vertexneighbors (vertex); - - bool infinity_seen = false; - - facetT *neighbor, **neighborp; - - FOREACHneighbor_ (vertex) - { - if (neighbor->upperdelaunay) - { - if (! infinity_seen) - { - infinity_seen = true; - ni[k]++; - } - } - else - { - neighbor->seen = true; - ni[k]++; - } - } - - k++; - } - - // If Qhull finds fewer regions than points, we will pad the end - // of the at_inf and C arrays so that they always contain at least - // as many elements as the given points array. - - // FIXME -- is it possible (or does it make sense) for - // num_voronoi_regions to ever be larger than num_points? - - octave_idx_type nr = (num_points > num_voronoi_regions - ? num_points : num_voronoi_regions); - - boolMatrix at_inf (nr, 1, false); - - // The list of Voronoi vertices. The first element is always - // Inf. - Matrix F (num_voronoi_vertices+1, dim); - - for (octave_idx_type d = 0; d < dim; d++) - F(0,d) = octave_Inf; - - // The cell array of vectors of indices into F that represent the - // vertices of the Voronoi regions (cells). - - Cell C (nr, 1); - - // Now loop through the list of vertices again and store the - // coordinates of the Voronoi vertices and the lists of indices - // for the cells. - - FORALLfacets - { - facet->seen = false; - } - - octave_idx_type i = 0; - k = 0; - - FORALLvertices - { - if (qh hull_dim == 3) - qh_order_vertexneighbors (vertex); - - bool infinity_seen = false; - - octave_idx_type idx = qh_pointid (vertex->point); - - octave_idx_type num_vertices = ni[k++]; - - // Qhull seems to sometimes produces regions with a single - // vertex. Is that a bug? How can a region have just one - // vertex? Let's skip it. - - if (num_vertices == 1) - continue; - - RowVector facet_list (num_vertices); - - octave_idx_type m = 0; - - facetT *neighbor, **neighborp; - - FOREACHneighbor_(vertex) - { - if (neighbor->upperdelaunay) - { - if (! infinity_seen) - { - infinity_seen = true; - facet_list(m++) = 1; - at_inf(idx) = true; - } - } - else - { - if (! neighbor->seen) - { - i++; - for (octave_idx_type d = 0; d < dim; d++) - F(i,d) = neighbor->center[d]; - - neighbor->seen = true; - neighbor->visitid = i; - } - - facet_list(m++) = neighbor->visitid + 1; - } - } - - C(idx) = facet_list; - } - - retval(2) = at_inf; - retval(1) = C; - retval(0) = F; - } - else - error ("%s: qhull failed", caller.c_str ()); - - // Free memory from Qhull - qh_freeqhull (! qh_ALL); - - int curlong, totlong; - qh_memfreeshort (&curlong, &totlong); - - if (curlong || totlong) - warning ("%s: qhull did not free %d bytes of long memory (%d pieces)", - caller.c_str (), totlong, curlong); - -#else - error ("%s: not available in this version of Octave", caller.c_str ()); -#endif - - return retval; -} - -/* -## No test needed for internal helper function. -%!assert (1) -*/
--- a/src/DLD-FUNCTIONS/amd.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - -Copyright (C) 2008-2012 David Bateman - -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/>. - -*/ - -// This is the octave interface to amd, which bore the copyright given -// in the help of the functions. - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <cstdlib> - -#include <string> -#include <vector> - -#include "ov.h" -#include "defun-dld.h" -#include "pager.h" -#include "ov-re-mat.h" - -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "oct-map.h" - -#include "oct-sparse.h" -#include "oct-locbuf.h" - -#ifdef IDX_TYPE_LONG -#define AMD_NAME(name) amd_l ## name -#else -#define AMD_NAME(name) amd ## name -#endif - -DEFUN_DLD (amd, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} amd (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} amd (@var{S}, @var{opts})\n\ -\n\ -Return the approximate minimum degree permutation of a matrix. This\n\ -permutation such that the Cholesky@tie{}factorization of @code{@var{S}\n\ -(@var{p}, @var{p})} tends to be sparser than the Cholesky@tie{}factorization\n\ -of @var{S} itself. @code{amd} is typically faster than @code{symamd} but\n\ -serves a similar purpose.\n\ -\n\ -The optional parameter @var{opts} is a structure that controls the\n\ -behavior of @code{amd}. The fields of the structure are\n\ -\n\ -@table @asis\n\ -@item @var{opts}.dense\n\ -Determines what @code{amd} considers to be a dense row or column of the\n\ -input matrix. Rows or columns with more than @code{max(16, (dense *\n\ -sqrt (@var{n})} entries, where @var{n} is the order of the matrix @var{S},\n\ -are ignored by @code{amd} during the calculation of the permutation\n\ -The value of dense must be a positive scalar and its default value is 10.0\n\ -\n\ -@item @var{opts}.aggressive\n\ -If this value is a non zero scalar, then @code{amd} performs aggressive\n\ -absorption. The default is not to perform aggressive absorption.\n\ -@end table\n\ -\n\ -The author of the code itself is Timothy A. Davis\n\ -@email{davis@@cise.ufl.edu}, University of Florida (see\n\ -@url{http://www.cise.ufl.edu/research/sparse/amd}).\n\ -@seealso{symamd, colamd}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_AMD - int nargin = args.length (); - - if (nargin < 1 || nargin > 2) - print_usage (); - else - { - octave_idx_type n_row, n_col; - const octave_idx_type *ridx, *cidx; - SparseMatrix sm; - SparseComplexMatrix scm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0).sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - } - else - { - if (args(0).is_complex_type ()) - sm = SparseMatrix (real (args(0).complex_matrix_value ())); - else - sm = SparseMatrix (args(0).matrix_value ()); - - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - if (!error_state && n_row != n_col) - error ("amd: matrix S must be square"); - - if (!error_state) - { - OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL); - AMD_NAME (_defaults) (Control) ; - if (nargin > 1) - { - octave_scalar_map arg1 = args(1).scalar_map_value (); - - if (!error_state) - { - octave_value tmp; - - tmp = arg1.getfield ("dense"); - if (tmp.is_defined ()) - Control[AMD_DENSE] = tmp.double_value (); - - tmp = arg1.getfield ("aggressive"); - if (tmp.is_defined ()) - Control[AMD_AGGRESSIVE] = tmp.double_value (); - } - else - error ("amd: OPTS argument must be a scalar structure"); - } - - if (!error_state) - { - OCTAVE_LOCAL_BUFFER (octave_idx_type, P, n_col); - Matrix xinfo (AMD_INFO, 1); - double *Info = xinfo.fortran_vec (); - - // FIXME -- how can we manage the memory allocation of - // amd in a cleaner manner? - amd_malloc = malloc; - amd_free = free; - amd_calloc = calloc; - amd_realloc = realloc; - amd_printf = printf; - - octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P, - Control, Info); - - switch (result) - { - case AMD_OUT_OF_MEMORY: - error ("amd: out of memory"); - break; - case AMD_INVALID: - error ("amd: matrix S is corrupted"); - break; - default: - { - if (nargout > 1) - retval(1) = xinfo; - - Matrix Pout (1, n_col); - for (octave_idx_type i = 0; i < n_col; i++) - Pout.xelem (i) = P[i] + 1; - - retval(0) = Pout; - } - } - } - } - } -#else - - error ("amd: not available in this version of Octave"); - -#endif - - return retval; -}
--- a/src/DLD-FUNCTIONS/ccolamd.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,583 +0,0 @@ -/* - -Copyright (C) 2005-2012 David Bateman - -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/>. - -*/ - -// This is the octave interface to ccolamd, which bore the copyright given -// in the help of the functions. - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <cstdlib> - -#include <string> -#include <vector> - -#include "ov.h" -#include "defun-dld.h" -#include "pager.h" -#include "ov-re-mat.h" - -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" - -#include "oct-sparse.h" -#include "oct-locbuf.h" - -#ifdef IDX_TYPE_LONG -#define CCOLAMD_NAME(name) ccolamd_l ## name -#define CSYMAMD_NAME(name) csymamd_l ## name -#else -#define CCOLAMD_NAME(name) ccolamd ## name -#define CSYMAMD_NAME(name) csymamd ## name -#endif - -DEFUN_DLD (ccolamd, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} ccolamd (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs})\n\ -@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs}, @var{cmember})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} ccolamd (@dots{})\n\ -\n\ -Constrained column approximate minimum degree permutation.\n\ -@code{@var{p} = ccolamd (@var{S})} returns the column approximate minimum\n\ -degree permutation vector for the sparse matrix @var{S}. For a non-symmetric\n\ -matrix\n\ -@var{S},\n\ -@code{@var{S}(:, @var{p})} tends to have sparser LU@tie{}factors than\n\ -@var{S}. @code{chol (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))} also\n\ -tends to be sparser than @code{chol (@var{S}' * @var{S})}. @code{@var{p} =\n\ -ccolamd (@var{S}, 1)} optimizes the ordering for @code{lu (@var{S}(:,\n\ -@var{p}))}. The ordering is followed by a column elimination tree\n\ -post-ordering.\n\ -\n\ -@var{knobs} is an optional 1-element to 5-element input vector, with a\n\ -default value of @code{[0 10 10 1 0]} if not present or empty. Entries not\n\ -present are set to their defaults.\n\ -\n\ -@table @code\n\ -@item @var{knobs}(1)\n\ -if nonzero, the ordering is optimized for @code{lu (S(:, p))}. It will be a\n\ -poor ordering for @code{chol (@var{S}(:, @var{p})' * @var{S}(:,\n\ -@var{p}))}. This is the most important knob for ccolamd.\n\ -\n\ -@item @var{knobs}(2)\n\ -if @var{S} is m-by-n, rows with more than @code{max (16, @var{knobs}(2) *\n\ -sqrt (n))} entries are ignored.\n\ -\n\ -@item @var{knobs}(3)\n\ -columns with more than @code{max (16, @var{knobs}(3) * sqrt (min (@var{m},\n\ -@var{n})))} entries are ignored and ordered last in the output permutation\n\ -(subject to the cmember constraints).\n\ -\n\ -@item @var{knobs}(4)\n\ -if nonzero, aggressive absorption is performed.\n\ -\n\ -@item @var{knobs}(5)\n\ -if nonzero, statistics and knobs are printed.\n\ -\n\ -@end table\n\ -\n\ -@var{cmember} is an optional vector of length @math{n}. It defines the\n\ -constraints on the column ordering. If @code{@var{cmember}(j) = @var{c}},\n\ -then column @var{j} is in constraint set @var{c} (@var{c} must be in the\n\ -range 1 to\n\ -n). In the output permutation @var{p}, all columns in set 1 appear\n\ -first, followed by all columns in set 2, and so on. @code{@var{cmember} =\n\ -ones (1,n)} if not present or empty.\n\ -@code{ccolamd (@var{S}, [], 1 : n)} returns @code{1 : n}\n\ -\n\ -@code{@var{p} = ccolamd (@var{S})} is about the same as\n\ -@code{@var{p} = colamd (@var{S})}. @var{knobs} and its default values\n\ -differ. @code{colamd} always does aggressive absorption, and it finds an\n\ -ordering suitable for both @code{lu (@var{S}(:, @var{p}))} and @code{chol\n\ -(@var{S}(:, @var{p})' * @var{S}(:, @var{p}))}; it cannot optimize its\n\ -ordering for @code{lu (@var{S}(:, @var{p}))} to the extent that\n\ -@code{ccolamd (@var{S}, 1)} can.\n\ -\n\ -@var{stats} is an optional 20-element output vector that provides data\n\ -about the ordering and the validity of the input matrix @var{S}. Ordering\n\ -statistics are in @code{@var{stats}(1 : 3)}. @code{@var{stats}(1)} and\n\ -@code{@var{stats}(2)} are the number of dense or empty rows and columns\n\ -ignored by @sc{ccolamd} and @code{@var{stats}(3)} is the number of garbage\n\ -collections performed on the internal data structure used by @sc{ccolamd}\n\ -(roughly of size @code{2.2 * nnz (@var{S}) + 4 * @var{m} + 7 * @var{n}}\n\ -integers).\n\ -\n\ -@code{@var{stats}(4 : 7)} provide information if CCOLAMD was able to\n\ -continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ -invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ -unsorted or contains duplicate entries, or zero if no such column exists.\n\ -@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ -index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ -such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ -or out-of-order row indices. @code{@var{stats}(8 : 20)} is always zero in\n\ -the current version of @sc{ccolamd} (reserved for future use).\n\ -\n\ -The authors of the code itself are S. Larimore, T. Davis (Univ. of Florida)\n\ -and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\ -by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\ -and a grant from Sandia National Lab. See\n\ -@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\ -colamd, symamd, and other related orderings.\n\ -@seealso{colamd, csymamd}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_CCOLAMD - - int nargin = args.length (); - int spumoni = 0; - - if (nargout > 2 || nargin < 1 || nargin > 3) - usage ("ccolamd: incorrect number of input and/or output arguments"); - else - { - // Get knobs - OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS); - CCOLAMD_NAME (_set_defaults) (knobs); - - // Check for user-passed knobs - if (nargin > 1) - { - NDArray User_knobs = args(1).array_value (); - int nel_User_knobs = User_knobs.length (); - - if (nel_User_knobs > 0) - knobs[CCOLAMD_LU] = (User_knobs(0) != 0); - if (nel_User_knobs > 1) - knobs[CCOLAMD_DENSE_ROW] = User_knobs(1); - if (nel_User_knobs > 2) - knobs[CCOLAMD_DENSE_COL] = User_knobs(2); - if (nel_User_knobs > 3) - knobs[CCOLAMD_AGGRESSIVE] = (User_knobs(3) != 0); - if (nel_User_knobs > 4) - spumoni = (User_knobs(4) != 0); - - // print knob settings if spumoni is set - if (spumoni) - { - octave_stdout << "\nccolamd version " << CCOLAMD_MAIN_VERSION << "." - << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE - << ":\nknobs(1): " << User_knobs(0) << ", order for "; - if (knobs[CCOLAMD_LU] != 0) - octave_stdout << "lu (A)\n"; - else - octave_stdout << "chol (A'*A)\n"; - - if (knobs[CCOLAMD_DENSE_ROW] >= 0) - octave_stdout << "knobs(2): " << User_knobs(1) - << ", rows with > max (16," - << knobs[CCOLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" - << " entries removed\n"; - else - octave_stdout << "knobs(2): " << User_knobs(1) - << ", no dense rows removed\n"; - - if (knobs[CCOLAMD_DENSE_COL] >= 0) - octave_stdout << "knobs(3): " << User_knobs(2) - << ", cols with > max (16," - << knobs[CCOLAMD_DENSE_COL] << "*sqrt (size(A)))" - << " entries removed\n"; - else - octave_stdout << "knobs(3): " << User_knobs(2) - << ", no dense columns removed\n"; - - if (knobs[CCOLAMD_AGGRESSIVE] != 0) - octave_stdout << "knobs(4): " << User_knobs(3) - << ", aggressive absorption: yes"; - else - octave_stdout << "knobs(4): " << User_knobs(3) - << ", aggressive absorption: no"; - - octave_stdout << "knobs(5): " << User_knobs(4) - << ", statistics and knobs printed\n"; - } - } - - octave_idx_type n_row, n_col, nnz; - octave_idx_type *ridx, *cidx; - SparseComplexMatrix scm; - SparseMatrix sm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0). sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - nnz = scm.nnz (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - - n_row = sm.rows (); - n_col = sm.cols (); - nnz = sm.nnz (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - } - else - { - if (args(0).is_complex_type ()) - sm = SparseMatrix (real (args(0).complex_matrix_value ())); - else - sm = SparseMatrix (args(0).matrix_value ()); - - n_row = sm.rows (); - n_col = sm.cols (); - nnz = sm.nnz (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - // Allocate workspace for ccolamd - OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1); - for (octave_idx_type i = 0; i < n_col+1; i++) - p[i] = cidx[i]; - - octave_idx_type Alen = CCOLAMD_NAME (_recommended) (nnz, n_row, n_col); - OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen); - for (octave_idx_type i = 0; i < nnz; i++) - A[i] = ridx[i]; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS); - - if (nargin > 2) - { - NDArray in_cmember = args(2).array_value (); - octave_idx_type cslen = in_cmember.length (); - OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen); - for (octave_idx_type i = 0; i < cslen; i++) - // convert cmember from 1-based to 0-based - cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1); - - if (cslen != n_col) - error ("ccolamd: CMEMBER must be of length equal to #cols of A"); - else - // Order the columns (destroys A) - if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, cmember)) - { - CCOLAMD_NAME (_report) (stats) ; - error ("ccolamd: internal error!"); - return retval; - } - } - else - { - // Order the columns (destroys A) - if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, 0)) - { - CCOLAMD_NAME (_report) (stats) ; - error ("ccolamd: internal error!"); - return retval; - } - } - - // return the permutation vector - NDArray out_perm (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - out_perm(i) = p[i] + 1; - - retval(0) = out_perm; - - // print stats if spumoni > 0 - if (spumoni > 0) - CCOLAMD_NAME (_report) (stats) ; - - // Return the stats vector - if (nargout == 2) - { - NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); - for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) - out_stats(i) = stats[i] ; - retval(1) = out_stats; - - // fix stats (5) and (6), for 1-based information on - // jumbled matrix. note that this correction doesn't - // occur if symamd returns FALSE - out_stats (CCOLAMD_INFO1) ++ ; - out_stats (CCOLAMD_INFO2) ++ ; - } - } - -#else - - error ("ccolamd: not available in this version of Octave"); - -#endif - - return retval; -} - -DEFUN_DLD (csymamd, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} csymamd (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs})\n\ -@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs}, @var{cmember})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} csymamd (@dots{})\n\ -\n\ -For a symmetric positive definite matrix @var{S}, returns the permutation\n\ -vector @var{p} such that @code{@var{S}(@var{p},@var{p})} tends to have a\n\ -sparser Cholesky@tie{}factor than @var{S}. Sometimes @code{csymamd} works\n\ -well for symmetric indefinite matrices too. The matrix @var{S} is assumed\n\ -to be symmetric; only the strictly lower triangular part is referenced.\n\ -@var{S} must be square. The ordering is followed by an elimination tree\n\ -post-ordering.\n\ -\n\ -@var{knobs} is an optional 1-element to 3-element input vector, with a\n\ -default value of @code{[10 1 0]} if present or empty. Entries not\n\ -present are set to their defaults.\n\ -\n\ -@table @code\n\ -@item @var{knobs}(1)\n\ -If @var{S} is n-by-n, then rows and columns with more than\n\ -@code{max(16,@var{knobs}(1)*sqrt(n))} entries are ignored, and ordered\n\ -last in the output permutation (subject to the cmember constraints).\n\ -\n\ -@item @var{knobs}(2)\n\ -If nonzero, aggressive absorption is performed.\n\ -\n\ -@item @var{knobs}(3)\n\ -If nonzero, statistics and knobs are printed.\n\ -\n\ -@end table\n\ -\n\ -@var{cmember} is an optional vector of length n. It defines the constraints\n\ -on the ordering. If @code{@var{cmember}(j) = @var{S}}, then row/column j is\n\ -in constraint set @var{c} (@var{c} must be in the range 1 to n). In the\n\ -output permutation @var{p}, rows/columns in set 1 appear first, followed\n\ -by all rows/columns in set 2, and so on. @code{@var{cmember} = ones (1,n)}\n\ -if not present or empty. @code{csymamd (@var{S},[],1:n)} returns @code{1:n}.\n\ -\n\ -@code{@var{p} = csymamd (@var{S})} is about the same as @code{@var{p} =\n\ -symamd (@var{S})}. @var{knobs} and its default values differ.\n\ -\n\ -@code{@var{stats}(4:7)} provide information if CCOLAMD was able to\n\ -continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ -invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ -unsorted or contains duplicate entries, or zero if no such column exists.\n\ -@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ -index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ -such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ -or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in\n\ -the current version of @sc{ccolamd} (reserved for future use).\n\ -\n\ -The authors of the code itself are S. Larimore, T. Davis (Uni of Florida)\n\ -and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\ -by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\ -and a grant from Sandia National Lab. See\n\ -@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\ -colamd, symamd, and other related orderings.\n\ -@seealso{symamd, ccolamd}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#if HAVE_CCOLAMD - - int nargin = args.length (); - int spumoni = 0; - - if (nargout > 2 || nargin < 1 || nargin > 3) - usage ("ccolamd: incorrect number of input and/or output arguments"); - else - { - // Get knobs - OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS); - CCOLAMD_NAME (_set_defaults) (knobs); - - // Check for user-passed knobs - if (nargin > 1) - { - NDArray User_knobs = args(1).array_value (); - int nel_User_knobs = User_knobs.length (); - - if (nel_User_knobs > 0) - knobs[CCOLAMD_DENSE_ROW] = User_knobs(0); - if (nel_User_knobs > 0) - knobs[CCOLAMD_AGGRESSIVE] = User_knobs(1); - if (nel_User_knobs > 1) - spumoni = static_cast<int> (User_knobs(2)); - - // print knob settings if spumoni is set - if (spumoni) - { - octave_stdout << "\ncsymamd version " << CCOLAMD_MAIN_VERSION << "." - << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE << "\n"; - - if (knobs[CCOLAMD_DENSE_ROW] >= 0) - octave_stdout << "knobs(1): " << User_knobs(0) - << ", rows/cols with > max (16," - << knobs[CCOLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" - << " entries removed\n"; - else - octave_stdout << "knobs(1): " << User_knobs(0) - << ", no dense rows/cols removed\n"; - - if (knobs[CCOLAMD_AGGRESSIVE] != 0) - octave_stdout << "knobs(2): " << User_knobs(1) - << ", aggressive absorption: yes"; - else - octave_stdout << "knobs(2): " << User_knobs(1) - << ", aggressive absorption: no"; - - - octave_stdout << "knobs(3): " << User_knobs(2) - << ", statistics and knobs printed\n"; - } - } - - octave_idx_type n_row, n_col; - octave_idx_type *ridx, *cidx; - SparseMatrix sm; - SparseComplexMatrix scm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0).sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - } - else - { - if (args(0).is_complex_type ()) - sm = SparseMatrix (real (args(0).complex_matrix_value ())); - else - sm = SparseMatrix (args(0).matrix_value ()); - - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - if (n_row != n_col) - { - error ("csymamd: matrix S must be square"); - return retval; - } - - // Allocate workspace for symamd - OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS); - - if (nargin > 2) - { - NDArray in_cmember = args(2).array_value (); - octave_idx_type cslen = in_cmember.length (); - OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen); - for (octave_idx_type i = 0; i < cslen; i++) - // convert cmember from 1-based to 0-based - cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1); - - if (cslen != n_col) - error ("csymamd: CMEMBER must be of length equal to #cols of A"); - else - if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, - &calloc, &free, cmember, -1)) - { - CSYMAMD_NAME (_report) (stats) ; - error ("csymamd: internal error!") ; - return retval; - } - } - else - { - if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, - &calloc, &free, 0, -1)) - { - CSYMAMD_NAME (_report) (stats) ; - error ("csymamd: internal error!") ; - return retval; - } - } - - // return the permutation vector - NDArray out_perm (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - out_perm(i) = perm[i] + 1; - - retval(0) = out_perm; - - // Return the stats vector - if (nargout == 2) - { - NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); - for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) - out_stats(i) = stats[i] ; - retval(1) = out_stats; - - // fix stats (5) and (6), for 1-based information on - // jumbled matrix. note that this correction doesn't - // occur if symamd returns FALSE - out_stats (CCOLAMD_INFO1) ++ ; - out_stats (CCOLAMD_INFO2) ++ ; - } - - // print stats if spumoni > 0 - if (spumoni > 0) - CSYMAMD_NAME (_report) (stats) ; - - // Return the stats vector - if (nargout == 2) - { - NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); - for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) - out_stats(i) = stats[i] ; - retval(1) = out_stats; - - // fix stats (5) and (6), for 1-based information on - // jumbled matrix. note that this correction doesn't - // occur if symamd returns FALSE - out_stats (CCOLAMD_INFO1) ++ ; - out_stats (CCOLAMD_INFO2) ++ ; - } - } - -#else - - error ("csymamd: not available in this version of Octave"); - -#endif - - return retval; -}
--- a/src/DLD-FUNCTIONS/chol.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1385 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton -Copyright (C) 2008-2009 Jaroslav Hajek -Copyright (C) 2008-2009 VZLU Prague - -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> -#endif - -#include "CmplxCHOL.h" -#include "dbleCHOL.h" -#include "fCmplxCHOL.h" -#include "floatCHOL.h" -#include "SparseCmplxCHOL.h" -#include "SparsedbleCHOL.h" -#include "oct-spparms.h" -#include "sparse-util.h" - -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -template <class CHOLT> -static octave_value -get_chol_r (const CHOLT& fact) -{ - return octave_value (fact.chol_matrix (), - MatrixType (MatrixType::Upper)); -} - -template <class CHOLT> -static octave_value -get_chol_l (const CHOLT& fact) -{ - return octave_value (fact.chol_matrix ().transpose (), - MatrixType (MatrixType::Lower)); -} - -DEFUN_DLD (chol, args, nargout, -"-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{R} =} chol (@var{A})\n\ -@deftypefnx {Loadable Function} {[@var{R}, @var{p}] =} chol (@var{A})\n\ -@deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S})\n\ -@deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S}, \"vector\")\n\ -@deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, \"lower\")\n\ -@deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, \"upper\")\n\ -@cindex Cholesky factorization\n\ -Compute the Cholesky@tie{}factor, @var{R}, of the symmetric positive definite\n\ -matrix @var{A}, where\n\ -@tex\n\ -$ R^T R = A $.\n\ -@end tex\n\ -@ifnottex\n\ -\n\ -@example\n\ -@var{R}' * @var{R} = @var{A}.\n\ -@end example\n\ -\n\ -@end ifnottex\n\ -\n\ -Called with one output argument @code{chol} fails if @var{A} or @var{S} is\n\ -not positive definite. With two or more output arguments @var{p} flags\n\ -whether the matrix was positive definite and @code{chol} does not fail. A\n\ -zero value indicated that the matrix was positive definite and the @var{R}\n\ -gives the factorization, and @var{p} will have a positive value otherwise.\n\ -\n\ -If called with 3 outputs then a sparsity preserving row/column permutation\n\ -is applied to @var{A} prior to the factorization. That is @var{R}\n\ -is the factorization of @code{@var{A}(@var{Q},@var{Q})} such that\n\ -@tex\n\ -$ R^T R = Q^T A Q$.\n\ -@end tex\n\ -@ifnottex\n\ -\n\ -@example\n\ -@var{R}' * @var{R} = @var{Q}' * @var{A} * @var{Q}.\n\ -@end example\n\ -\n\ -@end ifnottex\n\ -\n\ -The sparsity preserving permutation is generally returned as a matrix.\n\ -However, given the flag \"vector\", @var{Q} will be returned as a vector\n\ -such that\n\ -@tex\n\ -$ R^T R = A (Q, Q)$.\n\ -@end tex\n\ -@ifnottex\n\ -\n\ -@example\n\ -@var{R}' * @var{R} = @var{A}(@var{Q}, @var{Q}).\n\ -@end example\n\ -\n\ -@end ifnottex\n\ -\n\ -Called with either a sparse or full matrix and using the \"lower\" flag,\n\ -@code{chol} returns the lower triangular factorization such that\n\ -@tex\n\ -$ L L^T = A $.\n\ -@end tex\n\ -@ifnottex\n\ -\n\ -@example\n\ -@var{L} * @var{L}' = @var{A}.\n\ -@end example\n\ -\n\ -@end ifnottex\n\ -\n\ -For full matrices, if the \"lower\" flag is set only the lower triangular\n\ -part of the matrix is used for the factorization, otherwise the upper\n\ -triangular part is used.\n\ -\n\ -In general the lower triangular factorization is significantly faster for\n\ -sparse matrices.\n\ -@seealso{cholinv, chol2inv}\n\ -@end deftypefn") -{ - octave_value_list retval; - int nargin = args.length (); - bool LLt = false; - bool vecout = false; - - if (nargin < 1 || nargin > 3 || nargout > 3 - || (! args(0).is_sparse_type () && nargout > 2)) - { - print_usage (); - return retval; - } - - int n = 1; - while (n < nargin && ! error_state) - { - std::string tmp = args(n++).string_value (); - - if (! error_state ) - { - if (tmp.compare ("vector") == 0) - vecout = true; - else if (tmp.compare ("lower") == 0) - // FIXME currently the option "lower" is handled by transposing the - // matrix, factorizing it with the lapack function DPOTRF ('U', ...) - // and finally transposing the factor. It would be more efficient to use - // DPOTRF ('L', ...) in this case. - LLt = true; - else if (tmp.compare ("upper") == 0) - LLt = false; - else - error ("chol: unexpected second or third input"); - } - else - error ("chol: expecting trailing string arguments"); - } - - if (! error_state) - { - octave_value arg = args(0); - - octave_idx_type nr = arg.rows (); - octave_idx_type nc = arg.columns (); - bool natural = (nargout != 3); - - int arg_is_empty = empty_arg ("chol", nr, nc); - - if (arg_is_empty < 0) - return retval; - if (arg_is_empty > 0) - return octave_value (Matrix ()); - - if (arg.is_sparse_type ()) - { - if (arg.is_real_type ()) - { - SparseMatrix m = arg.sparse_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - SparseCHOL fact (m, info, natural); - if (nargout == 3) - { - if (vecout) - retval(2) = fact.perm (); - else - retval(2) = fact.Q (); - } - - if (nargout > 1 || info == 0) - { - retval(1) = fact.P (); - if (LLt) - retval(0) = fact.L (); - else - retval(0) = fact.R (); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - SparseComplexMatrix m = arg.sparse_complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - SparseComplexCHOL fact (m, info, natural); - - if (nargout == 3) - { - if (vecout) - retval(2) = fact.perm (); - else - retval(2) = fact.Q (); - } - - if (nargout > 1 || info == 0) - { - retval(1) = fact.P (); - if (LLt) - retval(0) = fact.L (); - else - retval(0) = fact.R (); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else - gripe_wrong_type_arg ("chol", arg); - } - else if (arg.is_single_type ()) - { - if (arg.is_real_type ()) - { - FloatMatrix m = arg.float_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - - FloatCHOL fact; - if (LLt) - fact = FloatCHOL (m.transpose (), info); - else - fact = FloatCHOL (m, info); - - if (nargout == 2 || info == 0) - { - retval(1) = info; - if (LLt) - retval(0) = get_chol_l (fact); - else - retval(0) = get_chol_r (fact); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - FloatComplexMatrix m = arg.float_complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - - FloatComplexCHOL fact; - if (LLt) - fact = FloatComplexCHOL (m.transpose (), info); - else - fact = FloatComplexCHOL (m, info); - - if (nargout == 2 || info == 0) - { - retval(1) = info; - if (LLt) - retval(0) = get_chol_l (fact); - else - retval(0) = get_chol_r (fact); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else - gripe_wrong_type_arg ("chol", arg); - } - else - { - if (arg.is_real_type ()) - { - Matrix m = arg.matrix_value (); - - if (! error_state) - { - octave_idx_type info; - - CHOL fact; - if (LLt) - fact = CHOL (m.transpose (), info); - else - fact = CHOL (m, info); - - if (nargout == 2 || info == 0) - { - retval(1) = info; - if (LLt) - retval(0) = get_chol_l (fact); - else - retval(0) = get_chol_r (fact); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - ComplexMatrix m = arg.complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - - ComplexCHOL fact; - if (LLt) - fact = ComplexCHOL (m.transpose (), info); - else - fact = ComplexCHOL (m, info); - - if (nargout == 2 || info == 0) - { - retval(1) = info; - if (LLt) - retval(0) = get_chol_l (fact); - else - retval(0) = get_chol_r (fact); - } - else - error ("chol: input matrix must be positive definite"); - } - } - else - gripe_wrong_type_arg ("chol", arg); - } - } - - return retval; -} - -/* -%!assert (chol ([2, 1; 1, 1]), [sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)], sqrt (eps)) -%!assert (chol (single ([2, 1; 1, 1])), single ([sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)]), sqrt (eps ("single"))) - -%!error chol () -%!error <matrix must be positive definite> chol ([1, 2; 3, 4]) -%!error <requires square matrix> chol ([1, 2; 3, 4; 5, 6]) -%!error <unexpected second or third input> chol (1, 2) -*/ - -DEFUN_DLD (cholinv, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} cholinv (@var{A})\n\ -Use the Cholesky@tie{}factorization to compute the inverse of the\n\ -symmetric positive definite matrix @var{A}.\n\ -@seealso{chol, chol2inv, inv}\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 1) - { - octave_value arg = args(0); - - octave_idx_type nr = arg.rows (); - octave_idx_type nc = arg.columns (); - - if (nr == 0 || nc == 0) - retval = Matrix (); - else - { - if (arg.is_sparse_type ()) - { - if (arg.is_real_type ()) - { - SparseMatrix m = arg.sparse_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - SparseCHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - SparseComplexMatrix m = arg.sparse_complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - SparseComplexCHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else - gripe_wrong_type_arg ("cholinv", arg); - } - else if (arg.is_single_type ()) - { - if (arg.is_real_type ()) - { - FloatMatrix m = arg.float_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - FloatCHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - FloatComplexMatrix m = arg.float_complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - FloatComplexCHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else - gripe_wrong_type_arg ("chol", arg); - } - else - { - if (arg.is_real_type ()) - { - Matrix m = arg.matrix_value (); - - if (! error_state) - { - octave_idx_type info; - CHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else if (arg.is_complex_type ()) - { - ComplexMatrix m = arg.complex_matrix_value (); - - if (! error_state) - { - octave_idx_type info; - ComplexCHOL chol (m, info); - if (info == 0) - retval = chol.inverse (); - else - error ("cholinv: A must be positive definite"); - } - } - else - gripe_wrong_type_arg ("chol", arg); - } - } - } - else - print_usage (); - - return retval; -} - -/* -%!shared A, Ainv -%! A = [2,0.2;0.2,1]; -%! Ainv = inv (A); -%!test -%! Ainv1 = cholinv (A); -%! assert (norm (Ainv-Ainv1), 0, 1e-10); -%!testif HAVE_CHOLMOD -%! Ainv2 = inv (sparse (A)); -%! assert (norm (Ainv-Ainv2), 0, 1e-10); -%!testif HAVE_CHOLMOD -%! Ainv3 = cholinv (sparse (A)); -%! assert (norm (Ainv-Ainv3), 0, 1e-10); -*/ - -DEFUN_DLD (chol2inv, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} chol2inv (@var{U})\n\ -Invert a symmetric, positive definite square matrix from its Cholesky\n\ -decomposition, @var{U}. Note that @var{U} should be an upper-triangular\n\ -matrix with positive diagonal elements. @code{chol2inv (@var{U})}\n\ -provides @code{inv (@var{U}'*@var{U})} but it is much faster than\n\ -using @code{inv}.\n\ -@seealso{chol, cholinv, inv}\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 1) - { - octave_value arg = args(0); - - octave_idx_type nr = arg.rows (); - octave_idx_type nc = arg.columns (); - - if (nr == 0 || nc == 0) - retval = Matrix (); - else - { - if (arg.is_sparse_type ()) - { - if (arg.is_real_type ()) - { - SparseMatrix r = arg.sparse_matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else if (arg.is_complex_type ()) - { - SparseComplexMatrix r = arg.sparse_complex_matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else - gripe_wrong_type_arg ("chol2inv", arg); - } - else if (arg.is_single_type ()) - { - if (arg.is_real_type ()) - { - FloatMatrix r = arg.float_matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else if (arg.is_complex_type ()) - { - FloatComplexMatrix r = arg.float_complex_matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else - gripe_wrong_type_arg ("chol2inv", arg); - - } - else - { - if (arg.is_real_type ()) - { - Matrix r = arg.matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else if (arg.is_complex_type ()) - { - ComplexMatrix r = arg.complex_matrix_value (); - - if (! error_state) - retval = chol2inv (r); - } - else - gripe_wrong_type_arg ("chol2inv", arg); - } - } - } - else - print_usage (); - - return retval; -} - -DEFUN_DLD (cholupdate, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{R1}, @var{info}] =} cholupdate (@var{R}, @var{u}, @var{op})\n\ -Update or downdate a Cholesky@tie{}factorization. Given an upper triangular\n\ -matrix @var{R} and a column vector @var{u}, attempt to determine another\n\ -upper triangular matrix @var{R1} such that\n\ -\n\ -@itemize @bullet\n\ -@item\n\ -@var{R1}'*@var{R1} = @var{R}'*@var{R} + @var{u}*@var{u}'\n\ -if @var{op} is \"+\"\n\ -\n\ -@item\n\ -@var{R1}'*@var{R1} = @var{R}'*@var{R} - @var{u}*@var{u}'\n\ -if @var{op} is \"-\"\n\ -@end itemize\n\ -\n\ -If @var{op} is \"-\", @var{info} is set to\n\ -\n\ -@itemize\n\ -@item 0 if the downdate was successful,\n\ -\n\ -@item 1 if @var{R}'*@var{R} - @var{u}*@var{u}' is not positive definite,\n\ -\n\ -@item 2 if @var{R} is singular.\n\ -@end itemize\n\ -\n\ -If @var{info} is not present, an error message is printed in cases 1 and 2.\n\ -@seealso{chol, qrupdate}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - - octave_value_list retval; - - if (nargin > 3 || nargin < 2) - { - print_usage (); - return retval; - } - - octave_value argr = args(0); - octave_value argu = args(1); - - if (argr.is_numeric_type () && argu.is_numeric_type () - && (nargin < 3 || args(2).is_string ())) - { - octave_idx_type n = argr.rows (); - - std::string op = (nargin < 3) ? "+" : args(2).string_value (); - - bool down = op == "-"; - - if (down || op == "+") - if (argr.columns () == n && argu.rows () == n && argu.columns () == 1) - { - int err = 0; - if (argr.is_single_type () || argu.is_single_type ()) - { - if (argr.is_real_type () && argu.is_real_type ()) - { - // real case - FloatMatrix R = argr.float_matrix_value (); - FloatColumnVector u = argu.float_column_vector_value (); - - FloatCHOL fact; - fact.set (R); - - if (down) - err = fact.downdate (u); - else - fact.update (u); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - FloatComplexMatrix R = argr.float_complex_matrix_value (); - FloatComplexColumnVector u = argu.float_complex_column_vector_value (); - - FloatComplexCHOL fact; - fact.set (R); - - if (down) - err = fact.downdate (u); - else - fact.update (u); - - retval(0) = get_chol_r (fact); - } - } - else - { - if (argr.is_real_type () && argu.is_real_type ()) - { - // real case - Matrix R = argr.matrix_value (); - ColumnVector u = argu.column_vector_value (); - - CHOL fact; - fact.set (R); - - if (down) - err = fact.downdate (u); - else - fact.update (u); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - ComplexMatrix R = argr.complex_matrix_value (); - ComplexColumnVector u = argu.complex_column_vector_value (); - - ComplexCHOL fact; - fact.set (R); - - if (down) - err = fact.downdate (u); - else - fact.update (u); - - retval(0) = get_chol_r (fact); - } - } - - if (nargout > 1) - retval(1) = err; - else if (err == 1) - error ("cholupdate: downdate violates positiveness"); - else if (err == 2) - error ("cholupdate: singular matrix"); - } - else - error ("cholupdate: dimension mismatch between R and U"); - else - error ("cholupdate: OP must be \"+\" or \"-\""); - } - else - print_usage (); - - return retval; -} - -/* -%!shared A, u, Ac, uc -%! A = [ 0.436997 -0.131721 0.124120 -0.061673 ; -%! -0.131721 0.738529 0.019851 -0.140295 ; -%! 0.124120 0.019851 0.354879 -0.059472 ; -%! -0.061673 -0.140295 -0.059472 0.600939 ]; -%! -%! u = [ 0.98950 ; -%! 0.39844 ; -%! 0.63484 ; -%! 0.13351 ]; -%! Ac = [ 0.5585528 + 0.0000000i -0.1662088 - 0.0315341i 0.0107873 + 0.0236411i -0.0276775 - 0.0186073i ; -%! -0.1662088 + 0.0315341i 0.6760061 + 0.0000000i 0.0011452 - 0.0475528i 0.0145967 + 0.0247641i ; -%! 0.0107873 - 0.0236411i 0.0011452 + 0.0475528i 0.6263149 - 0.0000000i -0.1585837 - 0.0719763i ; -%! -0.0276775 + 0.0186073i 0.0145967 - 0.0247641i -0.1585837 + 0.0719763i 0.6034234 - 0.0000000i ]; -%! -%! uc = [ 0.54267 + 0.91519i ; -%! 0.99647 + 0.43141i ; -%! 0.83760 + 0.68977i ; -%! 0.39160 + 0.90378i ]; - -%!test -%! R = chol (A); -%! R1 = cholupdate (R, u); -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - R'*R - u*u', Inf) < 1e1*eps); -%! -%! R1 = cholupdate (R1, u, "-"); -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1 - R, Inf) < 1e1*eps); - -%!test -%! R = chol (Ac); -%! R1 = cholupdate (R, uc); -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - R'*R - uc*uc', Inf) < 1e1*eps); -%! -%! R1 = cholupdate (R1, uc, "-"); -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1 - R, Inf) < 1e1*eps); - -%!test -%! R = chol (single (A)); -%! R1 = cholupdate (R, single (u)); -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1'*R1 - R'*R - single (u*u'), Inf) < 1e1*eps ("single")); -%! -%! R1 = cholupdate (R1, single (u), "-"); -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1 - R, Inf) < 2e1*eps ("single")); - -%!test -%! R = chol (single (Ac)); -%! R1 = cholupdate (R, single (uc)); -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1'*R1 - R'*R - single (uc*uc'), Inf) < 1e1*eps ("single")); -%! -%! R1 = cholupdate (R1, single (uc), "-"); -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1 - R, Inf) < 2e1*eps ("single")); -*/ - -DEFUN_DLD (cholinsert, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{R1} =} cholinsert (@var{R}, @var{j}, @var{u})\n\ -@deftypefnx {Loadable Function} {[@var{R1}, @var{info}] =} cholinsert (@var{R}, @var{j}, @var{u})\n\ -Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ -positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ -triangular, return the Cholesky@tie{}factorization of\n\ -@var{A1}, where @w{A1(p,p) = A}, @w{A1(:,j) = A1(j,:)' = u} and\n\ -@w{p = [1:j-1,j+1:n+1]}. @w{u(j)} should be positive.\n\ -On return, @var{info} is set to\n\ -\n\ -@itemize\n\ -@item 0 if the insertion was successful,\n\ -\n\ -@item 1 if @var{A1} is not positive definite,\n\ -\n\ -@item 2 if @var{R} is singular.\n\ -@end itemize\n\ -\n\ -If @var{info} is not present, an error message is printed in cases 1 and 2.\n\ -@seealso{chol, cholupdate, choldelete}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - - octave_value_list retval; - - if (nargin != 3) - { - print_usage (); - return retval; - } - - octave_value argr = args(0); - octave_value argj = args(1); - octave_value argu = args(2); - - if (argr.is_numeric_type () && argu.is_numeric_type () - && argj.is_real_scalar ()) - { - octave_idx_type n = argr.rows (); - octave_idx_type j = argj.scalar_value (); - - if (argr.columns () == n && argu.rows () == n+1 && argu.columns () == 1) - { - if (j > 0 && j <= n+1) - { - int err = 0; - if (argr.is_single_type () || argu.is_single_type ()) - { - if (argr.is_real_type () && argu.is_real_type ()) - { - // real case - FloatMatrix R = argr.float_matrix_value (); - FloatColumnVector u = argu.float_column_vector_value (); - - FloatCHOL fact; - fact.set (R); - err = fact.insert_sym (u, j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - FloatComplexMatrix R = argr.float_complex_matrix_value (); - FloatComplexColumnVector u = argu.float_complex_column_vector_value (); - - FloatComplexCHOL fact; - fact.set (R); - err = fact.insert_sym (u, j-1); - - retval(0) = get_chol_r (fact); - } - } - else - { - if (argr.is_real_type () && argu.is_real_type ()) - { - // real case - Matrix R = argr.matrix_value (); - ColumnVector u = argu.column_vector_value (); - - CHOL fact; - fact.set (R); - err = fact.insert_sym (u, j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - ComplexMatrix R = argr.complex_matrix_value (); - ComplexColumnVector u = argu.complex_column_vector_value (); - - ComplexCHOL fact; - fact.set (R); - err = fact.insert_sym (u, j-1); - - retval(0) = get_chol_r (fact); - } - } - - if (nargout > 1) - retval(1) = err; - else if (err == 1) - error ("cholinsert: insertion violates positiveness"); - else if (err == 2) - error ("cholinsert: singular matrix"); - else if (err == 3) - error ("cholinsert: diagonal element must be real"); - } - else - error ("cholinsert: index J out of range"); - } - else - error ("cholinsert: dimension mismatch between R and U"); - } - else - print_usage (); - - return retval; -} - -/* -%!test -%! u2 = [ 0.35080 ; -%! 0.63930 ; -%! 3.31057 ; -%! -0.13825 ; -%! 0.45266 ]; -%! -%! R = chol (A); -%! -%! j = 3; p = [1:j-1, j+1:5]; -%! R1 = cholinsert (R, j, u2); -%! A1 = R1'*R1; -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (A1(p,p) - A, Inf) < 1e1*eps); - -%!test -%! u2 = [ 0.35080 + 0.04298i; -%! 0.63930 + 0.23778i; -%! 3.31057 + 0.00000i; -%! -0.13825 + 0.19879i; -%! 0.45266 + 0.50020i]; -%! -%! R = chol (Ac); -%! -%! j = 3; p = [1:j-1, j+1:5]; -%! R1 = cholinsert (R, j, u2); -%! A1 = R1'*R1; -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (A1(p,p) - Ac, Inf) < 1e1*eps); - -%!test -%! u2 = single ([ 0.35080 ; -%! 0.63930 ; -%! 3.31057 ; -%! -0.13825 ; -%! 0.45266 ]); -%! -%! R = chol (single (A)); -%! -%! j = 3; p = [1:j-1, j+1:5]; -%! R1 = cholinsert (R, j, u2); -%! A1 = R1'*R1; -%! -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (A1(p,p) - A, Inf) < 1e1*eps ("single")); - -%!test -%! u2 = single ([ 0.35080 + 0.04298i; -%! 0.63930 + 0.23778i; -%! 3.31057 + 0.00000i; -%! -0.13825 + 0.19879i; -%! 0.45266 + 0.50020i]); -%! -%! R = chol (single (Ac)); -%! -%! j = 3; p = [1:j-1, j+1:5]; -%! R1 = cholinsert (R, j, u2); -%! A1 = R1'*R1; -%! -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (A1(p,p) - single (Ac), Inf) < 2e1*eps ("single")); - -%!test -%! cu = chol (triu (A), "upper"); -%! cl = chol (tril (A), "lower"); -%! assert (cu, cl', eps); - -%!test -%! cca = chol (Ac); -%! -%! ccal = chol (Ac, "lower"); -%! ccal2 = chol (tril (Ac), "lower"); -%! -%! ccau = chol (Ac, "upper"); -%! ccau2 = chol (triu (Ac), "upper"); -%! -%! assert (cca'*cca, Ac, eps); -%! assert (ccau'*ccau, Ac, eps); -%! assert (ccau2'*ccau2, Ac, eps); -%! -%! assert (cca, ccal', eps); -%! assert (cca, ccau, eps); -%! assert (cca, ccal2', eps); -%! assert (cca, ccau2, eps); - -%!test -%! cca = chol (single (Ac)); -%! -%! ccal = chol (single (Ac), "lower"); -%! ccal2 = chol (tril (single (Ac)), "lower"); -%! -%! ccau = chol (single (Ac), "upper"); -%! ccau2 = chol (triu (single (Ac)), "upper"); -%! -%! assert (cca'*cca, single (Ac), eps ("single")); -%! assert (ccau'*ccau, single (Ac), eps ("single")); -%! assert (ccau2'*ccau2, single (Ac), eps ("single")); -%! -%! assert (cca, ccal', eps ("single")); -%! assert (cca, ccau, eps ("single")); -%! assert (cca, ccal2', eps ("single")); -%! assert (cca, ccau2, eps ("single")); - -%!test -%! a = [12, 2, 3, 4; -%! 2, 14, 5, 3; -%! 3, 5, 16, 6; -%! 4, 3, 6, 16]; -%! -%! b = [0, 1, 2, 3; -%! -1, 0, 1, 2; -%! -2, -1, 0, 1; -%! -3, -2, -1, 0]; -%! -%! ca = a + i*b; -%! -%! cca = chol (ca); -%! -%! ccal = chol (ca, "lower"); -%! ccal2 = chol (tril (ca), "lower"); -%! -%! ccau = chol (ca, "upper"); -%! ccau2 = chol (triu (ca), "upper"); -%! -%! assert (cca'*cca, ca, 16*eps); -%! assert (ccau'*ccau, ca, 16*eps); -%! assert (ccau2'*ccau2, ca, 16*eps); -%! -%! assert (cca, ccal', 16*eps); -%! assert (cca, ccau, 16*eps); -%! assert (cca, ccal2', 16*eps); -%! assert (cca, ccau2, 16*eps); -*/ - -DEFUN_DLD (choldelete, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{R1} =} choldelete (@var{R}, @var{j})\n\ -Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ -positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ -triangular, return the Cholesky@tie{}factorization of @w{A(p,p)}, where\n\ -@w{p = [1:j-1,j+1:n+1]}.\n\ -@seealso{chol, cholupdate, cholinsert}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - - octave_value_list retval; - - if (nargin != 2) - { - print_usage (); - return retval; - } - - octave_value argr = args(0); - octave_value argj = args(1); - - if (argr.is_numeric_type () && argj.is_real_scalar ()) - { - octave_idx_type n = argr.rows (); - octave_idx_type j = argj.scalar_value (); - - if (argr.columns () == n) - { - if (j > 0 && j <= n) - { - if (argr.is_single_type ()) - { - if (argr.is_real_type ()) - { - // real case - FloatMatrix R = argr.float_matrix_value (); - - FloatCHOL fact; - fact.set (R); - fact.delete_sym (j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - FloatComplexMatrix R = argr.float_complex_matrix_value (); - - FloatComplexCHOL fact; - fact.set (R); - fact.delete_sym (j-1); - - retval(0) = get_chol_r (fact); - } - } - else - { - if (argr.is_real_type ()) - { - // real case - Matrix R = argr.matrix_value (); - - CHOL fact; - fact.set (R); - fact.delete_sym (j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - ComplexMatrix R = argr.complex_matrix_value (); - - ComplexCHOL fact; - fact.set (R); - fact.delete_sym (j-1); - - retval(0) = get_chol_r (fact); - } - } - } - else - error ("choldelete: index J out of range"); - } - else - error ("choldelete: matrix R must be square"); - } - else - print_usage (); - - return retval; -} - -/* -%!test -%! R = chol (A); -%! -%! j = 3; p = [1:j-1,j+1:4]; -%! R1 = choldelete (R, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); - -%!test -%! R = chol (Ac); -%! -%! j = 3; p = [1:j-1,j+1:4]; -%! R1 = choldelete (R, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); - -%!test -%! R = chol (single (A)); -%! -%! j = 3; p = [1:j-1,j+1:4]; -%! R1 = choldelete (R, j); -%! -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); - -%!test -%! R = chol (single (Ac)); -%! -%! j = 3; p = [1:j-1,j+1:4]; -%! R1 = choldelete (R,j); -%! -%! assert (norm (triu (R1)-R1, Inf), single (0)); -%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); -*/ - -DEFUN_DLD (cholshift, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{R1} =} cholshift (@var{R}, @var{i}, @var{j})\n\ -Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ -positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ -triangular, return the Cholesky@tie{}factorization of\n\ -@w{@var{A}(p,p)}, where @w{p} is the permutation @*\n\ -@code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*\n\ - or @*\n\ -@code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*\n\ -\n\ -@seealso{chol, cholinsert, choldelete}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - - octave_value_list retval; - - if (nargin != 3) - { - print_usage (); - return retval; - } - - octave_value argr = args(0); - octave_value argi = args(1); - octave_value argj = args(2); - - if (argr.is_numeric_type () && argi.is_real_scalar () && argj.is_real_scalar ()) - { - octave_idx_type n = argr.rows (); - octave_idx_type i = argi.scalar_value (); - octave_idx_type j = argj.scalar_value (); - - if (argr.columns () == n) - { - if (j > 0 && j <= n+1 && i > 0 && i <= n+1) - { - - if (argr.is_single_type () && argi.is_single_type () && - argj.is_single_type ()) - { - if (argr.is_real_type ()) - { - // real case - FloatMatrix R = argr.float_matrix_value (); - - FloatCHOL fact; - fact.set (R); - fact.shift_sym (i-1, j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - FloatComplexMatrix R = argr.float_complex_matrix_value (); - - FloatComplexCHOL fact; - fact.set (R); - fact.shift_sym (i-1, j-1); - - retval(0) = get_chol_r (fact); - } - } - else - { - if (argr.is_real_type ()) - { - // real case - Matrix R = argr.matrix_value (); - - CHOL fact; - fact.set (R); - fact.shift_sym (i-1, j-1); - - retval(0) = get_chol_r (fact); - } - else - { - // complex case - ComplexMatrix R = argr.complex_matrix_value (); - - ComplexCHOL fact; - fact.set (R); - fact.shift_sym (i-1, j-1); - - retval(0) = get_chol_r (fact); - } - } - } - else - error ("cholshift: index I or J is out of range"); - } - else - error ("cholshift: R must be a square matrix"); - } - else - print_usage (); - - return retval; -} - -/* -%!test -%! R = chol (A); -%! -%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); -%! -%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1) - R1, Inf), 0); -%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); - -%!test -%! R = chol (Ac); -%! -%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); -%! -%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); - -%!test -%! R = chol (single (A)); -%! -%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); -%! -%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); - -%!test -%! R = chol (single (Ac)); -%! -%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); -%! -%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; -%! R1 = cholshift (R, i, j); -%! -%! assert (norm (triu (R1)-R1, Inf), 0); -%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); -*/
--- a/src/DLD-FUNCTIONS/colamd.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,768 +0,0 @@ -/* - -Copyright (C) 2004-2012 David Bateman -Copyright (C) 1998-2004 Andy Adler - -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/>. - -*/ - -// This is the octave interface to colamd, which bore the copyright given -// in the help of the functions. - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <cstdlib> - -#include <string> -#include <vector> - -#include "ov.h" -#include "defun-dld.h" -#include "pager.h" -#include "ov-re-mat.h" - -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" - -#include "oct-sparse.h" -#include "oct-locbuf.h" - -#ifdef IDX_TYPE_LONG -#define COLAMD_NAME(name) colamd_l ## name -#define SYMAMD_NAME(name) symamd_l ## name -#else -#define COLAMD_NAME(name) colamd ## name -#define SYMAMD_NAME(name) symamd ## name -#endif - -// The symmetric column elimination tree code take from the Davis LDL code. -// Copyright given elsewhere in this file. -static void -symetree (const octave_idx_type *ridx, const octave_idx_type *cidx, - octave_idx_type *Parent, octave_idx_type *P, octave_idx_type n) -{ - OCTAVE_LOCAL_BUFFER (octave_idx_type, Flag, n); - OCTAVE_LOCAL_BUFFER (octave_idx_type, Pinv, (P ? n : 0)); - if (P) - // If P is present then compute Pinv, the inverse of P - for (octave_idx_type k = 0 ; k < n ; k++) - Pinv[P[k]] = k ; - - for (octave_idx_type k = 0 ; k < n ; k++) - { - // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) - Parent[k] = n ; // parent of k is not yet known - Flag[k] = k ; // mark node k as visited - octave_idx_type kk = (P) ? (P[k]) : (k) ; // kth original, or permuted, column - octave_idx_type p2 = cidx[kk+1] ; - for (octave_idx_type p = cidx[kk] ; p < p2 ; p++) - { - // A (i,k) is nonzero (original or permuted A) - octave_idx_type i = (Pinv) ? (Pinv[ridx[p]]) : (ridx[p]) ; - if (i < k) - { - // follow path from i to root of etree, stop at flagged node - for ( ; Flag[i] != k ; i = Parent[i]) - { - // find parent of i if not yet determined - if (Parent[i] == n) - Parent[i] = k ; - Flag[i] = k ; // mark i as visited - } - } - } - } -} - -// The elimination tree post-ordering code below is taken from SuperLU -static inline octave_idx_type -make_set (octave_idx_type i, octave_idx_type *pp) -{ - pp[i] = i; - return i; -} - -static inline octave_idx_type -link (octave_idx_type s, octave_idx_type t, octave_idx_type *pp) -{ - pp[s] = t; - return t; -} - -static inline octave_idx_type -find (octave_idx_type i, octave_idx_type *pp) -{ - register octave_idx_type p, gp; - - p = pp[i]; - gp = pp[p]; - - while (gp != p) - { - pp[i] = gp; - i = gp; - p = pp[i]; - gp = pp[p]; - } - - return p; -} - -static octave_idx_type -etdfs (octave_idx_type v, octave_idx_type *first_kid, - octave_idx_type *next_kid, octave_idx_type *post, - octave_idx_type postnum) -{ - for (octave_idx_type w = first_kid[v]; w != -1; w = next_kid[w]) - postnum = etdfs (w, first_kid, next_kid, post, postnum); - - post[postnum++] = v; - - return postnum; -} - -static void -tree_postorder (octave_idx_type n, octave_idx_type *parent, - octave_idx_type *post) -{ - // Allocate storage for working arrays and results - OCTAVE_LOCAL_BUFFER (octave_idx_type, first_kid, n+1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, next_kid, n+1); - - // Set up structure describing children - for (octave_idx_type v = 0; v <= n; first_kid[v++] = -1) - /* do nothing */; - - for (octave_idx_type v = n-1; v >= 0; v--) - { - octave_idx_type dad = parent[v]; - next_kid[v] = first_kid[dad]; - first_kid[dad] = v; - } - - // Depth-first search from dummy root vertex #n - etdfs (n, first_kid, next_kid, post, 0); -} - -static void -coletree (const octave_idx_type *ridx, const octave_idx_type *colbeg, - octave_idx_type *colend, octave_idx_type *parent, - octave_idx_type nr, octave_idx_type nc) -{ - OCTAVE_LOCAL_BUFFER (octave_idx_type, root, nc); - OCTAVE_LOCAL_BUFFER (octave_idx_type, pp, nc); - OCTAVE_LOCAL_BUFFER (octave_idx_type, firstcol, nr); - - // Compute firstcol[row] = first nonzero column in row - for (octave_idx_type row = 0; row < nr; firstcol[row++] = nc) - /* do nothing */; - - for (octave_idx_type col = 0; col < nc; col++) - for (octave_idx_type p = colbeg[col]; p < colend[col]; p++) - { - octave_idx_type row = ridx[p]; - if (firstcol[row] > col) - firstcol[row] = col; - } - - // Compute etree by Liu's algorithm for symmetric matrices, - // except use (firstcol[r],c) in place of an edge (r,c) of A. - // Thus each row clique in A'*A is replaced by a star - // centered at its first vertex, which has the same fill. - for (octave_idx_type col = 0; col < nc; col++) - { - octave_idx_type cset = make_set (col, pp); - root[cset] = col; - parent[col] = nc; - for (octave_idx_type p = colbeg[col]; p < colend[col]; p++) - { - octave_idx_type row = firstcol[ridx[p]]; - if (row >= col) - continue; - octave_idx_type rset = find (row, pp); - octave_idx_type rroot = root[rset]; - if (rroot != col) - { - parent[rroot] = col; - cset = link (cset, rset, pp); - root[cset] = col; - } - } - } -} - -DEFUN_DLD (colamd, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} colamd (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} colamd (@var{S}, @var{knobs})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{S})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{S}, @var{knobs})\n\ -\n\ -Column approximate minimum degree permutation.\n\ -@code{@var{p} = colamd (@var{S})} returns the column approximate minimum\n\ -degree permutation vector for the sparse matrix @var{S}. For a\n\ -non-symmetric matrix @var{S}, @code{@var{S}(:,@var{p})} tends to have\n\ -sparser LU@tie{}factors than @var{S}. The Cholesky@tie{}factorization of\n\ -@code{@var{S}(:,@var{p})' * @var{S}(:,@var{p})} also tends to be sparser\n\ -than that of @code{@var{S}' * @var{S}}.\n\ -\n\ -@var{knobs} is an optional one- to three-element input vector. If @var{S} is\n\ -m-by-n, then rows with more than @code{max(16,@var{knobs}(1)*sqrt(n))}\n\ -entries are ignored. Columns with more than\n\ -@code{max (16,@var{knobs}(2)*sqrt(min(m,n)))} entries are removed prior to\n\ -ordering, and ordered last in the output permutation @var{p}. Only\n\ -completely dense rows or columns are removed if @code{@var{knobs}(1)} and\n\ -@code{@var{knobs}(2)} are < 0, respectively. If @code{@var{knobs}(3)} is\n\ -nonzero, @var{stats} and @var{knobs} are printed. The default is\n\ -@code{@var{knobs} = [10 10 0]}. Note that @var{knobs} differs from earlier\n\ -versions of colamd.\n\ -\n\ -@var{stats} is an optional 20-element output vector that provides data\n\ -about the ordering and the validity of the input matrix @var{S}. Ordering\n\ -statistics are in @code{@var{stats}(1:3)}. @code{@var{stats}(1)} and\n\ -@code{@var{stats}(2)} are the number of dense or empty rows and columns\n\ -ignored by @sc{colamd} and @code{@var{stats}(3)} is the number of garbage\n\ -collections performed on the internal data structure used by @sc{colamd}\n\ -(roughly of size @code{2.2 * nnz(@var{S}) + 4 * @var{m} + 7 * @var{n}}\n\ -integers).\n\ -\n\ -Octave built-in functions are intended to generate valid sparse matrices,\n\ -with no duplicate entries, with ascending row indices of the nonzeros\n\ -in each column, with a non-negative number of entries in each column (!)\n\ -and so on. If a matrix is invalid, then @sc{colamd} may or may not be able\n\ -to continue. If there are duplicate entries (a row index appears two or\n\ -more times in the same column) or if the row indices in a column are out\n\ -of order, then @sc{colamd} can correct these errors by ignoring the duplicate\n\ -entries and sorting each column of its internal copy of the matrix\n\ -@var{S} (the input matrix @var{S} is not repaired, however). If a matrix\n\ -is invalid in other ways then @sc{colamd} cannot continue, an error message\n\ -is printed, and no output arguments (@var{p} or @var{stats}) are returned.\n\ -@sc{colamd} is thus a simple way to check a sparse matrix to see if it's\n\ -valid.\n\ -\n\ -@code{@var{stats}(4:7)} provide information if COLAMD was able to\n\ -continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ -invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ -unsorted or contains duplicate entries, or zero if no such column exists.\n\ -@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ -index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ -such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ -or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in\n\ -the current version of @sc{colamd} (reserved for future use).\n\ -\n\ -The ordering is followed by a column elimination tree post-ordering.\n\ -\n\ -The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ -Davis @email{davis@@cise.ufl.edu}, University of Florida. The algorithm was\n\ -developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ -Ng, Oak Ridge National Laboratory. (see\n\ -@url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ -@seealso{colperm, symamd, ccolamd}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_COLAMD - - int nargin = args.length (); - int spumoni = 0; - - if (nargout > 2 || nargin < 1 || nargin > 2) - print_usage (); - else - { - // Get knobs - OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); - COLAMD_NAME (_set_defaults) (knobs); - - // Check for user-passed knobs - if (nargin == 2) - { - NDArray User_knobs = args(1).array_value (); - int nel_User_knobs = User_knobs.length (); - - if (nel_User_knobs > 0) - knobs[COLAMD_DENSE_ROW] = User_knobs(0); - if (nel_User_knobs > 1) - knobs[COLAMD_DENSE_COL] = User_knobs(1) ; - if (nel_User_knobs > 2) - spumoni = static_cast<int> (User_knobs(2)); - - // print knob settings if spumoni is set - if (spumoni) - { - - octave_stdout << "\ncolamd version " << COLAMD_MAIN_VERSION << "." - << COLAMD_SUB_VERSION << ", " << COLAMD_DATE << ":\n"; - - if (knobs[COLAMD_DENSE_ROW] >= 0) - octave_stdout << "knobs(1): " << User_knobs (0) - << ", rows with > max (16," - << knobs[COLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" - << " entries removed\n"; - else - octave_stdout << "knobs(1): " << User_knobs (0) - << ", only completely dense rows removed\n"; - - if (knobs[COLAMD_DENSE_COL] >= 0) - octave_stdout << "knobs(2): " << User_knobs (1) - << ", cols with > max (16," - << knobs[COLAMD_DENSE_COL] << "*sqrt (size(A)))" - << " entries removed\n"; - else - octave_stdout << "knobs(2): " << User_knobs (1) - << ", only completely dense columns removed\n"; - - octave_stdout << "knobs(3): " << User_knobs (2) - << ", statistics and knobs printed\n"; - - } - } - - octave_idx_type n_row, n_col, nnz; - octave_idx_type *ridx, *cidx; - SparseComplexMatrix scm; - SparseMatrix sm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0). sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - nnz = scm.nnz (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - - n_row = sm.rows (); - n_col = sm.cols (); - nnz = sm.nnz (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - } - else - { - if (args(0).is_complex_type ()) - sm = SparseMatrix (real (args(0).complex_matrix_value ())); - else - sm = SparseMatrix (args(0).matrix_value ()); - - n_row = sm.rows (); - n_col = sm.cols (); - nnz = sm.nnz (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - // Allocate workspace for colamd - OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1); - for (octave_idx_type i = 0; i < n_col+1; i++) - p[i] = cidx[i]; - - octave_idx_type Alen = COLAMD_NAME (_recommended) (nnz, n_row, n_col); - OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen); - for (octave_idx_type i = 0; i < nnz; i++) - A[i] = ridx[i]; - - // Order the columns (destroys A) - OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, COLAMD_STATS); - if (! COLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats)) - { - COLAMD_NAME (_report) (stats) ; - error ("colamd: internal error!"); - return retval; - } - - // column elimination tree post-ordering (reuse variables) - OCTAVE_LOCAL_BUFFER (octave_idx_type, colbeg, n_col + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, colend, n_col + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); - - for (octave_idx_type i = 0; i < n_col; i++) - { - colbeg[i] = cidx[p[i]]; - colend[i] = cidx[p[i]+1]; - } - - coletree (ridx, colbeg, colend, etree, n_row, n_col); - - // Calculate the tree post-ordering - tree_postorder (n_col, etree, colbeg); - - // return the permutation vector - NDArray out_perm (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - out_perm(i) = p[colbeg[i]] + 1; - - retval(0) = out_perm; - - // print stats if spumoni > 0 - if (spumoni > 0) - COLAMD_NAME (_report) (stats) ; - - // Return the stats vector - if (nargout == 2) - { - NDArray out_stats (dim_vector (1, COLAMD_STATS)); - for (octave_idx_type i = 0 ; i < COLAMD_STATS ; i++) - out_stats(i) = stats[i] ; - retval(1) = out_stats; - - // fix stats (5) and (6), for 1-based information on - // jumbled matrix. note that this correction doesn't - // occur if symamd returns FALSE - out_stats (COLAMD_INFO1) ++ ; - out_stats (COLAMD_INFO2) ++ ; - } - } - -#else - - error ("colamd: not available in this version of Octave"); - -#endif - - return retval; -} - -DEFUN_DLD (symamd, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} symamd (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} symamd (@var{S}, @var{knobs})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{S})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{S}, @var{knobs})\n\ -\n\ -For a symmetric positive definite matrix @var{S}, returns the permutation\n\ -vector p such that @code{@var{S}(@var{p}, @var{p})} tends to have a\n\ -sparser Cholesky@tie{}factor than @var{S}. Sometimes @code{symamd} works\n\ -well for symmetric indefinite matrices too. The matrix @var{S} is assumed\n\ -to be symmetric; only the strictly lower triangular part is referenced.\n\ -@var{S} must be square.\n\ -\n\ -@var{knobs} is an optional one- to two-element input vector. If @var{S} is\n\ -n-by-n, then rows and columns with more than\n\ -@code{max (16,@var{knobs}(1)*sqrt(n))} entries are removed prior to ordering,\n\ -and ordered last in the output permutation @var{p}. No rows/columns are\n\ -removed if @code{@var{knobs}(1) < 0}. If @code{@var{knobs} (2)} is nonzero,\n\ -@code{stats} and @var{knobs} are printed. The default is @code{@var{knobs}\n\ -= [10 0]}. Note that @var{knobs} differs from earlier versions of symamd.\n\ -\n\ -@var{stats} is an optional 20-element output vector that provides data\n\ -about the ordering and the validity of the input matrix @var{S}. Ordering\n\ -statistics are in @code{@var{stats}(1:3)}. @code{@var{stats}(1) =\n\ -@var{stats}(2)} is the number of dense or empty rows and columns\n\ -ignored by SYMAMD and @code{@var{stats}(3)} is the number of garbage\n\ -collections performed on the internal data structure used by SYMAMD\n\ -(roughly of size @code{8.4 * nnz (tril (@var{S}, -1)) + 9 * @var{n}}\n\ -integers).\n\ -\n\ -Octave built-in functions are intended to generate valid sparse matrices,\n\ -with no duplicate entries, with ascending row indices of the nonzeros\n\ -in each column, with a non-negative number of entries in each column (!)\n\ -and so on. If a matrix is invalid, then SYMAMD may or may not be able\n\ -to continue. If there are duplicate entries (a row index appears two or\n\ -more times in the same column) or if the row indices in a column are out\n\ -of order, then SYMAMD can correct these errors by ignoring the duplicate\n\ -entries and sorting each column of its internal copy of the matrix S (the\n\ -input matrix S is not repaired, however). If a matrix is invalid in\n\ -other ways then SYMAMD cannot continue, an error message is printed, and\n\ -no output arguments (@var{p} or @var{stats}) are returned. SYMAMD is\n\ -thus a simple way to check a sparse matrix to see if it's valid.\n\ -\n\ -@code{@var{stats}(4:7)} provide information if SYMAMD was able to\n\ -continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1\n\ -if invalid. @code{@var{stats}(5)} is the rightmost column index that\n\ -is unsorted or contains duplicate entries, or zero if no such column\n\ -exists. @code{@var{stats}(6)} is the last seen duplicate or out-of-order\n\ -row index in the column index given by @code{@var{stats}(5)}, or zero\n\ -if no such row index exists. @code{@var{stats}(7)} is the number of\n\ -duplicate or out-of-order row indices. @code{@var{stats}(8:20)} is\n\ -always zero in the current version of SYMAMD (reserved for future use).\n\ -\n\ -The ordering is followed by a column elimination tree post-ordering.\n\ -\n\ -The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ -Davis @email{davis@@cise.ufl.edu}, University of Florida. The algorithm was\n\ -developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ -Ng, Oak Ridge National Laboratory. (see\n\ -@url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ -@seealso{colperm, colamd}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_COLAMD - - int nargin = args.length (); - int spumoni = 0; - - if (nargout > 2 || nargin < 1 || nargin > 2) - print_usage (); - else - { - // Get knobs - OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); - COLAMD_NAME (_set_defaults) (knobs); - - // Check for user-passed knobs - if (nargin == 2) - { - NDArray User_knobs = args(1).array_value (); - int nel_User_knobs = User_knobs.length (); - - if (nel_User_knobs > 0) - knobs[COLAMD_DENSE_ROW] = User_knobs(COLAMD_DENSE_ROW); - if (nel_User_knobs > 1) - spumoni = static_cast<int> (User_knobs (1)); - } - - // print knob settings if spumoni is set - if (spumoni > 0) - octave_stdout << "symamd: dense row/col fraction: " - << knobs[COLAMD_DENSE_ROW] << std::endl; - - octave_idx_type n_row, n_col; - octave_idx_type *ridx, *cidx; - SparseMatrix sm; - SparseComplexMatrix scm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0).sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - } - else - { - if (args(0).is_complex_type ()) - sm = SparseMatrix (real (args(0).complex_matrix_value ())); - else - sm = SparseMatrix (args(0).matrix_value ()); - - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - if (n_row != n_col) - { - error ("symamd: matrix S must be square"); - return retval; - } - - // Allocate workspace for symamd - OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, COLAMD_STATS); - if (!SYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, &calloc, &free)) - { - SYMAMD_NAME (_report) (stats) ; - error ("symamd: internal error!") ; - return retval; - } - - // column elimination tree post-ordering - OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); - symetree (ridx, cidx, etree, perm, n_col); - - // Calculate the tree post-ordering - OCTAVE_LOCAL_BUFFER (octave_idx_type, post, n_col + 1); - tree_postorder (n_col, etree, post); - - // return the permutation vector - NDArray out_perm (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - out_perm(i) = perm[post[i]] + 1; - - retval(0) = out_perm; - - // print stats if spumoni > 0 - if (spumoni > 0) - SYMAMD_NAME (_report) (stats) ; - - // Return the stats vector - if (nargout == 2) - { - NDArray out_stats (dim_vector (1, COLAMD_STATS)); - for (octave_idx_type i = 0 ; i < COLAMD_STATS ; i++) - out_stats(i) = stats[i] ; - retval(1) = out_stats; - - // fix stats (5) and (6), for 1-based information on - // jumbled matrix. note that this correction doesn't - // occur if symamd returns FALSE - out_stats (COLAMD_INFO1) ++ ; - out_stats (COLAMD_INFO2) ++ ; - } - } - -#else - - error ("symamd: not available in this version of Octave"); - -#endif - - return retval; -} - -DEFUN_DLD (etree, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} etree (@var{S})\n\ -@deftypefnx {Loadable Function} {@var{p} =} etree (@var{S}, @var{typ})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{q}] =} etree (@var{S}, @var{typ})\n\ -\n\ -Return the elimination tree for the matrix @var{S}. By default @var{S}\n\ -is assumed to be symmetric and the symmetric elimination tree is\n\ -returned. The argument @var{typ} controls whether a symmetric or\n\ -column elimination tree is returned. Valid values of @var{typ} are\n\ -\"sym\" or \"col\", for symmetric or column elimination tree respectively\n\ -\n\ -Called with a second argument, @code{etree} also returns the postorder\n\ -permutations on the tree.\n\ -@end deftypefn") -{ - octave_value_list retval; - - int nargin = args.length (); - - if (nargout > 2 || nargin < 1 || nargin > 2) - print_usage (); - else - { - octave_idx_type n_row, n_col; - octave_idx_type *ridx, *cidx; - bool is_sym = true; - SparseMatrix sm; - SparseComplexMatrix scm; - - if (args(0).is_sparse_type ()) - { - if (args(0).is_complex_type ()) - { - scm = args(0).sparse_complex_matrix_value (); - n_row = scm.rows (); - n_col = scm.cols (); - ridx = scm.xridx (); - cidx = scm.xcidx (); - } - else - { - sm = args(0).sparse_matrix_value (); - n_row = sm.rows (); - n_col = sm.cols (); - ridx = sm.xridx (); - cidx = sm.xcidx (); - } - - } - else - { - error ("etree: S must be a sparse matrix"); - return retval; - } - - if (nargin == 2) - { - if (args(1).is_string ()) - { - std::string str = args(1).string_value (); - if (str.find ("C") == 0 || str.find ("c") == 0) - is_sym = false; - } - else - { - error ("etree: TYP must be a string"); - return retval; - } - } - - // column elimination tree post-ordering (reuse variables) - OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); - - if (is_sym) - { - if (n_row != n_col) - { - error ("etree: S is marked as symmetric, but is not square"); - return retval; - } - - symetree (ridx, cidx, etree, 0, n_col); - } - else - { - OCTAVE_LOCAL_BUFFER (octave_idx_type, colbeg, n_col); - OCTAVE_LOCAL_BUFFER (octave_idx_type, colend, n_col); - - for (octave_idx_type i = 0; i < n_col; i++) - { - colbeg[i] = cidx[i]; - colend[i] = cidx[i+1]; - } - - coletree (ridx, colbeg, colend, etree, n_row, n_col); - } - - NDArray tree (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - // We flag a root with n_col while Matlab does it with zero - // Convert for matlab compatiable output - if (etree[i] == n_col) - tree(i) = 0; - else - tree(i) = etree[i] + 1; - - retval(0) = tree; - - if (nargout == 2) - { - // Calculate the tree post-ordering - OCTAVE_LOCAL_BUFFER (octave_idx_type, post, n_col + 1); - tree_postorder (n_col, etree, post); - - NDArray postorder (dim_vector (1, n_col)); - for (octave_idx_type i = 0; i < n_col; i++) - postorder(i) = post[i] + 1; - - retval(1) = postorder; - } - } - - return retval; -}
--- a/src/DLD-FUNCTIONS/config-module.awk Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -BEGIN { - FS = "|"; - nfiles = 0; - - print "## DO NOT EDIT -- generated from module-files by config-module.awk"; - print "" - print "EXTRA_DIST += \\" - print " DLD-FUNCTIONS/config-module.sh \\" - print " DLD-FUNCTIONS/config-module.awk \\" - print " DLD-FUNCTIONS/module-files \\" - print " DLD-FUNCTIONS/oct-qhull.h" - print "" -} -/^#.*/ { next; } -{ - nfiles++; - files[nfiles] = $1; - cppflags[nfiles] = $2; - ldflags[nfiles] = $3; - libraries[nfiles] = $4; -} END { - sep = " \\\n"; - print "DLD_FUNCTIONS_SRC = \\"; - for (i = 1; i <= nfiles; i++) { - if (i == nfiles) - sep = "\n"; - printf (" DLD-FUNCTIONS/%s%s", files[i], sep); - } - print ""; - - sep = " \\\n"; - print "DLD_FUNCTIONS_LIBS = $(DLD_FUNCTIONS_SRC:.cc=.la)"; - print ""; - print "if AMCOND_ENABLE_DYNAMIC_LINKING"; - print ""; - print "octlib_LTLIBRARIES += $(DLD_FUNCTIONS_LIBS)"; - print ""; - print "## Use stamp files to avoid problems with checking timestamps"; - print "## of symbolic links"; - print ""; - for (i = 1; i <= nfiles; i++) { - basename = files[i]; - sub (/\.cc$/, "", basename); - printf ("DLD-FUNCTIONS/$(am__leading_dot)%s.oct-stamp: DLD-FUNCTIONS/%s.la\n", basename, basename); - print "\trm -f $(<:.la=.oct)"; - print "\tla=$(<F) && \\"; - print "\t of=$(<F:.la=.oct) && \\"; - print "\t cd DLD-FUNCTIONS && \\"; - print "\t $(LN_S) .libs/`$(SED) -n -e \"s/dlname='\\([^']*\\)'/\\1/p\" < $$la` $$of && \\"; - print "\t touch $(@F)"; - print ""; - } - print "else"; - print ""; - print "noinst_LTLIBRARIES += $(DLD_FUNCTIONS_LIBS)"; - print ""; - print "endif"; - - for (i = 1; i <= nfiles; i++) { - basename = files[i]; - sub (/\.cc$/, "", basename); - print ""; - printf ("DLD_FUNCTIONS_%s_la_SOURCES = DLD-FUNCTIONS/%s\n", - basename, files[i]); - if (cppflags[i]) - { - printf ("DLD-FUNCTIONS/%s.df: CPPFLAGS += %s\n", - basename, cppflags[i]); - printf ("DLD_FUNCTIONS_%s_la_CPPFLAGS = $(AM_CPPFLAGS) %s\n", - basename, cppflags[i]); - } - printf ("DLD_FUNCTIONS_%s_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED_LDFLAG) %s $(OCT_LINK_OPTS)\n", - basename, ldflags[i]); - printf ("DLD_FUNCTIONS_%s_la_LIBADD = $(DLD_LIBOCTINTERP_LIBADD) ../liboctave/liboctave.la ../libcruft/libcruft.la %s $(OCT_LINK_DEPS)\n", - basename, libraries[i]); - } -}
--- a/src/DLD-FUNCTIONS/config-module.sh Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -#! /bin/sh - -set -e - -: ${AWK=awk} - -if [ $# -eq 1 ]; then - top_srcdir="$1"; -else - top_srcdir="../.." -fi - -move_if_change="$top_srcdir/build-aux/move-if-change" - -dld_dir=$top_srcdir/src/DLD-FUNCTIONS - -$AWK -f $dld_dir/config-module.awk < $dld_dir/module-files > $dld_dir/module.mk-t - -$move_if_change $dld_dir/module.mk-t $dld_dir/module.mk
--- a/src/DLD-FUNCTIONS/convhulln.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,316 +0,0 @@ -/* - -Copyright (C) 2000-2012 Kai Habel - -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/>. - -*/ - -/* -29. July 2000 - Kai Habel: first release -2002-04-22 Paul Kienzle -* Use warning(...) function rather than writing to cerr -2006-05-01 Tom Holroyd -* add support for consistent winding in all dimensions; output is -* guaranteed to be simplicial. -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sstream> - -#include "Cell.h" -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" -#include "parse.h" -#include "unwind-prot.h" - -#if defined (HAVE_QHULL) -# include "oct-qhull.h" -# if defined (NEED_QHULL_VERSION) -char qh_version[] = "convhulln.oct 2007-07-24"; -# endif -#endif - -static void -close_fcn (FILE *f) -{ - gnulib::fclose (f); -} - -DEFUN_DLD (convhulln, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{h} =} convhulln (@var{pts})\n\ -@deftypefnx {Loadable Function} {@var{h} =} convhulln (@var{pts}, @var{options})\n\ -@deftypefnx {Loadable Function} {[@var{h}, @var{v}] =} convhulln (@dots{})\n\ -Compute the convex hull of the set of points @var{pts} which is a matrix\n\ -of size [n, dim] containing n points in a space of dimension dim.\n\ -The hull @var{h} is an index vector into the set of points and specifies\n\ -which points form the enclosing hull.\n\ -\n\ -An optional second argument, which must be a string or cell array of strings,\n\ -contains options passed to the underlying qhull command.\n\ -See the documentation for the Qhull library for details\n\ -@url{http://www.qhull.org/html/qh-quick.htm#options}.\n\ -The default options depend on the dimension of the input:\n\ -\n\ -@itemize\n\ -@item 2D, 3D, 4D: @var{options} = @code{@{\"Qt\"@}}\n\ -\n\ -@item 5D and higher: @var{options} = @code{@{\"Qt\", \"Qx\"@}}\n\ -@end itemize\n\ -\n\ -If @var{options} is not present or @code{[]} then the default arguments are\n\ -used. Otherwise, @var{options} replaces the default argument list.\n\ -To append user options to the defaults it is necessary to repeat the\n\ -default arguments in @var{options}. Use a null string to pass no arguments.\n\ -\n\ -If the second output @var{v} is requested the volume of the enclosing\n\ -convex hull is calculated.\n\n\ -@seealso{convhull, delaunayn, voronoin}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#if defined (HAVE_QHULL) - - int nargin = args.length (); - if (nargin < 1 || nargin > 2) - { - print_usage (); - return retval; - } - - Matrix points (args(0).matrix_value ()); - const octave_idx_type dim = points.columns (); - const octave_idx_type num_points = points.rows (); - - points = points.transpose (); - - std::string options; - - if (dim <= 4) - options = " Qt"; - else - options = " Qt Qx"; - - if (nargin == 2) - { - if (args(1).is_string ()) - options = " " + args(1).string_value (); - else if (args(1).is_empty ()) - ; // Use default options. - else if (args(1).is_cellstr ()) - { - options = ""; - - Array<std::string> tmp = args(1).cellstr_value (); - - for (octave_idx_type i = 0; i < tmp.numel (); i++) - options += " " + tmp(i); - } - else - { - error ("convhulln: OPTIONS must be a string, cell array of strings, or empty"); - return retval; - } - } - - boolT ismalloc = false; - - unwind_protect frame; - - // Replace the outfile pointer with stdout for debugging information. -#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) - FILE *outfile = gnulib::fopen ("NUL", "w"); -#else - FILE *outfile = gnulib::fopen ("/dev/null", "w"); -#endif - FILE *errfile = stderr; - - if (outfile) - frame.add_fcn (close_fcn, outfile); - else - { - error ("convhulln: unable to create temporary file for output"); - return retval; - } - - // qh_new_qhull command and points arguments are not const... - - std::string cmd = "qhull" + options; - - OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); - - strcpy (cmd_str, cmd.c_str ()); - - int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), - ismalloc, cmd_str, outfile, errfile); - if (! exitcode) - { - bool nonsimp_seen = false; - - octave_idx_type nf = qh num_facets; - - Matrix idx (nf, dim + 1); - - facetT *facet; - - octave_idx_type i = 0; - - FORALLfacets - { - octave_idx_type j = 0; - - if (! nonsimp_seen && ! facet->simplicial) - { - nonsimp_seen = true; - - if (cmd.find ("QJ") != std::string::npos) - { - // Should never happen with QJ. - error ("convhulln: qhull failed: option 'QJ' returned non-simplicial facet"); - return retval; - } - } - - if (dim == 3) - { - setT *vertices = qh_facet3vertex (facet); - - vertexT *vertex, **vertexp; - - FOREACHvertex_ (vertices) - idx(i, j++) = 1 + qh_pointid(vertex->point); - - qh_settempfree (&vertices); - } - else - { - if (facet->toporient ^ qh_ORIENTclock) - { - vertexT *vertex, **vertexp; - - FOREACHvertex_ (facet->vertices) - idx(i, j++) = 1 + qh_pointid(vertex->point); - } - else - { - vertexT *vertex, **vertexp; - - FOREACHvertexreverse12_ (facet->vertices) - idx(i, j++) = 1 + qh_pointid(vertex->point); - } - } - if (j < dim) - warning ("convhulln: facet %d only has %d vertices", i, j); - - i++; - } - - // Remove extra dimension if all facets were simplicial. - - if (! nonsimp_seen) - idx.resize (nf, dim, 0.0); - - if (nargout == 2) - { - // Calculate volume of convex hull, taken from qhull src/geom2.c. - - realT area; - realT dist; - - FORALLfacets - { - if (! facet->normal) - continue; - - if (facet->upperdelaunay && qh ATinfinity) - continue; - - facet->f.area = area = qh_facetarea (facet); - facet->isarea = True; - - if (qh DELAUNAY) - { - if (facet->upperdelaunay == qh UPPERdelaunay) - qh totarea += area; - } - else - { - qh totarea += area; - qh_distplane (qh interior_point, facet, &dist); - qh totvol += -dist * area/ qh hull_dim; - } - } - - retval(1) = octave_value (qh totvol); - } - - retval(0) = idx; - } - else - error ("convhulln: qhull failed"); - - // Free memory from Qhull - qh_freeqhull (! qh_ALL); - - int curlong, totlong; - qh_memfreeshort (&curlong, &totlong); - - if (curlong || totlong) - warning ("convhulln: did not free %d bytes of long memory (%d pieces)", - totlong, curlong); - -#else - error ("convhulln: not available in this version of Octave"); -#endif - - return retval; -} - -/* -%!testif HAVE_QHULL -%! cube = [0 0 0;1 0 0;1 1 0;0 1 0;0 0 1;1 0 1;1 1 1;0 1 1]; -%! [h, v] = convhulln (cube, "Qt"); -%! assert (size (h), [12 3]); -%! h = sortrows (sort (h, 2), [1:3]); -%! assert (h, [1 2 4; 1 2 6; 1 4 8; 1 5 6; 1 5 8; 2 3 4; 2 3 7; 2 6 7; 3 4 7; 4 7 8; 5 6 7; 5 7 8]); -%! assert (v, 1, 10*eps); -%! [h2, v2] = convhulln (cube); % Test defaut option = "Qt" -%! assert (size (h2), size (h)); -%! h2 = sortrows (sort (h2, 2), [1:3]); -%! assert (h2, h); -%! assert (v2, v, 10*eps); - -%!testif HAVE_QHULL -%! cube = [0 0 0;1 0 0;1 1 0;0 1 0;0 0 1;1 0 1;1 1 1;0 1 1]; -%! [h, v] = convhulln (cube, "QJ"); -%! assert (size (h), [12 3]); -%! assert (sortrows (sort (h, 2), [1:3]), [1 2 4; 1 2 5; 1 4 5; 2 3 4; 2 3 6; 2 5 6; 3 4 8; 3 6 7; 3 7 8; 4 5 8; 5 6 8; 6 7 8]); -%! assert (v, 1.0, 1e6*eps); - -%!testif HAVE_QHULL -%! tetrahedron = [1 1 1;-1 -1 1;-1 1 -1;1 -1 -1]; -%! [h, v] = convhulln (tetrahedron); -%! h = sortrows (sort (h, 2), [1 2 3]); -%! assert (h, [1 2 3;1 2 4; 1 3 4; 2 3 4]); -%! assert (v, 8/3, 10*eps); -*/
--- a/src/DLD-FUNCTIONS/dmperm.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,229 +0,0 @@ -/* - -Copyright (C) 2005-2012 David Bateman -Copyright (C) 1998-2005 Andy Adler - -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> -#endif - -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -#include "oct-sparse.h" -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "SparseQR.h" -#include "SparseCmplxQR.h" - -#ifdef IDX_TYPE_LONG -#define CXSPARSE_NAME(name) cs_dl ## name -#else -#define CXSPARSE_NAME(name) cs_di ## name -#endif - -static RowVector -put_int (octave_idx_type *p, octave_idx_type n) -{ - RowVector ret (n); - for (octave_idx_type i = 0; i < n; i++) - ret.xelem (i) = p[i] + 1; - return ret; -} - -#if HAVE_CXSPARSE -static octave_value_list -dmperm_internal (bool rank, const octave_value arg, int nargout) -{ - octave_value_list retval; - octave_idx_type nr = arg.rows (); - octave_idx_type nc = arg.columns (); - SparseMatrix m; - SparseComplexMatrix cm; - CXSPARSE_NAME () csm; - csm.m = nr; - csm.n = nc; - csm.x = 0; - csm.nz = -1; - - if (arg.is_real_type ()) - { - m = arg.sparse_matrix_value (); - csm.nzmax = m.nnz (); - csm.p = m.xcidx (); - csm.i = m.xridx (); - } - else - { - cm = arg.sparse_complex_matrix_value (); - csm.nzmax = cm.nnz (); - csm.p = cm.xcidx (); - csm.i = cm.xridx (); - } - - if (!error_state) - { - if (nargout <= 1 || rank) - { -#if defined(CS_VER) && (CS_VER >= 2) - octave_idx_type *jmatch = CXSPARSE_NAME (_maxtrans) (&csm, 0); -#else - octave_idx_type *jmatch = CXSPARSE_NAME (_maxtrans) (&csm); -#endif - if (rank) - { - octave_idx_type r = 0; - for (octave_idx_type i = 0; i < nc; i++) - if (jmatch[nr+i] >= 0) - r++; - retval(0) = static_cast<double>(r); - } - else - retval(0) = put_int (jmatch + nr, nc); - CXSPARSE_NAME (_free) (jmatch); - } - else - { -#if defined(CS_VER) && (CS_VER >= 2) - CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm, 0); -#else - CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm); -#endif - - //retval(5) = put_int (dm->rr, 5); - //retval(4) = put_int (dm->cc, 5); -#if defined(CS_VER) && (CS_VER >= 2) - retval(3) = put_int (dm->s, dm->nb+1); - retval(2) = put_int (dm->r, dm->nb+1); - retval(1) = put_int (dm->q, nc); - retval(0) = put_int (dm->p, nr); -#else - retval(3) = put_int (dm->S, dm->nb+1); - retval(2) = put_int (dm->R, dm->nb+1); - retval(1) = put_int (dm->Q, nc); - retval(0) = put_int (dm->P, nr); -#endif - CXSPARSE_NAME (_dfree) (dm); - } - } - return retval; -} -#endif - -DEFUN_DLD (dmperm, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} dmperm (@var{S})\n\ -@deftypefnx {Loadable Function} {[@var{p}, @var{q}, @var{r}, @var{S}] =} dmperm (@var{S})\n\ -\n\ -@cindex Dulmage-Mendelsohn decomposition\n\ -Perform a Dulmage-Mendelsohn permutation of the sparse matrix @var{S}.\n\ -With a single output argument @code{dmperm} performs the row permutations\n\ -@var{p} such that @code{@var{S}(@var{p},:)} has no zero elements on the\n\ -diagonal.\n\ -\n\ -Called with two or more output arguments, returns the row and column\n\ -permutations, such that @code{@var{S}(@var{p}, @var{q})} is in block\n\ -triangular form. The values of @var{r} and @var{S} define the boundaries\n\ -of the blocks. If @var{S} is square then @code{@var{r} == @var{S}}.\n\ -\n\ -The method used is described in: A. Pothen & C.-J. Fan. @cite{Computing the\n\ -Block Triangular Form of a Sparse Matrix}. ACM Trans. Math. Software,\n\ -16(4):303-324, 1990.\n\ -@seealso{colamd, ccolamd}\n\ -@end deftypefn") -{ - int nargin = args.length (); - octave_value_list retval; - - if (nargin != 1) - { - print_usage (); - return retval; - } - -#if HAVE_CXSPARSE - retval = dmperm_internal (false, args(0), nargout); -#else - error ("dmperm: not available in this version of Octave"); -#endif - - return retval; -} - -/* -%!testif HAVE_CXSPARSE -%! n = 20; -%! a = speye (n,n); -%! a = a(randperm (n),:); -%! assert (a(dmperm (a),:), speye (n)); - -%!testif HAVE_CXSPARSE -%! n = 20; -%! d = 0.2; -%! a = tril (sprandn (n,n,d), -1) + speye (n,n); -%! a = a(randperm (n), randperm (n)); -%! [p,q,r,s] = dmperm (a); -%! assert (tril (a(p,q), -1), sparse (n, n)); -*/ - -DEFUN_DLD (sprank, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} sprank (@var{S})\n\ -@cindex structural rank\n\ -\n\ -Calculate the structural rank of the sparse matrix @var{S}. Note that\n\ -only the structure of the matrix is used in this calculation based on\n\ -a Dulmage-Mendelsohn permutation to block triangular form. As such the\n\ -numerical rank of the matrix @var{S} is bounded by\n\ -@code{sprank (@var{S}) >= rank (@var{S})}. Ignoring floating point errors\n\ -@code{sprank (@var{S}) == rank (@var{S})}.\n\ -@seealso{dmperm}\n\ -@end deftypefn") -{ - int nargin = args.length (); - octave_value_list retval; - - if (nargin != 1) - { - print_usage (); - return retval; - } - -#if HAVE_CXSPARSE - retval = dmperm_internal (true, args(0), nargout); -#else - error ("sprank: not available in this version of Octave"); -#endif - - return retval; -} - -/* -%!testif HAVE_CXSPARSE -%! assert (sprank (speye (20)), 20) -%!testif HAVE_CXSPARSE -%! assert (sprank ([1,0,2,0;2,0,4,0]), 2) - -%!error sprank (1,2) -*/
--- a/src/DLD-FUNCTIONS/eigs.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1521 +0,0 @@ -/* - -Copyright (C) 2005-2012 David Bateman - -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> -#endif - -#include "ov.h" -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "quit.h" -#include "variables.h" -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "oct-map.h" -#include "pager.h" -#include "unwind-prot.h" - -#include "eigs-base.cc" - -// Global pointer for user defined function. -static octave_function *eigs_fcn = 0; - -// Have we warned about imaginary values returned from user function? -static bool warned_imaginary = false; - -// Is this a recursive call? -static int call_depth = 0; - -ColumnVector -eigs_func (const ColumnVector &x, int &eigs_error) -{ - ColumnVector retval; - octave_value_list args; - args(0) = x; - - if (eigs_fcn) - { - octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args); - - if (error_state) - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - return retval; - } - - if (tmp.length () && tmp(0).is_defined ()) - { - if (! warned_imaginary && tmp(0).is_complex_type ()) - { - warning ("eigs: ignoring imaginary part returned from user-supplied function"); - warned_imaginary = true; - } - - retval = ColumnVector (tmp(0).vector_value ()); - - if (error_state) - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - } - } - else - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - } - } - - return retval; -} - -ComplexColumnVector -eigs_complex_func (const ComplexColumnVector &x, int &eigs_error) -{ - ComplexColumnVector retval; - octave_value_list args; - args(0) = x; - - if (eigs_fcn) - { - octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args); - - if (error_state) - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - return retval; - } - - if (tmp.length () && tmp(0).is_defined ()) - { - retval = ComplexColumnVector (tmp(0).complex_vector_value ()); - - if (error_state) - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - } - } - else - { - eigs_error = 1; - gripe_user_supplied_eval ("eigs"); - } - } - - return retval; -} - -DEFUN_DLD (eigs, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{d} =} eigs (@var{A})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k}, @var{sigma})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k}, @var{sigma}, @var{opts})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma}, @var{opts})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma}, @var{opts})\n\ -@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma}, @var{opts})\n\ -@deftypefnx {Loadable Function} {[@var{V}, @var{d}] =} eigs (@var{A}, @dots{})\n\ -@deftypefnx {Loadable Function} {[@var{V}, @var{d}] =} eigs (@var{af}, @var{n}, @dots{})\n\ -@deftypefnx {Loadable Function} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{A}, @dots{})\n\ -@deftypefnx {Loadable Function} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{af}, @var{n}, @dots{})\n\ -Calculate a limited number of eigenvalues and eigenvectors of @var{A},\n\ -based on a selection criteria. The number of eigenvalues and eigenvectors to\n\ -calculate is given by @var{k} and defaults to 6.\n\ -\n\ -By default, @code{eigs} solve the equation\n\ -@tex\n\ -$A \\nu = \\lambda \\nu$,\n\ -@end tex\n\ -@ifinfo\n\ -@code{A * v = lambda * v},\n\ -@end ifinfo\n\ -where\n\ -@tex\n\ -$\\lambda$ is a scalar representing one of the eigenvalues, and $\\nu$\n\ -@end tex\n\ -@ifinfo\n\ -@code{lambda} is a scalar representing one of the eigenvalues, and @code{v}\n\ -@end ifinfo\n\ -is the corresponding eigenvector. If given the positive definite matrix\n\ -@var{B} then @code{eigs} solves the general eigenvalue equation\n\ -@tex\n\ -$A \\nu = \\lambda B \\nu$.\n\ -@end tex\n\ -@ifinfo\n\ -@code{A * v = lambda * B * v}.\n\ -@end ifinfo\n\ -\n\ -The argument @var{sigma} determines which eigenvalues are returned.\n\ -@var{sigma} can be either a scalar or a string. When @var{sigma} is a\n\ -scalar, the @var{k} eigenvalues closest to @var{sigma} are returned. If\n\ -@var{sigma} is a string, it must have one of the following values.\n\ -\n\ -@table @asis\n\ -@item \"lm\"\n\ -Largest Magnitude (default).\n\ -\n\ -@item \"sm\"\n\ -Smallest Magnitude.\n\ -\n\ -@item \"la\"\n\ -Largest Algebraic (valid only for real symmetric problems).\n\ -\n\ -@item \"sa\"\n\ -Smallest Algebraic (valid only for real symmetric problems).\n\ -\n\ -@item \"be\"\n\ -Both Ends, with one more from the high-end if @var{k} is odd (valid only for\n\ -real symmetric problems).\n\ -\n\ -@item \"lr\"\n\ -Largest Real part (valid only for complex or unsymmetric problems).\n\ -\n\ -@item \"sr\"\n\ -Smallest Real part (valid only for complex or unsymmetric problems).\n\ -\n\ -@item \"li\"\n\ -Largest Imaginary part (valid only for complex or unsymmetric problems).\n\ -\n\ -@item \"si\"\n\ -Smallest Imaginary part (valid only for complex or unsymmetric problems).\n\ -@end table\n\ -\n\ -If @var{opts} is given, it is a structure defining possible options that\n\ -@code{eigs} should use. The fields of the @var{opts} structure are:\n\ -\n\ -@table @code\n\ -@item issym\n\ -If @var{af} is given, then flags whether the function @var{af} defines a\n\ -symmetric problem. It is ignored if @var{A} is given. The default is false.\n\ -\n\ -@item isreal\n\ -If @var{af} is given, then flags whether the function @var{af} defines a\n\ -real problem. It is ignored if @var{A} is given. The default is true.\n\ -\n\ -@item tol\n\ -Defines the required convergence tolerance, calculated as\n\ -@code{tol * norm (A)}. The default is @code{eps}.\n\ -\n\ -@item maxit\n\ -The maximum number of iterations. The default is 300.\n\ -\n\ -@item p\n\ -The number of Lanzcos basis vectors to use. More vectors will result in\n\ -faster convergence, but a greater use of memory. The optimal value of\n\ -@code{p} is problem dependent and should be in the range @var{k} to @var{n}.\n\ -The default value is @code{2 * @var{k}}.\n\ -\n\ -@item v0\n\ -The starting vector for the algorithm. An initial vector close to the\n\ -final vector will speed up convergence. The default is for @sc{arpack}\n\ -to randomly generate a starting vector. If specified, @code{v0} must be\n\ -an @var{n}-by-1 vector where @code{@var{n} = rows (@var{A})}\n\ -\n\ -@item disp\n\ -The level of diagnostic printout (0|1|2). If @code{disp} is 0 then\n\ -diagnostics are disabled. The default value is 0.\n\ -\n\ -@item cholB\n\ -Flag if @code{chol (@var{B})} is passed rather than @var{B}. The default is\n\ -false.\n\ -\n\ -@item permB\n\ -The permutation vector of the Cholesky@tie{}factorization of @var{B} if\n\ -@code{cholB} is true. That is @code{chol (@var{B}(permB, permB))}. The\n\ -default is @code{1:@var{n}}.\n\ -\n\ -@end table\n\ -\n\ -It is also possible to represent @var{A} by a function denoted @var{af}.\n\ -@var{af} must be followed by a scalar argument @var{n} defining the length\n\ -of the vector argument accepted by @var{af}. @var{af} can be\n\ -a function handle, an inline function, or a string. When @var{af} is a\n\ -string it holds the name of the function to use.\n\ -\n\ -@var{af} is a function of the form @code{y = af (x)}\n\ -where the required return value of @var{af} is determined by\n\ -the value of @var{sigma}. The four possible forms are\n\ -\n\ -@table @code\n\ -@item A * x\n\ -if @var{sigma} is not given or is a string other than \"sm\".\n\ -\n\ -@item A \\ x\n\ -if @var{sigma} is 0 or \"sm\".\n\ -\n\ -@item (A - sigma * I) \\ x\n\ -for the standard eigenvalue problem, where @code{I} is the identity matrix of\n\ -the same size as @var{A}.\n\ -\n\ -@item (A - sigma * B) \\ x\n\ -for the general eigenvalue problem.\n\ -@end table\n\ -\n\ -The return arguments of @code{eigs} depend on the number of return arguments\n\ -requested. With a single return argument, a vector @var{d} of length @var{k}\n\ -is returned containing the @var{k} eigenvalues that have been found. With\n\ -two return arguments, @var{V} is a @var{n}-by-@var{k} matrix whose columns\n\ -are the @var{k} eigenvectors corresponding to the returned eigenvalues. The\n\ -eigenvalues themselves are returned in @var{d} in the form of a\n\ -@var{n}-by-@var{k} matrix, where the elements on the diagonal are the\n\ -eigenvalues.\n\ -\n\ -Given a third return argument @var{flag}, @code{eigs} returns the status\n\ -of the convergence. If @var{flag} is 0 then all eigenvalues have converged.\n\ -Any other value indicates a failure to converge.\n\ -\n\ -This function is based on the @sc{arpack} package, written by R. Lehoucq,\n\ -K. Maschhoff, D. Sorensen, and C. Yang. For more information see\n\ -@url{http://www.caam.rice.edu/software/ARPACK/}.\n\ -\n\ -@seealso{eig, svds}\n\ -@end deftypefn") -{ - octave_value_list retval; -#ifdef HAVE_ARPACK - int nargin = args.length (); - std::string fcn_name; - octave_idx_type n = 0; - octave_idx_type k = 6; - Complex sigma = 0.; - double sigmar, sigmai; - bool have_sigma = false; - std::string typ = "LM"; - Matrix amm, bmm, bmt; - ComplexMatrix acm, bcm, bct; - SparseMatrix asmm, bsmm, bsmt; - SparseComplexMatrix ascm, bscm, bsct; - int b_arg = 0; - bool have_b = false; - bool have_a_fun = false; - bool a_is_complex = false; - bool b_is_complex = false; - bool symmetric = false; - bool sym_tested = false; - bool cholB = false; - bool a_is_sparse = false; - ColumnVector permB; - int arg_offset = 0; - double tol = DBL_EPSILON; - int maxit = 300; - int disp = 0; - octave_idx_type p = -1; - ColumnVector resid; - ComplexColumnVector cresid; - octave_idx_type info = 1; - - warned_imaginary = false; - - unwind_protect frame; - - frame.protect_var (call_depth); - call_depth++; - - if (call_depth > 1) - { - error ("eigs: invalid recursive call"); - if (fcn_name.length ()) - clear_function (fcn_name); - return retval; - } - - if (nargin == 0) - print_usage (); - else if (args(0).is_function_handle () || args(0).is_inline_function () - || args(0).is_string ()) - { - if (args(0).is_string ()) - { - std::string name = args(0).string_value (); - std::string fname = "function y = "; - fcn_name = unique_symbol_name ("__eigs_fcn_"); - fname.append (fcn_name); - fname.append ("(x) y = "); - eigs_fcn = extract_function (args(0), "eigs", fcn_name, fname, - "; endfunction"); - } - else - eigs_fcn = args(0).function_value (); - - if (!eigs_fcn) - { - error ("eigs: unknown function"); - return retval; - } - - if (nargin < 2) - { - error ("eigs: incorrect number of arguments"); - return retval; - } - else - { - n = args(1).nint_value (); - arg_offset = 1; - have_a_fun = true; - } - } - else - { - if (args(0).is_complex_type ()) - { - if (args(0).is_sparse_type ()) - { - ascm = (args(0).sparse_complex_matrix_value ()); - a_is_sparse = true; - } - else - acm = (args(0).complex_matrix_value ()); - a_is_complex = true; - symmetric = false; // ARPACK doesn't special case complex symmetric - sym_tested = true; - } - else - { - if (args(0).is_sparse_type ()) - { - asmm = (args(0).sparse_matrix_value ()); - a_is_sparse = true; - } - else - { - amm = (args(0).matrix_value ()); - } - } - - } - - // Note hold off reading B till later to avoid issues of double - // copies of the matrix if B is full/real while A is complex. - if (!error_state && nargin > 1 + arg_offset && - !(args(1 + arg_offset).is_real_scalar ())) - { - if (args(1+arg_offset).is_complex_type ()) - { - b_arg = 1+arg_offset; - have_b = true; - b_is_complex = true; - arg_offset++; - } - else - { - b_arg = 1+arg_offset; - have_b = true; - arg_offset++; - } - } - - if (!error_state && nargin > (1+arg_offset)) - k = args(1+arg_offset).nint_value (); - - if (!error_state && nargin > (2+arg_offset)) - { - if (args(2+arg_offset).is_string ()) - { - typ = args(2+arg_offset).string_value (); - - // Use STL function to convert to upper case - transform (typ.begin (), typ.end (), typ.begin (), toupper); - - sigma = 0.; - } - else - { - sigma = args(2+arg_offset).complex_value (); - - if (! error_state) - have_sigma = true; - else - { - error ("eigs: SIGMA must be a scalar or a string"); - return retval; - } - } - } - - sigmar = std::real (sigma); - sigmai = std::imag (sigma); - - if (!error_state && nargin > (3+arg_offset)) - { - if (args(3+arg_offset).is_map ()) - { - octave_scalar_map map = args(3+arg_offset).scalar_map_value (); - - if (! error_state) - { - octave_value tmp; - - // issym is ignored for complex matrix inputs - tmp = map.getfield ("issym"); - if (tmp.is_defined () && !sym_tested) - { - symmetric = tmp.double_value () != 0.; - sym_tested = true; - } - - // isreal is ignored if A is not a function - tmp = map.getfield ("isreal"); - if (tmp.is_defined () && have_a_fun) - a_is_complex = ! (tmp.double_value () != 0.); - - tmp = map.getfield ("tol"); - if (tmp.is_defined ()) - tol = tmp.double_value (); - - tmp = map.getfield ("maxit"); - if (tmp.is_defined ()) - maxit = tmp.nint_value (); - - tmp = map.getfield ("p"); - if (tmp.is_defined ()) - p = tmp.nint_value (); - - tmp = map.getfield ("v0"); - if (tmp.is_defined ()) - { - if (a_is_complex || b_is_complex) - cresid = ComplexColumnVector (tmp.complex_vector_value ()); - else - resid = ColumnVector (tmp.vector_value ()); - } - - tmp = map.getfield ("disp"); - if (tmp.is_defined ()) - disp = tmp.nint_value (); - - tmp = map.getfield ("cholB"); - if (tmp.is_defined ()) - cholB = tmp.double_value () != 0.; - - tmp = map.getfield ("permB"); - if (tmp.is_defined ()) - permB = ColumnVector (tmp.vector_value ()) - 1.0; - } - else - { - error ("eigs: OPTS argument must be a scalar structure"); - return retval; - } - } - else - { - error ("eigs: OPTS argument must be a structure"); - return retval; - } - } - - if (nargin > (4+arg_offset)) - { - error ("eigs: incorrect number of arguments"); - return retval; - } - - // Test undeclared (no issym) matrix inputs for symmetry - if (!sym_tested && !have_a_fun) - { - if (a_is_sparse) - symmetric = asmm.is_symmetric (); - else - symmetric = amm.is_symmetric (); - } - - if (have_b) - { - if (a_is_complex || b_is_complex) - { - if (a_is_sparse) - bscm = args(b_arg).sparse_complex_matrix_value (); - else - bcm = args(b_arg).complex_matrix_value (); - } - else - { - if (a_is_sparse) - bsmm = args(b_arg).sparse_matrix_value (); - else - bmm = args(b_arg).matrix_value (); - } - } - - // Mode 1 for SM mode seems unstable for some reason. - // Use Mode 3 instead, with sigma = 0. - if (!error_state && !have_sigma && typ == "SM") - have_sigma = true; - - if (!error_state) - { - octave_idx_type nconv; - if (a_is_complex || b_is_complex) - { - ComplexMatrix eig_vec; - ComplexColumnVector eig_val; - - - if (have_a_fun) - nconv = EigsComplexNonSymmetricFunc - (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec, eig_val, - cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - else if (have_sigma) - { - if (a_is_sparse) - nconv = EigsComplexNonSymmetricMatrixShift - (ascm, sigma, k, p, info, eig_vec, eig_val, bscm, permB, - cresid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else - nconv = EigsComplexNonSymmetricMatrixShift - (acm, sigma, k, p, info, eig_vec, eig_val, bcm, permB, cresid, - octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - } - else - { - if (a_is_sparse) - nconv = EigsComplexNonSymmetricMatrix - (ascm, typ, k, p, info, eig_vec, eig_val, bscm, permB, cresid, - octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - else - nconv = EigsComplexNonSymmetricMatrix - (acm, typ, k, p, info, eig_vec, eig_val, bcm, permB, cresid, - octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - } - - if (nargout < 2) - retval(0) = eig_val; - else - { - retval(2) = double (info); - retval(1) = ComplexDiagMatrix (eig_val); - retval(0) = eig_vec; - } - } - else if (sigmai != 0.) - { - // Promote real problem to a complex one. - ComplexMatrix eig_vec; - ComplexColumnVector eig_val; - - if (have_a_fun) - nconv = EigsComplexNonSymmetricFunc - (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec, eig_val, - cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - else - { - if (a_is_sparse) - nconv = EigsComplexNonSymmetricMatrixShift - (SparseComplexMatrix (asmm), sigma, k, p, info, eig_vec, - eig_val, SparseComplexMatrix (bsmm), permB, cresid, - octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - else - nconv = EigsComplexNonSymmetricMatrixShift - (ComplexMatrix (amm), sigma, k, p, info, eig_vec, - eig_val, ComplexMatrix (bmm), permB, cresid, - octave_stdout, tol, (nargout > 1), cholB, disp, maxit); - } - - if (nargout < 2) - retval(0) = eig_val; - else - { - retval(2) = double (info); - retval(1) = ComplexDiagMatrix (eig_val); - retval(0) = eig_vec; - } - } - else - { - if (symmetric) - { - Matrix eig_vec; - ColumnVector eig_val; - - if (have_a_fun) - nconv = EigsRealSymmetricFunc - (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else if (have_sigma) - { - if (a_is_sparse) - nconv = EigsRealSymmetricMatrixShift - (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else - nconv = EigsRealSymmetricMatrixShift - (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - } - else - { - if (a_is_sparse) - nconv = EigsRealSymmetricMatrix - (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else - nconv = EigsRealSymmetricMatrix - (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - } - - if (nargout < 2) - retval(0) = eig_val; - else - { - retval(2) = double (info); - retval(1) = DiagMatrix (eig_val); - retval(0) = eig_vec; - } - } - else - { - ComplexMatrix eig_vec; - ComplexColumnVector eig_val; - - if (have_a_fun) - nconv = EigsRealNonSymmetricFunc - (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else if (have_sigma) - { - if (a_is_sparse) - nconv = EigsRealNonSymmetricMatrixShift - (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else - nconv = EigsRealNonSymmetricMatrixShift - (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - } - else - { - if (a_is_sparse) - nconv = EigsRealNonSymmetricMatrix - (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - else - nconv = EigsRealNonSymmetricMatrix - (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB, - resid, octave_stdout, tol, (nargout > 1), cholB, disp, - maxit); - } - - if (nargout < 2) - retval(0) = eig_val; - else - { - retval(2) = double (info); - retval(1) = ComplexDiagMatrix (eig_val); - retval(0) = eig_vec; - } - } - } - - if (nconv <= 0) - warning ("eigs: None of the %d requested eigenvalues converged", k); - else if (nconv < k) - warning ("eigs: Only %d of the %d requested eigenvalues converged", - nconv, k); - } - - if (! fcn_name.empty ()) - clear_function (fcn_name); -#else - error ("eigs: not available in this version of Octave"); -#endif - - return retval; -} - -/* #### SPARSE MATRIX VERSIONS #### */ - -/* -## Real positive definite tests, n must be even -%!shared n, k, A, d0, d2 -%! n = 20; -%! k = 4; -%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)]); -%! d0 = eig (A); -%! d2 = sort (d0); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); # initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (d1, d0(end:-1:(end-k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, "sm"); -%! assert (d1, d0(k:-1:1), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "la"); -%! assert (d1, d2(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sa"); -%! assert (d1, d2(1:k), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "be"); -%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1, "be"); -%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (d1(idx1), d0(idx0(1:k)), 1e-11); -%!testif HAVE_ARPACK, HAVE_CHOLMOD -%! d1 = eigs (A, speye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (eigs (A, k, 4.1), eigs (A, speye (n), k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (eigs (A, k, 4.1), eigs (A, speye (n), k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (d1, d0(k:-1:1), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (d1, eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! AA = speye (10); -%! fn = @(x) AA * x; -%! opts.issym = 1; opts.isreal = 1; -%! assert (eigs (fn, 10, AA, 3, "lm", opts), [1; 1; 1], 10*eps); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "la"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sa"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "be"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/ - -/* -## Real unsymmetric tests -%!shared n, k, A, d0 -%! n = 20; -%! k = 4; -%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)]); -%! d0 = eig (A); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); % initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, "sm"); -%! assert (abs (d1), abs (d0(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lr"); -%! [~, idx] = sort (real (d0)); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "li"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "si"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); -%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); -%!testif HAVE_ARPACK, HAVE_CHOLMOD -%! d1 = eigs (A, speye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, speye (n), k, 4.1)), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, speye (n), k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (abs (d1), d0(1:k), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "li"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "si"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/ - -/* -## Complex hermitian tests -%!shared n, k, A, d0 -%! n = 20; -%! k = 4; -%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)]); -%! d0 = eig (A); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); % initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, "sm"); -%! assert (abs (d1), abs (d0(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "li"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "si"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); -%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); -%!testif HAVE_ARPACK, HAVE_CHOLMOD -%! d1 = eigs (A, speye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! d1 = eigs (A, speye (n), k, 4.1, opts); -%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); -%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); -%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); -%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, speye (n), k, 4.1)), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, speye (n), k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (abs (d1), d0(1:k), 1e-11); -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK, HAVE_UMFPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "li"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "si"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/ - -/* #### FULL MATRIX VERSIONS #### */ - -/* -## Real positive definite tests, n must be even -%!shared n, k, A, d0, d2 -%! n = 20; -%! k = 4; -%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)])); -%! d0 = eig (A); -%! d2 = sort (d0); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); % initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (d1, d0(end:-1:(end-k)),1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sm"); -%! assert (d1, d0(k:-1:1), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "la"); -%! assert (d1, d2(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sa"); -%! assert (d1, d2(1:k), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "be"); -%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1, "be"); -%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (d1(idx1), d0(idx0(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, eye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! assert (eigs (A, k, 4.1), eigs (A, eye (n), k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! assert (eigs (A, k, 4.1), eigs (A, eye (n), k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (d1, d0(k:-1:1), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 1; opts.isreal = 1; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (d1, eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "la"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sa"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "be"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/ - -/* -## Real unsymmetric tests -%!shared n, k, A, d0 -%! n = 20; -%! k = 4; -%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)])); -%! d0 = eig (A); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); % initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sm"); -%! assert (abs (d1), abs (d0(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lr"); -%! [~, idx] = sort (real (d0)); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "li"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "si"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); -%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, eye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, eye (n), k, 4.1)), 1e-11); -%!testif HAVE_ARPACK -%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, eye (n), k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (abs (d1), d0(1:k), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 0; opts.isreal = 1; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "li"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "si"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/ - -/* -## Complex hermitian tests -%!shared n, k, A, d0 -%! n = 20; -%! k = 4; -%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)])); -%! d0 = eig (A); -%! [~, idx] = sort (abs (d0)); -%! d0 = d0(idx); -%! rand ("state", 42); % initialize generator to make eigs behavior reproducible -%!testif HAVE_ARPACK -%! d1 = eigs (A, k); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k+1); -%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sm"); -%! assert (abs (d1), abs (d0(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "lr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "sr"); -%! [~, idx] = sort (real (abs (d0))); -%! d2 = d0(idx); -%! assert (real (d1), real (d2(1:k)), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "li"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, "si"); -%! [~, idx] = sort (imag (abs (d0))); -%! d2 = d0(idx); -%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, k, 4.1); -%! [~, idx0] = sort (abs (d0 - 4.1)); -%! [~, idx1] = sort (abs (d1 - 4.1)); -%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); -%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); -%!testif HAVE_ARPACK -%! d1 = eigs (A, eye (n), k, "lm"); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! d1 = eigs (A, eye (n), k, 4.1, opts); -%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); -%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! opts.cholB = true; -%! q = [2:n,1]; -%! opts.permB = q; -%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); -%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); -%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, eye (n), k, 4.1)), 1e-11); -%!testif HAVE_ARPACK -%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, eye (n), k, 4.1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A * x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, "lm", opts); -%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) A \ x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, "sm", opts); -%! assert (abs (d1), d0(1:k), 1e-11); -%!testif HAVE_ARPACK -%! fn = @(x) (A - 4.1 * eye (n)) \ x; -%! opts.issym = 0; opts.isreal = 0; -%! d1 = eigs (fn, n, k, 4.1, opts); -%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sm"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "lr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "sr"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "li"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -%!testif HAVE_ARPACK -%! [v1,d1] = eigs (A, k, "si"); -%! d1 = diag (d1); -%! for i=1:k -%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); -%! endfor -*/
--- a/src/DLD-FUNCTIONS/fftw.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/* - -Copyright (C) 2006-2012 David Bateman - -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> -#endif - -#include <algorithm> - -#include "oct-fftw.h" - -#include "defun-dld.h" -#include "error.h" -#include "ov.h" - -DEFUN_DLD (fftw, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{method} =} fftw (\"planner\")\n\ -@deftypefnx {Loadable Function} {} fftw (\"planner\", @var{method})\n\ -@deftypefnx {Loadable Function} {@var{wisdom} =} fftw (\"dwisdom\")\n\ -@deftypefnx {Loadable Function} {} fftw (\"dwisdom\", @var{wisdom})\n\ -\n\ -Manage @sc{fftw} wisdom data. Wisdom data can be used to significantly\n\ -accelerate the calculation of the FFTs, but implies an initial cost\n\ -in its calculation. When the @sc{fftw} libraries are initialized, they read\n\ -a system wide wisdom file (typically in @file{/etc/fftw/wisdom}), allowing\n\ -wisdom to be shared between applications other than Octave. Alternatively,\n\ -the @code{fftw} function can be used to import wisdom. For example,\n\ -\n\ -@example\n\ -@var{wisdom} = fftw (\"dwisdom\")\n\ -@end example\n\ -\n\ -@noindent\n\ -will save the existing wisdom used by Octave to the string @var{wisdom}.\n\ -This string can then be saved to a file and restored using the @code{save}\n\ -and @code{load} commands respectively. This existing wisdom can be\n\ -reimported as follows\n\ -\n\ -@example\n\ -fftw (\"dwisdom\", @var{wisdom})\n\ -@end example\n\ -\n\ -If @var{wisdom} is an empty matrix, then the wisdom used is cleared.\n\ -\n\ -During the calculation of Fourier transforms further wisdom is generated.\n\ -The fashion in which this wisdom is generated is also controlled by\n\ -the @code{fftw} function. There are five different manners in which the\n\ -wisdom can be treated:\n\ -\n\ -@table @asis\n\ -@item \"estimate\"\n\ -Specifies that no run-time measurement of the optimal means of\n\ -calculating a particular is performed, and a simple heuristic is used\n\ -to pick a (probably sub-optimal) plan. The advantage of this method is\n\ -that there is little or no overhead in the generation of the plan, which\n\ -is appropriate for a Fourier transform that will be calculated once.\n\ -\n\ -@item \"measure\"\n\ -In this case a range of algorithms to perform the transform is considered\n\ -and the best is selected based on their execution time.\n\ -\n\ -@item \"patient\"\n\ -Similar to \"measure\", but a wider range of algorithms is considered.\n\ -\n\ -@item \"exhaustive\"\n\ -Like \"measure\", but all possible algorithms that may be used to\n\ -treat the transform are considered.\n\ -\n\ -@item \"hybrid\"\n\ -As run-time measurement of the algorithm can be expensive, this is a\n\ -compromise where \"measure\" is used for transforms up to the size of 8192\n\ -and beyond that the \"estimate\" method is used.\n\ -@end table\n\ -\n\ -The default method is \"estimate\". The current method can\n\ -be queried with\n\ -\n\ -@example\n\ -@var{method} = fftw (\"planner\")\n\ -@end example\n\ -\n\ -@noindent\n\ -or set by using\n\ -\n\ -@example\n\ -fftw (\"planner\", @var{method})\n\ -@end example\n\ -\n\ -Note that calculated wisdom will be lost when restarting Octave. However,\n\ -the wisdom data can be reloaded if it is saved to a file as described\n\ -above. Saved wisdom files should not be used on different platforms since\n\ -they will not be efficient and the point of calculating the wisdom is lost.\n\ -@seealso{fft, ifft, fft2, ifft2, fftn, ifftn}\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin < 1 || nargin > 2) - { - print_usage (); - return retval; - } - -#if defined (HAVE_FFTW) - if (args(0).is_string ()) - { - std::string arg0 = args(0).string_value (); - - if (!error_state) - { - // Use STL function to convert to lower case - std::transform (arg0.begin (), arg0.end (), arg0.begin (), tolower); - - if (nargin == 2) - { - std::string arg1 = args(1).string_value (); - if (!error_state) - { - if (arg0 == "planner") - { - std::transform (arg1.begin (), arg1.end (), - arg1.begin (), tolower); - octave_fftw_planner::FftwMethod meth - = octave_fftw_planner::UNKNOWN; - octave_float_fftw_planner::FftwMethod methf - = octave_float_fftw_planner::UNKNOWN; - - if (arg1 == "estimate") - { - meth = octave_fftw_planner::ESTIMATE; - methf = octave_float_fftw_planner::ESTIMATE; - } - else if (arg1 == "measure") - { - meth = octave_fftw_planner::MEASURE; - methf = octave_float_fftw_planner::MEASURE; - } - else if (arg1 == "patient") - { - meth = octave_fftw_planner::PATIENT; - methf = octave_float_fftw_planner::PATIENT; - } - else if (arg1 == "exhaustive") - { - meth = octave_fftw_planner::EXHAUSTIVE; - methf = octave_float_fftw_planner::EXHAUSTIVE; - } - else if (arg1 == "hybrid") - { - meth = octave_fftw_planner::HYBRID; - methf = octave_float_fftw_planner::HYBRID; - } - else - error ("unrecognized planner METHOD"); - - if (!error_state) - { - meth = octave_fftw_planner::method (meth); - octave_float_fftw_planner::method (methf); - - if (meth == octave_fftw_planner::MEASURE) - retval = octave_value ("measure"); - else if (meth == octave_fftw_planner::PATIENT) - retval = octave_value ("patient"); - else if (meth == octave_fftw_planner::EXHAUSTIVE) - retval = octave_value ("exhaustive"); - else if (meth == octave_fftw_planner::HYBRID) - retval = octave_value ("hybrid"); - else - retval = octave_value ("estimate"); - } - } - else if (arg0 == "dwisdom") - { - char *str = fftw_export_wisdom_to_string (); - - if (arg1.length () < 1) - fftw_forget_wisdom (); - else if (! fftw_import_wisdom_from_string (arg1.c_str ())) - error ("could not import supplied WISDOM"); - - if (!error_state) - retval = octave_value (std::string (str)); - - free (str); - } - else if (arg0 == "swisdom") - { - char *str = fftwf_export_wisdom_to_string (); - - if (arg1.length () < 1) - fftwf_forget_wisdom (); - else if (! fftwf_import_wisdom_from_string (arg1.c_str ())) - error ("could not import supplied WISDOM"); - - if (!error_state) - retval = octave_value (std::string (str)); - - free (str); - } - else - error ("unrecognized argument"); - } - } - else - { - if (arg0 == "planner") - { - octave_fftw_planner::FftwMethod meth = - octave_fftw_planner::method (); - - if (meth == octave_fftw_planner::MEASURE) - retval = octave_value ("measure"); - else if (meth == octave_fftw_planner::PATIENT) - retval = octave_value ("patient"); - else if (meth == octave_fftw_planner::EXHAUSTIVE) - retval = octave_value ("exhaustive"); - else if (meth == octave_fftw_planner::HYBRID) - retval = octave_value ("hybrid"); - else - retval = octave_value ("estimate"); - } - else if (arg0 == "dwisdom") - { - char *str = fftw_export_wisdom_to_string (); - retval = octave_value (std::string (str)); - free (str); - } - else if (arg0 == "swisdom") - { - char *str = fftwf_export_wisdom_to_string (); - retval = octave_value (std::string (str)); - free (str); - } - else - error ("unrecognized argument"); - } - } - } -#else - - warning ("fftw: this copy of Octave was not configured to use the FFTW3 planner"); - -#endif - - return retval; -}
--- a/src/DLD-FUNCTIONS/module-files Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# FILE|CPPFLAGS|LDFLAGS|LIBRARIES -__delaunayn__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) -__dsearchn__.cc -__fltk_uigetfile__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) -__glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS) -__init_fltk__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) -__init_gnuplot__.cc -__magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) -__voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) -amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -ccolamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -chol.cc -colamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -convhulln.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) -dmperm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -eigs.cc|$(ARPACK_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(ARPACK_LDFLAGS) $(SPARSE_XLDFLAGS)|$(ARPACK_LIBS) $(SPARSE_XLIBS) $(LAPACK_LIBS) $(BLAS_LIBS) -fftw.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) -qr.cc|$(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(QRUPDATE_LDFLAGS) $(SPARSE_XLDFLAGS)|$(QRUPDATE_LIBS) $(SPARSE_XLIBS) -symbfact.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -symrcm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) -tsearch.cc -urlwrite.cc|$(CURL_CPPFLAGS)|$(CURL_LDFLAGS)|$(CURL_LIBS)
--- a/src/DLD-FUNCTIONS/oct-qhull.h Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - -Copyright (C) 2012 John W. Eaton - -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/>. - -*/ - -#if !defined (octave_oct_qhull_h) -#define octave_oct_qhull_h 1 - -#include <cstdio> - -extern "C" { - -#if defined (HAVE_LIBQHULL_LIBQHULL_H) -# include <libqhull/libqhull.h> -# include <libqhull/qset.h> -# include <libqhull/geom.h> -# include <libqhull/poly.h> -# include <libqhull/io.h> -#elif defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H) -# if defined (HAVE_QHULL_LIBQHULL_H) -# include <qhull/libqhull.h> -# else -# include <qhull/qhull.h> -# endif -# include <qhull/qset.h> -# include <qhull/geom.h> -# include <qhull/poly.h> -# include <qhull/io.h> -#elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H) -# if defined (HAVE_LIBQHULL_H) -# include <libqhull.h> -# else -# include <qhull.h> -# endif -# include <qset.h> -# include <geom.h> -# include <poly.h> -# include <io.h> -#endif - -} - -#endif
--- a/src/DLD-FUNCTIONS/qr.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1598 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton -Copyright (C) 2008-2009 Jaroslav Hajek -Copyright (C) 2008-2009 VZLU Prague - -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> -#endif - -#include "CmplxQR.h" -#include "CmplxQRP.h" -#include "dbleQR.h" -#include "dbleQRP.h" -#include "fCmplxQR.h" -#include "fCmplxQRP.h" -#include "floatQR.h" -#include "floatQRP.h" -#include "SparseQR.h" -#include "SparseCmplxQR.h" - - -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -template <class MT> -static octave_value -get_qr_r (const base_qr<MT>& fact) -{ - MT R = fact.R (); - if (R.is_square () && fact.regular ()) - return octave_value (R, MatrixType (MatrixType::Upper)); - else - return R; -} - -// [Q, R] = qr (X): form Q unitary and R upper triangular such -// that Q * R = X -// -// [Q, R] = qr (X, 0): form the economy decomposition such that if X is -// m by n then only the first n columns of Q are -// computed. -// -// [Q, R, P] = qr (X): form QRP factorization of X where -// P is a permutation matrix such that -// A * P = Q * R -// -// [Q, R, P] = qr (X, 0): form the economy decomposition with -// permutation vector P such that Q * R = X (:, P) -// -// qr (X) alone returns the output of the LAPACK routine dgeqrf, such -// that R = triu (qr (X)) - -DEFUN_DLD (qr, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})\n\ -@deftypefnx {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A}, '0')\n\ -@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B})\n\ -@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B}, '0')\n\ -@cindex QR factorization\n\ -Compute the QR@tie{}factorization of @var{A}, using standard @sc{lapack}\n\ -subroutines. For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},\n\ -\n\ -@example\n\ -[@var{Q}, @var{R}] = qr (@var{A})\n\ -@end example\n\ -\n\ -@noindent\n\ -returns\n\ -\n\ -@example\n\ -@group\n\ -@var{Q} =\n\ -\n\ - -0.31623 -0.94868\n\ - -0.94868 0.31623\n\ -\n\ -@var{R} =\n\ -\n\ - -3.16228 -4.42719\n\ - 0.00000 -0.63246\n\ -@end group\n\ -@end example\n\ -\n\ -The @code{qr} factorization has applications in the solution of least\n\ -squares problems\n\ -@tex\n\ -$$\n\ -\\min_x \\left\\Vert A x - b \\right\\Vert_2\n\ -$$\n\ -@end tex\n\ -@ifnottex\n\ -\n\ -@example\n\ -min norm(A x - b)\n\ -@end example\n\ -\n\ -@end ifnottex\n\ -for overdetermined systems of equations (i.e.,\n\ -@tex\n\ -$A$\n\ -@end tex\n\ -@ifnottex\n\ -@var{A}\n\ -@end ifnottex\n\ - is a tall, thin matrix). The QR@tie{}factorization is\n\ -@tex\n\ -$QR = A$ where $Q$ is an orthogonal matrix and $R$ is upper triangular.\n\ -@end tex\n\ -@ifnottex\n\ -@code{@var{Q} * @var{Q} = @var{A}} where @var{Q} is an orthogonal matrix and\n\ -@var{R} is upper triangular.\n\ -@end ifnottex\n\ -\n\ -If given a second argument of '0', @code{qr} returns an economy-sized\n\ -QR@tie{}factorization, omitting zero rows of @var{R} and the corresponding\n\ -columns of @var{Q}.\n\ -\n\ -If the matrix @var{A} is full, the permuted QR@tie{}factorization\n\ -@code{[@var{Q}, @var{R}, @var{P}] = qr (@var{A})} forms the\n\ -QR@tie{}factorization such that the diagonal entries of @var{R} are\n\ -decreasing in magnitude order. For example, given the matrix @code{a = [1,\n\ -2; 3, 4]},\n\ -\n\ -@example\n\ -[@var{Q}, @var{R}, @var{P}] = qr (@var{A})\n\ -@end example\n\ -\n\ -@noindent\n\ -returns\n\ -\n\ -@example\n\ -@group\n\ -@var{Q} =\n\ -\n\ - -0.44721 -0.89443\n\ - -0.89443 0.44721\n\ -\n\ -@var{R} =\n\ -\n\ - -4.47214 -3.13050\n\ - 0.00000 0.44721\n\ -\n\ -@var{P} =\n\ -\n\ - 0 1\n\ - 1 0\n\ -@end group\n\ -@end example\n\ -\n\ -The permuted @code{qr} factorization @code{[@var{Q}, @var{R}, @var{P}] = qr\n\ -(@var{A})} factorization allows the construction of an orthogonal basis of\n\ -@code{span (A)}.\n\ -\n\ -If the matrix @var{A} is sparse, then compute the sparse\n\ -QR@tie{}factorization of @var{A}, using @sc{CSparse}. As the matrix @var{Q}\n\ -is in general a full matrix, this function returns the @var{Q}-less\n\ -factorization @var{R} of @var{A}, such that @code{@var{R} = chol (@var{A}' *\n\ -@var{A})}.\n\ -\n\ -If the final argument is the scalar @code{0} and the number of rows is\n\ -larger than the number of columns, then an economy factorization is\n\ -returned. That is @var{R} will have only @code{size (@var{A},1)} rows.\n\ -\n\ -If an additional matrix @var{B} is supplied, then @code{qr} returns\n\ -@var{C}, where @code{@var{C} = @var{Q}' * @var{B}}. This allows the\n\ -least squares approximation of @code{@var{A} \\ @var{B}} to be calculated\n\ -as\n\ -\n\ -@example\n\ -@group\n\ -[@var{C}, @var{R}] = qr (@var{A}, @var{B})\n\ -x = @var{R} \\ @var{C}\n\ -@end group\n\ -@end example\n\ -@end deftypefn") -{ - octave_value_list retval; - - int nargin = args.length (); - - if (nargin < 1 || nargin > (args(0).is_sparse_type () ? 3 : 2)) - { - print_usage (); - return retval; - } - - octave_value arg = args(0); - - int arg_is_empty = empty_arg ("qr", arg.rows (), arg.columns ()); - - if (arg_is_empty < 0) - return retval; - - if (arg.is_sparse_type ()) - { - bool economy = false; - bool is_cmplx = false; - int have_b = 0; - - if (arg.is_complex_type ()) - is_cmplx = true; - if (nargin > 1) - { - have_b = 1; - if (args(nargin-1).is_scalar_type ()) - { - int val = args(nargin-1).int_value (); - if (val == 0) - { - economy = true; - have_b = (nargin > 2 ? 2 : 0); - } - } - if (have_b > 0 && args(have_b).is_complex_type ()) - is_cmplx = true; - } - - if (!error_state) - { - if (have_b && nargout < 2) - error ("qr: incorrect number of output arguments"); - else if (is_cmplx) - { - SparseComplexQR q (arg.sparse_complex_matrix_value ()); - if (!error_state) - { - if (have_b > 0) - { - retval(1) = q.R (economy); - retval(0) = q.C (args(have_b).complex_matrix_value ()); - if (arg.rows () < arg.columns ()) - warning ("qr: non minimum norm solution for under-determined problem"); - } - else if (nargout > 1) - { - retval(1) = q.R (economy); - retval(0) = q.Q (); - } - else - retval(0) = q.R (economy); - } - } - else - { - SparseQR q (arg.sparse_matrix_value ()); - if (!error_state) - { - if (have_b > 0) - { - retval(1) = q.R (economy); - retval(0) = q.C (args(have_b).matrix_value ()); - if (args(0).rows () < args(0).columns ()) - warning ("qr: non minimum norm solution for under-determined problem"); - } - else if (nargout > 1) - { - retval(1) = q.R (economy); - retval(0) = q.Q (); - } - else - retval(0) = q.R (economy); - } - } - } - } - else - { - QR::type type = (nargout == 0 || nargout == 1) ? QR::raw - : (nargin == 2 ? QR::economy : QR::std); - - if (arg.is_single_type ()) - { - if (arg.is_real_type ()) - { - FloatMatrix m = arg.float_matrix_value (); - - if (! error_state) - { - switch (nargout) - { - case 0: - case 1: - { - FloatQR fact (m, type); - retval(0) = fact.R (); - } - break; - - case 2: - { - FloatQR fact (m, type); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - - default: - { - FloatQRP fact (m, type); - if (type == QR::economy) - retval(2) = fact.Pvec (); - else - retval(2) = fact.P (); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - } - } - } - else if (arg.is_complex_type ()) - { - FloatComplexMatrix m = arg.float_complex_matrix_value (); - - if (! error_state) - { - switch (nargout) - { - case 0: - case 1: - { - FloatComplexQR fact (m, type); - retval(0) = fact.R (); - } - break; - - case 2: - { - FloatComplexQR fact (m, type); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - - default: - { - FloatComplexQRP fact (m, type); - if (type == QR::economy) - retval(2) = fact.Pvec (); - else - retval(2) = fact.P (); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - } - } - } - } - else - { - if (arg.is_real_type ()) - { - Matrix m = arg.matrix_value (); - - if (! error_state) - { - switch (nargout) - { - case 0: - case 1: - { - QR fact (m, type); - retval(0) = fact.R (); - } - break; - - case 2: - { - QR fact (m, type); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - - default: - { - QRP fact (m, type); - if (type == QR::economy) - retval(2) = fact.Pvec (); - else - retval(2) = fact.P (); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - } - } - } - else if (arg.is_complex_type ()) - { - ComplexMatrix m = arg.complex_matrix_value (); - - if (! error_state) - { - switch (nargout) - { - case 0: - case 1: - { - ComplexQR fact (m, type); - retval(0) = fact.R (); - } - break; - - case 2: - { - ComplexQR fact (m, type); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - - default: - { - ComplexQRP fact (m, type); - if (type == QR::economy) - retval(2) = fact.Pvec (); - else - retval(2) = fact.P (); - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - break; - } - } - } - else - gripe_wrong_type_arg ("qr", arg); - } - } - - return retval; -} - -/* -%!test -%! a = [0, 2, 1; 2, 1, 2]; -%! -%! [q, r] = qr (a); -%! [qe, re] = qr (a, 0); -%! -%! assert (q * r, a, sqrt (eps)); -%! assert (qe * re, a, sqrt (eps)); - -%!test -%! a = [0, 2, 1; 2, 1, 2]; -%! -%! [q, r, p] = qr (a); # FIXME: not giving right dimensions. -%! [qe, re, pe] = qr (a, 0); -%! -%! assert (q * r, a * p, sqrt (eps)); -%! assert (qe * re, a(:, pe), sqrt (eps)); - -%!test -%! a = [0, 2; 2, 1; 1, 2]; -%! -%! [q, r] = qr (a); -%! [qe, re] = qr (a, 0); -%! -%! assert (q * r, a, sqrt (eps)); -%! assert (qe * re, a, sqrt (eps)); - -%!test -%! a = [0, 2; 2, 1; 1, 2]; -%! -%! [q, r, p] = qr (a); -%! [qe, re, pe] = qr (a, 0); -%! -%! assert (q * r, a * p, sqrt (eps)); -%! assert (qe * re, a(:, pe), sqrt (eps)); - -%!error qr () -%!error qr ([1, 2; 3, 4], 0, 2) - -%!function retval = __testqr (q, r, a, p) -%! tol = 100*eps (class (q)); -%! retval = 0; -%! if (nargin == 3) -%! n1 = norm (q*r - a); -%! n2 = norm (q'*q - eye (columns (q))); -%! retval = (n1 < tol && n2 < tol); -%! else -%! n1 = norm (q'*q - eye (columns (q))); -%! retval = (n1 < tol); -%! if (isvector (p)) -%! n2 = norm (q*r - a(:,p)); -%! retval = (retval && n2 < tol); -%! else -%! n2 = norm (q*r - a*p); -%! retval = (retval && n2 < tol); -%! endif -%! endif -%!endfunction - -%!test -%! t = ones (24, 1); -%! j = 1; -%! -%! if (false) # eliminate big matrix tests -%! a = rand (5000, 20); -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps; -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! endif -%! -%! a = [ ones(1,15); sqrt(eps)*eye(15) ]; -%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps; -%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); -%! -%! a = [ ones(1,15); sqrt(eps)*eye(15) ]; -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps; -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! -%! a = [ 611 196 -192 407 -8 -52 -49 29 -%! 196 899 113 -192 -71 -43 -8 -44 -%! -192 113 899 196 61 49 8 52 -%! 407 -192 196 611 8 44 59 -23 -%! -8 -71 61 8 411 -599 208 208 -%! -52 -43 49 44 -599 411 208 208 -%! -49 -8 8 59 208 208 99 -911 -%! 29 -44 52 -23 208 208 -911 99 ]; -%! [q,r] = qr (a); -%! -%! assert (all (t) && norm (q*r - a) < 5000*eps); - -%!test -%! a = single ([0, 2, 1; 2, 1, 2]); -%! -%! [q, r] = qr (a); -%! [qe, re] = qr (a, 0); -%! -%! assert (q * r, a, sqrt (eps ("single"))); -%! assert (qe * re, a, sqrt (eps ("single"))); - -%!test -%! a = single ([0, 2, 1; 2, 1, 2]); -%! -%! [q, r, p] = qr (a); # FIXME: not giving right dimensions. -%! [qe, re, pe] = qr (a, 0); -%! -%! assert (q * r, a * p, sqrt (eps ("single"))); -%! assert (qe * re, a(:, pe), sqrt (eps ("single"))); - -%!test -%! a = single ([0, 2; 2, 1; 1, 2]); -%! -%! [q, r] = qr (a); -%! [qe, re] = qr (a, 0); -%! -%! assert (q * r, a, sqrt (eps ("single"))); -%! assert (qe * re, a, sqrt (eps ("single"))); - -%!test -%! a = single ([0, 2; 2, 1; 1, 2]); -%! -%! [q, r, p] = qr (a); -%! [qe, re, pe] = qr (a, 0); -%! -%! assert (q * r, a * p, sqrt (eps ("single"))); -%! assert (qe * re, a(:, pe), sqrt (eps ("single"))); - -%!error qr () -%!error qr ([1, 2; 3, 4], 0, 2) - -%!test -%! t = ones (24, 1); -%! j = 1; -%! -%! if (false) # eliminate big matrix tests -%! a = rand (5000,20); -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps ("single"); -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! endif -%! -%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ]; -%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps ("single"); -%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); -%! -%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ]; -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); -%! -%! a = a+1i*eps ("single"); -%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); -%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); -%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); -%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a',p); -%! -%! a = [ 611 196 -192 407 -8 -52 -49 29 -%! 196 899 113 -192 -71 -43 -8 -44 -%! -192 113 899 196 61 49 8 52 -%! 407 -192 196 611 8 44 59 -23 -%! -8 -71 61 8 411 -599 208 208 -%! -52 -43 49 44 -599 411 208 208 -%! -49 -8 8 59 208 208 99 -911 -%! 29 -44 52 -23 208 208 -911 99 ]; -%! [q,r] = qr (a); -%! -%! assert (all (t) && norm (q*r-a) < 5000*eps ("single")); - -## The deactivated tests below can't be tested till rectangular back-subs is -## implemented for sparse matrices. - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = sprandn (n,n,d) + speye (n,n); -%! r = qr (a); -%! assert (r'*r, a'*a, 1e-10) - -%!testif HAVE_COLAMD -%! n = 20; d = 0.2; -%! a = sprandn (n,n,d) + speye (n,n); -%! q = symamd (a); -%! a = a(q,q); -%! r = qr (a); -%! assert (r'*r, a'*a, 1e-10) - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = sprandn (n,n,d) + speye (n,n); -%! [c,r] = qr (a, ones (n,1)); -%! assert (r\c, full (a)\ones (n,1), 10e-10) - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = sprandn (n,n,d) + speye (n,n); -%! b = randn (n,2); -%! [c,r] = qr (a, b); -%! assert (r\c, full (a)\b, 10e-10) - -%% Test under-determined systems!! -%!#testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = sprandn (n,n+1,d) + speye (n,n+1); -%! b = randn (n,2); -%! [c,r] = qr (a, b); -%! assert (r\c, full (a)\b, 10e-10) - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = 1i*sprandn (n,n,d) + speye (n,n); -%! r = qr (a); -%! assert (r'*r,a'*a,1e-10) - -%!testif HAVE_COLAMD -%! n = 20; d = 0.2; -%! a = 1i*sprandn (n,n,d) + speye (n,n); -%! q = symamd (a); -%! a = a(q,q); -%! r = qr (a); -%! assert (r'*r, a'*a, 1e-10) - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = 1i*sprandn (n,n,d) + speye (n,n); -%! [c,r] = qr (a, ones (n,1)); -%! assert (r\c, full (a)\ones (n,1), 10e-10) - -%!testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = 1i*sprandn (n,n,d) + speye (n,n); -%! b = randn (n,2); -%! [c,r] = qr (a, b); -%! assert (r\c, full (a)\b, 10e-10) - -%% Test under-determined systems!! -%!#testif HAVE_CXSPARSE -%! n = 20; d = 0.2; -%! a = 1i*sprandn (n,n+1,d) + speye (n,n+1); -%! b = randn (n,2); -%! [c,r] = qr (a, b); -%! assert (r\c, full (a)\b, 10e-10) - -%!error qr (sprandn (10,10,0.2), ones (10,1)) -*/ - -static -bool check_qr_dims (const octave_value& q, const octave_value& r, - bool allow_ecf = false) -{ - octave_idx_type m = q.rows (), k = r.rows (), n = r.columns (); - return ((q.ndims () == 2 && r.ndims () == 2 && k == q.columns ()) - && (m == k || (allow_ecf && k == n && k < m))); -} - -static -bool check_index (const octave_value& i, bool vector_allowed = false) -{ - return ((i.is_real_type () || i.is_integer_type ()) - && (i.is_scalar_type () || vector_allowed)); -} - -DEFUN_DLD (qrupdate, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrupdate (@var{Q}, @var{R}, @var{u}, @var{v})\n\ -Given a QR@tie{}factorization of a real or complex matrix\n\ -@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ -@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization\n\ -of @w{@var{A} + @var{u}*@var{v}'}, where @var{u} and @var{v} are\n\ -column vectors (rank-1 update) or matrices with equal number of columns\n\ -(rank-k update). Notice that the latter case is done as a sequence of rank-1\n\ -updates; thus, for k large enough, it will be both faster and more accurate\n\ -to recompute the factorization from scratch.\n\ -\n\ -The QR@tie{}factorization supplied may be either full\n\ -(Q is square) or economized (R is square).\n\ -\n\ -@seealso{qr, qrinsert, qrdelete}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - octave_value_list retval; - - if (nargin != 4) - { - print_usage (); - return retval; - } - - octave_value argq = args(0); - octave_value argr = args(1); - octave_value argu = args(2); - octave_value argv = args(3); - - if (argq.is_numeric_type () && argr.is_numeric_type () - && argu.is_numeric_type () && argv.is_numeric_type ()) - { - if (check_qr_dims (argq, argr, true)) - { - if (argq.is_real_type () - && argr.is_real_type () - && argu.is_real_type () - && argv.is_real_type ()) - { - // all real case - if (argq.is_single_type () - || argr.is_single_type () - || argu.is_single_type () - || argv.is_single_type ()) - { - FloatMatrix Q = argq.float_matrix_value (); - FloatMatrix R = argr.float_matrix_value (); - FloatMatrix u = argu.float_matrix_value (); - FloatMatrix v = argv.float_matrix_value (); - - FloatQR fact (Q, R); - fact.update (u, v); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - Matrix Q = argq.matrix_value (); - Matrix R = argr.matrix_value (); - Matrix u = argu.matrix_value (); - Matrix v = argv.matrix_value (); - - QR fact (Q, R); - fact.update (u, v); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - else - { - // complex case - if (argq.is_single_type () - || argr.is_single_type () - || argu.is_single_type () - || argv.is_single_type ()) - { - FloatComplexMatrix Q = argq.float_complex_matrix_value (); - FloatComplexMatrix R = argr.float_complex_matrix_value (); - FloatComplexMatrix u = argu.float_complex_matrix_value (); - FloatComplexMatrix v = argv.float_complex_matrix_value (); - - FloatComplexQR fact (Q, R); - fact.update (u, v); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - ComplexMatrix Q = argq.complex_matrix_value (); - ComplexMatrix R = argr.complex_matrix_value (); - ComplexMatrix u = argu.complex_matrix_value (); - ComplexMatrix v = argv.complex_matrix_value (); - - ComplexQR fact (Q, R); - fact.update (u, v); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - } - else - error ("qrupdate: Q and R dimensions don't match"); - } - else - error ("qrupdate: Q, R, U, and V must be numeric"); - - return retval; -} - -/* -%!shared A, u, v, Ac, uc, vc -%! A = [0.091364 0.613038 0.999083; -%! 0.594638 0.425302 0.603537; -%! 0.383594 0.291238 0.085574; -%! 0.265712 0.268003 0.238409; -%! 0.669966 0.743851 0.445057 ]; -%! -%! u = [0.85082; -%! 0.76426; -%! 0.42883; -%! 0.53010; -%! 0.80683 ]; -%! -%! v = [0.98810; -%! 0.24295; -%! 0.43167 ]; -%! -%! Ac = [0.620405 + 0.956953i 0.480013 + 0.048806i 0.402627 + 0.338171i; -%! 0.589077 + 0.658457i 0.013205 + 0.279323i 0.229284 + 0.721929i; -%! 0.092758 + 0.345687i 0.928679 + 0.241052i 0.764536 + 0.832406i; -%! 0.912098 + 0.721024i 0.049018 + 0.269452i 0.730029 + 0.796517i; -%! 0.112849 + 0.603871i 0.486352 + 0.142337i 0.355646 + 0.151496i ]; -%! -%! uc = [0.20351 + 0.05401i; -%! 0.13141 + 0.43708i; -%! 0.29808 + 0.08789i; -%! 0.69821 + 0.38844i; -%! 0.74871 + 0.25821i ]; -%! -%! vc = [0.85839 + 0.29468i; -%! 0.20820 + 0.93090i; -%! 0.86184 + 0.34689i ]; -%! - -%!test -%! [Q,R] = qr (A); -%! [Q,R] = qrupdate (Q, R, u, v); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R)-R), Inf) == 0); -%! assert (norm (vec (Q*R - A - u*v'), Inf) < norm (A)*1e1*eps); -%! -%!test -%! [Q,R] = qr (Ac); -%! [Q,R] = qrupdate (Q, R, uc, vc); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R)-R), Inf) == 0); -%! assert (norm (vec (Q*R - Ac - uc*vc'), Inf) < norm (Ac)*1e1*eps); - -%!test -%! [Q,R] = qr (single (A)); -%! [Q,R] = qrupdate (Q, R, single (u), single (v)); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R)-R), Inf) == 0); -%! assert (norm (vec (Q*R - single (A) - single (u)*single (v)'), Inf) < norm (single (A))*1e1*eps ("single")); -%! -%!test -%! [Q,R] = qr (single (Ac)); -%! [Q,R] = qrupdate (Q, R, single (uc), single (vc)); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R)-R), Inf) == 0); -%! assert (norm (vec (Q*R - single (Ac) - single (uc)*single (vc)'), Inf) < norm (single (Ac))*1e1*eps ("single")); -*/ - -DEFUN_DLD (qrinsert, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrinsert (@var{Q}, @var{R}, @var{j}, @var{x}, @var{orient})\n\ -Given a QR@tie{}factorization of a real or complex matrix\n\ -@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ -@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of\n\ -@w{[A(:,1:j-1) x A(:,j:n)]}, where @var{u} is a column vector to be\n\ -inserted into @var{A} (if @var{orient} is @code{\"col\"}), or the\n\ -QR@tie{}factorization of @w{[A(1:j-1,:);x;A(:,j:n)]}, where @var{x}\n\ -is a row vector to be inserted into @var{A} (if @var{orient} is\n\ -@code{\"row\"}).\n\ -\n\ -The default value of @var{orient} is @code{\"col\"}.\n\ -If @var{orient} is @code{\"col\"},\n\ -@var{u} may be a matrix and @var{j} an index vector\n\ -resulting in the QR@tie{}factorization of a matrix @var{B} such that\n\ -@w{B(:,@var{j})} gives @var{u} and @w{B(:,@var{j}) = []} gives @var{A}.\n\ -Notice that the latter case is done as a sequence of k insertions;\n\ -thus, for k large enough, it will be both faster and more accurate to\n\ -recompute the factorization from scratch.\n\ -\n\ -If @var{orient} is @code{\"col\"},\n\ -the QR@tie{}factorization supplied may be either full\n\ -(Q is square) or economized (R is square).\n\ -\n\ -If @var{orient} is @code{\"row\"}, full factorization is needed.\n\ -@seealso{qr, qrupdate, qrdelete}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - octave_value_list retval; - - if (nargin < 4 || nargin > 5) - { - print_usage (); - return retval; - } - - octave_value argq = args(0); - octave_value argr = args(1); - octave_value argj = args(2); - octave_value argx = args(3); - - if (argq.is_numeric_type () && argr.is_numeric_type () - && argx.is_numeric_type () - && (nargin < 5 || args(4).is_string ())) - { - std::string orient = (nargin < 5) ? "col" : args(4).string_value (); - - bool col = orient == "col"; - - if (col || orient == "row") - if (check_qr_dims (argq, argr, col) - && (col || argx.rows () == 1)) - { - if (check_index (argj, col)) - { - MArray<octave_idx_type> j - = argj.octave_idx_type_vector_value (); - - octave_idx_type one = 1; - - if (argq.is_real_type () - && argr.is_real_type () - && argx.is_real_type ()) - { - // real case - if (argq.is_single_type () - || argr.is_single_type () - || argx.is_single_type ()) - { - FloatMatrix Q = argq.float_matrix_value (); - FloatMatrix R = argr.float_matrix_value (); - FloatMatrix x = argx.float_matrix_value (); - - FloatQR fact (Q, R); - - if (col) - fact.insert_col (x, j-one); - else - fact.insert_row (x.row (0), j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - - } - else - { - Matrix Q = argq.matrix_value (); - Matrix R = argr.matrix_value (); - Matrix x = argx.matrix_value (); - - QR fact (Q, R); - - if (col) - fact.insert_col (x, j-one); - else - fact.insert_row (x.row (0), j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - - } - } - else - { - // complex case - if (argq.is_single_type () - || argr.is_single_type () - || argx.is_single_type ()) - { - FloatComplexMatrix Q = argq.float_complex_matrix_value (); - FloatComplexMatrix R = argr.float_complex_matrix_value (); - FloatComplexMatrix x = argx.float_complex_matrix_value (); - - FloatComplexQR fact (Q, R); - - if (col) - fact.insert_col (x, j-one); - else - fact.insert_row (x.row (0), j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - ComplexMatrix Q = argq.complex_matrix_value (); - ComplexMatrix R = argr.complex_matrix_value (); - ComplexMatrix x = argx.complex_matrix_value (); - - ComplexQR fact (Q, R); - - if (col) - fact.insert_col (x, j-one); - else - fact.insert_row (x.row (0), j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - - } - else - error ("qrinsert: invalid index J"); - } - else - error ("qrinsert: dimension mismatch"); - - else - error ("qrinsert: ORIENT must be \"col\" or \"row\""); - } - else - print_usage (); - - return retval; -} - -/* -%!test -%! [Q,R] = qr (A); -%! [Q,R] = qrinsert (Q, R, 3, u); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [A(:,1:2) u A(:,3)]), Inf) < norm (A)*1e1*eps); -%!test -%! [Q,R] = qr (Ac); -%! [Q,R] = qrinsert (Q, R, 3, uc); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [Ac(:,1:2) uc Ac(:,3)]), Inf) < norm (Ac)*1e1*eps); -%!test -%! x = [0.85082 0.76426 0.42883 ]; -%! -%! [Q,R] = qr (A); -%! [Q,R] = qrinsert (Q, R, 3, x, "row"); -%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [A(1:2,:);x;A(3:5,:)]), Inf) < norm (A)*1e1*eps); -%!test -%! x = [0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ]; -%! -%! [Q,R] = qr (Ac); -%! [Q,R] = qrinsert (Q, R, 3, x, "row"); -%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [Ac(1:2,:);x;Ac(3:5,:)]), Inf) < norm (Ac)*1e1*eps); - -%!test -%! [Q,R] = qr (single (A)); -%! [Q,R] = qrinsert (Q, R, 3, single (u)); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - single ([A(:,1:2) u A(:,3)])), Inf) < norm (single (A))*1e1*eps ("single")); -%!test -%! [Q,R] = qr (single (Ac)); -%! [Q,R] = qrinsert (Q, R, 3, single (uc)); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - single ([Ac(:,1:2) uc Ac(:,3)])), Inf) < norm (single (Ac))*1e1*eps ("single")); -%!test -%! x = single ([0.85082 0.76426 0.42883 ]); -%! -%! [Q,R] = qr (single (A)); -%! [Q,R] = qrinsert (Q, R, 3, x, "row"); -%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - single ([A(1:2,:);x;A(3:5,:)])), Inf) < norm (single (A))*1e1*eps ("single")); -%!test -%! x = single ([0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ]); -%! -%! [Q,R] = qr (single (Ac)); -%! [Q,R] = qrinsert (Q, R, 3, x, "row"); -%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - single ([Ac(1:2,:);x;Ac(3:5,:)])), Inf) < norm (single (Ac))*1e1*eps ("single")); -*/ - -DEFUN_DLD (qrdelete, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrdelete (@var{Q}, @var{R}, @var{j}, @var{orient})\n\ -Given a QR@tie{}factorization of a real or complex matrix\n\ -@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ -@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of\n\ -@w{[A(:,1:j-1) A(:,j+1:n)]}, i.e., @var{A} with one column deleted\n\ -(if @var{orient} is \"col\"), or the QR@tie{}factorization of\n\ -@w{[A(1:j-1,:);A(j+1:n,:)]}, i.e., @var{A} with one row deleted (if\n\ -@var{orient} is \"row\").\n\ -\n\ -The default value of @var{orient} is \"col\".\n\ -\n\ -If @var{orient} is @code{\"col\"},\n\ -@var{j} may be an index vector\n\ -resulting in the QR@tie{}factorization of a matrix @var{B} such that\n\ -@w{A(:,@var{j}) = []} gives @var{B}.\n\ -Notice that the latter case is done as a sequence of k deletions;\n\ -thus, for k large enough, it will be both faster and more accurate to\n\ -recompute the factorization from scratch.\n\ -\n\ -If @var{orient} is @code{\"col\"},\n\ -the QR@tie{}factorization supplied may be either full\n\ -(Q is square) or economized (R is square).\n\ -\n\ -If @var{orient} is @code{\"row\"}, full factorization is needed.\n\ -@seealso{qr, qrinsert, qrupdate}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - octave_value_list retval; - - if (nargin < 3 || nargin > 4) - { - print_usage (); - return retval; - } - - octave_value argq = args(0); - octave_value argr = args(1); - octave_value argj = args(2); - - if (argq.is_numeric_type () && argr.is_numeric_type () - && (nargin < 4 || args(3).is_string ())) - { - std::string orient = (nargin < 4) ? "col" : args(3).string_value (); - - bool col = orient == "col"; - - if (col || orient == "row") - if (check_qr_dims (argq, argr, col)) - { - if (check_index (argj, col)) - { - MArray<octave_idx_type> j - = argj.octave_idx_type_vector_value (); - - octave_idx_type one = 1; - - if (argq.is_real_type () - && argr.is_real_type ()) - { - // real case - if (argq.is_single_type () - || argr.is_single_type ()) - { - FloatMatrix Q = argq.float_matrix_value (); - FloatMatrix R = argr.float_matrix_value (); - - FloatQR fact (Q, R); - - if (col) - fact.delete_col (j-one); - else - fact.delete_row (j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - Matrix Q = argq.matrix_value (); - Matrix R = argr.matrix_value (); - - QR fact (Q, R); - - if (col) - fact.delete_col (j-one); - else - fact.delete_row (j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - else - { - // complex case - if (argq.is_single_type () - || argr.is_single_type ()) - { - FloatComplexMatrix Q = argq.float_complex_matrix_value (); - FloatComplexMatrix R = argr.float_complex_matrix_value (); - - FloatComplexQR fact (Q, R); - - if (col) - fact.delete_col (j-one); - else - fact.delete_row (j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - ComplexMatrix Q = argq.complex_matrix_value (); - ComplexMatrix R = argr.complex_matrix_value (); - - ComplexQR fact (Q, R); - - if (col) - fact.delete_col (j-one); - else - fact.delete_row (j(0)-one); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - } - else - error ("qrdelete: invalid index J"); - } - else - error ("qrdelete: dimension mismatch"); - - else - error ("qrdelete: ORIENT must be \"col\" or \"row\""); - } - else - print_usage (); - - return retval; -} - -/* -%!test -%! AA = [0.091364 0.613038 0.027504 0.999083; -%! 0.594638 0.425302 0.562834 0.603537; -%! 0.383594 0.291238 0.742073 0.085574; -%! 0.265712 0.268003 0.783553 0.238409; -%! 0.669966 0.743851 0.457255 0.445057 ]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps); -%! -%!test -%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; -%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; -%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; -%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; -%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3); -%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps); -%! -%!test -%! AA = [0.091364 0.613038 0.027504 0.999083; -%! 0.594638 0.425302 0.562834 0.603537; -%! 0.383594 0.291238 0.742073 0.085574; -%! 0.265712 0.268003 0.783553 0.238409; -%! 0.669966 0.743851 0.457255 0.445057 ]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3, "row"); -%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps); -%! -%!test -%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; -%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; -%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; -%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; -%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3, "row"); -%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps); - -%!test -%! AA = single ([0.091364 0.613038 0.027504 0.999083; -%! 0.594638 0.425302 0.562834 0.603537; -%! 0.383594 0.291238 0.742073 0.085574; -%! 0.265712 0.268003 0.783553 0.238409; -%! 0.669966 0.743851 0.457255 0.445057 ]); -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single")); -%! -%!test -%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; -%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; -%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; -%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; -%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3); -%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single")); -%! -%!test -%! AA = single ([0.091364 0.613038 0.027504 0.999083; -%! 0.594638 0.425302 0.562834 0.603537; -%! 0.383594 0.291238 0.742073 0.085574; -%! 0.265712 0.268003 0.783553 0.238409; -%! 0.669966 0.743851 0.457255 0.445057 ]); -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3, "row"); -%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1.5e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); -%!testif HAVE_QRUPDATE -%! # Same test as above but with more precicision -%! AA = single ([0.091364 0.613038 0.027504 0.999083; -%! 0.594638 0.425302 0.562834 0.603537; -%! 0.383594 0.291238 0.742073 0.085574; -%! 0.265712 0.268003 0.783553 0.238409; -%! 0.669966 0.743851 0.457255 0.445057 ]); -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3, "row"); -%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); -%! -%!test -%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; -%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; -%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; -%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; -%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrdelete (Q, R, 3, "row"); -%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); -*/ - -DEFUN_DLD (qrshift, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrshift (@var{Q}, @var{R}, @var{i}, @var{j})\n\ -Given a QR@tie{}factorization of a real or complex matrix\n\ -@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ -@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization\n\ -of @w{@var{A}(:,p)}, where @w{p} is the permutation @*\n\ -@code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*\n\ - or @*\n\ -@code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*\n\ -\n\ -@seealso{qr, qrinsert, qrdelete}\n\ -@end deftypefn") -{ - octave_idx_type nargin = args.length (); - octave_value_list retval; - - if (nargin != 4) - { - print_usage (); - return retval; - } - - octave_value argq = args(0); - octave_value argr = args(1); - octave_value argi = args(2); - octave_value argj = args(3); - - if (argq.is_numeric_type () && argr.is_numeric_type ()) - { - if (check_qr_dims (argq, argr, true)) - { - if (check_index (argi) && check_index (argj)) - { - octave_idx_type i = argi.int_value (); - octave_idx_type j = argj.int_value (); - - if (argq.is_real_type () - && argr.is_real_type ()) - { - // all real case - if (argq.is_single_type () - && argr.is_single_type ()) - { - FloatMatrix Q = argq.float_matrix_value (); - FloatMatrix R = argr.float_matrix_value (); - - FloatQR fact (Q, R); - fact.shift_cols (i-1, j-1); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - Matrix Q = argq.matrix_value (); - Matrix R = argr.matrix_value (); - - QR fact (Q, R); - fact.shift_cols (i-1, j-1); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - else - { - // complex case - if (argq.is_single_type () - && argr.is_single_type ()) - { - FloatComplexMatrix Q = argq.float_complex_matrix_value (); - FloatComplexMatrix R = argr.float_complex_matrix_value (); - - FloatComplexQR fact (Q, R); - fact.shift_cols (i-1, j-1); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - else - { - ComplexMatrix Q = argq.complex_matrix_value (); - ComplexMatrix R = argr.complex_matrix_value (); - - ComplexQR fact (Q, R); - fact.shift_cols (i-1, j-1); - - retval(1) = get_qr_r (fact); - retval(0) = fact.Q (); - } - } - } - else - error ("qrshift: invalid index I or J"); - } - else - error ("qrshift: dimensions mismatch"); - } - else - error ("qrshift: Q and R must be numeric"); - - return retval; -} - -/* -%!test -%! AA = A.'; -%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); -%! -%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); -%! -%!test -%! AA = Ac.'; -%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); -%! -%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); - -%!test -%! AA = single (A).'; -%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); -%! -%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); -%! -%!test -%! AA = single (Ac).'; -%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); -%! -%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; -%! -%! [Q,R] = qr (AA); -%! [Q,R] = qrshift (Q, R, i, j); -%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); -%! assert (norm (vec (triu (R) - R), Inf) == 0); -%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); -*/
--- a/src/DLD-FUNCTIONS/symbfact.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,363 +0,0 @@ -/* - -Copyright (C) 2005-2012 David Bateman -Copyright (C) 1998-2005 Andy Adler - -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> -#endif - -#include "SparseCmplxCHOL.h" -#include "SparsedbleCHOL.h" -#include "oct-spparms.h" -#include "sparse-util.h" -#include "oct-locbuf.h" - -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -DEFUN_DLD (symbfact, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{count}, @var{h}, @var{parent}, @var{post}, @var{r}] =} symbfact (@var{S})\n\ -@deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ})\n\ -@deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ}, @var{mode})\n\ -\n\ -Perform a symbolic factorization analysis on the sparse matrix @var{S}.\n\ -Where\n\ -\n\ -@table @var\n\ -@item S\n\ -@var{S} is a complex or real sparse matrix.\n\ -\n\ -@item typ\n\ -Is the type of the factorization and can be one of\n\ -\n\ -@table @samp\n\ -@item sym\n\ -Factorize @var{S}. This is the default.\n\ -\n\ -@item col\n\ -Factorize @code{@var{S}' * @var{S}}.\n\ -\n\ -@item row\n\ -Factorize @xcode{@var{S} * @var{S}'}.\n\ -\n\ -@item lo\n\ -Factorize @xcode{@var{S}'}\n\ -@end table\n\ -\n\ -@item mode\n\ -The default is to return the Cholesky@tie{}factorization for @var{r}, and if\n\ -@var{mode} is 'L', the conjugate transpose of the Cholesky@tie{}factorization\n\ -is returned. The conjugate transpose version is faster and uses less\n\ -memory, but returns the same values for @var{count}, @var{h}, @var{parent}\n\ -and @var{post} outputs.\n\ -@end table\n\ -\n\ -The output variables are\n\ -\n\ -@table @var\n\ -@item count\n\ -The row counts of the Cholesky@tie{}factorization as determined by @var{typ}.\n\ -\n\ -@item h\n\ -The height of the elimination tree.\n\ -\n\ -@item parent\n\ -The elimination tree itself.\n\ -\n\ -@item post\n\ -A sparse boolean matrix whose structure is that of the Cholesky\n\ -factorization as determined by @var{typ}.\n\ -@end table\n\ -@end deftypefn") -{ - octave_value_list retval; - int nargin = args.length (); - - if (nargin < 1 || nargin > 3 || nargout > 5) - { - print_usage (); - return retval; - } - -#ifdef HAVE_CHOLMOD - - cholmod_common Common; - cholmod_common *cm = &Common; - CHOLMOD_NAME(start) (cm); - - double spu = octave_sparse_params::get_key ("spumoni"); - if (spu == 0.) - { - cm->print = -1; - cm->print_function = 0; - } - else - { - cm->print = static_cast<int> (spu) + 2; - cm->print_function =&SparseCholPrint; - } - - cm->error_handler = &SparseCholError; - cm->complex_divide = CHOLMOD_NAME(divcomplex); - cm->hypotenuse = CHOLMOD_NAME(hypot); - - double dummy; - cholmod_sparse Astore; - cholmod_sparse *A = &Astore; - A->packed = true; - A->sorted = true; - A->nz = 0; -#ifdef IDX_TYPE_LONG - A->itype = CHOLMOD_LONG; -#else - A->itype = CHOLMOD_INT; -#endif - A->dtype = CHOLMOD_DOUBLE; - A->stype = 1; - A->x = &dummy; - - if (args(0).is_real_type ()) - { - const SparseMatrix a = args(0).sparse_matrix_value (); - A->nrow = a.rows (); - A->ncol = a.cols (); - A->p = a.cidx (); - A->i = a.ridx (); - A->nzmax = a.nnz (); - A->xtype = CHOLMOD_REAL; - - if (a.rows () > 0 && a.cols () > 0) - A->x = a.data (); - } - else if (args(0).is_complex_type ()) - { - const SparseComplexMatrix a = args(0).sparse_complex_matrix_value (); - A->nrow = a.rows (); - A->ncol = a.cols (); - A->p = a.cidx (); - A->i = a.ridx (); - A->nzmax = a.nnz (); - A->xtype = CHOLMOD_COMPLEX; - - if (a.rows () > 0 && a.cols () > 0) - A->x = a.data (); - } - else - gripe_wrong_type_arg ("symbfact", args(0)); - - octave_idx_type coletree = false; - octave_idx_type n = A->nrow; - - if (nargin > 1) - { - char ch; - std::string str = args(1).string_value (); - ch = tolower (str.c_str ()[0]); - if (ch == 'r') - A->stype = 0; - else if (ch == 'c') - { - n = A->ncol; - coletree = true; - A->stype = 0; - } - else if (ch == 's') - A->stype = 1; - else if (ch == 's') - A->stype = -1; - else - error ("symbfact: unrecognized TYP in symbolic factorization"); - } - - if (A->stype && A->nrow != A->ncol) - error ("symbfact: S must be a square matrix"); - - if (!error_state) - { - OCTAVE_LOCAL_BUFFER (octave_idx_type, Parent, n); - OCTAVE_LOCAL_BUFFER (octave_idx_type, Post, n); - OCTAVE_LOCAL_BUFFER (octave_idx_type, ColCount, n); - OCTAVE_LOCAL_BUFFER (octave_idx_type, First, n); - OCTAVE_LOCAL_BUFFER (octave_idx_type, Level, n); - - cholmod_sparse *F = CHOLMOD_NAME(transpose) (A, 0, cm); - cholmod_sparse *Aup, *Alo; - - if (A->stype == 1 || coletree) - { - Aup = A ; - Alo = F ; - } - else - { - Aup = F ; - Alo = A ; - } - - CHOLMOD_NAME(etree) (Aup, Parent, cm); - - if (cm->status < CHOLMOD_OK) - { - error ("matrix corrupted"); - goto symbfact_error; - } - - if (CHOLMOD_NAME(postorder) (Parent, n, 0, Post, cm) != n) - { - error ("postorder failed"); - goto symbfact_error; - } - - CHOLMOD_NAME(rowcolcounts) (Alo, 0, 0, Parent, Post, 0, - ColCount, First, Level, cm); - - if (cm->status < CHOLMOD_OK) - { - error ("matrix corrupted"); - goto symbfact_error; - } - - if (nargout > 4) - { - cholmod_sparse *A1, *A2; - - if (A->stype == 1) - { - A1 = A; - A2 = 0; - } - else if (A->stype == -1) - { - A1 = F; - A2 = 0; - } - else if (coletree) - { - A1 = F; - A2 = A; - } - else - { - A1 = A; - A2 = F; - } - - // count the total number of entries in L - octave_idx_type lnz = 0 ; - for (octave_idx_type j = 0 ; j < n ; j++) - lnz += ColCount[j]; - - - // allocate the output matrix L (pattern-only) - SparseBoolMatrix L (n, n, lnz); - - // initialize column pointers - lnz = 0; - for (octave_idx_type j = 0 ; j < n ; j++) - { - L.xcidx(j) = lnz; - lnz += ColCount[j]; - } - L.xcidx(n) = lnz; - - - /* create a copy of the column pointers */ - octave_idx_type *W = First; - for (octave_idx_type j = 0 ; j < n ; j++) - W[j] = L.xcidx (j); - - // get workspace for computing one row of L - cholmod_sparse *R = cholmod_allocate_sparse (n, 1, n, false, true, - 0, CHOLMOD_PATTERN, cm); - octave_idx_type *Rp = static_cast<octave_idx_type *>(R->p); - octave_idx_type *Ri = static_cast<octave_idx_type *>(R->i); - - // compute L one row at a time - for (octave_idx_type k = 0 ; k < n ; k++) - { - // get the kth row of L and store in the columns of L - CHOLMOD_NAME (row_subtree) (A1, A2, k, Parent, R, cm) ; - for (octave_idx_type p = 0 ; p < Rp[1] ; p++) - L.xridx (W[Ri[p]]++) = k ; - - // add the diagonal entry - L.xridx (W[k]++) = k ; - } - - // free workspace - cholmod_free_sparse (&R, cm) ; - - - // transpose L to get R, or leave as is - if (nargin < 3) - L = L.transpose (); - - // fill numerical values of L with one's - for (octave_idx_type p = 0 ; p < lnz ; p++) - L.xdata(p) = true; - - retval(4) = L; - } - - ColumnVector tmp (n); - if (nargout > 3) - { - for (octave_idx_type i = 0; i < n; i++) - tmp(i) = Post[i] + 1; - retval(3) = tmp; - } - - if (nargout > 2) - { - for (octave_idx_type i = 0; i < n; i++) - tmp(i) = Parent[i] + 1; - retval(2) = tmp; - } - - if (nargout > 1) - { - /* compute the elimination tree height */ - octave_idx_type height = 0 ; - for (int i = 0 ; i < n ; i++) - height = (height > Level[i] ? height : Level[i]); - height++ ; - retval(1) = static_cast<double> (height); - } - - for (octave_idx_type i = 0; i < n; i++) - tmp(i) = ColCount[i]; - retval(0) = tmp; - } - - symbfact_error: -#else - error ("symbfact: not available in this version of Octave"); -#endif - - return retval; -}
--- a/src/DLD-FUNCTIONS/symrcm.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,702 +0,0 @@ -/* - -Copyright (C) 2007-2012 Michael Weitzel - -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/>. - -*/ - -/* -An implementation of the Reverse Cuthill-McKee algorithm (symrcm) - -The implementation of this algorithm is based in the descriptions found in - -@INPROCEEDINGS{, - author = {E. Cuthill and J. McKee}, - title = {Reducing the Bandwidth of Sparse Symmetric Matrices}, - booktitle = {Proceedings of the 24th ACM National Conference}, - publisher = {Brandon Press}, - pages = {157 -- 172}, - location = {New Jersey}, - year = {1969} -} - -@BOOK{, - author = {Alan George and Joseph W. H. Liu}, - title = {Computer Solution of Large Sparse Positive Definite Systems}, - publisher = {Prentice Hall Series in Computational Mathematics}, - ISBN = {0-13-165274-5}, - year = {1981} -} - -The algorithm represents a heuristic approach to the NP-complete minimum -bandwidth problem. - -Written by Michael Weitzel <michael.weitzel@@uni-siegen.de> - <weitzel@@ldknet.org> -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "ov.h" -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "utils.h" -#include "oct-locbuf.h" - -#include "ov-re-mat.h" -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "oct-sparse.h" - -// A node struct for the Cuthill-McKee algorithm -struct CMK_Node -{ - // the node's id (matrix row index) - octave_idx_type id; - // the node's degree - octave_idx_type deg; - // minimal distance to the root of the spanning tree - octave_idx_type dist; -}; - -// A simple queue. -// Queues Q have a fixed maximum size N (rows,cols of the matrix) and are -// stored in an array. qh and qt point to queue head and tail. - -// Enqueue operation (adds a node "o" at the tail) - -inline static void -Q_enq (CMK_Node *Q, octave_idx_type N, octave_idx_type& qt, const CMK_Node& o) -{ - Q[qt] = o; - qt = (qt + 1) % (N + 1); -} - -// Dequeue operation (removes a node from the head) - -inline static CMK_Node -Q_deq (CMK_Node * Q, octave_idx_type N, octave_idx_type& qh) -{ - CMK_Node r = Q[qh]; - qh = (qh + 1) % (N + 1); - return r; -} - -// Predicate (queue empty) -#define Q_empty(Q, N, qh, qt) ((qh) == (qt)) - -// A simple, array-based binary heap (used as a priority queue for nodes) - -// the left descendant of entry i -#define LEFT(i) (((i) << 1) + 1) // = (2*(i)+1) -// the right descendant of entry i -#define RIGHT(i) (((i) << 1) + 2) // = (2*(i)+2) -// the parent of entry i -#define PARENT(i) (((i) - 1) >> 1) // = floor(((i)-1)/2) - -// Builds a min-heap (the root contains the smallest element). A is an array -// with the graph's nodes, i is a starting position, size is the length of A. - -static void -H_heapify_min (CMK_Node *A, octave_idx_type i, octave_idx_type size) -{ - octave_idx_type j = i; - for (;;) - { - octave_idx_type l = LEFT(j); - octave_idx_type r = RIGHT(j); - - octave_idx_type smallest; - if (l < size && A[l].deg < A[j].deg) - smallest = l; - else - smallest = j; - - if (r < size && A[r].deg < A[smallest].deg) - smallest = r; - - if (smallest != j) - { - std::swap (A[j], A[smallest]); - j = smallest; - } - else - break; - } -} - -// Heap operation insert. Running time is O(log(n)) - -static void -H_insert (CMK_Node *H, octave_idx_type& h, const CMK_Node& o) -{ - octave_idx_type i = h++; - - H[i] = o; - - if (i == 0) - return; - do - { - octave_idx_type p = PARENT(i); - if (H[i].deg < H[p].deg) - { - std::swap (H[i], H[p]); - - i = p; - } - else - break; - } - while (i > 0); -} - -// Heap operation remove-min. Removes the smalles element in O(1) and -// reorganizes the heap optionally in O(log(n)) - -inline static CMK_Node -H_remove_min (CMK_Node *H, octave_idx_type& h, int reorg/*=1*/) -{ - CMK_Node r = H[0]; - H[0] = H[--h]; - if (reorg) - H_heapify_min (H, 0, h); - return r; -} - -// Predicate (heap empty) -#define H_empty(H, h) ((h) == 0) - -// Helper function for the Cuthill-McKee algorithm. Tries to determine a -// pseudo-peripheral node of the graph as starting node. - -static octave_idx_type -find_starting_node (octave_idx_type N, const octave_idx_type *ridx, - const octave_idx_type *cidx, const octave_idx_type *ridx2, - const octave_idx_type *cidx2, octave_idx_type *D, - octave_idx_type start) -{ - CMK_Node w; - - OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); - boolNDArray btmp (dim_vector (1, N), false); - bool *visit = btmp.fortran_vec (); - - octave_idx_type qh = 0; - octave_idx_type qt = 0; - CMK_Node x; - x.id = start; - x.deg = D[start]; - x.dist = 0; - Q_enq (Q, N, qt, x); - visit[start] = true; - - // distance level - octave_idx_type level = 0; - // current largest "eccentricity" - octave_idx_type max_dist = 0; - - for (;;) - { - while (! Q_empty (Q, N, qh, qt)) - { - CMK_Node v = Q_deq (Q, N, qh); - - if (v.dist > x.dist || (v.id != x.id && v.deg > x.deg)) - x = v; - - octave_idx_type i = v.id; - - // add all unvisited neighbors to the queue - octave_idx_type j1 = cidx[i]; - octave_idx_type j2 = cidx2[i]; - while (j1 < cidx[i+1] || j2 < cidx2[i+1]) - { - OCTAVE_QUIT; - - if (j1 == cidx[i+1]) - { - octave_idx_type r2 = ridx2[j2++]; - if (! visit[r2]) - { - // the distance of node j is dist(i)+1 - w.id = r2; - w.deg = D[r2]; - w.dist = v.dist+1; - Q_enq (Q, N, qt, w); - visit[r2] = true; - - if (w.dist > level) - level = w.dist; - } - } - else if (j2 == cidx2[i+1]) - { - octave_idx_type r1 = ridx[j1++]; - if (! visit[r1]) - { - // the distance of node j is dist(i)+1 - w.id = r1; - w.deg = D[r1]; - w.dist = v.dist+1; - Q_enq (Q, N, qt, w); - visit[r1] = true; - - if (w.dist > level) - level = w.dist; - } - } - else - { - octave_idx_type r1 = ridx[j1]; - octave_idx_type r2 = ridx2[j2]; - if (r1 <= r2) - { - if (! visit[r1]) - { - w.id = r1; - w.deg = D[r1]; - w.dist = v.dist+1; - Q_enq (Q, N, qt, w); - visit[r1] = true; - - if (w.dist > level) - level = w.dist; - } - j1++; - if (r1 == r2) - j2++; - } - else - { - if (! visit[r2]) - { - w.id = r2; - w.deg = D[r2]; - w.dist = v.dist+1; - Q_enq (Q, N, qt, w); - visit[r2] = true; - - if (w.dist > level) - level = w.dist; - } - j2++; - } - } - } - } // finish of BFS - - if (max_dist < x.dist) - { - max_dist = x.dist; - - for (octave_idx_type i = 0; i < N; i++) - visit[i] = false; - - visit[x.id] = true; - x.dist = 0; - qt = qh = 0; - Q_enq (Q, N, qt, x); - } - else - break; - } - return x.id; -} - -// Calculates the node's degrees. This means counting the non-zero elements -// in the symmetric matrix' rows. This works for non-symmetric matrices -// as well. - -static octave_idx_type -calc_degrees (octave_idx_type N, const octave_idx_type *ridx, - const octave_idx_type *cidx, octave_idx_type *D) -{ - octave_idx_type max_deg = 0; - - for (octave_idx_type i = 0; i < N; i++) - D[i] = 0; - - for (octave_idx_type j = 0; j < N; j++) - { - for (octave_idx_type i = cidx[j]; i < cidx[j+1]; i++) - { - OCTAVE_QUIT; - octave_idx_type k = ridx[i]; - // there is a non-zero element (k,j) - D[k]++; - if (D[k] > max_deg) - max_deg = D[k]; - // if there is no element (j,k) there is one in - // the symmetric matrix: - if (k != j) - { - bool found = false; - for (octave_idx_type l = cidx[k]; l < cidx[k + 1]; l++) - { - OCTAVE_QUIT; - - if (ridx[l] == j) - { - found = true; - break; - } - else if (ridx[l] > j) - break; - } - - if (! found) - { - // A(j,k) == 0 - D[j]++; - if (D[j] > max_deg) - max_deg = D[j]; - } - } - } - } - return max_deg; -} - -// Transpose of the structure of a square sparse matrix - -static void -transpose (octave_idx_type N, const octave_idx_type *ridx, - const octave_idx_type *cidx, octave_idx_type *ridx2, - octave_idx_type *cidx2) -{ - octave_idx_type nz = cidx[N]; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, w, N + 1); - for (octave_idx_type i = 0; i < N; i++) - w[i] = 0; - for (octave_idx_type i = 0; i < nz; i++) - w[ridx[i]]++; - nz = 0; - for (octave_idx_type i = 0; i < N; i++) - { - OCTAVE_QUIT; - cidx2[i] = nz; - nz += w[i]; - w[i] = cidx2[i]; - } - cidx2[N] = nz; - w[N] = nz; - - for (octave_idx_type j = 0; j < N; j++) - for (octave_idx_type k = cidx[j]; k < cidx[j + 1]; k++) - { - OCTAVE_QUIT; - octave_idx_type q = w[ridx[k]]++; - ridx2[q] = j; - } -} - -// An implementation of the Cuthill-McKee algorithm. -DEFUN_DLD (symrcm, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{p} =} symrcm (@var{S})\n\ -Return the symmetric reverse Cuthill-McKee permutation of @var{S}.\n\ -@var{p} is a permutation vector such that\n\ -@code{@var{S}(@var{p}, @var{p})} tends to have its diagonal elements\n\ -closer to the diagonal than @var{S}. This is a good preordering for LU\n\ -or Cholesky@tie{}factorization of matrices that come from ``long, skinny''\n\ -problems. It works for both symmetric and asymmetric @var{S}.\n\ -\n\ -The algorithm represents a heuristic approach to the NP-complete\n\ -bandwidth minimization problem. The implementation is based in the\n\ -descriptions found in\n\ -\n\ -E. Cuthill, J. McKee. @cite{Reducing the Bandwidth of Sparse Symmetric\n\ -Matrices}. Proceedings of the 24th ACM National Conference, 157--172\n\ -1969, Brandon Press, New Jersey.\n\ -\n\ -A. George, J.W.H. Liu. @cite{Computer Solution of Large Sparse\n\ -Positive Definite Systems}, Prentice Hall Series in Computational\n\ -Mathematics, ISBN 0-13-165274-5, 1981.\n\ -\n\ -@seealso{colperm, colamd, symamd}\n\ -@end deftypefn") -{ - octave_value retval; - int nargin = args.length (); - - if (nargin != 1) - { - print_usage (); - return retval; - } - - octave_value arg = args(0); - - // the parameter of the matrix is converted into a sparse matrix - //(if necessary) - octave_idx_type *cidx; - octave_idx_type *ridx; - SparseMatrix Ar; - SparseComplexMatrix Ac; - - if (arg.is_real_type ()) - { - Ar = arg.sparse_matrix_value (); - // Note cidx/ridx are const, so use xridx and xcidx... - cidx = Ar.xcidx (); - ridx = Ar.xridx (); - } - else - { - Ac = arg.sparse_complex_matrix_value (); - cidx = Ac.xcidx (); - ridx = Ac.xridx (); - } - - if (error_state) - return retval; - - octave_idx_type nr = arg.rows (); - octave_idx_type nc = arg.columns (); - - if (nr != nc) - { - gripe_square_matrix_required ("symrcm"); - return retval; - } - - if (nr == 0 && nc == 0) - return octave_value (NDArray (dim_vector (1, 0))); - - // sizes of the heaps - octave_idx_type s = 0; - - // head- and tail-indices for the queue - octave_idx_type qt = 0, qh = 0; - CMK_Node v, w; - // dimension of the matrix - octave_idx_type N = nr; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, cidx2, N + 1); - OCTAVE_LOCAL_BUFFER (octave_idx_type, ridx2, cidx[N]); - transpose (N, ridx, cidx, ridx2, cidx2); - - // the permutation vector - NDArray P (dim_vector (1, N)); - - // compute the node degrees - OCTAVE_LOCAL_BUFFER (octave_idx_type, D, N); - octave_idx_type max_deg = calc_degrees (N, ridx, cidx, D); - - // if none of the nodes has a degree > 0 (a matrix of zeros) - // the return value corresponds to the identity permutation - if (max_deg == 0) - { - for (octave_idx_type i = 0; i < N; i++) - P(i) = i; - return octave_value (P); - } - - // a heap for the a node's neighbors. The number of neighbors is - // limited by the maximum degree max_deg: - OCTAVE_LOCAL_BUFFER (CMK_Node, S, max_deg); - - // a queue for the BFS. The array is always one element larger than - // the number of entries that are stored. - OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); - - // a counter (for building the permutation) - octave_idx_type c = -1; - - // upper bound for the bandwidth (=quality of solution) - // initialize the bandwidth of the graph with 0. B contains the - // the maximum of the theoretical lower limits of the subgraphs - // bandwidths. - octave_idx_type B = 0; - - // mark all nodes as unvisited; with the exception of the nodes - // that have degree==0 and build a CC of the graph. - - boolNDArray btmp (dim_vector (1, N), false); - bool *visit = btmp.fortran_vec (); - - do - { - // locate an unvisited starting node of the graph - octave_idx_type i; - for (i = 0; i < N; i++) - if (! visit[i]) - break; - - // locate a probably better starting node - v.id = find_starting_node (N, ridx, cidx, ridx2, cidx2, D, i); - - // mark the node as visited and enqueue it (a starting node - // for the BFS). Since the node will be a root of a spanning - // tree, its dist is 0. - v.deg = D[v.id]; - v.dist = 0; - visit[v.id] = true; - Q_enq (Q, N, qt, v); - - // lower bound for the bandwidth of a subgraph - // keep a "level" in the spanning tree (= min. distance to the - // root) for determining the bandwidth of the computed - // permutation P - octave_idx_type Bsub = 0; - // min. dist. to the root is 0 - octave_idx_type level = 0; - // the root is the first/only node on level 0 - octave_idx_type level_N = 1; - - while (! Q_empty (Q, N, qh, qt)) - { - v = Q_deq (Q, N, qh); - i = v.id; - - c++; - - // for computing the inverse permutation P where - // A(inv(P),inv(P)) or P'*A*P is banded - // P(i) = c; - - // for computing permutation P where - // A(P(i),P(j)) or P*A*P' is banded - P(c) = i; - - // put all unvisited neighbors j of node i on the heap - s = 0; - octave_idx_type j1 = cidx[i]; - octave_idx_type j2 = cidx2[i]; - - OCTAVE_QUIT; - while (j1 < cidx[i+1] || j2 < cidx2[i+1]) - { - OCTAVE_QUIT; - if (j1 == cidx[i+1]) - { - octave_idx_type r2 = ridx2[j2++]; - if (! visit[r2]) - { - // the distance of node j is dist(i)+1 - w.id = r2; - w.deg = D[r2]; - w.dist = v.dist+1; - H_insert (S, s, w); - visit[r2] = true; - } - } - else if (j2 == cidx2[i+1]) - { - octave_idx_type r1 = ridx[j1++]; - if (! visit[r1]) - { - w.id = r1; - w.deg = D[r1]; - w.dist = v.dist+1; - H_insert (S, s, w); - visit[r1] = true; - } - } - else - { - octave_idx_type r1 = ridx[j1]; - octave_idx_type r2 = ridx2[j2]; - if (r1 <= r2) - { - if (! visit[r1]) - { - w.id = r1; - w.deg = D[r1]; - w.dist = v.dist+1; - H_insert (S, s, w); - visit[r1] = true; - } - j1++; - if (r1 == r2) - j2++; - } - else - { - if (! visit[r2]) - { - w.id = r2; - w.deg = D[r2]; - w.dist = v.dist+1; - H_insert (S, s, w); - visit[r2] = true; - } - j2++; - } - } - } - - // add the neighbors to the queue (sorted by node degree) - while (! H_empty (S, s)) - { - OCTAVE_QUIT; - - // locate a neighbor of i with minimal degree in O(log(N)) - v = H_remove_min (S, s, 1); - - // entered the BFS a new level? - if (v.dist > level) - { - // adjustment of bandwith: - // "[...] the minimum bandwidth that - // can be obtained [...] is the - // maximum number of nodes per level" - if (Bsub < level_N) - Bsub = level_N; - - level = v.dist; - // v is the first node on the new level - level_N = 1; - } - else - { - // there is no new level but another node on - // this level: - level_N++; - } - - // enqueue v in O(1) - Q_enq (Q, N, qt, v); - } - - // synchronize the bandwidth with level_N once again: - if (Bsub < level_N) - Bsub = level_N; - } - // finish of BFS. If there are still unvisited nodes in the graph - // then it is split into CCs. The computed bandwidth is the maximum - // of all subgraphs. Update: - if (Bsub > B) - B = Bsub; - } - // are there any nodes left? - while (c+1 < N); - - // compute the reverse-ordering - s = N / 2 - 1; - for (octave_idx_type i = 0, j = N - 1; i <= s; i++, j--) - std::swap (P.elem (i), P.elem (j)); - - // increment all indices, since Octave is not C - return octave_value (P+1); -}
--- a/src/DLD-FUNCTIONS/tsearch.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - -Copyright (C) 2002-2012 Andreas Stahel - -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/>. - -*/ - -// Author: Andreas Stahel <Andreas.Stahel@hta-bi.bfh.ch> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <iostream> -#include <fstream> -#include <string> - -#include "lo-ieee.h" -#include "lo-math.h" - -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" -#include "parse.h" - -inline double max (double a, double b, double c) -{ - if (a < b) - return (b < c ? c : b); - else - return (a < c ? c : a); -} - -inline double min (double a, double b, double c) -{ - if (a > b) - return (b > c ? c : b); - else - return (a > c ? c : a); -} - -#define REF(x,k,i) x(static_cast<octave_idx_type>(elem((k), (i))) - 1) - -// for large data set the algorithm is very slow -// one should presort (how?) either the elements of the points of evaluation -// to cut down the time needed to decide which triangle contains the -// given point - -// e.g., build up a neighbouring triangle structure and use a simplex-like -// method to traverse it - -DEFUN_DLD (tsearch, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{idx} =} tsearch (@var{x}, @var{y}, @var{t}, @var{xi}, @var{yi})\n\ -Search for the enclosing Delaunay convex hull. For @code{@var{t} =\n\ -delaunay (@var{x}, @var{y})}, finds the index in @var{t} containing the\n\ -points @code{(@var{xi}, @var{yi})}. For points outside the convex hull,\n\ -@var{idx} is NaN.\n\ -@seealso{delaunay, delaunayn}\n\ -@end deftypefn") -{ - const double eps=1.0e-12; - - octave_value_list retval; - const int nargin = args.length (); - if (nargin != 5) - { - print_usage (); - return retval; - } - - const ColumnVector x (args(0).vector_value ()); - const ColumnVector y (args(1).vector_value ()); - const Matrix elem (args(2).matrix_value ()); - const ColumnVector xi (args(3).vector_value ()); - const ColumnVector yi (args(4).vector_value ()); - - if (error_state) - return retval; - - const octave_idx_type nelem = elem.rows (); - - ColumnVector minx (nelem); - ColumnVector maxx (nelem); - ColumnVector miny (nelem); - ColumnVector maxy (nelem); - for (octave_idx_type k = 0; k < nelem; k++) - { - minx(k) = min (REF (x, k, 0), REF (x, k, 1), REF (x, k, 2)) - eps; - maxx(k) = max (REF (x, k, 0), REF (x, k, 1), REF (x, k, 2)) + eps; - miny(k) = min (REF (y, k, 0), REF (y, k, 1), REF (y, k, 2)) - eps; - maxy(k) = max (REF (y, k, 0), REF (y, k, 1), REF (y, k, 2)) + eps; - } - - const octave_idx_type np = xi.length (); - ColumnVector values (np); - - double x0 = 0.0, y0 = 0.0; - double a11 = 0.0, a12 = 0.0, a21 = 0.0, a22 = 0.0, det = 0.0; - - octave_idx_type k = nelem; // k is a counter of elements - for (octave_idx_type kp = 0; kp < np; kp++) - { - const double xt = xi(kp); - const double yt = yi(kp); - - // check if last triangle contains the next point - if (k < nelem) - { - const double dx1 = xt - x0; - const double dx2 = yt - y0; - const double c1 = (a22 * dx1 - a21 * dx2) / det; - const double c2 = (-a12 * dx1 + a11 * dx2) / det; - if (c1 >= -eps && c2 >= -eps && (c1 + c2) <= (1 + eps)) - { - values(kp) = double(k+1); - continue; - } - } - - // it doesn't, so go through all elements - for (k = 0; k < nelem; k++) - { - OCTAVE_QUIT; - if (xt >= minx(k) && xt <= maxx(k) && yt >= miny(k) && yt <= maxy(k)) - { - // element inside the minimum rectangle: examine it closely - x0 = REF (x, k, 0); - y0 = REF (y, k, 0); - a11 = REF (x, k, 1) - x0; - a12 = REF (y, k, 1) - y0; - a21 = REF (x, k, 2) - x0; - a22 = REF (y, k, 2) - y0; - det = a11 * a22 - a21 * a12; - - // solve the system - const double dx1 = xt - x0; - const double dx2 = yt - y0; - const double c1 = (a22 * dx1 - a21 * dx2) / det; - const double c2 = (-a12 * dx1 + a11 * dx2) / det; - if ((c1 >= -eps) && (c2 >= -eps) && ((c1 + c2) <= (1 + eps))) - { - values(kp) = double(k+1); - break; - } - } //endif # examine this element closely - } //endfor # each element - - if (k == nelem) - values(kp) = lo_ieee_nan_value (); - - } //endfor # kp - - retval(0) = values; - - return retval; -} - -/* -%!shared x, y, tri -%! x = [-1;-1;1]; -%! y = [-1;1;-1]; -%! tri = [1, 2, 3]; -%!assert (tsearch (x,y,tri,-1,-1), 1) -%!assert (tsearch (x,y,tri, 1,-1), 1) -%!assert (tsearch (x,y,tri,-1, 1), 1) -%!assert (tsearch (x,y,tri,-1/3, -1/3), 1) -%!assert (tsearch (x,y,tri, 1, 1), NaN) - -%!error tsearch () -*/
--- a/src/DLD-FUNCTIONS/urlwrite.cc Tue Jul 31 20:46:47 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1740 +0,0 @@ -// urlwrite and urlread, a curl front-end for octave -/* - -Copyright (C) 2006-2012 Alexander Barth -Copyright (C) 2009 David Bateman - -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/>. - -*/ - -// Author: Alexander Barth <abarth@marine.usf.edu> -// Adapted-By: jwe - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string> -#include <fstream> -#include <iomanip> -#include <iostream> - -#include "dir-ops.h" -#include "file-ops.h" -#include "file-stat.h" -#include "oct-env.h" -#include "glob-match.h" - -#include "defun-dld.h" -#include "error.h" -#include "oct-obj.h" -#include "ov-cell.h" -#include "pager.h" -#include "oct-map.h" -#include "oct-refcount.h" -#include "unwind-prot.h" - -#ifdef HAVE_CURL - -#include <curl/curl.h> -#include <curl/curlver.h> -#include <curl/easy.h> - -// Backwards compatibility for curl < 7.17.0 -#if LIBCURL_VERSION_NUM < 0x071100 -#define CURLOPT_DIRLISTONLY CURLOPT_FTPLISTONLY -#endif - -static int -write_data (void *buffer, size_t size, size_t nmemb, void *streamp) -{ - std::ostream& stream = *(static_cast<std::ostream*> (streamp)); - stream.write (static_cast<const char*> (buffer), size*nmemb); - return (stream.fail () ? 0 : size * nmemb); -} - -static int -read_data (void *buffer, size_t size, size_t nmemb, void *streamp) -{ - std::istream& stream = *(static_cast<std::istream*> (streamp)); - stream.read (static_cast<char*> (buffer), size*nmemb); - if (stream.eof ()) - return stream.gcount (); - else - return (stream.fail () ? 0 : size * nmemb); -} - -static size_t -throw_away (void *, size_t size, size_t nmemb, void *) -{ - return static_cast<size_t>(size * nmemb); -} - -class -curl_handle -{ -private: - class - curl_handle_rep - { - public: - curl_handle_rep (void) : count (1), valid (true), ascii (false) - { - curl = curl_easy_init (); - if (!curl) - error ("can not create curl handle"); - } - - ~curl_handle_rep (void) - { - if (curl) - curl_easy_cleanup (curl); - } - - bool is_valid (void) const - { - return valid; - } - - bool perform (bool curlerror) const - { - bool retval = false; - if (!error_state) - { - BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; - - errnum = curl_easy_perform (curl); - if (errnum != CURLE_OK) - { - if (curlerror) - error ("%s", curl_easy_strerror (errnum)); - } - else - retval = true; - - END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; - } - return retval; - } - - CURL* handle (void) const - { - return curl; - } - - bool is_ascii (void) const - { - return ascii; - } - - bool is_binary (void) const - { - return !ascii; - } - - octave_refcount<size_t> count; - std::string host; - bool valid; - bool ascii; - mutable CURLcode errnum; - - private: - CURL *curl; - - // No copying! - - curl_handle_rep (const curl_handle_rep& ov); - - curl_handle_rep& operator = (const curl_handle_rep&); - }; - -public: - -// I'd love to rewrite this as a private method of the curl_handle -// class, but you can't pass the va_list from the wrapper setopt to -// the curl_easy_setopt function. -#define setopt(option, parameter) \ - { \ - CURLcode res = curl_easy_setopt (rep->handle (), option, parameter); \ - if (res != CURLE_OK) \ - error ("%s", curl_easy_strerror (res)); \ - } - - curl_handle (void) : rep (new curl_handle_rep ()) - { - rep->valid = false; - } - - curl_handle (const std::string& _host, const std::string& user, - const std::string& passwd) : - rep (new curl_handle_rep ()) - { - rep->host = _host; - init (user, passwd, std::cin, octave_stdout); - - std::string url = "ftp://" + _host; - setopt (CURLOPT_URL, url.c_str ()); - - // Setup the link, with no transfer - if (!error_state) - perform (); - } - - curl_handle (const std::string& url, const std::string& method, - const Cell& param, std::ostream& os, bool& retval) : - rep (new curl_handle_rep ()) - { - retval = false; - - init ("", "", std::cin, os); - - setopt (CURLOPT_NOBODY, 0); - - // Don't need to store the parameters here as we can't change - // the URL after the handle is created - std::string query_string = form_query_string (param); - - if (method == "get") - { - query_string = url + "?" + query_string; - setopt (CURLOPT_URL, query_string.c_str ()); - } - else if (method == "post") - { - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_POSTFIELDS, query_string.c_str ()); - } - else - setopt (CURLOPT_URL, url.c_str ()); - - if (!error_state) - retval = perform (false); - } - - curl_handle (const curl_handle& h) : rep (h.rep) - { - rep->count++; - } - - ~curl_handle (void) - { - if (--rep->count == 0) - delete rep; - } - - curl_handle& operator = (const curl_handle& h) - { - if (this != &h) - { - if (--rep->count == 0) - delete rep; - - rep = h.rep; - rep->count++; - } - return *this; - } - - bool is_valid (void) const - { - return rep->is_valid (); - } - - std::string lasterror (void) const - { - return std::string (curl_easy_strerror (rep->errnum)); - } - - void set_ostream (std::ostream& os) const - { - setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os)); - } - - void set_istream (std::istream& is) const - { - setopt (CURLOPT_READDATA, static_cast<void*> (&is)); - } - - void ascii (void) const - { - setopt (CURLOPT_TRANSFERTEXT, 1); - rep->ascii = true; - } - - void binary (void) const - { - setopt (CURLOPT_TRANSFERTEXT, 0); - rep->ascii = false; - } - - bool is_ascii (void) const - { - return rep->is_ascii (); - } - - bool is_binary (void) const - { - return rep->is_binary (); - } - - void cwd (const std::string& path) const - { - struct curl_slist *slist = 0; - std::string cmd = "cwd " + path; - slist = curl_slist_append (slist, cmd.c_str ()); - setopt (CURLOPT_POSTQUOTE, slist); - if (! error_state) - perform (); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - } - - void del (const std::string& file) const - { - struct curl_slist *slist = 0; - std::string cmd = "dele " + file; - slist = curl_slist_append (slist, cmd.c_str ()); - setopt (CURLOPT_POSTQUOTE, slist); - if (! error_state) - perform (); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - } - - void rmdir (const std::string& path) const - { - struct curl_slist *slist = 0; - std::string cmd = "rmd " + path; - slist = curl_slist_append (slist, cmd.c_str ()); - setopt (CURLOPT_POSTQUOTE, slist); - if (! error_state) - perform (); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - } - - bool mkdir (const std::string& path, bool curlerror = true) const - { - bool retval = false; - struct curl_slist *slist = 0; - std::string cmd = "mkd " + path; - slist = curl_slist_append (slist, cmd.c_str ()); - setopt (CURLOPT_POSTQUOTE, slist); - if (! error_state) - retval = perform (curlerror); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - return retval; - } - - void rename (const std::string& oldname, const std::string& newname) const - { - struct curl_slist *slist = 0; - std::string cmd = "rnfr " + oldname; - slist = curl_slist_append (slist, cmd.c_str ()); - cmd = "rnto " + newname; - slist = curl_slist_append (slist, cmd.c_str ()); - setopt (CURLOPT_POSTQUOTE, slist); - if (! error_state) - perform (); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - } - - void put (const std::string& file, std::istream& is) const - { - std::string url = "ftp://" + rep->host + "/" + file; - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_UPLOAD, 1); - setopt (CURLOPT_NOBODY, 0); - set_istream (is); - if (! error_state) - perform (); - set_istream (std::cin); - setopt (CURLOPT_NOBODY, 1); - setopt (CURLOPT_UPLOAD, 0); - url = "ftp://" + rep->host; - setopt (CURLOPT_URL, url.c_str ()); - } - - void get (const std::string& file, std::ostream& os) const - { - std::string url = "ftp://" + rep->host + "/" + file; - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_NOBODY, 0); - set_ostream (os); - if (! error_state) - perform (); - set_ostream (octave_stdout); - setopt (CURLOPT_NOBODY, 1); - url = "ftp://" + rep->host; - setopt (CURLOPT_URL, url.c_str ()); - } - - void dir (void) const - { - std::string url = "ftp://" + rep->host + "/"; - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_NOBODY, 0); - if (! error_state) - perform (); - setopt (CURLOPT_NOBODY, 1); - url = "ftp://" + rep->host; - setopt (CURLOPT_URL, url.c_str ()); - } - - string_vector list (void) const - { - std::ostringstream buf; - std::string url = "ftp://" + rep->host + "/"; - setopt (CURLOPT_WRITEDATA, static_cast<void*> (&buf)); - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_DIRLISTONLY, 1); - setopt (CURLOPT_NOBODY, 0); - if (! error_state) - perform (); - setopt (CURLOPT_NOBODY, 1); - url = "ftp://" + rep->host; - setopt (CURLOPT_WRITEDATA, static_cast<void*> (&octave_stdout)); - setopt (CURLOPT_DIRLISTONLY, 0); - setopt (CURLOPT_URL, url.c_str ()); - - // Count number of directory entries - std::string str = buf.str (); - octave_idx_type n = 0; - size_t pos = 0; - while (true) - { - pos = str.find_first_of ('\n', pos); - if (pos == std::string::npos) - break; - pos++; - n++; - } - string_vector retval (n); - pos = 0; - for (octave_idx_type i = 0; i < n; i++) - { - size_t newpos = str.find_first_of ('\n', pos); - if (newpos == std::string::npos) - break; - - retval(i) = str.substr(pos, newpos - pos); - pos = newpos + 1; - } - return retval; - } - - void get_fileinfo (const std::string& filename, double& filesize, - time_t& filetime, bool& fileisdir) const - { - std::string path = pwd (); - - std::string url = "ftp://" + rep->host + "/" + path + "/" + filename; - setopt (CURLOPT_URL, url.c_str ()); - setopt (CURLOPT_FILETIME, 1); - setopt (CURLOPT_HEADERFUNCTION, throw_away); - setopt (CURLOPT_WRITEFUNCTION, throw_away); - - // FIXME - // The MDTM command fails for a directory on the servers I tested - // so this is a means of testing for directories. It also means - // I can't get the date of directories! - if (! error_state) - { - if (! perform (false)) - { - fileisdir = true; - filetime = -1; - filesize = 0; - } - else - { - fileisdir = false; - time_t ft; - curl_easy_getinfo (rep->handle (), CURLINFO_FILETIME, &ft); - filetime = ft; - double fs; - curl_easy_getinfo (rep->handle (), - CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs); - filesize = fs; - } - } - - setopt (CURLOPT_WRITEFUNCTION, write_data); - setopt (CURLOPT_HEADERFUNCTION, 0); - setopt (CURLOPT_FILETIME, 0); - url = "ftp://" + rep->host; - setopt (CURLOPT_URL, url.c_str ()); - - // The MDTM command seems to reset the path to the root with the - // servers I tested with, so cd again into the correct path. Make - // the path absolute so that this will work even with servers that - // don't end up in the root after an MDTM command. - cwd ("/" + path); - } - - std::string pwd (void) const - { - struct curl_slist *slist = 0; - std::string retval; - std::ostringstream buf; - - slist = curl_slist_append (slist, "pwd"); - setopt (CURLOPT_POSTQUOTE, slist); - setopt (CURLOPT_HEADERFUNCTION, write_data); - setopt (CURLOPT_WRITEHEADER, static_cast<void *>(&buf)); - - if (! error_state) - { - perform (); - retval = buf.str (); - - // Can I assume that the path is alway in "" on the last line - size_t pos2 = retval.rfind ('"'); - size_t pos1 = retval.rfind ('"', pos2 - 1); - retval = retval.substr (pos1 + 1, pos2 - pos1 - 1); - } - setopt (CURLOPT_HEADERFUNCTION, 0); - setopt (CURLOPT_WRITEHEADER, 0); - setopt (CURLOPT_POSTQUOTE, 0); - curl_slist_free_all (slist); - - return retval; - } - - bool perform (bool curlerror = true) const - { - return rep->perform (curlerror); - } - -private: - curl_handle_rep *rep; - - std::string form_query_string (const Cell& param) - { - std::ostringstream query; - - for (int i = 0; i < param.numel (); i += 2) - { - std::string name = param(i).string_value (); - std::string text = param(i+1).string_value (); - - // Encode strings. - char *enc_name = curl_easy_escape (rep->handle (), name.c_str (), - name.length ()); - char *enc_text = curl_easy_escape (rep->handle (), text.c_str (), - text.length ()); - - query << enc_name << "=" << enc_text; - - curl_free (enc_name); - curl_free (enc_text); - - if (i < param.numel ()-1) - query << "&"; - } - - query.flush (); - - return query.str (); - } - - void init (const std::string& user, const std::string& passwd, - std::istream& is, std::ostream& os) - { - // No data transfer by default - setopt (CURLOPT_NOBODY, 1); - - // Set the username and password - std::string userpwd = user; - if (! passwd.empty ()) - userpwd += ":" + passwd; - if (! userpwd.empty ()) - setopt (CURLOPT_USERPWD, userpwd.c_str ()); - - // Define our callback to get called when there's data to be written. - setopt (CURLOPT_WRITEFUNCTION, write_data); - - // Set a pointer to our struct to pass to the callback. - setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os)); - - // Define our callback to get called when there's data to be read - setopt (CURLOPT_READFUNCTION, read_data); - - // Set a pointer to our struct to pass to the callback. - setopt (CURLOPT_READDATA, static_cast<void*> (&is)); - - // Follow redirects. - setopt (CURLOPT_FOLLOWLOCATION, true); - - // Don't use EPSV since connecting to sites that don't support it - // will hang for some time (3 minutes?) before moving on to try PASV - // instead. - setopt (CURLOPT_FTP_USE_EPSV, false); - - setopt (CURLOPT_NOPROGRESS, true); - setopt (CURLOPT_FAILONERROR, true); - - setopt (CURLOPT_POSTQUOTE, 0); - setopt (CURLOPT_QUOTE, 0); - } - -#undef setopt -}; - -class -curl_handles -{ -public: - - typedef std::map<std::string, curl_handle>::iterator iterator; - typedef std::map<std::string, curl_handle>::const_iterator const_iterator; - - curl_handles (void) : map () - { - curl_global_init (CURL_GLOBAL_DEFAULT); - } - - ~curl_handles (void) - { - // Remove the elements of the map explicitly as they should - // be deleted before the call to curl_global_cleanup - map.erase (begin (), end ()); - - curl_global_cleanup (); - } - - iterator begin (void) { return iterator (map.begin ()); } - const_iterator begin (void) const { return const_iterator (map.begin ()); } - - iterator end (void) { return iterator (map.end ()); } - const_iterator end (void) const { return const_iterator (map.end ()); } - - iterator seek (const std::string& k) { return map.find (k); } - const_iterator seek (const std::string& k) const { return map.find (k); } - - std::string key (const_iterator p) const { return p->first; } - - curl_handle& contents (const std::string& k) - { - return map[k]; - } - - curl_handle contents (const std::string& k) const - { - const_iterator p = seek (k); - return p != end () ? p->second : curl_handle (); - } - - curl_handle& contents (iterator p) - { return p->second; } - - curl_handle contents (const_iterator p) const - { return p->second; } - - void del (const std::string& k) - { - iterator p = map.find (k); - - if (p != map.end ()) - map.erase (p); - } - -private: - std::map<std::string, curl_handle> map; -}; - -static curl_handles handles; - -static void -cleanup_urlwrite (std::string filename) -{ - octave_unlink (filename); -} - -static void -reset_path (const curl_handle curl) -{ - curl.cwd (".."); -} - -static void -delete_file (std::string file) -{ - octave_unlink (file); -} -#endif - -DEFUN_DLD (urlwrite, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\ -@deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\ -@deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\ -@deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\ -Download a remote file specified by its @var{url} and save it as\n\ -@var{localfile}. For example:\n\ -\n\ -@example\n\ -@group\n\ -urlwrite (\"ftp://ftp.octave.org/pub/octave/README\",\n\ - \"README.txt\");\n\ -@end group\n\ -@end example\n\ -\n\ -The full path of the downloaded file is returned in @var{f}. The\n\ -variable @var{success} is 1 if the download was successful,\n\ -otherwise it is 0 in which case @var{message} contains an error\n\ -message. If no output argument is specified and an error occurs,\n\ -then the error is signaled through Octave's error handling mechanism.\n\ -\n\ -This function uses libcurl. Curl supports, among others, the HTTP,\n\ -FTP and FILE protocols. Username and password may be specified in\n\ -the URL, for example:\n\ -\n\ -@example\n\ -@group\n\ -urlwrite (\"http://username:password@@example.com/file.txt\",\n\ - \"file.txt\");\n\ -@end group\n\ -@end example\n\ -\n\ -GET and POST requests can be specified by @var{method} and @var{param}.\n\ -The parameter @var{method} is either @samp{get} or @samp{post}\n\ -and @var{param} is a cell array of parameter and value pairs.\n\ -For example:\n\ -\n\ -@example\n\ -@group\n\ -urlwrite (\"http://www.google.com/search\", \"search.html\",\n\ - \"get\", @{\"query\", \"octave\"@});\n\ -@end group\n\ -@end example\n\ -@seealso{urlread}\n\ -@end deftypefn") -{ - octave_value_list retval; - -#ifdef HAVE_CURL - - int nargin = args.length (); - - // verify arguments - if (nargin != 2 && nargin != 4) - { - print_usage (); - return retval; - } - - std::string url = args(0).string_value (); - - if (error_state) - { - error ("urlwrite: URL must be a character string"); - return retval; - } - - // name to store the file if download is succesful - std::string filename = args(1).string_value (); - - if (error_state) - { - error ("urlwrite: LOCALFILE must be a character string"); - return retval; - } - - std::string method; - Cell param; // empty cell array - - if (nargin == 4) - { - method = args(2).string_value (); - - if (error_state) - { - error ("urlwrite: METHOD must be \"get\" or \"post\""); - return retval; - } - - if (method != "get" && method != "post") - { - error ("urlwrite: METHOD must be \"get\" or \"post\""); - return retval; - } - - param = args(3).cell_value (); - - if (error_state) - { - error ("urlwrite: parameters (PARAM) for get and post requests must be given as a cell"); - return retval; - } - - - if (param.numel () % 2 == 1 ) - { - error ("urlwrite: number of elements in PARAM must be even"); - return retval; - } - } - - // The file should only be deleted if it doesn't initially exist, we - // create it, and the download fails. We use unwind_protect to do - // it so that the deletion happens no matter how we exit the function. - - file_stat fs (filename); - - std::ofstream ofile (filename.c_str (), std::ios::out | std::ios::binary); - - if (! ofile.is_open ()) - { - error ("urlwrite: unable to open file"); - return retval; - } - - unwind_protect_safe frame; - - frame.add_fcn (cleanup_urlwrite, filename); - - bool ok; - curl_handle curl = curl_handle (url, method, param, ofile, ok); - - ofile.close (); - - if (!error_state) - frame.discard (); - else - frame.run (); - - if (nargout > 0) - { - if (ok) - { - retval(2) = std::string (); - retval(1) = true; - retval(0) = octave_env::make_absolute (filename); - } - else - { - retval(2) = curl.lasterror (); - retval(1) = false; - retval(0) = std::string (); - } - } - - if (nargout < 2 && ! ok) - error ("urlwrite: curl: %s", curl.lasterror ().c_str ()); - -#else - error ("urlwrite: not available in this version of Octave"); -#endif - - return retval; -} - -DEFUN_DLD (urlread, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\ -@deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\ -@deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\ -@deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\ -Download a remote file specified by its @var{url} and return its content\n\ -in string @var{s}. For example:\n\ -\n\ -@example\n\ -s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\ -@end example\n\ -\n\ -The variable @var{success} is 1 if the download was successful,\n\ -otherwise it is 0 in which case @var{message} contains an error\n\ -message. If no output argument is specified and an error occurs,\n\ -then the error is signaled through Octave's error handling mechanism.\n\ -\n\ -This function uses libcurl. Curl supports, among others, the HTTP,\n\ -FTP and FILE protocols. Username and password may be specified in the\n\ -URL@. For example:\n\ -\n\ -@example\n\ -s = urlread (\"http://user:password@@example.com/file.txt\");\n\ -@end example\n\ -\n\ -GET and POST requests can be specified by @var{method} and @var{param}.\n\ -The parameter @var{method} is either @samp{get} or @samp{post}\n\ -and @var{param} is a cell array of parameter and value pairs.\n\ -For example:\n\ -\n\ -@example\n\ -@group\n\ -s = urlread (\"http://www.google.com/search\", \"get\",\n\ - @{\"query\", \"octave\"@});\n\ -@end group\n\ -@end example\n\ -@seealso{urlwrite}\n\ -@end deftypefn") -{ - // Octave's return value - octave_value_list retval; - -#ifdef HAVE_CURL - - int nargin = args.length (); - - // verify arguments - if (nargin != 1 && nargin != 3) - { - print_usage (); - return retval; - } - - std::string url = args(0).string_value (); - - if (error_state) - { - error ("urlread: URL must be a character string"); - return retval; - } - - std::string method; - Cell param; // empty cell array - - if (nargin == 3) - { - method = args(1).string_value (); - - if (error_state) - { - error ("urlread: METHOD must be \"get\" or \"post\""); - return retval; - } - - if (method != "get" && method != "post") - { - error ("urlread: METHOD must be \"get\" or \"post\""); - return retval; - } - - param = args(2).cell_value (); - - if (error_state) - { - error ("urlread: parameters (PARAM) for get and post requests must be given as a cell"); - return retval; - } - - if (param.numel () % 2 == 1 ) - { - error ("urlread: number of elements in PARAM must be even"); - return retval; - } - } - - std::ostringstream buf; - - bool ok; - curl_handle curl = curl_handle (url, method, param, buf, ok); - - if (nargout > 0) - { - // Return empty string if no error occured. - retval(2) = ok ? "" : curl.lasterror (); - retval(1) = ok; - retval(0) = buf.str (); - } - - if (nargout < 2 && ! ok) - error ("urlread: curl: %s", curl.lasterror().c_str()); - -#else - error ("urlread: not available in this version of Octave"); -#endif - - return retval; -} - -DEFUN_DLD (__ftp__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp__ (@var{handle}, @var{host})\n\ -@deftypefnx {Loadable Function} {} __ftp__ (@var{handle}, @var{host}, @var{username}, @var{password})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - std::string handle; - std::string host; - std::string user = "anonymous"; - std::string passwd = ""; - - if (nargin < 2 || nargin > 4) - error ("incorrect number of arguments"); - else - { - handle = args(0).string_value (); - host = args(1).string_value (); - - if (nargin > 1) - user = args(2).string_value (); - - if (nargin > 2) - passwd = args(3).string_value (); - - if (!error_state) - { - handles.contents (handle) = curl_handle (host, user, passwd); - - if (error_state) - handles.del (handle); - } - } -#else - error ("__ftp__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_pwd__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_pwd__ (@var{handle})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ - octave_value retval; -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_pwd__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - retval = curl.pwd (); - else - error ("__ftp_pwd__: invalid ftp handle"); - } - } -#else - error ("__ftp_pwd__: not available in this version of Octave"); -#endif - - return retval; -} - -DEFUN_DLD (__ftp_cwd__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_cwd__ (@var{handle}, @var{path})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1 && nargin != 2) - error ("__ftp_cwd__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string path = ""; - - if (nargin > 1) - path = args(1).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.cwd (path); - else - error ("__ftp_cwd__: invalid ftp handle"); - } - } -#else - error ("__ftp_cwd__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_dir__, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_dir__ (@var{handle})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ - octave_value retval; -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_dir__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - { - if (nargout == 0) - curl.dir (); - else - { - string_vector sv = curl.list (); - octave_idx_type n = sv.length (); - if (n == 0) - { - string_vector flds (5); - flds(0) = "name"; - flds(1) = "date"; - flds(2) = "bytes"; - flds(3) = "isdir"; - flds(4) = "datenum"; - retval = octave_map (flds); - } - else - { - octave_map st; - Cell filectime (dim_vector (n, 1)); - Cell filesize (dim_vector (n, 1)); - Cell fileisdir (dim_vector (n, 1)); - Cell filedatenum (dim_vector (n, 1)); - - st.assign ("name", Cell (sv)); - - for (octave_idx_type i = 0; i < n; i++) - { - time_t ftime; - bool fisdir; - double fsize; - - curl.get_fileinfo (sv(i), fsize, ftime, fisdir); - - fileisdir (i) = fisdir; - filectime (i) = ctime (&ftime); - filesize (i) = fsize; - filedatenum (i) = double (ftime); - } - st.assign ("date", filectime); - st.assign ("bytes", filesize); - st.assign ("isdir", fileisdir); - st.assign ("datenum", filedatenum); - retval = st; - } - } - } - else - error ("__ftp_dir__: invalid ftp handle"); - } - } -#else - error ("__ftp_dir__: not available in this version of Octave"); -#endif - - return retval; -} - -DEFUN_DLD (__ftp_ascii__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_ascii__ (@var{handle})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_ascii__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.ascii (); - else - error ("__ftp_ascii__: invalid ftp handle"); - } - } -#else - error ("__ftp_ascii__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_binary__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_binary__ (@var{handle})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_binary__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.binary (); - else - error ("__ftp_binary__: invalid ftp handle"); - } - } -#else - error ("__ftp_binary__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_close__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_close__ (@var{handle})\n\ - Undocumented internal function\n\ - @end deftypefn") - { - #ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_close__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - if (!error_state) - handles.del (handle); - } - #else - error ("__ftp_close__: not available in this version of Octave"); - #endif - - return octave_value (); - } - -DEFUN_DLD (__ftp_mode__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_mode__ (@var{handle})\n\ - Undocumented internal function\n\ - @end deftypefn") - { - octave_value retval; - #ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 1) - error ("__ftp_mode__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - retval = (curl.is_ascii () ? "ascii" : "binary"); - else - error ("__ftp_binary__: invalid ftp handle"); - } - } - #else - error ("__ftp_mode__: not available in this version of Octave"); - #endif - - return retval; - } - -DEFUN_DLD (__ftp_delete__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_delete__ (@var{handle}, @var{path})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 2) - error ("__ftp_delete__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string file = args(1).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.del (file); - else - error ("__ftp_delete__: invalid ftp handle"); - } - } -#else - error ("__ftp_delete__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_rmdir__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_rmdir__ (@var{handle}, @var{path})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 2) - error ("__ftp_rmdir__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string dir = args(1).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.rmdir (dir); - else - error ("__ftp_rmdir__: invalid ftp handle"); - } - } -#else - error ("__ftp_rmdir__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_mkdir__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_mkdir__ (@var{handle}, @var{path})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 2) - error ("__ftp_mkdir__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string dir = args(1).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.mkdir (dir); - else - error ("__ftp_mkdir__: invalid ftp handle"); - } - } -#else - error ("__ftp_mkdir__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -DEFUN_DLD (__ftp_rename__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_rename__ (@var{handle}, @var{path})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 3) - error ("__ftp_rename__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string oldname = args(1).string_value (); - std::string newname = args(2).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - curl.rename (oldname, newname); - else - error ("__ftp_rename__: invalid ftp handle"); - } - } -#else - error ("__ftp_rename__: not available in this version of Octave"); -#endif - - return octave_value (); -} - -#ifdef HAVE_CURL -static string_vector -mput_directory (const curl_handle& curl, const std::string& base, - const std::string& dir) -{ - string_vector retval; - - if (! curl.mkdir (dir, false)) - warning ("__ftp_mput__: can not create the remote directory ""%s""", - (base.length () == 0 ? dir : base + - file_ops::dir_sep_str () + dir).c_str ()); - - curl.cwd (dir); - - if (! error_state) - { - unwind_protect_safe frame; - - frame.add_fcn (reset_path, curl); - - std::string realdir = base.length () == 0 ? dir : base + - file_ops::dir_sep_str () + dir; - - dir_entry dirlist (realdir); - - if (dirlist) - { - string_vector files = dirlist.read (); - - for (octave_idx_type i = 0; i < files.length (); i++) - { - std::string file = files (i); - - if (file == "." || file == "..") - continue; - - std::string realfile = realdir + file_ops::dir_sep_str () + file; - file_stat fs (realfile); - - if (! fs.exists ()) - { - error ("__ftp__mput: file ""%s"" does not exist", - realfile.c_str ()); - break; - } - - if (fs.is_dir ()) - { - retval.append (mput_directory (curl, realdir, file)); - - if (error_state) - break; - } - else - { - // FIXME Does ascii mode need to be flagged here? - std::ifstream ifile (realfile.c_str (), std::ios::in | - std::ios::binary); - - if (! ifile.is_open ()) - { - error ("__ftp_mput__: unable to open file ""%s""", - realfile.c_str ()); - break; - } - - curl.put (file, ifile); - - ifile.close (); - - if (error_state) - break; - - retval.append (realfile); - } - } - } - else - error ("__ftp_mput__: can not read the directory ""%s""", - realdir.c_str ()); - } - - return retval; -} -#endif - -DEFUN_DLD (__ftp_mput__, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_mput__ (@var{handle}, @var{files})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ - string_vector retval; - -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 2) - error ("__ftp_mput__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string pat = args(1).string_value (); - - if (!error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - { - glob_match pattern (file_ops::tilde_expand (pat)); - string_vector files = pattern.glob (); - - for (octave_idx_type i = 0; i < files.length (); i++) - { - std::string file = files (i); - - file_stat fs (file); - - if (! fs.exists ()) - { - error ("__ftp__mput: file does not exist"); - break; - } - - if (fs.is_dir ()) - { - retval.append (mput_directory (curl, "", file)); - if (error_state) - break; - } - else - { - // FIXME Does ascii mode need to be flagged here? - std::ifstream ifile (file.c_str (), std::ios::in | - std::ios::binary); - - if (! ifile.is_open ()) - { - error ("__ftp_mput__: unable to open file"); - break; - } - - curl.put (file, ifile); - - ifile.close (); - - if (error_state) - break; - - retval.append (file); - } - } - } - else - error ("__ftp_mput__: invalid ftp handle"); - } - } -#else - error ("__ftp_mput__: not available in this version of Octave"); -#endif - - return (nargout > 0 ? octave_value (retval) : octave_value ()); -} - -#ifdef HAVE_CURL -static void -getallfiles (const curl_handle& curl, const std::string& dir, - const std::string& target) -{ - std::string sep = file_ops::dir_sep_str (); - file_stat fs (dir); - - if (!fs || !fs.is_dir ()) - { - std::string msg; - int status = octave_mkdir (dir, 0777, msg); - - if (status < 0) - error ("__ftp_mget__: can't create directory %s%s%s. %s", - target.c_str (), sep.c_str (), dir.c_str (), msg.c_str ()); - } - - if (! error_state) - { - curl.cwd (dir); - - if (! error_state) - { - unwind_protect_safe frame; - - frame.add_fcn (reset_path, curl); - - string_vector sv = curl.list (); - - for (octave_idx_type i = 0; i < sv.length (); i++) - { - time_t ftime; - bool fisdir; - double fsize; - - curl.get_fileinfo (sv(i), fsize, ftime, fisdir); - - if (fisdir) - getallfiles (curl, sv(i), target + dir + sep); - else - { - std::string realfile = target + dir + sep + sv(i); - std::ofstream ofile (realfile.c_str (), - std::ios::out | - std::ios::binary); - - if (! ofile.is_open ()) - { - error ("__ftp_mget__: unable to open file"); - break; - } - - unwind_protect_safe frame2; - - frame2.add_fcn (delete_file, realfile); - - curl.get (sv(i), ofile); - - ofile.close (); - - if (!error_state) - frame2.discard (); - else - frame2.run (); - } - - if (error_state) - break; - } - } - } -} -#endif - -DEFUN_DLD (__ftp_mget__, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} __ftp_mget__ (@var{handle}, @var{files})\n\ -Undocumented internal function\n\ -@end deftypefn") -{ -#ifdef HAVE_CURL - int nargin = args.length (); - - if (nargin != 2 && nargin != 3) - error ("__ftp_mget__: incorrect number of arguments"); - else - { - std::string handle = args(0).string_value (); - std::string file = args(1).string_value (); - std::string target; - - if (nargin == 3) - target = args(2).string_value () + file_ops::dir_sep_str (); - - if (! error_state) - { - const curl_handle curl = handles.contents (handle); - - if (curl.is_valid ()) - { - string_vector sv = curl.list (); - octave_idx_type n = 0; - glob_match pattern (file); - - for (octave_idx_type i = 0; i < sv.length (); i++) - { - if (pattern.match (sv(i))) - { - n++; - - time_t ftime; - bool fisdir; - double fsize; - - curl.get_fileinfo (sv(i), fsize, ftime, fisdir); - - if (fisdir) - getallfiles (curl, sv(i), target); - else - { - std::ofstream ofile ((target + sv(i)).c_str (), - std::ios::out | - std::ios::binary); - - if (! ofile.is_open ()) - { - error ("__ftp_mget__: unable to open file"); - break; - } - - unwind_protect_safe frame; - - frame.add_fcn (delete_file, target + sv(i)); - - curl.get (sv(i), ofile); - - ofile.close (); - - if (!error_state) - frame.discard (); - else - frame.run (); - } - - if (error_state) - break; - } - } - if (n == 0) - error ("__ftp_mget__: file not found"); - } - } - } -#else - error ("__ftp_mget__: not available in this version of Octave"); -#endif - - return octave_value (); -}
--- a/src/Makefile.am Tue Jul 31 20:46:47 2012 -0400 +++ b/src/Makefile.am Tue Jul 31 21:57:58 2012 -0400 @@ -314,14 +314,14 @@ include operators/module.mk include template-inst/module.mk include corefcn/module.mk -include DLD-FUNCTIONS/module.mk +include dldfcn/module.mk -$(srcdir)/DLD-FUNCTIONS/module.mk: $(srcdir)/DLD-FUNCTIONS/config-module.sh $(srcdir)/DLD-FUNCTIONS/config-module.awk $(srcdir)/DLD-FUNCTIONS/module-files - $(srcdir)/DLD-FUNCTIONS/config-module.sh $(top_srcdir) +$(srcdir)/dldfcn/module.mk: $(srcdir)/dldfcn/config-module.sh $(srcdir)/dldfcn/config-module.awk $(srcdir)/dldfcn/module-files + $(srcdir)/dldfcn/config-module.sh $(top_srcdir) if AMCOND_ENABLE_DYNAMIC_LINKING - OCT_FILES = $(DLD_FUNCTIONS_LIBS:.la=.oct) - OCT_STAMP_FILES = $(subst DLD-FUNCTIONS/,DLD-FUNCTIONS/$(am__leading_dot),$(DLD_FUNCTIONS_LIBS:.la=.oct-stamp)) + OCT_FILES = $(DLDFCN_LIBS:.la=.oct) + OCT_STAMP_FILES = $(subst dldfcn/,dldfcn/$(am__leading_dot),$(DLDFCN_LIBS:.la=.oct-stamp)) DLD_LIBOCTINTERP_LIBADD = liboctinterp.la else OCT_FILES = @@ -387,17 +387,17 @@ ## Section for defining and creating DEF_FILES SRC_DEF_FILES := $(shell $(srcdir)/find-defun-files.sh "$(srcdir)" $(DIST_SRC)) -DLD_FUNCTIONS_DEF_FILES = $(DLD_FUNCTIONS_SRC:.cc=.df) +DLDFCN_DEF_FILES = $(DLDFCN_SRC:.cc=.df) ## builtins.cc depends on $(DEF_FILES), so DEF_FILES should only include ## .df files that correspond to sources included in liboctave. if AMCOND_ENABLE_DYNAMIC_LINKING DEF_FILES = $(SRC_DEF_FILES) else - DEF_FILES = $(SRC_DEF_FILES) $(DLD_FUNCTIONS_DEF_FILES) + DEF_FILES = $(SRC_DEF_FILES) $(DLDFCN_DEF_FILES) endif -ALL_DEF_FILES = $(SRC_DEF_FILES) $(DLD_FUNCTIONS_DEF_FILES) +ALL_DEF_FILES = $(SRC_DEF_FILES) $(DLDFCN_DEF_FILES) $(SRC_DEF_FILES): mkdefs Makefile @@ -483,10 +483,10 @@ $(MAKE) -C $(@D) $(@F) if AMCOND_ENABLE_DYNAMIC_LINKING -DLD_FUNCTIONS_PKG_ADD_FILE = DLD-FUNCTIONS/PKG_ADD +DLDFCN_PKG_ADD_FILE = dldfcn/PKG_ADD -DLD-FUNCTIONS/PKG_ADD: $(DLD_FUNCTIONS_DEF_FILES) mk-pkg-add - $(srcdir)/mk-pkg-add $(DLD_FUNCTIONS_DEF_FILES) > $@-t +dldfcn/PKG_ADD: $(DLDFCN_DEF_FILES) mk-pkg-add + $(srcdir)/mk-pkg-add $(DLDFCN_DEF_FILES) > $@-t mv $@-t $@ endif @@ -510,9 +510,9 @@ $(top_srcdir)/build-aux/move-if-change $@ DOCSTRINGS touch $@ -all-local: $(OCT_STAMP_FILES) $(DLD_FUNCTIONS_PKG_ADD_FILE) .DOCSTRINGS +all-local: $(OCT_STAMP_FILES) $(DLDFCN_PKG_ADD_FILE) .DOCSTRINGS else -all-local: $(OCT_STAMP_FILES) $(DLD_FUNCTIONS_PKG_ADD_FILE) +all-local: $(OCT_STAMP_FILES) $(DLDFCN_PKG_ADD_FILE) endif if AMCOND_BUILD_COMPILED_AUX_PROGRAMS @@ -566,11 +566,11 @@ if AMCOND_ENABLE_DYNAMIC_LINKING install-oct: $(top_srcdir)/build-aux/mkinstalldirs $(DESTDIR)$(octfiledir) - if [ -n "`cat $(DLD_FUNCTIONS_PKG_ADD_FILE)`" ]; then \ - $(INSTALL_DATA) $(DLD_FUNCTIONS_PKG_ADD_FILE) $(DESTDIR)$(octfiledir)/PKG_ADD; \ + if [ -n "`cat $(DLDFCN_PKG_ADD_FILE)`" ]; then \ + $(INSTALL_DATA) $(DLDFCN_PKG_ADD_FILE) $(DESTDIR)$(octfiledir)/PKG_ADD; \ fi cd $(DESTDIR)$(octlibdir) && \ - for ltlib in $(DLD_FUNCTIONS_LIBS); do \ + for ltlib in $(DLDFCN_LIBS); do \ f=`echo $$ltlib | $(SED) 's,.*/,,'`; \ dl=`$(SED) -n -e "s/dlname='\([^']*\)'/\1/p" < $$f`; \ if [ -n "$$dl" ]; then \ @@ -595,7 +595,7 @@ CLEANFILES = \ $(bin_SCRIPTS) \ - $(DLD_FUNCTIONS_PKG_ADD_FILE) \ + $(DLDFCN_PKG_ADD_FILE) \ graphics-props.cc \ oct-parse.output
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__delaunayn__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,229 @@ +/* + +Copyright (C) 2000-2012 Kai Habel + +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/>. + +*/ + +/* + 16. July 2000 - Kai Habel: first release + + 25. September 2002 - Changes by Rafael Laboissiere <rafael@laboissiere.net> + + * Added Qbb option to normalize the input and avoid crashes in Octave. + * delaunayn accepts now a second (optional) argument that must be a string + containing extra options to the qhull command. + * Fixed doc string. The dimension of the result matrix is [m, dim+1], and + not [n, dim-1]. + + 6. June 2006: Changes by Alexander Barth <abarth@marine.usf.edu> + + * triangulate non-simplicial facets + * allow options to be specified as cell array of strings + * change the default options (for compatibility with matlab) +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <string> + +#include "Cell.h" +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "unwind-prot.h" + +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) +char qh_version[] = "__delaunayn__.oct 2007-08-21"; +# endif +#endif + +static void +close_fcn (FILE *f) +{ + gnulib::fclose (f); +} + +DEFUN_DLD (__delaunayn__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{T} =} __delaunayn__ (@var{pts})\n\ +@deftypefnx {Loadable Function} {@var{T} =} __delaunayn__ (@var{pts}, @var{options})\n\ +Undocumented internal function.\n\ +@end deftypefn") + +{ + octave_value_list retval; + +#if defined (HAVE_QHULL) + + retval(0) = 0.0; + + int nargin = args.length (); + if (nargin < 1 || nargin > 2) + { + print_usage (); + return retval; + } + + Matrix p (args(0).matrix_value ()); + const octave_idx_type dim = p.columns (); + const octave_idx_type n = p.rows (); + + // Default options + std::string options; + if (dim <= 3) + options = "Qt Qbb Qc Qz"; + else + options = "Qt Qbb Qc Qx"; + + if (nargin == 2) + { + if (args(1).is_string ()) + options = args(1).string_value (); + else if (args(1).is_empty ()) + ; // Use default options + else if (args(1).is_cellstr ()) + { + options = ""; + Array<std::string> tmp = args(1).cellstr_value (); + + for (octave_idx_type i = 0; i < tmp.numel (); i++) + options += tmp(i) + " "; + } + else + { + error ("__delaunayn__: OPTIONS argument must be a string, cell array of strings, or empty"); + return retval; + } + } + + if (n > dim + 1) + { + p = p.transpose (); + double *pt_array = p.fortran_vec (); + boolT ismalloc = false; + + // Qhull flags argument is not const char* + OCTAVE_LOCAL_BUFFER (char, flags, 9 + options.length ()); + + sprintf (flags, "qhull d %s", options.c_str ()); + + unwind_protect frame; + + // Replace the outfile pointer with stdout for debugging information. +#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) + FILE *outfile = gnulib::fopen ("NUL", "w"); +#else + FILE *outfile = gnulib::fopen ("/dev/null", "w"); +#endif + FILE *errfile = stderr; + + if (outfile) + frame.add_fcn (close_fcn, outfile); + else + { + error ("__delaunayn__: unable to create temporary file for output"); + return retval; + } + + int exitcode = qh_new_qhull (dim, n, pt_array, + ismalloc, flags, outfile, errfile); + if (! exitcode) + { + // triangulate non-simplicial facets + qh_triangulate (); + + facetT *facet; + vertexT *vertex, **vertexp; + octave_idx_type nf = 0, i = 0; + + FORALLfacets + { + if (! facet->upperdelaunay) + nf++; + + // Double check. Non-simplicial facets will cause segfault below + if (! facet->simplicial) + { + error ("__delaunayn__: Qhull returned non-simplicial facets -- try delaunayn with different options"); + exitcode = 1; + break; + } + } + + if (! exitcode) + { + Matrix simpl (nf, dim+1); + + FORALLfacets + { + if (! facet->upperdelaunay) + { + octave_idx_type j = 0; + + FOREACHvertex_ (facet->vertices) + { + simpl(i, j++) = 1 + qh_pointid(vertex->point); + } + i++; + } + } + + retval(0) = simpl; + } + } + else + error ("__delaunayn__: qhull failed"); + + // Free memory from Qhull + qh_freeqhull (! qh_ALL); + + int curlong, totlong; + qh_memfreeshort (&curlong, &totlong); + + if (curlong || totlong) + warning ("__delaunay__: did not free %d bytes of long memory (%d pieces)", + totlong, curlong); + } + else if (n == dim + 1) + { + // one should check if nx points span a simplex + // I will look at this later. + RowVector vec (n); + for (octave_idx_type i = 0; i < n; i++) + vec(i) = i + 1.0; + + retval(0) = vec; + } + +#else + error ("__delaunayn__: not available in this version of Octave"); +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__dsearchn__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,115 @@ +/* + +Copyright (C) 2007-2012 David Bateman + +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> +#endif + +#include <iostream> +#include <fstream> +#include <string> + +#include "lo-math.h" + +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" + +DEFUN_DLD (__dsearchn__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{idx}, @var{d}] =} dsearch (@var{x}, @var{xi})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + int nargin = args.length (); + octave_value_list retval; + + if (nargin != 2) + { + print_usage (); + return retval; + } + + Matrix x = args(0).matrix_value ().transpose (); + Matrix xi = args(1).matrix_value ().transpose (); + + if (! error_state) + { + if (x.rows () != xi.rows () || x.columns () < 1) + error ("__dsearch__: number of rows of X and XI must match"); + else + { + octave_idx_type n = x.rows (); + octave_idx_type nx = x.columns (); + octave_idx_type nxi = xi.columns (); + + ColumnVector idx (nxi); + double *pidx = idx.fortran_vec (); + ColumnVector dist (nxi); + double *pdist = dist.fortran_vec (); + +#define DIST(dd, y, yi, m) \ + dd = 0.; \ + for (octave_idx_type k = 0; k < m; k++) \ + { \ + double yd = y[k] - yi[k]; \ + dd += yd * yd; \ + } \ + dd = sqrt (dd); + + const double *pxi = xi.fortran_vec (); + for (octave_idx_type i = 0; i < nxi; i++) + { + double d0; + const double *px = x.fortran_vec (); + DIST(d0, px, pxi, n); + *pidx = 1.; + for (octave_idx_type j = 1; j < nx; j++) + { + px += n; + double d; + DIST (d, px, pxi, n); + if (d < d0) + { + d0 = d; + *pidx = static_cast<double>(j + 1); + } + OCTAVE_QUIT; + } + + *pdist++ = d0; + pidx++; + pxi += n; + } + + retval(1) = dist; + retval(0) = idx; + } + } + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__fltk_uigetfile__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,142 @@ +/* + +Copyright (C) 2010-2012 Kai Habel + +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> +#endif + +#if defined (HAVE_FLTK) + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#endif + +#include <FL/Fl.H> +#include <FL/Fl_File_Chooser.H> + +// FLTK headers may include X11/X.h which defines Complex, and that +// conflicts with Octave's Complex typedef. We don't need the X11 +// Complex definition in this file, so remove it before including Octave +// headers which may require Octave's Complex typedef. +#undef Complex + +#include "defun-dld.h" +#include "file-ops.h" + +DEFUN_DLD (__fltk_uigetfile__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __fltk_uigetfile__ (@dots{})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + // Expected argument list: + // + // args(0) ... FileFilter in fltk format + // args(1) ... Title + // args(2) ... Default Filename + // args(3) ... PostionValue [x,y] + // args(4) ... SelectValue "on"/"off"/"dir"/"create" + + octave_value_list retval (3, octave_value (0)); + + std::string file_filter = args(0).string_value (); + std::string title = args(1).string_value (); + std::string default_name = args(2).string_value (); + Matrix pos = args(3).matrix_value (); + + int multi_type = Fl_File_Chooser::SINGLE; + std::string flabel = "Filename:"; + + std::string multi = args(4).string_value (); + if (multi == "on") + multi_type = Fl_File_Chooser::MULTI; + else if (multi == "dir") + { + multi_type = Fl_File_Chooser::DIRECTORY; + flabel = "Directory:"; + } + else if (multi == "create") + multi_type = Fl_File_Chooser::CREATE; + + Fl_File_Chooser::filename_label = flabel.c_str (); + + Fl_File_Chooser fc (default_name.c_str (), file_filter.c_str (), + multi_type, title.c_str ()); + + fc.preview (0); + + if (multi_type == Fl_File_Chooser::CREATE) + fc.ok_label ("Save"); + + fc.show (); + + while (fc.shown ()) + Fl::wait (); + + if (fc.value ()) + { + int file_count = fc.count (); + std::string fname; + + //fltk uses forward slash even for windows + std::string sep = "/"; + std::size_t idx; + + if (file_count == 1 && multi_type != Fl_File_Chooser::DIRECTORY) + { + fname = fc.value (); + idx = fname.find_last_of (sep); + retval(0) = fname.substr (idx + 1); + } + else + { + Cell file_cell = Cell (file_count, 1); + for (octave_idx_type n = 1; n <= file_count; n++) + { + fname = fc.value (n); + idx = fname.find_last_of (sep); + file_cell(n - 1) = fname.substr (idx + 1); + } + retval(0) = file_cell; + } + + if (multi_type == Fl_File_Chooser::DIRECTORY) + retval(0) = std::string (fc.value ()); + else + { + retval(1) = std::string (fc.directory ()) + sep; + retval(2) = fc.filter_value () + 1; + } + } + + fc.hide (); + Fl::flush (); + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/ + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__glpk__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,861 @@ +/* + +Copyright (C) 2005-2012 Nicolo' Giorgetti + +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> +#endif + +#include <cfloat> +#include <csetjmp> +#include <ctime> + +#include "lo-ieee.h" + +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-map.h" +#include "oct-obj.h" +#include "pager.h" + +#if defined (HAVE_GLPK) + +extern "C" +{ +#if defined (HAVE_GLPK_GLPK_H) +#include <glpk/glpk.h> +#else +#include <glpk.h> +#endif + +#if 0 +#ifdef GLPK_PRE_4_14 + +#ifndef _GLPLIB_H +#include <glplib.h> +#endif +#ifndef lib_set_fault_hook +#define lib_set_fault_hook lib_fault_hook +#endif +#ifndef lib_set_print_hook +#define lib_set_print_hook lib_print_hook +#endif + +#else + +void _glp_lib_print_hook (int (*func)(void *info, char *buf), void *info); +void _glp_lib_fault_hook (int (*func)(void *info, char *buf), void *info); + +#endif +#endif +} + +#define NIntP 17 +#define NRealP 10 + +int lpxIntParam[NIntP] = { + 0, + 1, + 0, + 1, + 0, + -1, + 0, + 200, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1 +}; + +int IParam[NIntP] = { + LPX_K_MSGLEV, + LPX_K_SCALE, + LPX_K_DUAL, + LPX_K_PRICE, + LPX_K_ROUND, + LPX_K_ITLIM, + LPX_K_ITCNT, + LPX_K_OUTFRQ, + LPX_K_MPSINFO, + LPX_K_MPSOBJ, + LPX_K_MPSORIG, + LPX_K_MPSWIDE, + LPX_K_MPSFREE, + LPX_K_MPSSKIP, + LPX_K_BRANCH, + LPX_K_BTRACK, + LPX_K_PRESOL +}; + + +double lpxRealParam[NRealP] = { + 0.07, + 1e-7, + 1e-7, + 1e-9, + -DBL_MAX, + DBL_MAX, + -1.0, + 0.0, + 1e-6, + 1e-7 +}; + +int RParam[NRealP] = { + LPX_K_RELAX, + LPX_K_TOLBND, + LPX_K_TOLDJ, + LPX_K_TOLPIV, + LPX_K_OBJLL, + LPX_K_OBJUL, + LPX_K_TMLIM, + LPX_K_OUTDLY, + LPX_K_TOLINT, + LPX_K_TOLOBJ +}; + +static jmp_buf mark; //-- Address for long jump to jump to + +#if 0 +int +glpk_fault_hook (void * /* info */, char *msg) +{ + error ("CRITICAL ERROR in GLPK: %s", msg); + longjmp (mark, -1); +} + +int +glpk_print_hook (void * /* info */, char *msg) +{ + message (0, "%s", msg); + return 1; +} +#endif + +int +glpk (int sense, int n, int m, double *c, int nz, int *rn, int *cn, + double *a, double *b, char *ctype, int *freeLB, double *lb, + int *freeUB, double *ub, int *vartype, int isMIP, int lpsolver, + int save_pb, double *xmin, double *fmin, double *status, + double *lambda, double *redcosts, double *time, double *mem) +{ + int errnum; + int typx = 0; + int method; + + clock_t t_start = clock (); + +#if 0 +#ifdef GLPK_PRE_4_14 + lib_set_fault_hook (0, glpk_fault_hook); +#else + _glp_lib_fault_hook (glpk_fault_hook, 0); +#endif + + if (lpxIntParam[0] > 1) +#ifdef GLPK_PRE_4_14 + lib_set_print_hook (0, glpk_print_hook); +#else + _glp_lib_print_hook (glpk_print_hook, 0); +#endif +#endif + + LPX *lp = lpx_create_prob (); + + + //-- Set the sense of optimization + if (sense == 1) + lpx_set_obj_dir (lp, LPX_MIN); + else + lpx_set_obj_dir (lp, LPX_MAX); + + //-- If the problem has integer structural variables switch to MIP + if (isMIP) + lpx_set_class (lp, LPX_MIP); + + lpx_add_cols (lp, n); + for (int i = 0; i < n; i++) + { + //-- Define type of the structural variables + if (! freeLB[i] && ! freeUB[i]) + { + if (lb[i] != ub[i]) + lpx_set_col_bnds (lp, i+1, LPX_DB, lb[i], ub[i]); + else + lpx_set_col_bnds (lp, i+1, LPX_FX, lb[i], ub[i]); + } + else + { + if (! freeLB[i] && freeUB[i]) + lpx_set_col_bnds (lp, i+1, LPX_LO, lb[i], ub[i]); + else + { + if (freeLB[i] && ! freeUB[i]) + lpx_set_col_bnds (lp, i+1, LPX_UP, lb[i], ub[i]); + else + lpx_set_col_bnds (lp, i+1, LPX_FR, lb[i], ub[i]); + } + } + + // -- Set the objective coefficient of the corresponding + // -- structural variable. No constant term is assumed. + lpx_set_obj_coef(lp,i+1,c[i]); + + if (isMIP) + lpx_set_col_kind (lp, i+1, vartype[i]); + } + + lpx_add_rows (lp, m); + + for (int i = 0; i < m; i++) + { + /* If the i-th row has no lower bound (types F,U), the + corrispondent parameter will be ignored. + If the i-th row has no upper bound (types F,L), the corrispondent + parameter will be ignored. + If the i-th row is of S type, the i-th LB is used, but + the i-th UB is ignored. + */ + + switch (ctype[i]) + { + case 'F': + typx = LPX_FR; + break; + + case 'U': + typx = LPX_UP; + break; + + case 'L': + typx = LPX_LO; + break; + + case 'S': + typx = LPX_FX; + break; + + case 'D': + typx = LPX_DB; + break; + } + + lpx_set_row_bnds (lp, i+1, typx, b[i], b[i]); + + } + + lpx_load_matrix (lp, nz, rn, cn, a); + + if (save_pb) + { + static char tmp[] = "outpb.lp"; + if (lpx_write_cpxlp (lp, tmp) != 0) + { + error ("__glpk__: unable to write problem"); + longjmp (mark, -1); + } + } + + //-- scale the problem data (if required) + //-- if (scale && (!presol || method == 1)) lpx_scale_prob (lp); + //-- LPX_K_SCALE=IParam[1] LPX_K_PRESOL=IParam[16] + if (lpxIntParam[1] && (! lpxIntParam[16] || lpsolver != 1)) + lpx_scale_prob (lp); + + //-- build advanced initial basis (if required) + if (lpsolver == 1 && ! lpxIntParam[16]) + lpx_adv_basis (lp); + + for (int i = 0; i < NIntP; i++) + lpx_set_int_parm (lp, IParam[i], lpxIntParam[i]); + + for (int i = 0; i < NRealP; i++) + lpx_set_real_parm (lp, RParam[i], lpxRealParam[i]); + + if (lpsolver == 1) + method = 'S'; + else + method = 'T'; + + switch (method) + { + case 'S': + { + if (isMIP) + { + method = 'I'; + errnum = lpx_simplex (lp); + errnum = lpx_integer (lp); + } + else + errnum = lpx_simplex (lp); + } + break; + + case 'T': + errnum = lpx_interior (lp); + break; + + default: + break; +#if 0 +#ifdef GLPK_PRE_4_14 + insist (method != method); +#else + static char tmp[] = "method != method"; + glpk_fault_hook (0, tmp); +#endif +#endif + } + + /* errnum assumes the following results: + errnum = 0 <=> No errors + errnum = 1 <=> Iteration limit exceeded. + errnum = 2 <=> Numerical problems with basis matrix. + */ + if (errnum == LPX_E_OK) + { + if (isMIP) + { + *status = lpx_mip_status (lp); + *fmin = lpx_mip_obj_val (lp); + } + else + { + if (lpsolver == 1) + { + *status = lpx_get_status (lp); + *fmin = lpx_get_obj_val (lp); + } + else + { + *status = lpx_ipt_status (lp); + *fmin = lpx_ipt_obj_val (lp); + } + } + + if (isMIP) + { + for (int i = 0; i < n; i++) + xmin[i] = lpx_mip_col_val (lp, i+1); + } + else + { + /* Primal values */ + for (int i = 0; i < n; i++) + { + if (lpsolver == 1) + xmin[i] = lpx_get_col_prim (lp, i+1); + else + xmin[i] = lpx_ipt_col_prim (lp, i+1); + } + + /* Dual values */ + for (int i = 0; i < m; i++) + { + if (lpsolver == 1) + lambda[i] = lpx_get_row_dual (lp, i+1); + else + lambda[i] = lpx_ipt_row_dual (lp, i+1); + } + + /* Reduced costs */ + for (int i = 0; i < lpx_get_num_cols (lp); i++) + { + if (lpsolver == 1) + redcosts[i] = lpx_get_col_dual (lp, i+1); + else + redcosts[i] = lpx_ipt_col_dual (lp, i+1); + } + } + + *time = (clock () - t_start) / CLOCKS_PER_SEC; + +#ifdef GLPK_PRE_4_14 + *mem = (lib_env_ptr () -> mem_tpeak); +#else + *mem = 0; +#endif + + lpx_delete_prob (lp); + return 0; + } + + lpx_delete_prob (lp); + + *status = errnum; + + return errnum; +} + +#endif + +#define OCTAVE_GLPK_GET_REAL_PARAM(NAME, IDX) \ + do \ + { \ + octave_value tmp = PARAM.getfield (NAME); \ + \ + if (tmp.is_defined ()) \ + { \ + if (! tmp.is_empty ()) \ + { \ + lpxRealParam[IDX] = tmp.scalar_value (); \ + \ + if (error_state) \ + { \ + error ("glpk: invalid value in PARAM." NAME); \ + return retval; \ + } \ + } \ + else \ + { \ + error ("glpk: invalid value in PARAM." NAME); \ + return retval; \ + } \ + } \ + } \ + while (0) + +#define OCTAVE_GLPK_GET_INT_PARAM(NAME, VAL) \ + do \ + { \ + octave_value tmp = PARAM.getfield (NAME); \ + \ + if (tmp.is_defined ()) \ + { \ + if (! tmp.is_empty ()) \ + { \ + VAL = tmp.int_value (); \ + \ + if (error_state) \ + { \ + error ("glpk: invalid value in PARAM." NAME); \ + return retval; \ + } \ + } \ + else \ + { \ + error ("glpk: invalid value in PARAM." NAME); \ + return retval; \ + } \ + } \ + } \ + while (0) + +DEFUN_DLD (__glpk__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{values}] =} __glpk__ (@var{args})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + // The list of values to return. See the declaration in oct-obj.h + octave_value_list retval; + +#if defined (HAVE_GLPK) + + int nrhs = args.length (); + + if (nrhs != 9) + { + print_usage (); + return retval; + } + + //-- 1nd Input. A column array containing the objective function + //-- coefficients. + volatile int mrowsc = args(0).rows (); + + Matrix C (args(0).matrix_value ()); + + if (error_state) + { + error ("__glpk__: invalid value of C"); + return retval; + } + + double *c = C.fortran_vec (); + Array<int> rn; + Array<int> cn; + ColumnVector a; + volatile int mrowsA; + volatile int nz = 0; + + //-- 2nd Input. A matrix containing the constraints coefficients. + // If matrix A is NOT a sparse matrix + if (args(1).is_sparse_type ()) + { + SparseMatrix A = args(1).sparse_matrix_value (); // get the sparse matrix + + if (error_state) + { + error ("__glpk__: invalid value of A"); + return retval; + } + + mrowsA = A.rows (); + octave_idx_type Anc = A.cols (); + octave_idx_type Anz = A.nnz (); + rn.resize (dim_vector (Anz+1, 1)); + cn.resize (dim_vector (Anz+1, 1)); + a.resize (Anz+1, 0.0); + + if (Anc != mrowsc) + { + error ("__glpk__: invalid value of A"); + return retval; + } + + for (octave_idx_type j = 0; j < Anc; j++) + for (octave_idx_type i = A.cidx (j); i < A.cidx (j+1); i++) + { + nz++; + rn(nz) = A.ridx (i) + 1; + cn(nz) = j + 1; + a(nz) = A.data(i); + } + } + else + { + Matrix A (args(1).matrix_value ()); // get the matrix + + if (error_state) + { + error ("__glpk__: invalid value of A"); + return retval; + } + + mrowsA = A.rows (); + rn.resize (dim_vector (mrowsA*mrowsc+1, 1)); + cn.resize (dim_vector (mrowsA*mrowsc+1, 1)); + a.resize (mrowsA*mrowsc+1, 0.0); + + for (int i = 0; i < mrowsA; i++) + { + for (int j = 0; j < mrowsc; j++) + { + if (A(i,j) != 0) + { + nz++; + rn(nz) = i + 1; + cn(nz) = j + 1; + a(nz) = A(i,j); + } + } + } + + } + + //-- 3rd Input. A column array containing the right-hand side value + // for each constraint in the constraint matrix. + Matrix B (args(2).matrix_value ()); + + if (error_state) + { + error ("__glpk__: invalid value of B"); + return retval; + } + + double *b = B.fortran_vec (); + + //-- 4th Input. An array of length mrowsc containing the lower + //-- bound on each of the variables. + Matrix LB (args(3).matrix_value ()); + + if (error_state || LB.length () < mrowsc) + { + error ("__glpk__: invalid value of LB"); + return retval; + } + + double *lb = LB.fortran_vec (); + + //-- LB argument, default: Free + Array<int> freeLB (dim_vector (mrowsc, 1)); + for (int i = 0; i < mrowsc; i++) + { + if (xisinf (lb[i])) + { + freeLB(i) = 1; + lb[i] = -octave_Inf; + } + else + freeLB(i) = 0; + } + + //-- 5th Input. An array of at least length numcols containing the upper + //-- bound on each of the variables. + Matrix UB (args(4).matrix_value ()); + + if (error_state || UB.length () < mrowsc) + { + error ("__glpk__: invalid value of UB"); + return retval; + } + + double *ub = UB.fortran_vec (); + + Array<int> freeUB (dim_vector (mrowsc, 1)); + for (int i = 0; i < mrowsc; i++) + { + if (xisinf (ub[i])) + { + freeUB(i) = 1; + ub[i] = octave_Inf; + } + else + freeUB(i) = 0; + } + + //-- 6th Input. A column array containing the sense of each constraint + //-- in the constraint matrix. + charMatrix CTYPE (args(5).char_matrix_value ()); + + if (error_state) + { + error ("__glpk__: invalid value of CTYPE"); + return retval; + } + + char *ctype = CTYPE.fortran_vec (); + + //-- 7th Input. A column array containing the types of the variables. + charMatrix VTYPE (args(6).char_matrix_value ()); + + if (error_state) + { + error ("__glpk__: invalid value of VARTYPE"); + return retval; + } + + Array<int> vartype (dim_vector (mrowsc, 1)); + volatile int isMIP = 0; + for (int i = 0; i < mrowsc ; i++) + { + if (VTYPE(i,0) == 'I') + { + isMIP = 1; + vartype(i) = LPX_IV; + } + else + vartype(i) = LPX_CV; + } + + //-- 8th Input. Sense of optimization. + volatile int sense; + double SENSE = args(7).scalar_value (); + + if (error_state) + { + error ("__glpk__: invalid value of SENSE"); + return retval; + } + + if (SENSE >= 0) + sense = 1; + else + sense = -1; + + //-- 9th Input. A structure containing the control parameters. + octave_scalar_map PARAM = args(8).scalar_map_value (); + + if (error_state) + { + error ("__glpk__: invalid value of PARAM"); + return retval; + } + + //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + //-- Integer parameters + //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + //-- Level of messages output by the solver + OCTAVE_GLPK_GET_INT_PARAM ("msglev", lpxIntParam[0]); + if (lpxIntParam[0] < 0 || lpxIntParam[0] > 3) + { + error ("__glpk__: PARAM.msglev must be 0 (no output [default]) or 1 (error messages only) or 2 (normal output) or 3 (full output)"); + return retval; + } + + //-- scaling option + OCTAVE_GLPK_GET_INT_PARAM ("scale", lpxIntParam[1]); + if (lpxIntParam[1] < 0 || lpxIntParam[1] > 2) + { + error ("__glpk__: PARAM.scale must be 0 (no scaling) or 1 (equilibration scaling [default]) or 2 (geometric mean scaling)"); + return retval; + } + + //-- Dual dimplex option + OCTAVE_GLPK_GET_INT_PARAM ("dual", lpxIntParam[2]); + if (lpxIntParam[2] < 0 || lpxIntParam[2] > 1) + { + error ("__glpk__: PARAM.dual must be 0 (do NOT use dual simplex [default]) or 1 (use dual simplex)"); + return retval; + } + + //-- Pricing option + OCTAVE_GLPK_GET_INT_PARAM ("price", lpxIntParam[3]); + if (lpxIntParam[3] < 0 || lpxIntParam[3] > 1) + { + error ("__glpk__: PARAM.price must be 0 (textbook pricing) or 1 (steepest edge pricing [default])"); + return retval; + } + + //-- Solution rounding option + OCTAVE_GLPK_GET_INT_PARAM ("round", lpxIntParam[4]); + if (lpxIntParam[4] < 0 || lpxIntParam[4] > 1) + { + error ("__glpk__: PARAM.round must be 0 (report all primal and dual values [default]) or 1 (replace tiny primal and dual values by exact zero)"); + return retval; + } + + //-- Simplex iterations limit + OCTAVE_GLPK_GET_INT_PARAM ("itlim", lpxIntParam[5]); + + //-- Simplex iterations count + OCTAVE_GLPK_GET_INT_PARAM ("itcnt", lpxIntParam[6]); + + //-- Output frequency, in iterations + OCTAVE_GLPK_GET_INT_PARAM ("outfrq", lpxIntParam[7]); + + //-- Branching heuristic option + OCTAVE_GLPK_GET_INT_PARAM ("branch", lpxIntParam[14]); + if (lpxIntParam[14] < 0 || lpxIntParam[14] > 2) + { + error ("__glpk__: PARAM.branch must be (MIP only) 0 (branch on first variable) or 1 (branch on last variable) or 2 (branch using a heuristic by Driebeck and Tomlin [default]"); + return retval; + } + + //-- Backtracking heuristic option + OCTAVE_GLPK_GET_INT_PARAM ("btrack", lpxIntParam[15]); + if (lpxIntParam[15] < 0 || lpxIntParam[15] > 2) + { + error ("__glpk__: PARAM.btrack must be (MIP only) 0 (depth first search) or 1 (breadth first search) or 2 (backtrack using the best projection heuristic [default]"); + return retval; + } + + //-- Presolver option + OCTAVE_GLPK_GET_INT_PARAM ("presol", lpxIntParam[16]); + if (lpxIntParam[16] < 0 || lpxIntParam[16] > 1) + { + error ("__glpk__: PARAM.presol must be 0 (do NOT use LP presolver) or 1 (use LP presolver [default])"); + return retval; + } + + //-- LPsolver option + volatile int lpsolver = 1; + OCTAVE_GLPK_GET_INT_PARAM ("lpsolver", lpsolver); + if (lpsolver < 1 || lpsolver > 2) + { + error ("__glpk__: PARAM.lpsolver must be 1 (simplex method) or 2 (interior point method)"); + return retval; + } + + //-- Save option + volatile int save_pb = 0; + OCTAVE_GLPK_GET_INT_PARAM ("save", save_pb); + save_pb = save_pb != 0; + + //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + //-- Real parameters + //-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + //-- Ratio test option + OCTAVE_GLPK_GET_REAL_PARAM ("relax", 0); + + //-- Relative tolerance used to check if the current basic solution + //-- is primal feasible + OCTAVE_GLPK_GET_REAL_PARAM ("tolbnd", 1); + + //-- Absolute tolerance used to check if the current basic solution + //-- is dual feasible + OCTAVE_GLPK_GET_REAL_PARAM ("toldj", 2); + + //-- Relative tolerance used to choose eligible pivotal elements of + //-- the simplex table in the ratio test + OCTAVE_GLPK_GET_REAL_PARAM ("tolpiv", 3); + + OCTAVE_GLPK_GET_REAL_PARAM ("objll", 4); + + OCTAVE_GLPK_GET_REAL_PARAM ("objul", 5); + + OCTAVE_GLPK_GET_REAL_PARAM ("tmlim", 6); + + OCTAVE_GLPK_GET_REAL_PARAM ("outdly", 7); + + OCTAVE_GLPK_GET_REAL_PARAM ("tolint", 8); + + OCTAVE_GLPK_GET_REAL_PARAM ("tolobj", 9); + + //-- Assign pointers to the output parameters + ColumnVector xmin (mrowsc, octave_NA); + double fmin = octave_NA; + double status; + ColumnVector lambda (mrowsA, octave_NA); + ColumnVector redcosts (mrowsc, octave_NA); + double time; + double mem; + + int jmpret = setjmp (mark); + + if (jmpret == 0) + glpk (sense, mrowsc, mrowsA, c, nz, rn.fortran_vec (), + cn.fortran_vec (), a.fortran_vec (), b, ctype, + freeLB.fortran_vec (), lb, freeUB.fortran_vec (), ub, + vartype.fortran_vec (), isMIP, lpsolver, save_pb, + xmin.fortran_vec (), &fmin, &status, lambda.fortran_vec (), + redcosts.fortran_vec (), &time, &mem); + + octave_scalar_map extra; + + if (! isMIP) + { + extra.assign ("lambda", lambda); + extra.assign ("redcosts", redcosts); + } + + extra.assign ("time", time); + extra.assign ("mem", mem); + + retval(3) = extra; + retval(2) = status; + retval(1) = fmin; + retval(0) = xmin; + +#else + + gripe_not_supported ("glpk"); + +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__init_fltk__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,2129 @@ +/* + +Copyright (C) 2007-2012 Shai Ayal + +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/>. + +*/ + +/* + +To initialize: + + graphics_toolkit ("fltk"); + plot (randn (1e3, 1)); + +*/ + +// PKG_ADD: register_graphics_toolkit ("fltk"); + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "defun-dld.h" +#include "error.h" + +#if defined (HAVE_FLTK) + +#include <map> +#include <set> +#include <sstream> +#include <iostream> + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#endif + +#include <FL/Fl.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Choice.H> +#include <FL/Fl_File_Chooser.H> +#include <FL/Fl_Gl_Window.H> +#include <FL/Fl_Menu_Bar.H> +#include <FL/Fl_Menu_Button.H> +#include <FL/Fl_Output.H> +#include <FL/Fl_Window.H> +#include <FL/fl_ask.H> +#include <FL/fl_draw.H> +#include <FL/gl.h> + +// FLTK headers may include X11/X.h which defines Complex, and that +// conflicts with Octave's Complex typedef. We don't need the X11 +// Complex definition in this file, so remove it before including Octave +// headers which may require Octave's Complex typedef. +#undef Complex + +#include "cmd-edit.h" +#include "lo-ieee.h" + +#include "file-ops.h" +#include "gl-render.h" +#include "gl2ps-renderer.h" +#include "graphics.h" +#include "parse.h" +#include "sysdep.h" +#include "toplev.h" +#include "variables.h" + +#define FLTK_GRAPHICS_TOOLKIT_NAME "fltk" + +// Give FLTK no more than 0.01 sec to do its stuff. +static double fltk_maxtime = 1e-2; + +const char* help_text = "\ +Keyboard Shortcuts\n\ +a - autoscale\n\ +p - pan/zoom\n\ +r - rotate\n\ +g - toggle grid\n\ +\n\ +Mouse\n\ +left drag - pan\n\ +mouse wheel - zoom\n\ +right drag - rectangle zoom\n\ +left double click - autoscale\n\ +"; + +class OpenGL_fltk : public Fl_Gl_Window +{ +public: + OpenGL_fltk (int xx, int yy, int ww, int hh, double num) + : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), renderer (), + in_zoom (false), zoom_box (), print_mode (false) + { + // Ask for double buffering and a depth buffer. + mode (FL_DEPTH | FL_DOUBLE); + } + + ~OpenGL_fltk (void) { } + + void zoom (bool z) + { + in_zoom = z; + if (! in_zoom) + hide_overlay (); + } + + bool zoom (void) { return in_zoom; } + void set_zoom_box (const Matrix& zb) { zoom_box = zb; } + + void print (const std::string& cmd, const std::string& term) + { + print_mode = true; + print_cmd = cmd; + print_term = term; + } + + void resize (int xx, int yy, int ww, int hh) + { + Fl_Gl_Window::resize (xx, yy, ww, hh); + setup_viewport (ww, hh); + redraw (); + } + + bool renumber (double new_number) + { + bool retval = false; + + if (number != new_number) + { + number = new_number; + retval = true; + } + + return retval; + } + +private: + double number; + opengl_renderer renderer; + bool in_zoom; + // (x1,y1,x2,y2) + Matrix zoom_box; + + bool print_mode; + std::string print_cmd; + std::string print_term; + + void setup_viewport (int ww, int hh) + { + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glViewport (0, 0, ww, hh); + } + + void draw (void) + { + if (! valid ()) + { + valid (1); + setup_viewport (w (), h ()); + } + + if (print_mode) + { + FILE *fp = octave_popen (print_cmd.c_str (), "w"); + glps_renderer rend (fp, print_term); + + rend.draw (gh_manager::get_object (number)); + + octave_pclose (fp); + print_mode = false; + } + else + { + renderer.draw (gh_manager::get_object (number)); + + if (zoom ()) + overlay (); + } + } + + void zoom_box_vertex (void) + { + glVertex2d (zoom_box(0), h () - zoom_box(1)); + glVertex2d (zoom_box(0), h () - zoom_box(3)); + glVertex2d (zoom_box(2), h () - zoom_box(3)); + glVertex2d (zoom_box(2), h () - zoom_box(1)); + glVertex2d (zoom_box(0), h () - zoom_box(1)); + } + + void overlay (void) + { + glPushMatrix (); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluOrtho2D (0.0, w (), 0.0, h ()); + + glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT); + glDisable (GL_DEPTH_TEST); + + glBegin (GL_POLYGON); + glColor4f (0.45, 0.62, 0.81, 0.1); + zoom_box_vertex (); + glEnd (); + + glBegin (GL_LINE_STRIP); + glLineWidth (1.5); + glColor4f (0.45, 0.62, 0.81, 0.9); + zoom_box_vertex (); + glEnd (); + + glPopAttrib (); + glPopMatrix (); + } + + int handle (int event) + { + int retval = Fl_Gl_Window::handle (event); + + switch (event) + { + case FL_ENTER: + window ()->cursor (FL_CURSOR_CROSS); + return 1; + + case FL_LEAVE: + window ()->cursor (FL_CURSOR_DEFAULT); + return 1; + } + + return retval; + } +}; + +// Parameter controlling how fast we zoom when using the scrool wheel. +static double wheel_zoom_speed = 0.05; +// Parameter controlling the GUI mode. +static enum { pan_zoom, rotate_zoom, none } gui_mode; + +void script_cb (Fl_Widget*, void* data) + { + static_cast<uimenu::properties*> (data)->execute_callback (); + } + + +class fltk_uimenu +{ +public: + fltk_uimenu (int xx, int yy, int ww, int hh) + { + menubar = new + Fl_Menu_Bar (xx, yy, ww, hh); + } + + int items_to_show (void) + { + //returns the number of visible menu items + int len = menubar->size (); + int n = 0; + for (int t = 0; t < len; t++ ) + { + const Fl_Menu_Item *m = static_cast<const Fl_Menu_Item*> (&(menubar->menu ()[t])); + if ((m->label () != NULL) && m->visible ()) + n++; + } + + return n; + } + + void show (void) + { + menubar->show (); + } + + void hide (void) + { + menubar->hide (); + } + + bool is_visible (void) + { + return menubar->visible (); + } + + int find_index_by_name (const std::string& findname) + { + // This function is derived from Greg Ercolano's function + // int GetIndexByName(...), see: + // http://seriss.com/people/erco/fltk/#Menu_ChangeLabel + // He agreed via PM that it can be included in octave using GPLv3 + // Kai Habel (14.10.2010) + + std::string menupath; + for (int t = 0; t < menubar->size (); t++ ) + { + Fl_Menu_Item *m = const_cast<Fl_Menu_Item*> (&(menubar->menu ()[t])); + if (m->submenu ()) + { + // item has submenu + if (!menupath.empty ()) + menupath += "/"; + menupath += m->label (); + + if (menupath.compare (findname) == 0 ) + return (t); + } + else + { + // End of submenu? Pop back one level. + if (m->label () == NULL) + { + std::size_t idx = menupath.find_last_of ("/"); + if (idx != std::string::npos) + menupath.erase (idx); + else + menupath.clear (); + continue; + } + // Menu item? + std::string itempath = menupath; + if (!itempath.empty ()) + itempath += "/"; + itempath += m->label (); + + if (itempath.compare (findname) == 0) + return (t); + } + } + return (-1); + } + + Matrix find_uimenu_children (uimenu::properties& uimenup) const + { + Matrix uimenu_childs = uimenup.get_all_children (); + Matrix retval = do_find_uimenu_children (uimenu_childs); + return retval; + } + + Matrix find_uimenu_children (figure::properties& figp) const + { + Matrix uimenu_childs = figp.get_all_children (); + Matrix retval = do_find_uimenu_children (uimenu_childs); + return retval; + } + + Matrix do_find_uimenu_children (Matrix uimenu_childs) const + { + octave_idx_type k = 0; + + + Matrix pos = Matrix (uimenu_childs.numel (), 1); + + for (octave_idx_type ii = 0; ii < uimenu_childs.numel (); ii++) + { + graphics_object kidgo = gh_manager::get_object (uimenu_childs (ii)); + + if (kidgo.valid_object () && kidgo.isa ("uimenu")) + { + uimenu_childs(k) = uimenu_childs(ii); + pos(k++) = + dynamic_cast<uimenu::properties&> (kidgo.get_properties ()).get_position (); + } + } + + uimenu_childs.resize (k, 1); + pos.resize (k, 1); + Matrix retval = Matrix (k, 1); + // Don't know if this is the best method to sort. + // Can we avoid the for loop? + Array<octave_idx_type> sidx = pos.sort_rows_idx (DESCENDING); + for (octave_idx_type ii = 0; ii < k; ii++) + retval(ii) = uimenu_childs (sidx(ii)); + + return retval; + } + + void delete_entry (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + int idx = find_index_by_name (fltk_label.c_str ()); + + if (idx >= 0) + menubar->remove (idx); + } + + void update_accelerator (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); + if (item != NULL) + { + std::string acc = uimenup.get_accelerator (); + if (acc.length () > 0) + { + int key = FL_CTRL + acc[0]; + item->shortcut (key); + } + } + } + } + + void update_callback (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); + if (item != NULL) + { + if (!uimenup.get_callback ().is_empty ()) + item->callback (static_cast<Fl_Callback*> (script_cb), + static_cast<void*> (&uimenup)); + else + item->callback (NULL, static_cast<void*> (0)); + } + } + } + + void update_enable (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); + if (item != NULL) + { + if (uimenup.is_enable ()) + item->activate (); + else + item->deactivate (); + } + } + } + + void update_foregroundcolor (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); + if (item != NULL) + { + Matrix rgb = uimenup.get_foregroundcolor_rgb (); + + uchar r = static_cast<uchar> (gnulib::floor (rgb (0) * 255)); + uchar g = static_cast<uchar> (gnulib::floor (rgb (1) * 255)); + uchar b = static_cast<uchar> (gnulib::floor (rgb (2) * 255)); + + item->labelcolor (fl_rgb_color (r, g, b)); + } + } + } + + void update_seperator (const uimenu::properties& uimenup) + { + // Matlab places the separator before the current + // menu entry, while fltk places it after. So we need to find + // the previous item in this menu/submenu. (Kai) + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + int itemflags = 0, idx; + int curr_idx = find_index_by_name (fltk_label.c_str ()); + + for (idx = curr_idx - 1; idx >= 0; idx--) + { + Fl_Menu_Item* item = const_cast<Fl_Menu_Item*> (&menubar->menu () [idx]); + itemflags = item->flags; + if (item->label () != NULL) + break; + } + + if (idx >= 0 && idx < menubar->size ()) + { + if (uimenup.is_separator ()) + { + if (idx >= 0 && !(itemflags & FL_SUBMENU)) + menubar->mode (idx, itemflags | FL_MENU_DIVIDER); + } + else + menubar->mode (idx, itemflags & (~FL_MENU_DIVIDER)); + } + } + } + + void update_visible (uimenu::properties& uimenup) + { + std::string fltk_label = uimenup.get_fltk_label (); + if (!fltk_label.empty ()) + { + Fl_Menu_Item* item + = const_cast<Fl_Menu_Item*> (menubar->find_item (fltk_label.c_str ())); + if (item != NULL) + { + if (uimenup.is_visible ()) + item->show (); + else + item->hide (); + } + } + } + + void add_entry (uimenu::properties& uimenup) + { + + std::string fltk_label = uimenup.get_fltk_label (); + + if (!fltk_label.empty ()) + { + bool item_added = false; + do + { + const Fl_Menu_Item* item + = menubar->find_item (fltk_label.c_str ()); + + if (item == NULL) + { + Matrix uimenu_ch = find_uimenu_children (uimenup); + int len = uimenu_ch.numel (); + int flags = 0; + if (len > 0) + flags = FL_SUBMENU; + if (len == 0 && uimenup.is_checked ()) + flags += FL_MENU_TOGGLE + FL_MENU_VALUE; + menubar->add (fltk_label.c_str (), 0, 0, 0, flags); + item_added = true; + } + else + { + //avoid duplicate menulabels + std::size_t idx1 = fltk_label.find_last_of ("("); + std::size_t idx2 = fltk_label.find_last_of (")"); + int len = idx2 - idx1; + int val = 1; + if (len > 0) + { + std::string valstr = fltk_label.substr (idx1 + 1, len - 1); + fltk_label.erase (idx1, len + 1); + val = atoi (valstr.c_str ()); + if (val > 0 && val < 99) + val++; + } + std::ostringstream valstream; + valstream << val; + fltk_label += "(" + valstream.str () + ")"; + } + } + while (!item_added); + uimenup.set_fltk_label (fltk_label); + } + } + + void add_to_menu (uimenu::properties& uimenup) + { + Matrix kids = find_uimenu_children (uimenup); + int len = kids.length (); + std::string fltk_label = uimenup.get_fltk_label (); + + add_entry (uimenup); + update_foregroundcolor (uimenup); + update_callback (uimenup); + update_accelerator (uimenup); + update_enable (uimenup); + update_visible (uimenup); + update_seperator (uimenup); + + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); + if (kgo.valid_object ()) + { + uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); + add_to_menu (kprop); + } + } + } + + void add_to_menu (figure::properties& figp) + { + Matrix kids = find_uimenu_children (figp); + int len = kids.length (); + menubar->clear (); + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); + + if (kgo.valid_object ()) + { + uimenu::properties& kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); + add_to_menu (kprop); + } + } + } + + template <class T_prop> + void remove_from_menu (T_prop& prop) + { + Matrix kids; + std::string type = prop.get_type (); + kids = find_uimenu_children (prop); + int len = kids.length (); + + for (octave_idx_type ii = 0; ii < len; ii++) + { + graphics_object kgo = gh_manager::get_object (kids (len - (ii + 1))); + + if (kgo.valid_object ()) + { + uimenu::properties kprop = dynamic_cast<uimenu::properties&> (kgo.get_properties ()); + remove_from_menu (kprop); + } + } + + if (type.compare ("uimenu") == 0) + delete_entry (dynamic_cast<uimenu::properties&> (prop)); + else if (type.compare ("figure") == 0) + menubar->clear (); + } + + ~fltk_uimenu (void) + { + delete menubar; + } + +private: + + // No copying! + + fltk_uimenu (const fltk_uimenu&); + + fltk_uimenu operator = (const fltk_uimenu&); + + Fl_Menu_Bar* menubar; +}; + +class plot_window : public Fl_Window +{ + friend class fltk_uimenu; +public: + plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp) + : Fl_Window (xx, yy, ww, hh, "octave"), window_label (), shift (0), + ndim (2), fp (xfp), canvas (0), autoscale (0), togglegrid (0), + panzoom (0), rotate (0), help (0), status (0), + ax_obj (), pos_x (0), pos_y (0) + { + callback (window_close, static_cast<void*> (this)); + size_range (4*status_h, 2*status_h); + + // FIXME: The function below is only available in FLTK >= 1.3 + // At some point support for FLTK 1.1 will be dropped in Octave. + // At that point this function should be uncommented. + // The current solution is to call xclass() before show() for each window. + // Set WM_CLASS which allows window managers to properly group related + // windows. Otherwise, the class is just "FLTK" + //default_xclass ("Octave"); + + begin (); + { + + canvas = new OpenGL_fltk (0, 0, ww, hh - status_h, number ()); + + uimenu = new fltk_uimenu (0, 0, ww, menu_h); + uimenu->hide (); + + bottom = new Fl_Box (0, hh - status_h, ww, status_h); + bottom->box (FL_FLAT_BOX); + + ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ())); + + autoscale = new Fl_Button (0, hh - status_h, status_h, status_h, "A"); + autoscale->callback (button_callback, static_cast<void*> (this)); + autoscale->tooltip ("Autoscale"); + + togglegrid = new Fl_Button (status_h, hh - status_h, status_h, + status_h, "G"); + togglegrid->callback (button_callback, static_cast<void*> (this)); + togglegrid->tooltip ("Toggle Grid"); + + panzoom = new Fl_Button (2 * status_h, hh - status_h, status_h, + status_h, "P"); + panzoom->callback (button_callback, static_cast<void*> (this)); + panzoom->tooltip ("Mouse Pan/Zoom"); + + rotate = new Fl_Button (3 * status_h, hh - status_h, status_h, + status_h, "R"); + rotate->callback (button_callback, static_cast<void*> (this)); + rotate->tooltip ("Mouse Rotate"); + + if (ndim == 2) + rotate->deactivate (); + + help = new Fl_Button (4 * status_h, hh - status_h, status_h, + status_h, "?"); + help->callback (button_callback, static_cast<void*> (this)); + help->tooltip ("Help"); + + status = new Fl_Output (5 * status_h, hh - status_h, + ww > 2*status_h ? ww - status_h : 0, + status_h, ""); + + status->textcolor (FL_BLACK); + status->color (FL_GRAY); + status->textfont (FL_COURIER); + status->textsize (10); + status->box (FL_ENGRAVED_BOX); + + // This allows us to have a valid OpenGL context right away. + canvas->mode (FL_DEPTH | FL_DOUBLE ); + if (fp.is_visible ()) + { + // FIXME: This code should be removed when Octave drops support + // for FLTK 1.1. Search for default_xclass in this file to find + // code that should be uncommented to take its place. + // + // Set WM_CLASS which allows window managers to properly group + // related windows. Otherwise, the class is just "FLTK" + xclass ("Octave"); + show (); + if (fp.get_currentaxes ().ok ()) + show_canvas (); + else + hide_canvas (); + } + } + end (); + + status->show (); + autoscale->show (); + togglegrid->show (); + panzoom->show (); + rotate->show (); + + set_name (); + resizable (canvas); + gui_mode = (ndim == 3 ? rotate_zoom : pan_zoom); + uimenu->add_to_menu (fp); + if (uimenu->items_to_show ()) + show_menubar (); + else + hide_menubar (); + } + + ~plot_window (void) + { + canvas->hide (); + status->hide (); + uimenu->hide (); + this->hide (); + } + + double number (void) { return fp.get___myhandle__ ().value (); } + + void renumber (double new_number) + { + if (canvas) + { + if (canvas->renumber (new_number)) + mark_modified (); + } + else + error ("unable to renumber figure"); + } + + void print (const std::string& cmd, const std::string& term) + { + canvas->print (cmd, term); + + // Print immediately so the output file will exist when the drawnow + // command is done. + mark_modified (); + Fl::wait (fltk_maxtime); + } + + void show_menubar (void) + { + if (!uimenu->is_visible ()) + { + canvas->resize (canvas->x (), + canvas->y () + menu_h, + canvas->w (), + canvas->h () - menu_h); + uimenu->show (); + mark_modified (); + } + } + + void hide_menubar (void) + { + if (uimenu->is_visible ()) + { + canvas->resize (canvas->x (), + canvas->y () - menu_h, + canvas->w (), + canvas->h () + menu_h); + uimenu->hide (); + mark_modified (); + } + } + + void uimenu_update (const graphics_handle& gh, int id) + { + graphics_object uimenu_obj = gh_manager::get_object (gh); + + if (uimenu_obj.valid_object () && uimenu_obj.isa ("uimenu")) + { + uimenu::properties& uimenup = + dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ()); + std::string fltk_label = uimenup.get_fltk_label (); + graphics_object fig = uimenu_obj.get_ancestor ("figure"); + figure::properties& figp = + dynamic_cast<figure::properties&> (fig.get_properties ()); + + switch (id) + { + case base_properties::ID_BEINGDELETED: + uimenu->remove_from_menu (uimenup); + break; + + case base_properties::ID_VISIBLE: + uimenu->update_visible (uimenup); + break; + + case uimenu::properties::ID_ACCELERATOR: + uimenu->update_accelerator (uimenup); + break; + + case uimenu::properties::ID_CALLBACK: + uimenu->update_callback (uimenup); + break; + + case uimenu::properties::ID_CHECKED: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + + case uimenu::properties::ID_ENABLE: + uimenu->update_enable (uimenup); + break; + + case uimenu::properties::ID_FOREGROUNDCOLOR: + uimenu->update_foregroundcolor (uimenup); + break; + + case uimenu::properties::ID_LABEL: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + + case uimenu::properties::ID_POSITION: + uimenu->add_to_menu (figp);//rebuilding entire menu + break; + + case uimenu::properties::ID_SEPARATOR: + uimenu->update_seperator (uimenup); + break; + } + + if (uimenu->items_to_show ()) + show_menubar (); + else + hide_menubar (); + + mark_modified (); + } + } + + void show_canvas (void) + { + if (fp.is_visible ()) + { + canvas->show (); + canvas->make_current (); + } + } + + void hide_canvas (void) + { + canvas->hide (); + } + + void mark_modified (void) + { + damage (FL_DAMAGE_ALL); + canvas->damage (FL_DAMAGE_ALL); + ndim = calc_dimensions (gh_manager::get_object (fp.get___myhandle__ ())); + + if (ndim == 3) + rotate->activate (); + else if (ndim == 2 && gui_mode == rotate_zoom) + { + rotate->deactivate (); + gui_mode = pan_zoom; + } + } + + void set_name (void) + { + window_label = fp.get_title (); + label (window_label.c_str ()); + } + +private: + + // No copying! + + plot_window (const plot_window&); + + plot_window& operator = (const plot_window&); + + // window name -- this must exists for the duration of the window's + // life + std::string window_label; + + // Mod keys status + int shift; + + // Number of dimensions, 2 or 3. + int ndim; + + // Figure properties. + figure::properties& fp; + + // Status area height. + static const int status_h = 20; + + // Menu height + static const int menu_h = 20; + + // Window callback. + static void window_close (Fl_Widget*, void* data) + { + octave_value_list args; + args(0) = static_cast<plot_window*> (data)->number (); + feval ("close", args); + } + + // Button callbacks. + static void button_callback (Fl_Widget* ww, void* data) + { + static_cast<plot_window*> (data)->button_press (ww, data); + } + + void button_press (Fl_Widget* widg, void*) + { + if (widg == autoscale) + axis_auto (); + + if (widg == togglegrid) + toggle_grid (); + + if (widg == panzoom) + gui_mode = pan_zoom; + + if (widg == rotate && ndim == 3) + gui_mode = rotate_zoom; + + if (widg == help) + fl_message ("%s", help_text); + } + + fltk_uimenu* uimenu; + OpenGL_fltk* canvas; + Fl_Box* bottom; + Fl_Button* autoscale; + Fl_Button* togglegrid; + Fl_Button* panzoom; + Fl_Button* rotate; + Fl_Button* help; + Fl_Output* status; + graphics_object ax_obj; + int pos_x; + int pos_y; + + void axis_auto (void) + { + octave_value_list args; + args(0) = fp.get_currentaxes ().as_octave_value (); + args(1) = "auto"; + feval ("axis", args); + mark_modified (); + } + + void toggle_grid (void) + { + octave_value_list args; + if (fp.get_currentaxes ().ok ()) + args(0) = fp.get_currentaxes ().as_octave_value (); + + feval ("grid", args); + mark_modified (); + } + + void pixel2pos (const graphics_handle& ax, int px, int py, double& xx, + double& yy) const + { + pixel2pos ( gh_manager::get_object (ax), px, py, xx, yy); + } + + void pixel2pos (graphics_object ax, int px, int py, double& xx, + double& yy) const + { + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + ColumnVector pp = ap.pixel2coord (px, py); + xx = pp(0); + yy = pp(1); + } + } + + graphics_handle pixel2axes_or_ca (int px, int py ) + { + Matrix kids = fp.get_children (); + int len = kids.length (); + + for (int k = 0; k < len; k++) + { + graphics_handle hnd = gh_manager::lookup (kids(k)); + + if (hnd.ok ()) + { + graphics_object kid = gh_manager::get_object (hnd); + + if (kid.valid_object () && kid.isa ("axes")) + { + Matrix bb = kid.get_properties ().get_boundingbox (true); + + if (bb(0) <= px && px < (bb(0)+bb(2)) + && bb(1) <= py && py < (bb(1)+bb(3))) + { + return hnd; + } + } + } + } + return fp.get_currentaxes (); + } + + void pixel2status (const graphics_handle& ax, int px0, int py0, + int px1 = -1, int py1 = -1) + { + pixel2status (gh_manager::get_object (ax), px0, py0, px1, py1); + } + + void pixel2status (graphics_object ax, int px0, int py0, + int px1 = -1, int py1 = -1) + { + double x0, y0, x1, y1; + std::stringstream cbuf; + cbuf.precision (4); + cbuf.width (6); + pixel2pos (ax, px0, py0, x0, y0); + cbuf << "[" << x0 << ", " << y0 << "]"; + if (px1 >= 0) + { + pixel2pos (ax, px1, py1, x1, y1); + cbuf << " -> ["<< x1 << ", " << y1 << "]"; + } + + status->value (cbuf.str ().c_str ()); + status->redraw (); + } + + void view2status (graphics_object ax) + { + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + std::stringstream cbuf; + cbuf.precision (4); + cbuf.width (6); + Matrix v (1,2,0); + v = ap.get ("view").matrix_value (); + cbuf << "[azimuth: " << v(0) << ", elevation: " << v(1) << "]"; + + status->value (cbuf.str ().c_str ()); + status->redraw (); + } + } + + void set_currentpoint (int px, int py) + { + if (!fp.is_beingdeleted ()) + { + Matrix pos (1,2,0); + pos(0) = px; + pos(1) = h () - status_h - menu_h - py; + fp.set_currentpoint (pos); + } + } + + void set_axes_currentpoint (graphics_object ax, int px, int py) + { + if (ax.valid_object ()) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + + double xx, yy; + pixel2pos (ax, px, py, xx, yy); + + Matrix pos (2,3,0); + pos(0,0) = xx; + pos(1,0) = yy; + pos(0,1) = xx; + pos(1,1) = yy; + + ap.set_currentpoint (pos); + } + } + + int key2shift (int key) + { + if (key == FL_Shift_L || key == FL_Shift_R) + return FL_SHIFT; + + if (key == FL_Control_L || key == FL_Control_R) + return FL_CTRL; + + if (key == FL_Alt_L || key == FL_Alt_R) + return FL_ALT; + + if (key == FL_Meta_L || key == FL_Meta_R) + return FL_META; + + return 0; + } + + int key2ascii (int key) + { + if (key < 256) return key; + if (key == FL_Tab) return '\t'; + if (key == FL_Enter) return 0x0a; + if (key == FL_BackSpace) return 0x08; + if (key == FL_Escape) return 0x1b; + + return 0; + } + + Cell modifier2cell () + { + string_vector mod; + + if (shift & FL_SHIFT) + mod.append (std::string ("shift")); + if (shift & FL_CTRL) + mod.append (std::string ("control")); + if (shift & FL_ALT || shift & FL_META) + mod.append (std::string ("alt")); + + return Cell (mod); + } + + void resize (int xx,int yy,int ww,int hh) + { + Fl_Window::resize (xx, yy, ww, hh); + + Matrix pos (1,4,0); + pos(0) = xx; + pos(1) = yy; + pos(2) = ww; + pos(3) = hh - status_h - menu_h; + + fp.set_boundingbox (pos, true); + } + + void draw (void) + { + Matrix pos = fp.get_boundingbox (true); + Fl_Window::resize (pos(0), pos(1), pos(2), pos(3) + status_h + menu_h); + + return Fl_Window::draw (); + } + + int handle (int event) + { + graphics_handle gh; + + graphics_object fig = gh_manager::get_object (fp.get___myhandle__ ()); + int retval = Fl_Window::handle (event); + + // We only handle events which are in the canvas area. + if (!Fl::event_inside (canvas)) + return retval; + + if (!fp.is_beingdeleted ()) + { + switch (event) + { + case FL_KEYDOWN: + { + int key = Fl::event_key (); + + shift |= key2shift (key); + int key_a = key2ascii (key); + if (key_a && fp.get_keypressfcn ().is_defined ()) + { + Octave_map evt; + evt.assign ("Character", octave_value (key_a)); + evt.assign ("Key", octave_value (std::tolower (key_a))); + evt.assign ("Modifier", octave_value (modifier2cell ())); + fp.execute_keypressfcn (evt); + } + switch (key) + { + case 'a': + case 'A': + axis_auto (); + break; + + case 'g': + case 'G': + toggle_grid (); + break; + + case 'p': + case 'P': + gui_mode = pan_zoom; + break; + + case 'r': + case 'R': + gui_mode = rotate_zoom; + break; + } + } + break; + + case FL_KEYUP: + { + int key = Fl::event_key (); + + shift &= (~key2shift (key)); + int key_a = key2ascii (key); + if (key_a && fp.get_keyreleasefcn ().is_defined ()) + { + Octave_map evt; + evt.assign ("Character", octave_value (key_a)); + evt.assign ("Key", octave_value (std::tolower (key_a))); + evt.assign ("Modifier", octave_value (modifier2cell ())); + fp.execute_keyreleasefcn (evt); + } + } + break; + + case FL_MOVE: + pixel2status (pixel2axes_or_ca (Fl::event_x (), Fl::event_y ()), + Fl::event_x (), Fl::event_y ()); + break; + + case FL_PUSH: + pos_x = Fl::event_x (); + pos_y = Fl::event_y (); + + set_currentpoint (Fl::event_x (), Fl::event_y ()); + + gh = pixel2axes_or_ca (pos_x, pos_y); + + if (gh.ok ()) + { + ax_obj = gh_manager::get_object (gh); + set_axes_currentpoint (ax_obj, pos_x, pos_y); + } + + fp.execute_windowbuttondownfcn (); + + if (Fl::event_button () == 1 || Fl::event_button () == 3) + return 1; + + break; + + case FL_DRAG: + if (fp.get_windowbuttonmotionfcn ().is_defined ()) + { + set_currentpoint (Fl::event_x (), Fl::event_y ()); + fp.execute_windowbuttonmotionfcn (); + } + + if (Fl::event_button () == 1) + { + if (ax_obj && ax_obj.isa ("axes")) + { + if (gui_mode == pan_zoom) + pixel2status (ax_obj, pos_x, pos_y, + Fl::event_x (), Fl::event_y ()); + else + view2status (ax_obj); + axes::properties& ap = + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); + + double x0, y0, x1, y1; + Matrix pos = fp.get_boundingbox (true); + pixel2pos (ax_obj, pos_x, pos_y, x0, y0); + pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (), x1, y1); + + if (gui_mode == pan_zoom) + ap.translate_view (x0, x1, y0, y1); + else if (gui_mode == rotate_zoom) + { + double daz, del; + daz = (Fl::event_x () - pos_x) / pos(2) * 360; + del = (Fl::event_y () - pos_y) / pos(3) * 360; + ap.rotate_view (del, daz); + } + + pos_x = Fl::event_x (); + pos_y = Fl::event_y (); + mark_modified (); + } + return 1; + } + else if (Fl::event_button () == 3) + { + pixel2status (ax_obj, pos_x, pos_y, + Fl::event_x (), Fl::event_y ()); + Matrix zoom_box (1,4,0); + zoom_box (0) = pos_x; + zoom_box (1) = pos_y; + zoom_box (2) = Fl::event_x (); + zoom_box (3) = Fl::event_y (); + canvas->set_zoom_box (zoom_box); + canvas->zoom (true); + canvas->redraw (); + } + + break; + + case FL_MOUSEWHEEL: + { + graphics_object ax = + gh_manager::get_object (pixel2axes_or_ca (Fl::event_x (), + Fl::event_y ())); + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + + // Determine if we're zooming in or out. + const double factor = + (Fl::event_dy () > 0) ? 1.0 + wheel_zoom_speed : 1.0 - wheel_zoom_speed; + + // Get the point we're zooming about. + double x1, y1; + pixel2pos (ax, Fl::event_x (), Fl::event_y (), x1, y1); + + ap.zoom_about_point (x1, y1, factor, false); + mark_modified (); + } + } + return 1; + + case FL_RELEASE: + if (fp.get_windowbuttonupfcn ().is_defined ()) + { + set_currentpoint (Fl::event_x (), Fl::event_y ()); + fp.execute_windowbuttonupfcn (); + } + + if (Fl::event_button () == 1) + { + if ( Fl::event_clicks () == 1) + { + if (ax_obj && ax_obj.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); + ap.set_xlimmode ("auto"); + ap.set_ylimmode ("auto"); + ap.set_zlimmode ("auto"); + mark_modified (); + } + } + } + if (Fl::event_button () == 3) + { + // End of drag -- zoom. + if (canvas->zoom ()) + { + canvas->zoom (false); + double x0,y0,x1,y1; + if (ax_obj && ax_obj.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); + pixel2pos (ax_obj, pos_x, pos_y, x0, y0); + int pos_x1 = Fl::event_x (); + int pos_y1 = Fl::event_y (); + pixel2pos (ax_obj, pos_x1, pos_y1, x1, y1); + Matrix xl (1,2,0); + Matrix yl (1,2,0); + int dx = abs (pos_x - pos_x1); + int dy = abs (pos_y - pos_y1); + // Smallest zoom box must be 4 pixels square + if ((dx > 4) && (dy > 4)) + { + if (x0 < x1) + { + xl(0) = x0; + xl(1) = x1; + } + else + { + xl(0) = x1; + xl(1) = x0; + } + if (y0 < y1) + { + yl(0) = y0; + yl(1) = y1; + } + else + { + yl(0) = y1; + yl(1) = y0; + } + ap.zoom (xl, yl); + } + mark_modified (); + } + } + } + break; + } + } + + return retval; + } +}; + +class figure_manager +{ +public: + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + instance = new figure_manager (); + + if (! instance) + { + ::error ("unable to create figure_manager object!"); + + retval = false; + } + + return retval; + } + + ~figure_manager (void) + { + close_all (); + } + + static void close_all (void) + { + if (instance_ok ()) + instance->do_close_all (); + } + + static void new_window (figure::properties& fp) + { + if (instance_ok ()) + instance->do_new_window (fp); + } + + static void delete_window (int idx) + { + if (instance_ok ()) + instance->do_delete_window (idx); + } + + static void delete_window (const std::string& idx_str) + { + delete_window (str2idx (idx_str)); + } + + static void renumber_figure (const std::string& idx_str, double new_number) + { + if (instance_ok ()) + instance->do_renumber_figure (str2idx (idx_str), new_number); + } + + static void toggle_window_visibility (int idx, bool is_visible) + { + if (instance_ok ()) + instance->do_toggle_window_visibility (idx, is_visible); + } + + static void toggle_window_visibility (const std::string& idx_str, + bool is_visible) + { + toggle_window_visibility (str2idx (idx_str), is_visible); + } + + static void mark_modified (int idx) + { + if (instance_ok ()) + instance->do_mark_modified (idx); + } + + static void mark_modified (const graphics_handle& gh) + { + mark_modified (hnd2idx (gh)); + } + + static void set_name (int idx) + { + if (instance_ok ()) + instance->do_set_name (idx); + } + + static void set_name (const std::string& idx_str) + { + set_name (str2idx (idx_str)); + } + + static Matrix get_size (int idx) + { + return instance_ok () ? instance->do_get_size (idx) : Matrix (); + } + + static Matrix get_size (const graphics_handle& gh) + { + return get_size (hnd2idx (gh)); + } + + static void print (const graphics_handle& gh, const std::string& cmd, + const std::string& term) + { + if (instance_ok ()) + instance->do_print (hnd2idx (gh), cmd, term); + } + + static void uimenu_update (const graphics_handle& figh, + const graphics_handle& uimenuh, int id) + { + if (instance_ok ()) + instance->do_uimenu_update (hnd2idx (figh), uimenuh, id); + } + + static void update_canvas (const graphics_handle& gh, + const graphics_handle& ca) + { + if (instance_ok ()) + instance->do_update_canvas (hnd2idx (gh), ca); + } + + static void toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) + { + if (instance_ok ()) + instance->do_toggle_menubar_visibility (fig_idx, menubar_is_figure); + } + + static void toggle_menubar_visibility (const std::string& fig_idx_str, + bool menubar_is_figure) + { + toggle_menubar_visibility (str2idx (fig_idx_str), menubar_is_figure); + } + +private: + + static figure_manager *instance; + + figure_manager (void) { } + + // No copying! + figure_manager (const figure_manager&); + figure_manager& operator = (const figure_manager&); + + // Singelton -- hide all of the above. + + static int curr_index; + typedef std::map<int, plot_window*> window_map; + typedef window_map::iterator wm_iterator;; + window_map windows; + + static std::string fltk_idx_header; + + void do_close_all (void) + { + wm_iterator win; + for (win = windows.begin (); win != windows.end (); win++) + delete win->second; + windows.clear (); + } + + void do_new_window (figure::properties& fp) + { + int idx = figprops2idx (fp); + + if (idx >= 0 && windows.find (idx) == windows.end ()) + { + Matrix pos = fp.get_boundingbox (true); + + int x = pos(0); + int y = pos(1); + int w = pos(2); + int h = pos(3); + + idx2figprops (curr_index, fp); + + windows[curr_index++] = new plot_window (x, y, w, h, fp); + } + } + + void do_delete_window (int idx) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + { + delete win->second; + windows.erase (win); + } + } + + void do_renumber_figure (int idx, double new_number) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + win->second->renumber (new_number); + } + + void do_toggle_window_visibility (int idx, bool is_visible) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + { + if (is_visible) + win->second->show (); + else + win->second->hide (); + + win->second->redraw (); + } + } + + void do_toggle_menubar_visibility (int fig_idx, bool menubar_is_figure) + { + wm_iterator win = windows.find (fig_idx); + + if (win != windows.end ()) + { + if (menubar_is_figure) + win->second->show_menubar (); + else + win->second->hide_menubar (); + + win->second->redraw (); + } + } + + void do_mark_modified (int idx) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + win->second->mark_modified (); + } + + void do_set_name (int idx) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + win->second->set_name (); + } + + Matrix do_get_size (int idx) + { + Matrix sz (1, 2, 0.0); + + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + { + sz(0) = win->second->w (); + sz(1) = win->second->h (); + } + + return sz; + } + + void do_print (int idx, const std::string& cmd, const std::string& term) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + win->second->print (cmd, term); + } + + void do_uimenu_update (int idx, const graphics_handle& gh, int id) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + win->second->uimenu_update (gh, id); + } + + void do_update_canvas (int idx, const graphics_handle& ca) + { + wm_iterator win = windows.find (idx); + + if (win != windows.end ()) + { + if (ca.ok ()) + win->second->show_canvas (); + else + win->second->hide_canvas (); + } + } + + static int str2idx (const caseless_str& clstr) + { + int ind; + if (clstr.find (fltk_idx_header,0) == 0) + { + std::istringstream istr (clstr.substr (fltk_idx_header.size ())); + if (istr >> ind) + return ind; + } + error ("figure_manager: could not recognize fltk index"); + return -1; + } + + void idx2figprops (int idx, figure::properties& fp) + { + std::ostringstream ind_str; + ind_str << fltk_idx_header << idx; + fp.set___plot_stream__ (ind_str.str ()); + } + + static int figprops2idx (const figure::properties& fp) + { + if (fp.get___graphics_toolkit__ () == FLTK_GRAPHICS_TOOLKIT_NAME) + { + octave_value ps = fp.get___plot_stream__ (); + if (ps.is_string ()) + return str2idx (ps.string_value ()); + else + return 0; + } + error ("figure_manager: figure is not fltk"); + return -1; + } + + static int hnd2idx (double h) + { + graphics_object fobj = gh_manager::get_object (h); + if (fobj && fobj.isa ("figure")) + { + figure::properties& fp = + dynamic_cast<figure::properties&> (fobj.get_properties ()); + return figprops2idx (fp); + } + error ("figure_manager: H (= %g) is not a figure", h); + return -1; + } + + static int hnd2idx (const graphics_handle& fh) + { + return hnd2idx (fh.value ()); + } +}; + +figure_manager *figure_manager::instance = 0; + +std::string figure_manager::fltk_idx_header="fltk index="; +int figure_manager::curr_index = 1; + +static bool toolkit_loaded = false; + +static int +__fltk_redraw__ (void) +{ + if (toolkit_loaded) + { + // We scan all figures and add those which use FLTK. + graphics_object obj = gh_manager::get_object (0); + if (obj && obj.isa ("root")) + { + base_properties& props = obj.get_properties (); + Matrix children = props.get_all_children (); + + for (octave_idx_type n = 0; n < children.numel (); n++) + { + graphics_object fobj = gh_manager::get_object (children (n)); + if (fobj && fobj.isa ("figure")) + { + figure::properties& fp = + dynamic_cast<figure::properties&> (fobj.get_properties ()); + if (fp.get___graphics_toolkit__ () + == FLTK_GRAPHICS_TOOLKIT_NAME) + figure_manager::new_window (fp); + } + } + } + + // it seems that we have to call Fl::check twice to get everything drawn + Fl::check (); + Fl::check (); + } + + return 0; +} + +class fltk_graphics_toolkit : public base_graphics_toolkit +{ +public: + fltk_graphics_toolkit (void) + : base_graphics_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME) { } + + ~fltk_graphics_toolkit (void) { } + + bool is_valid (void) const { return true; } + + bool initialize (const graphics_object& go) + { return go.isa ("figure"); } + + void finalize (const graphics_object& go) + { + if (go.isa ("figure")) + { + octave_value ov = go.get (caseless_str ("__plot_stream__")); + + if (! ov.is_empty ()) + figure_manager::delete_window (ov.string_value ()); + } + } + + void uimenu_set_fltk_label (graphics_object uimenu_obj) + { + if (uimenu_obj.valid_object ()) + { + uimenu::properties& uimenup = + dynamic_cast<uimenu::properties&> (uimenu_obj.get_properties ()); + std::string fltk_label = uimenup.get_label (); + graphics_object go = gh_manager::get_object (uimenu_obj.get_parent ()); + if (go.isa ("uimenu")) + fltk_label = dynamic_cast<const uimenu::properties&> (go.get_properties ()).get_fltk_label () + + "/" + + fltk_label; + else if (go.isa ("figure")) + ; + else + error ("unexpected parent object\n"); + + uimenup.set_fltk_label (fltk_label); + } + } + + void update (const graphics_object& go, int id) + { + if (go.isa ("figure")) + { + octave_value ov = go.get (caseless_str ("__plot_stream__")); + + if (! ov.is_empty ()) + { + const figure::properties& fp = + dynamic_cast<const figure::properties&> (go.get_properties ()); + + switch (id) + { + case base_properties::ID_VISIBLE: + figure_manager::toggle_window_visibility + (ov.string_value (), fp.is_visible ()); + break; + + case figure::properties::ID_MENUBAR: + figure_manager::toggle_menubar_visibility + (ov.string_value (), fp.menubar_is ("figure")); + break; + + case figure::properties::ID_CURRENTAXES: + figure_manager::update_canvas + (go.get_handle (), fp.get_currentaxes ()); + break; + + case figure::properties::ID_NAME: + case figure::properties::ID_NUMBERTITLE: + figure_manager::set_name (ov.string_value ()); + break; + + case figure::properties::ID_INTEGERHANDLE: + { + std::string tmp = ov.string_value (); + graphics_handle gh = fp.get___myhandle__ (); + figure_manager::renumber_figure (tmp, gh.value ()); + figure_manager::set_name (tmp); + } + break; + } + } + } + else if (go.isa ("uimenu")) + { + if (id == uimenu::properties::ID_LABEL) + uimenu_set_fltk_label (go); + + graphics_object fig = go.get_ancestor ("figure"); + figure_manager::uimenu_update (fig.get_handle (), go.get_handle (), id); + } + } + + void redraw_figure (const graphics_object& go) const + { + figure_manager::mark_modified (go.get_handle ()); + + __fltk_redraw__ (); + } + + void print_figure (const graphics_object& go, + const std::string& term, + const std::string& file_cmd, bool /*mono*/, + const std::string& /*debug_file*/) const + { + figure_manager::print (go.get_handle (), file_cmd, term); + redraw_figure (go); + } + + Matrix get_canvas_size (const graphics_handle& fh) const + { + return figure_manager::get_size (fh); + } + + double get_screen_resolution (void) const + { + // FLTK doesn't give this info. + return 72.0; + } + + Matrix get_screen_size (void) const + { + Matrix sz (1, 2, 0.0); + sz(0) = Fl::w (); + sz(1) = Fl::h (); + return sz; + } + + void close (void) + { + if (toolkit_loaded) + { + munlock ("__init_fltk__"); + + figure_manager::close_all (); + gtk_manager::unload_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME); + toolkit_loaded = false; + + octave_value_list args; + args(0) = "__fltk_redraw__"; + feval ("remove_input_event_hook", args, 0); + + // FIXME ??? + Fl::wait (fltk_maxtime); + } + } +}; + +// Initialize the fltk graphics toolkit. + +DEFUN_DLD (__init_fltk__, , , "") +{ + if (! toolkit_loaded) + { + mlock (); + + graphics_toolkit tk (new fltk_graphics_toolkit ()); + gtk_manager::load_toolkit (tk); + toolkit_loaded = true; + + octave_value_list args; + args(0) = "__fltk_redraw__"; + feval ("add_input_event_hook", args, 0); + } + + octave_value retval; + return retval; +} + +DEFUN_DLD (__fltk_redraw__, , , "") +{ + __fltk_redraw__ (); + + return octave_value (); +} + +DEFUN_DLD (__fltk_maxtime__, args, ,"") +{ + octave_value retval = fltk_maxtime; + + if (args.length () == 1) + { + if (args(0).is_real_scalar ()) + fltk_maxtime = args(0).double_value (); + else + error ("argument must be a real scalar"); + } + + return retval; +} + +#endif + +// FIXME -- This function should be abstracted and made potentially +// available to all graphics toolkits. This suggests putting it in +// graphics.cc as is done for drawnow() and having the master +// mouse_wheel_zoom function call fltk_mouse_wheel_zoom. The same +// should be done for gui_mode and fltk_gui_mode. For now (2011.01.30), +// just changing function names and docstrings. + +DEFUN_DLD (mouse_wheel_zoom, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{speed} =} mouse_wheel_zoom ()\n\ +@deftypefnx {Built-in Function} {} mouse_wheel_zoom (@var{speed})\n\ +Query or set the mouse wheel zoom factor.\n\ +\n\ +This function is currently implemented only for the FLTK graphics toolkit.\n\ +@seealso{gui_mode}\n\ +@end deftypefn") +{ +#if defined (HAVE_FLTK) + octave_value retval = wheel_zoom_speed; + + if (args.length () == 1) + { + if (args(0).is_real_scalar ()) + wheel_zoom_speed = args(0).double_value (); + else + error ("mouse_wheel_zoom: SPEED must be a real scalar"); + } + + return retval; +#else + error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries"); + return octave_value (); +#endif +} + +DEFUN_DLD (gui_mode, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{mode} =} gui_mode ()\n\ +@deftypefnx {Built-in Function} {} gui_mode (@var{mode})\n\ +Query or set the GUI mode for the current graphics toolkit.\n\ +The @var{mode} argument can be one of the following strings:\n\ +\n\ +@table @asis\n\ +@item '2d'\n\ +Allows panning and zooming of current axes.\n\ +\n\ +@item '3d'\n\ +Allows rotating and zooming of current axes.\n\ +\n\ +@item 'none'\n\ +Mouse inputs have no effect.\n\ +@end table\n\ +\n\ +This function is currently implemented only for the FLTK graphics toolkit.\n\ +@seealso{mouse_wheel_zoom}\n\ +@end deftypefn") +{ +#if defined (HAVE_FLTK) + caseless_str mode_str; + + if (gui_mode == pan_zoom) + mode_str = "2d"; + else if (gui_mode == rotate_zoom) + mode_str = "3d"; + else + mode_str = "none"; + + bool failed = false; + + if (args.length () == 1) + { + if (args(0).is_string ()) + { + mode_str = args(0).string_value (); + + if (mode_str.compare ("2d")) + gui_mode = pan_zoom; + else if (mode_str.compare ("3d")) + gui_mode = rotate_zoom; + else if (mode_str.compare ("none")) + gui_mode = none; + else + failed = true; + } + else + failed = true; + } + + if (failed) + error ("MODE must be one of the strings: \"2D\", \"3D\", or \"none\""); + + return octave_value (mode_str); +#else + error ("mouse_wheel_zoom: not available without OpenGL and FLTK libraries"); + return octave_value (); +#endif +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__init_gnuplot__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,193 @@ +/* + +Copyright (C) 2007-2012 John W. Eaton + +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/>. + +*/ + +/* + +To initialize: + + graphics_toolkit ("gnuplot"); + plot (randn (1e3, 1)); + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "defun-dld.h" +#include "error.h" +#include "graphics.h" +#include "parse.h" +#include "variables.h" + +// PKG_ADD: register_graphics_toolkit ("gnuplot"); + +static bool toolkit_loaded = false; + +class gnuplot_graphics_toolkit : public base_graphics_toolkit +{ +public: + gnuplot_graphics_toolkit (void) + : base_graphics_toolkit ("gnuplot") { } + + ~gnuplot_graphics_toolkit (void) { } + + bool is_valid (void) const { return true; } + + bool initialize (const graphics_object& go) + { + return go.isa ("figure"); + } + + void finalize (const graphics_object& go) + { + if (go.isa ("figure")) + { + const figure::properties& props = + dynamic_cast<const figure::properties&> (go.get_properties ()); + + send_quit (props.get___plot_stream__ ()); + } + } + + void update (const graphics_object& go, int id) + { + if (go.isa ("figure")) + { + graphics_object obj (go); + + figure::properties& props = + dynamic_cast<figure::properties&> (obj.get_properties ()); + + switch (id) + { + case base_properties::ID_VISIBLE: + if (! props.is_visible ()) + { + send_quit (props.get___plot_stream__ ()); + props.set___plot_stream__ (Matrix ()); + props.set___enhanced__ (false); + } + break; + } + } + } + + void redraw_figure (const graphics_object& go) const + { + octave_value_list args; + args(0) = go.get_handle ().as_octave_value (); + feval ("__gnuplot_drawnow__", args); + } + + void print_figure (const graphics_object& go, const std::string& term, + const std::string& file, bool mono, + const std::string& debug_file) const + { + octave_value_list args; + if (! debug_file.empty ()) + args(4) = debug_file; + args(3) = mono; + args(2) = file; + args(1) = term; + args(0) = go.get_handle ().as_octave_value (); + feval ("__gnuplot_drawnow__", args); + } + + Matrix get_canvas_size (const graphics_handle&) const + { + Matrix sz (1, 2, 0.0); + return sz; + } + + double get_screen_resolution (void) const + { return 72.0; } + + Matrix get_screen_size (void) const + { return Matrix (1, 2, 0.0); } + + void close (void) + { + if (toolkit_loaded) + { + munlock ("__init_gnuplot__"); + + gtk_manager::unload_toolkit ("gnuplot"); + + toolkit_loaded = false; + } + } + +private: + + void send_quit (const octave_value& pstream) const + { + if (! pstream.is_empty ()) + { + octave_value_list args; + Matrix fids = pstream.matrix_value (); + + if (! error_state) + { + args(1) = "\nquit;\n"; + args(0) = fids(0); + feval ("fputs", args); + + args.resize (1); + feval ("fflush", args); + feval ("pclose", args); + + if (fids.numel () > 1) + { + args(0) = fids(1); + feval ("pclose", args); + + if (fids.numel () > 2) + { + args(0) = fids(2); + feval ("waitpid", args); + } + } + } + } + } +}; + +// Initialize the fltk graphics toolkit. + +DEFUN_DLD (__init_gnuplot__, , , "") +{ + octave_value retval; + + if (! toolkit_loaded) + { + mlock (); + + graphics_toolkit tk (new gnuplot_graphics_toolkit ()); + gtk_manager::load_toolkit (tk); + + toolkit_loaded = true; + } + + return retval; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__magick_read__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,1216 @@ +/* + +Copyright (C) 2002-2012 Andy Adler +Copyright (C) 2008 Thomas L. Scofield +Copyright (C) 2010 David Grundberg + +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> +#endif + +#include <cmath> + +#include "file-stat.h" +#include "oct-env.h" +#include "oct-time.h" + +#include "defun-dld.h" +#include "error.h" +#include "ov-struct.h" + +#ifdef HAVE_MAGICK + +#include <Magick++.h> +#include <clocale> + +octave_value_list +read_indexed_images (std::vector<Magick::Image>& imvec, + const Array<int>& frameidx, bool wantalpha) +{ + octave_value_list output; + + int rows = imvec[0].baseRows (); + int columns = imvec[0].baseColumns (); + int nframes = frameidx.length (); + + dim_vector idim = dim_vector (); + idim.resize (4); + idim(0) = rows; + idim(1) = columns; + idim(2) = 1; + idim(3) = nframes; + + Array<int> idx (dim_vector (4, 1)); + + Magick::ImageType type = imvec[0].type (); + + unsigned int mapsize = imvec[0].colorMapSize (); + unsigned int i = mapsize; + unsigned int depth = 0; + while (i >>= 1) + depth++; + i = 0; + depth--; + while (depth >>= 1) + i++; + depth = 1 << i; + + switch (depth) + { + case 1: + case 2: + case 4: + case 8: + { + uint8NDArray im = uint8NDArray (idim); + + idx(2) = 0; + for (int frame = 0; frame < nframes; frame++) + { + imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + const Magick::IndexPacket *pix + = imvec[frameidx(frame)].getConstIndexes (); + + i = 0; + idx(3) = frame; + + for (int y = 0; y < rows; y++) + { + idx(0) = y; + for (int x = 0; x < columns; x++) + { + idx(1) = x; + im(idx) = static_cast<octave_uint8> (pix[i++]); + } + } + } + + output(0) = octave_value (im); + } + break; + + case 16: + { + uint16NDArray im = uint16NDArray (idim); + + idx(2) = 0; + for (int frame = 0; frame < nframes; frame++) + { + imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + const Magick::IndexPacket *pix + = imvec[frameidx(frame)].getConstIndexes (); + + i = 0; + idx(3) = frame; + + for (int y = 0; y < rows; y++) + { + idx(0) = y; + for (int x = 0; x < columns; x++) + { + idx(1) = x; + im(idx) = static_cast<octave_uint16> (pix[i++]); + } + } + } + + output(0) = octave_value (im); + } + break; + + default: + error ("__magic_read__: index depths greater than 16-bit are not supported"); + return octave_value_list (); + } + + Matrix map = Matrix (mapsize, 3); + Matrix alpha; + + switch (type) + { + case Magick::PaletteMatteType: +#if 0 + warning ("palettematte"); + Matrix map (mapsize, 3); + Matrix alpha (mapsize, 1); + for (i = 0; i < mapsize; i++) + { + warning ("%d", i); + Magick::ColorRGB c = imvec[0].colorMap (i); + map(i,0) = c.red (); + map(i,1) = c.green (); + map(i,2) = c.blue (); + alpha(i,1) = c.alpha (); + } + break; +#endif + + case Magick::PaletteType: + alpha = Matrix (0, 0); + for (i = 0; i < mapsize; i++) + { + Magick::ColorRGB c = imvec[0].colorMap (i); + map(i,0) = c.red (); + map(i,1) = c.green (); + map(i,2) = c.blue (); + } + break; + + default: + error ("__magick_read__: unsupported indexed image type"); + return octave_value_list (); + } + + if (wantalpha) + output(2) = alpha; + + output(1) = map; + + return output; +} + +template <class T> +octave_value_list +read_images (const std::vector<Magick::Image>& imvec, + const Array<int>& frameidx, unsigned int depth) +{ + typedef typename T::element_type P; + + octave_value_list retval (3, Matrix ()); + + T im; + + int rows = imvec[0].baseRows (); + int columns = imvec[0].baseColumns (); + int nframes = frameidx.length (); + + dim_vector idim = dim_vector (); + idim.resize (4); + idim(0) = rows; + idim(1) = columns; + idim(2) = 1; + idim(3) = nframes; + + Magick::ImageType type = imvec[0].type (); + const int divisor = ((uint64_t (1) << QuantumDepth) - 1) / + ((uint64_t (1) << depth) - 1); + + switch (type) + { + case Magick::BilevelType: + case Magick::GrayscaleType: + { + im = T (idim); + P *vec = im.fortran_vec (); + + for (int frame = 0; frame < nframes; frame++) + { + const Magick::PixelPacket *pix + = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + P *rbuf = vec; + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < columns; x++) + { + *rbuf = pix->red / divisor; + pix++; + rbuf += rows; + } + rbuf -= rows * columns - 1; + } + + // Next frame. + vec += rows * columns * idim(2); + } + } + break; + + case Magick::GrayscaleMatteType: + { + idim(2) = 2; + im = T (idim); + P *vec = im.fortran_vec (); + + for (int frame = 0; frame < nframes; frame++) + { + const Magick::PixelPacket *pix + = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + P *rbuf = vec; + P *obuf = vec + rows * columns; + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < columns; x++) + { + *rbuf = pix->red / divisor; + *obuf = pix->opacity / divisor; + pix++; + rbuf += rows; + obuf += rows; + } + rbuf -= rows * columns - 1; + obuf -= rows * columns - 1; + } + + // Next frame. + vec += rows * columns * idim(2); + } + } + break; + + case Magick::PaletteType: + case Magick::TrueColorType: + { + idim(2) = 3; + im = T (idim); + P *vec = im.fortran_vec (); + + for (int frame = 0; frame < nframes; frame++) + { + const Magick::PixelPacket *pix + = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + P *rbuf = vec; + P *gbuf = vec + rows * columns; + P *bbuf = vec + rows * columns * 2; + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < columns; x++) + { + *rbuf = pix->red / divisor; + *gbuf = pix->green / divisor; + *bbuf = pix->blue / divisor; + pix++; + rbuf += rows; + gbuf += rows; + bbuf += rows; + } + rbuf -= rows * columns - 1; + gbuf -= rows * columns - 1; + bbuf -= rows * columns - 1; + } + + // Next frame. + vec += rows * columns * idim(2); + } + } + break; + + case Magick::PaletteMatteType: + case Magick::TrueColorMatteType: + case Magick::ColorSeparationType: + { + idim(2) = 4; + im = T (idim); + P *vec = im.fortran_vec (); + + for (int frame = 0; frame < nframes; frame++) + { + const Magick::PixelPacket *pix + = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows); + + P *rbuf = vec; + P *gbuf = vec + rows * columns; + P *bbuf = vec + rows * columns * 2; + P *obuf = vec + rows * columns * 3; + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < columns; x++) + { + *rbuf = pix->red / divisor; + *gbuf = pix->green / divisor; + *bbuf = pix->blue / divisor; + *obuf = pix->opacity / divisor; + pix++; + rbuf += rows; + gbuf += rows; + bbuf += rows; + obuf += rows; + } + rbuf -= rows * columns - 1; + gbuf -= rows * columns - 1; + bbuf -= rows * columns - 1; + obuf -= rows * columns - 1; + } + + // Next frame. + vec += rows * columns * idim(2); + } + } + break; + + default: + error ("__magick_read__: undefined ImageMagick image type"); + return retval; + } + + retval(0) = im; + + return retval; +} + +#endif + +static void +maybe_initialize_magick (void) +{ +#ifdef HAVE_MAGICK + + static bool initialized = false; + + if (! initialized) + { + // Save the locale as GraphicsMagick might change this (depending on version) + const char *static_locale = setlocale (LC_ALL, NULL); + const std::string locale (static_locale); + + std::string program_name = octave_env::get_program_invocation_name (); + + Magick::InitializeMagick (program_name.c_str ()); + + // Restore locale from before GraphicsMagick initialisation + setlocale (LC_ALL, locale.c_str ()); + + if (QuantumDepth < 32) + warning ("your version of %s limits images to %d bits per pixel", + MagickPackageName, QuantumDepth); + + initialized = true; + } +#endif +} + +DEFUN_DLD (__magick_read__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Function File} {@var{m} =} __magick_read__ (@var{fname}, @var{index})\n\ +@deftypefnx {Function File} {[@var{m}, @var{colormap}] =} __magick_read__ (@var{fname}, @var{index})\n\ +@deftypefnx {Function File} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__ (@var{fname}, @var{index})\n\ +Read images with ImageMagick++. In general you should not be using this\n\ +function. Instead use @code{imread}.\n\ +@seealso{imread}\n\ +@end deftypefn") +{ + octave_value_list output; + +#ifdef HAVE_MAGICK + + maybe_initialize_magick (); + + if (args.length () > 3 || args.length () < 1 || ! args(0).is_string () + || nargout > 3) + { + print_usage (); + return output; + } + + Array<int> frameidx; + bool all_frames = false; + + if (args.length () == 2 && args(1).is_real_type ()) + frameidx = args(1).int_vector_value (); + else if (args.length () == 3 && args(1).is_string () + && args(1).string_value () == "frames") + { + if (args(2).is_string () && args(2).string_value () == "all") + all_frames = true; + else if (args(2).is_real_type ()) + frameidx = args(2).int_vector_value (); + } + else + { + frameidx = Array<int> (dim_vector (1, 1)); + frameidx(0) = 1; + } + + std::vector<Magick::Image> imvec; + + try + { + // Read a file into vector of image objects + Magick::readImages (&imvec, args(0).string_value ()); + } + catch (Magick::Warning& w) + { + warning ("Magick++ warning: %s", w.what ()); + } + catch (Magick::ErrorCoder& e) + { + warning ("Magick++ coder error: %s", e.what ()); + } + catch (Magick::Exception& e) + { + error ("Magick++ exception: %s", e.what ()); + return output; + } + + int nframes = imvec.size (); + if (all_frames) + { + frameidx = Array<int> (dim_vector (1, nframes)); + for (int i = 0; i < frameidx.length (); i++) + frameidx(i) = i; + } + else + { + for (int i = 0; i < frameidx.length (); i++) + { + frameidx(i) = frameidx(i) - 1; + + if (frameidx(i) >= nframes || frameidx(i) < 0) + { + error ("__magick_read__: invalid INDEX vector"); + return output; + } + } + } + + Magick::ClassType klass = imvec[0].classType (); + + if (klass == Magick::PseudoClass && nargout > 1) + output = read_indexed_images (imvec, frameidx, (nargout == 3)); + else + { + unsigned int depth = imvec[0].modulusDepth (); + if (depth > 1) + { + --depth; + int i = 1; + while (depth >>= 1) + i++; + depth = 1 << i; + } + + switch (depth) + { + case 1: + output = read_images<boolNDArray> (imvec, frameidx, depth); + break; + + case 2: + case 4: + case 8: + output = read_images<uint8NDArray> (imvec, frameidx, depth) ; + break; + + case 16: + output = read_images<uint16NDArray> (imvec, frameidx, depth); + break; + + case 32: + case 64: + default: + error ("__magick_read__: image depths greater than 16-bit are not supported"); + } + } +#else + + error ("imread: image reading capabilities were disabled when Octave was compiled"); + +#endif + + return output; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/ + +#ifdef HAVE_MAGICK + +static void +jpg_settings (std::vector<Magick::Image>& imvec, + const Octave_map& options, + bool) +{ + bool something_set = false; + + // Quality setting + octave_value result; + Octave_map::const_iterator p; + bool found_it = false; + + for (p = options.begin (); p != options.end (); p++) + { + if (options.key (p) == "Quality") + { + found_it = true; + result = options.contents (p).elem (0); + break; + } + } + + if (found_it && (! result.is_empty ())) + { + something_set = true; + + if (result.is_real_type ()) + { + int qlev = result.int_value (); + + if (qlev < 0 || qlev > 100) + warning ("warning: Quality setting invalid--use default of 75"); + else + { + for (size_t fnum = 0; fnum < imvec.size (); fnum++) + imvec[fnum].quality (static_cast<unsigned int>(qlev)); + } + } + else + warning ("warning: Quality setting invalid--use default of 75"); + } + + // Other settings go here + + if (! something_set) + warning ("__magick_write__ warning: all write parameters ignored"); +} + +static void +encode_bool_image (std::vector<Magick::Image>& imvec, const octave_value& img) +{ + unsigned int nframes = 1; + boolNDArray m = img.bool_array_value (); + + dim_vector dsizes = m.dims (); + if (dsizes.length () == 4) + nframes = dsizes(3); + + Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1)); + + octave_idx_type rows = m.rows (); + octave_idx_type columns = m.columns (); + + for (unsigned int ii = 0; ii < nframes; ii++) + { + Magick::Image im (Magick::Geometry (columns, rows), "black"); + im.classType (Magick::DirectClass); + im.depth (1); + + for (int y = 0; y < columns; y++) + { + idx(1) = y; + + for (int x = 0; x < rows; x++) + { + if (nframes > 1) + { + idx(2) = 0; + idx(3) = ii; + } + + idx(0) = x; + + if (m(idx)) + im.pixelColor (y, x, "white"); + } + } + + im.quantizeColorSpace (Magick::GRAYColorspace); + im.quantizeColors (2); + im.quantize (); + + imvec.push_back (im); + } +} + +template <class T> +static void +encode_uint_image (std::vector<Magick::Image>& imvec, + const octave_value& img, + bool has_map) +{ + unsigned int bitdepth = 0; + T m; + + if (img.is_uint8_type ()) + { + bitdepth = 8; + m = img.uint8_array_value (); + } + else if (img.is_uint16_type ()) + { + bitdepth = 16; + m = img.uint16_array_value (); + } + else + error ("__magick_write__: invalid image class"); + + dim_vector dsizes = m.dims (); + unsigned int nframes = 1; + if (dsizes.length () == 4) + nframes = dsizes(3); + + bool is_color = ((dsizes.length () > 2) && (dsizes(2) > 2)); + bool has_alpha = (dsizes.length () > 2 && (dsizes(2) == 2 || dsizes(2) == 4)); + + Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1)); + octave_idx_type rows = m.rows (); + octave_idx_type columns = m.columns (); + + unsigned int div_factor = (1 << bitdepth) - 1; + + for (unsigned int ii = 0; ii < nframes; ii++) + { + Magick::Image im (Magick::Geometry (columns, rows), "black"); + + im.depth (bitdepth); + + if (has_map) + im.classType (Magick::PseudoClass); + else + im.classType (Magick::DirectClass); + + if (is_color) + { + if (has_alpha) + im.type (Magick::TrueColorMatteType); + else + im.type (Magick::TrueColorType); + + Magick::ColorRGB c; + + for (int y = 0; y < columns; y++) + { + idx(1) = y; + + for (int x = 0; x < rows; x++) + { + idx(0) = x; + + if (nframes > 1) + idx(3) = ii; + + idx(2) = 0; + c.red (static_cast<double>(m(idx)) / div_factor); + + idx(2) = 1; + c.green (static_cast<double>(m(idx)) / div_factor); + + idx(2) = 2; + c.blue (static_cast<double>(m(idx)) / div_factor); + + if (has_alpha) + { + idx(2) = 3; + c.alpha (static_cast<double>(m(idx)) / div_factor); + } + + im.pixelColor (y, x, c); + } + } + } + else + { + if (has_alpha) + im.type (Magick::GrayscaleMatteType); + else + im.type (Magick::GrayscaleType); + + Magick::ColorGray c; + + for (int y = 0; y < columns; y++) + { + idx(1) = y; + + for (int x=0; x < rows; x++) + { + idx(0) = x; + + if (nframes > 1) + { + idx(2) = 0; + idx(3) = ii; + } + + if (has_alpha) + { + idx(2) = 1; + c.alpha (static_cast<double>(m(idx)) / div_factor); + idx(2) = 0; + } + + c.shade (static_cast<double>(m(idx)) / div_factor); + + im.pixelColor (y, x, c); + } + } + + im.quantizeColorSpace (Magick::GRAYColorspace); + im.quantizeColors (1 << bitdepth); + im.quantize (); + } + + imvec.push_back (im); + } +} + +static void +encode_map (std::vector<Magick::Image>& imvec, const NDArray& cmap) +{ + unsigned int mapsize = cmap.dim1 (); + + for (size_t fnum = 0; fnum < imvec.size (); fnum++) + { + imvec[fnum].colorMapSize (mapsize); + imvec[fnum].type (Magick::PaletteType); + } + + for (unsigned int ii = 0; ii < mapsize; ii++) + { + Magick::ColorRGB c (cmap(ii,0), cmap(ii,1), cmap(ii,2)); + + // FIXME -- is this case needed? + if (cmap.dim2 () == 4) + c.alpha (cmap(ii,3)); + + try + { + for_each (imvec.begin (), imvec.end (), + Magick::colorMapImage (ii, c)); + } + catch (Magick::Warning& w) + { + warning ("Magick++ warning: %s", w.what ()); + } + catch (Magick::ErrorCoder& e) + { + warning ("Magick++ coder error: %s", e.what ()); + } + catch (Magick::Exception& e) + { + error ("Magick++ exception: %s", e.what ()); + } + } +} + +static void +write_image (const std::string& filename, const std::string& fmt, + const octave_value& img, + const octave_value& map = octave_value (), + const octave_value& params = octave_value ()) +{ + std::vector<Magick::Image> imvec; + + bool has_map = map.is_defined (); + + if (has_map) + { + error ("__magick_write__: direct saving of indexed images not currently supported; use ind2rgb and save converted image"); + return; + } + + if (img.is_bool_type ()) + encode_bool_image (imvec, img); + else if (img.is_uint8_type ()) + encode_uint_image<uint8NDArray> (imvec, img, has_map); + else if (img.is_uint16_type ()) + encode_uint_image<uint16NDArray> (imvec, img, has_map); + else + error ("__magick_write__: image type not supported"); + + if (! error_state && has_map) + { + NDArray cmap = map.array_value (); + + if (! error_state) + encode_map (imvec, cmap); + } + + if (! error_state && params.is_defined ()) + { + Octave_map options = params.map_value (); + + // Insert calls here to handle parameters for various image formats + if (fmt == "jpg" || fmt == "jpeg") + jpg_settings (imvec, options, has_map); + else + warning ("warning: your parameter(s) currently not supported"); + } + + try + { + Magick::writeImages (imvec.begin (), imvec.end (), fmt + ":" + filename); + } + catch (Magick::Warning& w) + { + warning ("Magick++ warning: %s", w.what ()); + } + catch (Magick::ErrorCoder& e) + { + warning ("Magick++ coder error: %s", e.what ()); + } + catch (Magick::Exception& e) + { + error ("Magick++ exception: %s", e.what ()); + } +} + +#endif + +DEFUN_DLD (__magick_write__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img})\n\ +@deftypefnx {Function File} {} __magick_write__ (@var{fname}, @var{fmt}, @var{img}, @var{map})\n\ +Write images with ImageMagick++. In general you should not be using this\n\ +function. Instead use @code{imwrite}.\n\ +@seealso{imread}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_MAGICK + maybe_initialize_magick (); + + int nargin = args.length (); + + if (nargin > 2) + { + std::string filename = args(0).string_value (); + + if (! error_state) + { + std::string fmt = args(1).string_value (); + + if (! error_state) + { + if (nargin > 4) + write_image (filename, fmt, args(2), args(3), args(4)); + else if (nargin > 3) + if (args(3).is_real_type ()) + write_image (filename, fmt, args(2), args(3)); + else + write_image (filename, fmt, args(2), octave_value (), args(3)); + else + write_image (filename, fmt, args(2)); + } + else + error ("__magick_write__: FMT must be string"); + } + else + error ("__magick_write__: FNAME must be a string"); + } + else + print_usage (); +#else + + error ("__magick_write__: not available in this version of Octave"); + +#endif + +return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/ + +#ifdef HAVE_MAGICK + +template<class T> +static octave_value +magick_to_octave_value (const T magick) +{ + return octave_value (magick); +} + +static octave_value +magick_to_octave_value (const Magick::EndianType magick) +{ + switch (magick) + { + case Magick::LSBEndian: + return octave_value ("little-endian"); + + case Magick::MSBEndian: + return octave_value ("big-endian"); + + default: + return octave_value ("undefined"); + } +} + +static octave_value +magick_to_octave_value (const Magick::ResolutionType magick) +{ + switch (magick) + { + case Magick::PixelsPerInchResolution: + return octave_value ("pixels per inch"); + + case Magick::PixelsPerCentimeterResolution: + return octave_value ("pixels per centimeter"); + + default: + return octave_value ("undefined"); + } +} + +static octave_value +magick_to_octave_value (const Magick::ImageType magick) +{ + switch (magick) + { + case Magick::BilevelType: + case Magick::GrayscaleType: + case Magick::GrayscaleMatteType: + return octave_value ("grayscale"); + + case Magick::PaletteType: + case Magick::PaletteMatteType: + return octave_value ("indexed"); + + case Magick::TrueColorType: + case Magick::TrueColorMatteType: + case Magick::ColorSeparationType: + return octave_value ("truecolor"); + + default: + return octave_value ("undefined"); + } +} + +// We put this in a try-block because GraphicsMagick will throw +// exceptions if a parameter isn't present in the current image. +#define GET_PARAM(NAME, OUTNAME) \ + try \ + { \ + info.contents (OUTNAME)(frame,0) = magick_to_octave_value (im.NAME ()); \ + } \ + catch (Magick::Warning& w) \ + { \ + } + +#endif + +DEFUN_DLD (__magick_finfo__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __magick_finfo__ (@var{fname})\n\ +Read image information with GraphicsMagick++. In general you should\n\ +not be using this function. Instead use @code{imfinfo}.\n\ +@seealso{imfinfo, imread}\n\ +@end deftypefn") +{ + octave_value retval; + +#ifdef HAVE_MAGICK + + maybe_initialize_magick (); + + if (args.length () < 1 || ! args (0).is_string ()) + { + print_usage (); + return retval; + } + + const std::string filename = args (0).string_value (); + + try + { + // Read the file. + std::vector<Magick::Image> imvec; + Magick::readImages (&imvec, args(0).string_value ()); + int nframes = imvec.size (); + + // Create the right size for the output. + + static const char *fields[] = + { + "Filename", + "FileModDate", + "FileSize", + "Height", + "Width", + "BitDepth", + "Format", + "LongFormat", + "XResolution", + "YResolution", + "TotalColors", + "TileName", + "AnimationDelay", + "AnimationIterations", + "ByteOrder", + "Gamma", + "Matte", + "ModulusDepth", + "Quality", + "QuantizeColors", + "ResolutionUnits", + "ColorType", + "View", + 0 + }; + + Octave_map info (string_vector (fields), dim_vector (nframes, 1)); + + file_stat fs (filename); + + std::string filetime; + + if (fs) + { + octave_localtime mtime = fs.mtime (); + + filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S"); + } + else + { + std::string msg = fs.error (); + + error ("imfinfo: error reading `%s': %s", + filename.c_str (), msg.c_str ()); + + return retval; + } + + // For each frame in the image (some images contain multiple + // layers, each to be treated like a separate image). + for (int frame = 0; frame < nframes; frame++) + { + Magick::Image im = imvec[frame]; + + // Add file name and timestamp. + info.contents ("Filename")(frame,0) = filename; + info.contents ("FileModDate")(frame,0) = filetime; + + // Annoying CamelCase naming is for Matlab compatibility. + GET_PARAM (fileSize, "FileSize") + GET_PARAM (rows, "Height") + GET_PARAM (columns, "Width") + GET_PARAM (depth, "BitDepth") + GET_PARAM (magick, "Format") + GET_PARAM (format, "LongFormat") + GET_PARAM (xResolution, "XResolution") + GET_PARAM (yResolution, "YResolution") + GET_PARAM (totalColors, "TotalColors") + GET_PARAM (tileName, "TileName") + GET_PARAM (animationDelay, "AnimationDelay") + GET_PARAM (animationIterations, "AnimationIterations") + GET_PARAM (endian, "ByteOrder") + GET_PARAM (gamma, "Gamma") + GET_PARAM (matte, "Matte") + GET_PARAM (modulusDepth, "ModulusDepth") + GET_PARAM (quality, "Quality") + GET_PARAM (quantizeColors, "QuantizeColors") + GET_PARAM (resolutionUnits, "ResolutionUnits") + GET_PARAM (type, "ColorType") + GET_PARAM (view, "View") + } + + retval = octave_value (info); + } + catch (Magick::Warning& w) + { + warning ("Magick++ warning: %s", w.what ()); + } + catch (Magick::ErrorCoder& e) + { + warning ("Magick++ coder error: %s", e.what ()); + } + catch (Magick::Exception& e) + { + error ("Magick++ exception: %s", e.what ()); + return retval; + } + +#else + + error ("imfinfo: not available in this version of Octave"); + +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/ + +#undef GET_PARAM + +// Determine the file formats supported by GraphicsMagick. This is +// called once at the beginning of imread or imwrite to determine +// exactly which file formats are supported, so error messages can be +// displayed properly. + +DEFUN_DLD (__magick_format_list__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Function File} {} __magick_format_list__ (@var{formats})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + +#ifdef HAVE_MAGICK + maybe_initialize_magick (); + + std::list<std::string> accepted_formats; + + if (args.length () == 1) + { + Cell c = args (0).cell_value (); + + if (! error_state) + { + for (octave_idx_type i = 0; i < c.nelem (); i++) + { + try + { + std::string fmt = c.elem (i).string_value (); + + Magick::CoderInfo info(fmt); + + if (info.isReadable () && info.isWritable ()) + accepted_formats.push_back (fmt); + } + catch (Magick::Exception& e) + { + // Do nothing: exception here are simply missing formats. + } + } + } + else + error ("__magick_format_list__: expecting a cell array of image format names"); + } + else + print_usage (); + + retval = Cell (accepted_formats); + +#else + + error ("__magick_format_list__: not available in this version of Octave"); + +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/__voronoi__.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,334 @@ +/* + +Copyright (C) 2000-2012 Kai Habel + +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/>. + +*/ + +/* +20. Augiust 2000 - Kai Habel: first release +*/ + +/* +2003-12-14 Rafael Laboissiere <rafael@laboissiere.net> +Added optional second argument to pass options to the underlying +qhull command +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdio> + +#include <list> + +#include "lo-ieee.h" + +#include "Cell.h" +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "unwind-prot.h" + +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) +char qh_version[] = "__voronoi__.oct 2007-07-24"; +# endif +#endif + +static void +close_fcn (FILE *f) +{ + gnulib::fclose (f); +} + +DEFUN_DLD (__voronoi__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts})\n\ +@deftypefnx {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts}, @var{options})\n\ +@deftypefnx {Loadable Function} {@var{C}, @var{F}, @var{Inf_Pts} =} __voronoi__ (@dots{})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + + std::string caller = args(0).string_value (); + +#if defined (HAVE_QHULL) + + retval(0) = 0.0; + + int nargin = args.length (); + if (nargin < 2 || nargin > 3) + { + print_usage (); + return retval; + } + + Matrix points = args(1).matrix_value (); + const octave_idx_type dim = points.columns (); + const octave_idx_type num_points = points.rows (); + + points = points.transpose (); + + std::string options; + + if (dim <= 4) + options = " Qbb"; + else + options = " Qbb Qx"; + + if (nargin == 3) + { + octave_value opt_arg = args(2); + + if (opt_arg.is_string ()) + options = " " + opt_arg.string_value (); + else if (opt_arg.is_empty ()) + ; // Use default options. + else if (opt_arg.is_cellstr ()) + { + options = ""; + + Array<std::string> tmp = opt_arg.cellstr_value (); + + for (octave_idx_type i = 0; i < tmp.numel (); i++) + options += " " + tmp(i); + } + else + { + error ("%s: OPTIONS must be a string, cell array of strings, or empty", + caller.c_str ()); + return retval; + } + } + + boolT ismalloc = false; + + unwind_protect frame; + + // Replace the outfile pointer with stdout for debugging information. +#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) + FILE *outfile = gnulib::fopen ("NUL", "w"); +#else + FILE *outfile = gnulib::fopen ("/dev/null", "w"); +#endif + FILE *errfile = stderr; + + if (outfile) + frame.add_fcn (close_fcn, outfile); + else + { + error ("__voronoi__: unable to create temporary file for output"); + return retval; + } + + // qh_new_qhull command and points arguments are not const... + + std::string cmd = "qhull v" + options; + + OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); + + strcpy (cmd_str, cmd.c_str ()); + + int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), + ismalloc, cmd_str, outfile, errfile); + if (! exitcode) + { + // Calling findgood_all provides the number of Voronoi vertices + // (sets qh num_good). + + qh_findgood_all (qh facet_list); + + octave_idx_type num_voronoi_regions + = qh num_vertices - qh_setsize (qh del_vertices); + + octave_idx_type num_voronoi_vertices = qh num_good; + + // Find the voronoi centers for all facets. + + qh_setvoronoi_all (); + + facetT *facet; + vertexT *vertex; + octave_idx_type k; + + // Find the number of Voronoi vertices for each Voronoi cell and + // store them in NI so we can use them later to set the dimensions + // of the RowVector objects used to collect them. + + FORALLfacets + { + facet->seen = false; + } + + OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions); + for (octave_idx_type i = 0; i < num_voronoi_regions; i++) + ni[i] = 0; + + k = 0; + + FORALLvertices + { + if (qh hull_dim == 3) + qh_order_vertexneighbors (vertex); + + bool infinity_seen = false; + + facetT *neighbor, **neighborp; + + FOREACHneighbor_ (vertex) + { + if (neighbor->upperdelaunay) + { + if (! infinity_seen) + { + infinity_seen = true; + ni[k]++; + } + } + else + { + neighbor->seen = true; + ni[k]++; + } + } + + k++; + } + + // If Qhull finds fewer regions than points, we will pad the end + // of the at_inf and C arrays so that they always contain at least + // as many elements as the given points array. + + // FIXME -- is it possible (or does it make sense) for + // num_voronoi_regions to ever be larger than num_points? + + octave_idx_type nr = (num_points > num_voronoi_regions + ? num_points : num_voronoi_regions); + + boolMatrix at_inf (nr, 1, false); + + // The list of Voronoi vertices. The first element is always + // Inf. + Matrix F (num_voronoi_vertices+1, dim); + + for (octave_idx_type d = 0; d < dim; d++) + F(0,d) = octave_Inf; + + // The cell array of vectors of indices into F that represent the + // vertices of the Voronoi regions (cells). + + Cell C (nr, 1); + + // Now loop through the list of vertices again and store the + // coordinates of the Voronoi vertices and the lists of indices + // for the cells. + + FORALLfacets + { + facet->seen = false; + } + + octave_idx_type i = 0; + k = 0; + + FORALLvertices + { + if (qh hull_dim == 3) + qh_order_vertexneighbors (vertex); + + bool infinity_seen = false; + + octave_idx_type idx = qh_pointid (vertex->point); + + octave_idx_type num_vertices = ni[k++]; + + // Qhull seems to sometimes produces regions with a single + // vertex. Is that a bug? How can a region have just one + // vertex? Let's skip it. + + if (num_vertices == 1) + continue; + + RowVector facet_list (num_vertices); + + octave_idx_type m = 0; + + facetT *neighbor, **neighborp; + + FOREACHneighbor_(vertex) + { + if (neighbor->upperdelaunay) + { + if (! infinity_seen) + { + infinity_seen = true; + facet_list(m++) = 1; + at_inf(idx) = true; + } + } + else + { + if (! neighbor->seen) + { + i++; + for (octave_idx_type d = 0; d < dim; d++) + F(i,d) = neighbor->center[d]; + + neighbor->seen = true; + neighbor->visitid = i; + } + + facet_list(m++) = neighbor->visitid + 1; + } + } + + C(idx) = facet_list; + } + + retval(2) = at_inf; + retval(1) = C; + retval(0) = F; + } + else + error ("%s: qhull failed", caller.c_str ()); + + // Free memory from Qhull + qh_freeqhull (! qh_ALL); + + int curlong, totlong; + qh_memfreeshort (&curlong, &totlong); + + if (curlong || totlong) + warning ("%s: qhull did not free %d bytes of long memory (%d pieces)", + caller.c_str (), totlong, curlong); + +#else + error ("%s: not available in this version of Octave", caller.c_str ()); +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/amd.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,206 @@ +/* + +Copyright (C) 2008-2012 David Bateman + +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/>. + +*/ + +// This is the octave interface to amd, which bore the copyright given +// in the help of the functions. + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdlib> + +#include <string> +#include <vector> + +#include "ov.h" +#include "defun-dld.h" +#include "pager.h" +#include "ov-re-mat.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "oct-map.h" + +#include "oct-sparse.h" +#include "oct-locbuf.h" + +#ifdef IDX_TYPE_LONG +#define AMD_NAME(name) amd_l ## name +#else +#define AMD_NAME(name) amd ## name +#endif + +DEFUN_DLD (amd, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} amd (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} amd (@var{S}, @var{opts})\n\ +\n\ +Return the approximate minimum degree permutation of a matrix. This\n\ +permutation such that the Cholesky@tie{}factorization of @code{@var{S}\n\ +(@var{p}, @var{p})} tends to be sparser than the Cholesky@tie{}factorization\n\ +of @var{S} itself. @code{amd} is typically faster than @code{symamd} but\n\ +serves a similar purpose.\n\ +\n\ +The optional parameter @var{opts} is a structure that controls the\n\ +behavior of @code{amd}. The fields of the structure are\n\ +\n\ +@table @asis\n\ +@item @var{opts}.dense\n\ +Determines what @code{amd} considers to be a dense row or column of the\n\ +input matrix. Rows or columns with more than @code{max(16, (dense *\n\ +sqrt (@var{n})} entries, where @var{n} is the order of the matrix @var{S},\n\ +are ignored by @code{amd} during the calculation of the permutation\n\ +The value of dense must be a positive scalar and its default value is 10.0\n\ +\n\ +@item @var{opts}.aggressive\n\ +If this value is a non zero scalar, then @code{amd} performs aggressive\n\ +absorption. The default is not to perform aggressive absorption.\n\ +@end table\n\ +\n\ +The author of the code itself is Timothy A. Davis\n\ +@email{davis@@cise.ufl.edu}, University of Florida (see\n\ +@url{http://www.cise.ufl.edu/research/sparse/amd}).\n\ +@seealso{symamd, colamd}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_AMD + int nargin = args.length (); + + if (nargin < 1 || nargin > 2) + print_usage (); + else + { + octave_idx_type n_row, n_col; + const octave_idx_type *ridx, *cidx; + SparseMatrix sm; + SparseComplexMatrix scm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0).sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + } + else + { + if (args(0).is_complex_type ()) + sm = SparseMatrix (real (args(0).complex_matrix_value ())); + else + sm = SparseMatrix (args(0).matrix_value ()); + + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + if (!error_state && n_row != n_col) + error ("amd: matrix S must be square"); + + if (!error_state) + { + OCTAVE_LOCAL_BUFFER (double, Control, AMD_CONTROL); + AMD_NAME (_defaults) (Control) ; + if (nargin > 1) + { + octave_scalar_map arg1 = args(1).scalar_map_value (); + + if (!error_state) + { + octave_value tmp; + + tmp = arg1.getfield ("dense"); + if (tmp.is_defined ()) + Control[AMD_DENSE] = tmp.double_value (); + + tmp = arg1.getfield ("aggressive"); + if (tmp.is_defined ()) + Control[AMD_AGGRESSIVE] = tmp.double_value (); + } + else + error ("amd: OPTS argument must be a scalar structure"); + } + + if (!error_state) + { + OCTAVE_LOCAL_BUFFER (octave_idx_type, P, n_col); + Matrix xinfo (AMD_INFO, 1); + double *Info = xinfo.fortran_vec (); + + // FIXME -- how can we manage the memory allocation of + // amd in a cleaner manner? + amd_malloc = malloc; + amd_free = free; + amd_calloc = calloc; + amd_realloc = realloc; + amd_printf = printf; + + octave_idx_type result = AMD_NAME (_order) (n_col, cidx, ridx, P, + Control, Info); + + switch (result) + { + case AMD_OUT_OF_MEMORY: + error ("amd: out of memory"); + break; + case AMD_INVALID: + error ("amd: matrix S is corrupted"); + break; + default: + { + if (nargout > 1) + retval(1) = xinfo; + + Matrix Pout (1, n_col); + for (octave_idx_type i = 0; i < n_col; i++) + Pout.xelem (i) = P[i] + 1; + + retval(0) = Pout; + } + } + } + } + } +#else + + error ("amd: not available in this version of Octave"); + +#endif + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/ccolamd.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,583 @@ +/* + +Copyright (C) 2005-2012 David Bateman + +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/>. + +*/ + +// This is the octave interface to ccolamd, which bore the copyright given +// in the help of the functions. + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdlib> + +#include <string> +#include <vector> + +#include "ov.h" +#include "defun-dld.h" +#include "pager.h" +#include "ov-re-mat.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" + +#include "oct-sparse.h" +#include "oct-locbuf.h" + +#ifdef IDX_TYPE_LONG +#define CCOLAMD_NAME(name) ccolamd_l ## name +#define CSYMAMD_NAME(name) csymamd_l ## name +#else +#define CCOLAMD_NAME(name) ccolamd ## name +#define CSYMAMD_NAME(name) csymamd ## name +#endif + +DEFUN_DLD (ccolamd, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} ccolamd (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs})\n\ +@deftypefnx {Loadable Function} {@var{p} =} ccolamd (@var{S}, @var{knobs}, @var{cmember})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} ccolamd (@dots{})\n\ +\n\ +Constrained column approximate minimum degree permutation.\n\ +@code{@var{p} = ccolamd (@var{S})} returns the column approximate minimum\n\ +degree permutation vector for the sparse matrix @var{S}. For a non-symmetric\n\ +matrix\n\ +@var{S},\n\ +@code{@var{S}(:, @var{p})} tends to have sparser LU@tie{}factors than\n\ +@var{S}. @code{chol (@var{S}(:, @var{p})' * @var{S}(:, @var{p}))} also\n\ +tends to be sparser than @code{chol (@var{S}' * @var{S})}. @code{@var{p} =\n\ +ccolamd (@var{S}, 1)} optimizes the ordering for @code{lu (@var{S}(:,\n\ +@var{p}))}. The ordering is followed by a column elimination tree\n\ +post-ordering.\n\ +\n\ +@var{knobs} is an optional 1-element to 5-element input vector, with a\n\ +default value of @code{[0 10 10 1 0]} if not present or empty. Entries not\n\ +present are set to their defaults.\n\ +\n\ +@table @code\n\ +@item @var{knobs}(1)\n\ +if nonzero, the ordering is optimized for @code{lu (S(:, p))}. It will be a\n\ +poor ordering for @code{chol (@var{S}(:, @var{p})' * @var{S}(:,\n\ +@var{p}))}. This is the most important knob for ccolamd.\n\ +\n\ +@item @var{knobs}(2)\n\ +if @var{S} is m-by-n, rows with more than @code{max (16, @var{knobs}(2) *\n\ +sqrt (n))} entries are ignored.\n\ +\n\ +@item @var{knobs}(3)\n\ +columns with more than @code{max (16, @var{knobs}(3) * sqrt (min (@var{m},\n\ +@var{n})))} entries are ignored and ordered last in the output permutation\n\ +(subject to the cmember constraints).\n\ +\n\ +@item @var{knobs}(4)\n\ +if nonzero, aggressive absorption is performed.\n\ +\n\ +@item @var{knobs}(5)\n\ +if nonzero, statistics and knobs are printed.\n\ +\n\ +@end table\n\ +\n\ +@var{cmember} is an optional vector of length @math{n}. It defines the\n\ +constraints on the column ordering. If @code{@var{cmember}(j) = @var{c}},\n\ +then column @var{j} is in constraint set @var{c} (@var{c} must be in the\n\ +range 1 to\n\ +n). In the output permutation @var{p}, all columns in set 1 appear\n\ +first, followed by all columns in set 2, and so on. @code{@var{cmember} =\n\ +ones (1,n)} if not present or empty.\n\ +@code{ccolamd (@var{S}, [], 1 : n)} returns @code{1 : n}\n\ +\n\ +@code{@var{p} = ccolamd (@var{S})} is about the same as\n\ +@code{@var{p} = colamd (@var{S})}. @var{knobs} and its default values\n\ +differ. @code{colamd} always does aggressive absorption, and it finds an\n\ +ordering suitable for both @code{lu (@var{S}(:, @var{p}))} and @code{chol\n\ +(@var{S}(:, @var{p})' * @var{S}(:, @var{p}))}; it cannot optimize its\n\ +ordering for @code{lu (@var{S}(:, @var{p}))} to the extent that\n\ +@code{ccolamd (@var{S}, 1)} can.\n\ +\n\ +@var{stats} is an optional 20-element output vector that provides data\n\ +about the ordering and the validity of the input matrix @var{S}. Ordering\n\ +statistics are in @code{@var{stats}(1 : 3)}. @code{@var{stats}(1)} and\n\ +@code{@var{stats}(2)} are the number of dense or empty rows and columns\n\ +ignored by @sc{ccolamd} and @code{@var{stats}(3)} is the number of garbage\n\ +collections performed on the internal data structure used by @sc{ccolamd}\n\ +(roughly of size @code{2.2 * nnz (@var{S}) + 4 * @var{m} + 7 * @var{n}}\n\ +integers).\n\ +\n\ +@code{@var{stats}(4 : 7)} provide information if CCOLAMD was able to\n\ +continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ +invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ +unsorted or contains duplicate entries, or zero if no such column exists.\n\ +@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ +index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ +such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ +or out-of-order row indices. @code{@var{stats}(8 : 20)} is always zero in\n\ +the current version of @sc{ccolamd} (reserved for future use).\n\ +\n\ +The authors of the code itself are S. Larimore, T. Davis (Univ. of Florida)\n\ +and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\ +by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\ +and a grant from Sandia National Lab. See\n\ +@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\ +colamd, symamd, and other related orderings.\n\ +@seealso{colamd, csymamd}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_CCOLAMD + + int nargin = args.length (); + int spumoni = 0; + + if (nargout > 2 || nargin < 1 || nargin > 3) + usage ("ccolamd: incorrect number of input and/or output arguments"); + else + { + // Get knobs + OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS); + CCOLAMD_NAME (_set_defaults) (knobs); + + // Check for user-passed knobs + if (nargin > 1) + { + NDArray User_knobs = args(1).array_value (); + int nel_User_knobs = User_knobs.length (); + + if (nel_User_knobs > 0) + knobs[CCOLAMD_LU] = (User_knobs(0) != 0); + if (nel_User_knobs > 1) + knobs[CCOLAMD_DENSE_ROW] = User_knobs(1); + if (nel_User_knobs > 2) + knobs[CCOLAMD_DENSE_COL] = User_knobs(2); + if (nel_User_knobs > 3) + knobs[CCOLAMD_AGGRESSIVE] = (User_knobs(3) != 0); + if (nel_User_knobs > 4) + spumoni = (User_knobs(4) != 0); + + // print knob settings if spumoni is set + if (spumoni) + { + octave_stdout << "\nccolamd version " << CCOLAMD_MAIN_VERSION << "." + << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE + << ":\nknobs(1): " << User_knobs(0) << ", order for "; + if (knobs[CCOLAMD_LU] != 0) + octave_stdout << "lu (A)\n"; + else + octave_stdout << "chol (A'*A)\n"; + + if (knobs[CCOLAMD_DENSE_ROW] >= 0) + octave_stdout << "knobs(2): " << User_knobs(1) + << ", rows with > max (16," + << knobs[CCOLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" + << " entries removed\n"; + else + octave_stdout << "knobs(2): " << User_knobs(1) + << ", no dense rows removed\n"; + + if (knobs[CCOLAMD_DENSE_COL] >= 0) + octave_stdout << "knobs(3): " << User_knobs(2) + << ", cols with > max (16," + << knobs[CCOLAMD_DENSE_COL] << "*sqrt (size(A)))" + << " entries removed\n"; + else + octave_stdout << "knobs(3): " << User_knobs(2) + << ", no dense columns removed\n"; + + if (knobs[CCOLAMD_AGGRESSIVE] != 0) + octave_stdout << "knobs(4): " << User_knobs(3) + << ", aggressive absorption: yes"; + else + octave_stdout << "knobs(4): " << User_knobs(3) + << ", aggressive absorption: no"; + + octave_stdout << "knobs(5): " << User_knobs(4) + << ", statistics and knobs printed\n"; + } + } + + octave_idx_type n_row, n_col, nnz; + octave_idx_type *ridx, *cidx; + SparseComplexMatrix scm; + SparseMatrix sm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0). sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + nnz = scm.nnz (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + + n_row = sm.rows (); + n_col = sm.cols (); + nnz = sm.nnz (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + } + else + { + if (args(0).is_complex_type ()) + sm = SparseMatrix (real (args(0).complex_matrix_value ())); + else + sm = SparseMatrix (args(0).matrix_value ()); + + n_row = sm.rows (); + n_col = sm.cols (); + nnz = sm.nnz (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + // Allocate workspace for ccolamd + OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1); + for (octave_idx_type i = 0; i < n_col+1; i++) + p[i] = cidx[i]; + + octave_idx_type Alen = CCOLAMD_NAME (_recommended) (nnz, n_row, n_col); + OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen); + for (octave_idx_type i = 0; i < nnz; i++) + A[i] = ridx[i]; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS); + + if (nargin > 2) + { + NDArray in_cmember = args(2).array_value (); + octave_idx_type cslen = in_cmember.length (); + OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen); + for (octave_idx_type i = 0; i < cslen; i++) + // convert cmember from 1-based to 0-based + cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1); + + if (cslen != n_col) + error ("ccolamd: CMEMBER must be of length equal to #cols of A"); + else + // Order the columns (destroys A) + if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, cmember)) + { + CCOLAMD_NAME (_report) (stats) ; + error ("ccolamd: internal error!"); + return retval; + } + } + else + { + // Order the columns (destroys A) + if (! CCOLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats, 0)) + { + CCOLAMD_NAME (_report) (stats) ; + error ("ccolamd: internal error!"); + return retval; + } + } + + // return the permutation vector + NDArray out_perm (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + out_perm(i) = p[i] + 1; + + retval(0) = out_perm; + + // print stats if spumoni > 0 + if (spumoni > 0) + CCOLAMD_NAME (_report) (stats) ; + + // Return the stats vector + if (nargout == 2) + { + NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); + for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) + out_stats(i) = stats[i] ; + retval(1) = out_stats; + + // fix stats (5) and (6), for 1-based information on + // jumbled matrix. note that this correction doesn't + // occur if symamd returns FALSE + out_stats (CCOLAMD_INFO1) ++ ; + out_stats (CCOLAMD_INFO2) ++ ; + } + } + +#else + + error ("ccolamd: not available in this version of Octave"); + +#endif + + return retval; +} + +DEFUN_DLD (csymamd, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} csymamd (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs})\n\ +@deftypefnx {Loadable Function} {@var{p} =} csymamd (@var{S}, @var{knobs}, @var{cmember})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} csymamd (@dots{})\n\ +\n\ +For a symmetric positive definite matrix @var{S}, returns the permutation\n\ +vector @var{p} such that @code{@var{S}(@var{p},@var{p})} tends to have a\n\ +sparser Cholesky@tie{}factor than @var{S}. Sometimes @code{csymamd} works\n\ +well for symmetric indefinite matrices too. The matrix @var{S} is assumed\n\ +to be symmetric; only the strictly lower triangular part is referenced.\n\ +@var{S} must be square. The ordering is followed by an elimination tree\n\ +post-ordering.\n\ +\n\ +@var{knobs} is an optional 1-element to 3-element input vector, with a\n\ +default value of @code{[10 1 0]} if present or empty. Entries not\n\ +present are set to their defaults.\n\ +\n\ +@table @code\n\ +@item @var{knobs}(1)\n\ +If @var{S} is n-by-n, then rows and columns with more than\n\ +@code{max(16,@var{knobs}(1)*sqrt(n))} entries are ignored, and ordered\n\ +last in the output permutation (subject to the cmember constraints).\n\ +\n\ +@item @var{knobs}(2)\n\ +If nonzero, aggressive absorption is performed.\n\ +\n\ +@item @var{knobs}(3)\n\ +If nonzero, statistics and knobs are printed.\n\ +\n\ +@end table\n\ +\n\ +@var{cmember} is an optional vector of length n. It defines the constraints\n\ +on the ordering. If @code{@var{cmember}(j) = @var{S}}, then row/column j is\n\ +in constraint set @var{c} (@var{c} must be in the range 1 to n). In the\n\ +output permutation @var{p}, rows/columns in set 1 appear first, followed\n\ +by all rows/columns in set 2, and so on. @code{@var{cmember} = ones (1,n)}\n\ +if not present or empty. @code{csymamd (@var{S},[],1:n)} returns @code{1:n}.\n\ +\n\ +@code{@var{p} = csymamd (@var{S})} is about the same as @code{@var{p} =\n\ +symamd (@var{S})}. @var{knobs} and its default values differ.\n\ +\n\ +@code{@var{stats}(4:7)} provide information if CCOLAMD was able to\n\ +continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ +invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ +unsorted or contains duplicate entries, or zero if no such column exists.\n\ +@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ +index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ +such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ +or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in\n\ +the current version of @sc{ccolamd} (reserved for future use).\n\ +\n\ +The authors of the code itself are S. Larimore, T. Davis (Uni of Florida)\n\ +and S. Rajamanickam in collaboration with J. Bilbert and E. Ng. Supported\n\ +by the National Science Foundation (DMS-9504974, DMS-9803599, CCR-0203270),\n\ +and a grant from Sandia National Lab. See\n\ +@url{http://www.cise.ufl.edu/research/sparse} for ccolamd, csymamd, amd,\n\ +colamd, symamd, and other related orderings.\n\ +@seealso{symamd, ccolamd}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#if HAVE_CCOLAMD + + int nargin = args.length (); + int spumoni = 0; + + if (nargout > 2 || nargin < 1 || nargin > 3) + usage ("ccolamd: incorrect number of input and/or output arguments"); + else + { + // Get knobs + OCTAVE_LOCAL_BUFFER (double, knobs, CCOLAMD_KNOBS); + CCOLAMD_NAME (_set_defaults) (knobs); + + // Check for user-passed knobs + if (nargin > 1) + { + NDArray User_knobs = args(1).array_value (); + int nel_User_knobs = User_knobs.length (); + + if (nel_User_knobs > 0) + knobs[CCOLAMD_DENSE_ROW] = User_knobs(0); + if (nel_User_knobs > 0) + knobs[CCOLAMD_AGGRESSIVE] = User_knobs(1); + if (nel_User_knobs > 1) + spumoni = static_cast<int> (User_knobs(2)); + + // print knob settings if spumoni is set + if (spumoni) + { + octave_stdout << "\ncsymamd version " << CCOLAMD_MAIN_VERSION << "." + << CCOLAMD_SUB_VERSION << ", " << CCOLAMD_DATE << "\n"; + + if (knobs[CCOLAMD_DENSE_ROW] >= 0) + octave_stdout << "knobs(1): " << User_knobs(0) + << ", rows/cols with > max (16," + << knobs[CCOLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" + << " entries removed\n"; + else + octave_stdout << "knobs(1): " << User_knobs(0) + << ", no dense rows/cols removed\n"; + + if (knobs[CCOLAMD_AGGRESSIVE] != 0) + octave_stdout << "knobs(2): " << User_knobs(1) + << ", aggressive absorption: yes"; + else + octave_stdout << "knobs(2): " << User_knobs(1) + << ", aggressive absorption: no"; + + + octave_stdout << "knobs(3): " << User_knobs(2) + << ", statistics and knobs printed\n"; + } + } + + octave_idx_type n_row, n_col; + octave_idx_type *ridx, *cidx; + SparseMatrix sm; + SparseComplexMatrix scm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0).sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + } + else + { + if (args(0).is_complex_type ()) + sm = SparseMatrix (real (args(0).complex_matrix_value ())); + else + sm = SparseMatrix (args(0).matrix_value ()); + + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + if (n_row != n_col) + { + error ("csymamd: matrix S must be square"); + return retval; + } + + // Allocate workspace for symamd + OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, CCOLAMD_STATS); + + if (nargin > 2) + { + NDArray in_cmember = args(2).array_value (); + octave_idx_type cslen = in_cmember.length (); + OCTAVE_LOCAL_BUFFER (octave_idx_type, cmember, cslen); + for (octave_idx_type i = 0; i < cslen; i++) + // convert cmember from 1-based to 0-based + cmember[i] = static_cast<octave_idx_type>(in_cmember(i) - 1); + + if (cslen != n_col) + error ("csymamd: CMEMBER must be of length equal to #cols of A"); + else + if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, + &calloc, &free, cmember, -1)) + { + CSYMAMD_NAME (_report) (stats) ; + error ("csymamd: internal error!") ; + return retval; + } + } + else + { + if (!CSYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, + &calloc, &free, 0, -1)) + { + CSYMAMD_NAME (_report) (stats) ; + error ("csymamd: internal error!") ; + return retval; + } + } + + // return the permutation vector + NDArray out_perm (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + out_perm(i) = perm[i] + 1; + + retval(0) = out_perm; + + // Return the stats vector + if (nargout == 2) + { + NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); + for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) + out_stats(i) = stats[i] ; + retval(1) = out_stats; + + // fix stats (5) and (6), for 1-based information on + // jumbled matrix. note that this correction doesn't + // occur if symamd returns FALSE + out_stats (CCOLAMD_INFO1) ++ ; + out_stats (CCOLAMD_INFO2) ++ ; + } + + // print stats if spumoni > 0 + if (spumoni > 0) + CSYMAMD_NAME (_report) (stats) ; + + // Return the stats vector + if (nargout == 2) + { + NDArray out_stats (dim_vector (1, CCOLAMD_STATS)); + for (octave_idx_type i = 0 ; i < CCOLAMD_STATS ; i++) + out_stats(i) = stats[i] ; + retval(1) = out_stats; + + // fix stats (5) and (6), for 1-based information on + // jumbled matrix. note that this correction doesn't + // occur if symamd returns FALSE + out_stats (CCOLAMD_INFO1) ++ ; + out_stats (CCOLAMD_INFO2) ++ ; + } + } + +#else + + error ("csymamd: not available in this version of Octave"); + +#endif + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/chol.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,1385 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton +Copyright (C) 2008-2009 Jaroslav Hajek +Copyright (C) 2008-2009 VZLU Prague + +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> +#endif + +#include "CmplxCHOL.h" +#include "dbleCHOL.h" +#include "fCmplxCHOL.h" +#include "floatCHOL.h" +#include "SparseCmplxCHOL.h" +#include "SparsedbleCHOL.h" +#include "oct-spparms.h" +#include "sparse-util.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +template <class CHOLT> +static octave_value +get_chol_r (const CHOLT& fact) +{ + return octave_value (fact.chol_matrix (), + MatrixType (MatrixType::Upper)); +} + +template <class CHOLT> +static octave_value +get_chol_l (const CHOLT& fact) +{ + return octave_value (fact.chol_matrix ().transpose (), + MatrixType (MatrixType::Lower)); +} + +DEFUN_DLD (chol, args, nargout, +"-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{R} =} chol (@var{A})\n\ +@deftypefnx {Loadable Function} {[@var{R}, @var{p}] =} chol (@var{A})\n\ +@deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S})\n\ +@deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S}, \"vector\")\n\ +@deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, \"lower\")\n\ +@deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, \"upper\")\n\ +@cindex Cholesky factorization\n\ +Compute the Cholesky@tie{}factor, @var{R}, of the symmetric positive definite\n\ +matrix @var{A}, where\n\ +@tex\n\ +$ R^T R = A $.\n\ +@end tex\n\ +@ifnottex\n\ +\n\ +@example\n\ +@var{R}' * @var{R} = @var{A}.\n\ +@end example\n\ +\n\ +@end ifnottex\n\ +\n\ +Called with one output argument @code{chol} fails if @var{A} or @var{S} is\n\ +not positive definite. With two or more output arguments @var{p} flags\n\ +whether the matrix was positive definite and @code{chol} does not fail. A\n\ +zero value indicated that the matrix was positive definite and the @var{R}\n\ +gives the factorization, and @var{p} will have a positive value otherwise.\n\ +\n\ +If called with 3 outputs then a sparsity preserving row/column permutation\n\ +is applied to @var{A} prior to the factorization. That is @var{R}\n\ +is the factorization of @code{@var{A}(@var{Q},@var{Q})} such that\n\ +@tex\n\ +$ R^T R = Q^T A Q$.\n\ +@end tex\n\ +@ifnottex\n\ +\n\ +@example\n\ +@var{R}' * @var{R} = @var{Q}' * @var{A} * @var{Q}.\n\ +@end example\n\ +\n\ +@end ifnottex\n\ +\n\ +The sparsity preserving permutation is generally returned as a matrix.\n\ +However, given the flag \"vector\", @var{Q} will be returned as a vector\n\ +such that\n\ +@tex\n\ +$ R^T R = A (Q, Q)$.\n\ +@end tex\n\ +@ifnottex\n\ +\n\ +@example\n\ +@var{R}' * @var{R} = @var{A}(@var{Q}, @var{Q}).\n\ +@end example\n\ +\n\ +@end ifnottex\n\ +\n\ +Called with either a sparse or full matrix and using the \"lower\" flag,\n\ +@code{chol} returns the lower triangular factorization such that\n\ +@tex\n\ +$ L L^T = A $.\n\ +@end tex\n\ +@ifnottex\n\ +\n\ +@example\n\ +@var{L} * @var{L}' = @var{A}.\n\ +@end example\n\ +\n\ +@end ifnottex\n\ +\n\ +For full matrices, if the \"lower\" flag is set only the lower triangular\n\ +part of the matrix is used for the factorization, otherwise the upper\n\ +triangular part is used.\n\ +\n\ +In general the lower triangular factorization is significantly faster for\n\ +sparse matrices.\n\ +@seealso{cholinv, chol2inv}\n\ +@end deftypefn") +{ + octave_value_list retval; + int nargin = args.length (); + bool LLt = false; + bool vecout = false; + + if (nargin < 1 || nargin > 3 || nargout > 3 + || (! args(0).is_sparse_type () && nargout > 2)) + { + print_usage (); + return retval; + } + + int n = 1; + while (n < nargin && ! error_state) + { + std::string tmp = args(n++).string_value (); + + if (! error_state ) + { + if (tmp.compare ("vector") == 0) + vecout = true; + else if (tmp.compare ("lower") == 0) + // FIXME currently the option "lower" is handled by transposing the + // matrix, factorizing it with the lapack function DPOTRF ('U', ...) + // and finally transposing the factor. It would be more efficient to use + // DPOTRF ('L', ...) in this case. + LLt = true; + else if (tmp.compare ("upper") == 0) + LLt = false; + else + error ("chol: unexpected second or third input"); + } + else + error ("chol: expecting trailing string arguments"); + } + + if (! error_state) + { + octave_value arg = args(0); + + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + bool natural = (nargout != 3); + + int arg_is_empty = empty_arg ("chol", nr, nc); + + if (arg_is_empty < 0) + return retval; + if (arg_is_empty > 0) + return octave_value (Matrix ()); + + if (arg.is_sparse_type ()) + { + if (arg.is_real_type ()) + { + SparseMatrix m = arg.sparse_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + SparseCHOL fact (m, info, natural); + if (nargout == 3) + { + if (vecout) + retval(2) = fact.perm (); + else + retval(2) = fact.Q (); + } + + if (nargout > 1 || info == 0) + { + retval(1) = fact.P (); + if (LLt) + retval(0) = fact.L (); + else + retval(0) = fact.R (); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + SparseComplexMatrix m = arg.sparse_complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + SparseComplexCHOL fact (m, info, natural); + + if (nargout == 3) + { + if (vecout) + retval(2) = fact.perm (); + else + retval(2) = fact.Q (); + } + + if (nargout > 1 || info == 0) + { + retval(1) = fact.P (); + if (LLt) + retval(0) = fact.L (); + else + retval(0) = fact.R (); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else + gripe_wrong_type_arg ("chol", arg); + } + else if (arg.is_single_type ()) + { + if (arg.is_real_type ()) + { + FloatMatrix m = arg.float_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + + FloatCHOL fact; + if (LLt) + fact = FloatCHOL (m.transpose (), info); + else + fact = FloatCHOL (m, info); + + if (nargout == 2 || info == 0) + { + retval(1) = info; + if (LLt) + retval(0) = get_chol_l (fact); + else + retval(0) = get_chol_r (fact); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + FloatComplexMatrix m = arg.float_complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + + FloatComplexCHOL fact; + if (LLt) + fact = FloatComplexCHOL (m.transpose (), info); + else + fact = FloatComplexCHOL (m, info); + + if (nargout == 2 || info == 0) + { + retval(1) = info; + if (LLt) + retval(0) = get_chol_l (fact); + else + retval(0) = get_chol_r (fact); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else + gripe_wrong_type_arg ("chol", arg); + } + else + { + if (arg.is_real_type ()) + { + Matrix m = arg.matrix_value (); + + if (! error_state) + { + octave_idx_type info; + + CHOL fact; + if (LLt) + fact = CHOL (m.transpose (), info); + else + fact = CHOL (m, info); + + if (nargout == 2 || info == 0) + { + retval(1) = info; + if (LLt) + retval(0) = get_chol_l (fact); + else + retval(0) = get_chol_r (fact); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + ComplexMatrix m = arg.complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + + ComplexCHOL fact; + if (LLt) + fact = ComplexCHOL (m.transpose (), info); + else + fact = ComplexCHOL (m, info); + + if (nargout == 2 || info == 0) + { + retval(1) = info; + if (LLt) + retval(0) = get_chol_l (fact); + else + retval(0) = get_chol_r (fact); + } + else + error ("chol: input matrix must be positive definite"); + } + } + else + gripe_wrong_type_arg ("chol", arg); + } + } + + return retval; +} + +/* +%!assert (chol ([2, 1; 1, 1]), [sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)], sqrt (eps)) +%!assert (chol (single ([2, 1; 1, 1])), single ([sqrt(2), 1/sqrt(2); 0, 1/sqrt(2)]), sqrt (eps ("single"))) + +%!error chol () +%!error <matrix must be positive definite> chol ([1, 2; 3, 4]) +%!error <requires square matrix> chol ([1, 2; 3, 4; 5, 6]) +%!error <unexpected second or third input> chol (1, 2) +*/ + +DEFUN_DLD (cholinv, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} cholinv (@var{A})\n\ +Use the Cholesky@tie{}factorization to compute the inverse of the\n\ +symmetric positive definite matrix @var{A}.\n\ +@seealso{chol, chol2inv, inv}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1) + { + octave_value arg = args(0); + + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + + if (nr == 0 || nc == 0) + retval = Matrix (); + else + { + if (arg.is_sparse_type ()) + { + if (arg.is_real_type ()) + { + SparseMatrix m = arg.sparse_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + SparseCHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + SparseComplexMatrix m = arg.sparse_complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + SparseComplexCHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else + gripe_wrong_type_arg ("cholinv", arg); + } + else if (arg.is_single_type ()) + { + if (arg.is_real_type ()) + { + FloatMatrix m = arg.float_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + FloatCHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + FloatComplexMatrix m = arg.float_complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + FloatComplexCHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else + gripe_wrong_type_arg ("chol", arg); + } + else + { + if (arg.is_real_type ()) + { + Matrix m = arg.matrix_value (); + + if (! error_state) + { + octave_idx_type info; + CHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else if (arg.is_complex_type ()) + { + ComplexMatrix m = arg.complex_matrix_value (); + + if (! error_state) + { + octave_idx_type info; + ComplexCHOL chol (m, info); + if (info == 0) + retval = chol.inverse (); + else + error ("cholinv: A must be positive definite"); + } + } + else + gripe_wrong_type_arg ("chol", arg); + } + } + } + else + print_usage (); + + return retval; +} + +/* +%!shared A, Ainv +%! A = [2,0.2;0.2,1]; +%! Ainv = inv (A); +%!test +%! Ainv1 = cholinv (A); +%! assert (norm (Ainv-Ainv1), 0, 1e-10); +%!testif HAVE_CHOLMOD +%! Ainv2 = inv (sparse (A)); +%! assert (norm (Ainv-Ainv2), 0, 1e-10); +%!testif HAVE_CHOLMOD +%! Ainv3 = cholinv (sparse (A)); +%! assert (norm (Ainv-Ainv3), 0, 1e-10); +*/ + +DEFUN_DLD (chol2inv, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} chol2inv (@var{U})\n\ +Invert a symmetric, positive definite square matrix from its Cholesky\n\ +decomposition, @var{U}. Note that @var{U} should be an upper-triangular\n\ +matrix with positive diagonal elements. @code{chol2inv (@var{U})}\n\ +provides @code{inv (@var{U}'*@var{U})} but it is much faster than\n\ +using @code{inv}.\n\ +@seealso{chol, cholinv, inv}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1) + { + octave_value arg = args(0); + + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + + if (nr == 0 || nc == 0) + retval = Matrix (); + else + { + if (arg.is_sparse_type ()) + { + if (arg.is_real_type ()) + { + SparseMatrix r = arg.sparse_matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else if (arg.is_complex_type ()) + { + SparseComplexMatrix r = arg.sparse_complex_matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else + gripe_wrong_type_arg ("chol2inv", arg); + } + else if (arg.is_single_type ()) + { + if (arg.is_real_type ()) + { + FloatMatrix r = arg.float_matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else if (arg.is_complex_type ()) + { + FloatComplexMatrix r = arg.float_complex_matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else + gripe_wrong_type_arg ("chol2inv", arg); + + } + else + { + if (arg.is_real_type ()) + { + Matrix r = arg.matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else if (arg.is_complex_type ()) + { + ComplexMatrix r = arg.complex_matrix_value (); + + if (! error_state) + retval = chol2inv (r); + } + else + gripe_wrong_type_arg ("chol2inv", arg); + } + } + } + else + print_usage (); + + return retval; +} + +DEFUN_DLD (cholupdate, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{R1}, @var{info}] =} cholupdate (@var{R}, @var{u}, @var{op})\n\ +Update or downdate a Cholesky@tie{}factorization. Given an upper triangular\n\ +matrix @var{R} and a column vector @var{u}, attempt to determine another\n\ +upper triangular matrix @var{R1} such that\n\ +\n\ +@itemize @bullet\n\ +@item\n\ +@var{R1}'*@var{R1} = @var{R}'*@var{R} + @var{u}*@var{u}'\n\ +if @var{op} is \"+\"\n\ +\n\ +@item\n\ +@var{R1}'*@var{R1} = @var{R}'*@var{R} - @var{u}*@var{u}'\n\ +if @var{op} is \"-\"\n\ +@end itemize\n\ +\n\ +If @var{op} is \"-\", @var{info} is set to\n\ +\n\ +@itemize\n\ +@item 0 if the downdate was successful,\n\ +\n\ +@item 1 if @var{R}'*@var{R} - @var{u}*@var{u}' is not positive definite,\n\ +\n\ +@item 2 if @var{R} is singular.\n\ +@end itemize\n\ +\n\ +If @var{info} is not present, an error message is printed in cases 1 and 2.\n\ +@seealso{chol, qrupdate}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + + octave_value_list retval; + + if (nargin > 3 || nargin < 2) + { + print_usage (); + return retval; + } + + octave_value argr = args(0); + octave_value argu = args(1); + + if (argr.is_numeric_type () && argu.is_numeric_type () + && (nargin < 3 || args(2).is_string ())) + { + octave_idx_type n = argr.rows (); + + std::string op = (nargin < 3) ? "+" : args(2).string_value (); + + bool down = op == "-"; + + if (down || op == "+") + if (argr.columns () == n && argu.rows () == n && argu.columns () == 1) + { + int err = 0; + if (argr.is_single_type () || argu.is_single_type ()) + { + if (argr.is_real_type () && argu.is_real_type ()) + { + // real case + FloatMatrix R = argr.float_matrix_value (); + FloatColumnVector u = argu.float_column_vector_value (); + + FloatCHOL fact; + fact.set (R); + + if (down) + err = fact.downdate (u); + else + fact.update (u); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + FloatComplexMatrix R = argr.float_complex_matrix_value (); + FloatComplexColumnVector u = argu.float_complex_column_vector_value (); + + FloatComplexCHOL fact; + fact.set (R); + + if (down) + err = fact.downdate (u); + else + fact.update (u); + + retval(0) = get_chol_r (fact); + } + } + else + { + if (argr.is_real_type () && argu.is_real_type ()) + { + // real case + Matrix R = argr.matrix_value (); + ColumnVector u = argu.column_vector_value (); + + CHOL fact; + fact.set (R); + + if (down) + err = fact.downdate (u); + else + fact.update (u); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + ComplexMatrix R = argr.complex_matrix_value (); + ComplexColumnVector u = argu.complex_column_vector_value (); + + ComplexCHOL fact; + fact.set (R); + + if (down) + err = fact.downdate (u); + else + fact.update (u); + + retval(0) = get_chol_r (fact); + } + } + + if (nargout > 1) + retval(1) = err; + else if (err == 1) + error ("cholupdate: downdate violates positiveness"); + else if (err == 2) + error ("cholupdate: singular matrix"); + } + else + error ("cholupdate: dimension mismatch between R and U"); + else + error ("cholupdate: OP must be \"+\" or \"-\""); + } + else + print_usage (); + + return retval; +} + +/* +%!shared A, u, Ac, uc +%! A = [ 0.436997 -0.131721 0.124120 -0.061673 ; +%! -0.131721 0.738529 0.019851 -0.140295 ; +%! 0.124120 0.019851 0.354879 -0.059472 ; +%! -0.061673 -0.140295 -0.059472 0.600939 ]; +%! +%! u = [ 0.98950 ; +%! 0.39844 ; +%! 0.63484 ; +%! 0.13351 ]; +%! Ac = [ 0.5585528 + 0.0000000i -0.1662088 - 0.0315341i 0.0107873 + 0.0236411i -0.0276775 - 0.0186073i ; +%! -0.1662088 + 0.0315341i 0.6760061 + 0.0000000i 0.0011452 - 0.0475528i 0.0145967 + 0.0247641i ; +%! 0.0107873 - 0.0236411i 0.0011452 + 0.0475528i 0.6263149 - 0.0000000i -0.1585837 - 0.0719763i ; +%! -0.0276775 + 0.0186073i 0.0145967 - 0.0247641i -0.1585837 + 0.0719763i 0.6034234 - 0.0000000i ]; +%! +%! uc = [ 0.54267 + 0.91519i ; +%! 0.99647 + 0.43141i ; +%! 0.83760 + 0.68977i ; +%! 0.39160 + 0.90378i ]; + +%!test +%! R = chol (A); +%! R1 = cholupdate (R, u); +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - R'*R - u*u', Inf) < 1e1*eps); +%! +%! R1 = cholupdate (R1, u, "-"); +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1 - R, Inf) < 1e1*eps); + +%!test +%! R = chol (Ac); +%! R1 = cholupdate (R, uc); +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - R'*R - uc*uc', Inf) < 1e1*eps); +%! +%! R1 = cholupdate (R1, uc, "-"); +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1 - R, Inf) < 1e1*eps); + +%!test +%! R = chol (single (A)); +%! R1 = cholupdate (R, single (u)); +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1'*R1 - R'*R - single (u*u'), Inf) < 1e1*eps ("single")); +%! +%! R1 = cholupdate (R1, single (u), "-"); +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1 - R, Inf) < 2e1*eps ("single")); + +%!test +%! R = chol (single (Ac)); +%! R1 = cholupdate (R, single (uc)); +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1'*R1 - R'*R - single (uc*uc'), Inf) < 1e1*eps ("single")); +%! +%! R1 = cholupdate (R1, single (uc), "-"); +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1 - R, Inf) < 2e1*eps ("single")); +*/ + +DEFUN_DLD (cholinsert, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{R1} =} cholinsert (@var{R}, @var{j}, @var{u})\n\ +@deftypefnx {Loadable Function} {[@var{R1}, @var{info}] =} cholinsert (@var{R}, @var{j}, @var{u})\n\ +Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ +positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ +triangular, return the Cholesky@tie{}factorization of\n\ +@var{A1}, where @w{A1(p,p) = A}, @w{A1(:,j) = A1(j,:)' = u} and\n\ +@w{p = [1:j-1,j+1:n+1]}. @w{u(j)} should be positive.\n\ +On return, @var{info} is set to\n\ +\n\ +@itemize\n\ +@item 0 if the insertion was successful,\n\ +\n\ +@item 1 if @var{A1} is not positive definite,\n\ +\n\ +@item 2 if @var{R} is singular.\n\ +@end itemize\n\ +\n\ +If @var{info} is not present, an error message is printed in cases 1 and 2.\n\ +@seealso{chol, cholupdate, choldelete}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + + octave_value_list retval; + + if (nargin != 3) + { + print_usage (); + return retval; + } + + octave_value argr = args(0); + octave_value argj = args(1); + octave_value argu = args(2); + + if (argr.is_numeric_type () && argu.is_numeric_type () + && argj.is_real_scalar ()) + { + octave_idx_type n = argr.rows (); + octave_idx_type j = argj.scalar_value (); + + if (argr.columns () == n && argu.rows () == n+1 && argu.columns () == 1) + { + if (j > 0 && j <= n+1) + { + int err = 0; + if (argr.is_single_type () || argu.is_single_type ()) + { + if (argr.is_real_type () && argu.is_real_type ()) + { + // real case + FloatMatrix R = argr.float_matrix_value (); + FloatColumnVector u = argu.float_column_vector_value (); + + FloatCHOL fact; + fact.set (R); + err = fact.insert_sym (u, j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + FloatComplexMatrix R = argr.float_complex_matrix_value (); + FloatComplexColumnVector u = argu.float_complex_column_vector_value (); + + FloatComplexCHOL fact; + fact.set (R); + err = fact.insert_sym (u, j-1); + + retval(0) = get_chol_r (fact); + } + } + else + { + if (argr.is_real_type () && argu.is_real_type ()) + { + // real case + Matrix R = argr.matrix_value (); + ColumnVector u = argu.column_vector_value (); + + CHOL fact; + fact.set (R); + err = fact.insert_sym (u, j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + ComplexMatrix R = argr.complex_matrix_value (); + ComplexColumnVector u = argu.complex_column_vector_value (); + + ComplexCHOL fact; + fact.set (R); + err = fact.insert_sym (u, j-1); + + retval(0) = get_chol_r (fact); + } + } + + if (nargout > 1) + retval(1) = err; + else if (err == 1) + error ("cholinsert: insertion violates positiveness"); + else if (err == 2) + error ("cholinsert: singular matrix"); + else if (err == 3) + error ("cholinsert: diagonal element must be real"); + } + else + error ("cholinsert: index J out of range"); + } + else + error ("cholinsert: dimension mismatch between R and U"); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! u2 = [ 0.35080 ; +%! 0.63930 ; +%! 3.31057 ; +%! -0.13825 ; +%! 0.45266 ]; +%! +%! R = chol (A); +%! +%! j = 3; p = [1:j-1, j+1:5]; +%! R1 = cholinsert (R, j, u2); +%! A1 = R1'*R1; +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (A1(p,p) - A, Inf) < 1e1*eps); + +%!test +%! u2 = [ 0.35080 + 0.04298i; +%! 0.63930 + 0.23778i; +%! 3.31057 + 0.00000i; +%! -0.13825 + 0.19879i; +%! 0.45266 + 0.50020i]; +%! +%! R = chol (Ac); +%! +%! j = 3; p = [1:j-1, j+1:5]; +%! R1 = cholinsert (R, j, u2); +%! A1 = R1'*R1; +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (A1(p,p) - Ac, Inf) < 1e1*eps); + +%!test +%! u2 = single ([ 0.35080 ; +%! 0.63930 ; +%! 3.31057 ; +%! -0.13825 ; +%! 0.45266 ]); +%! +%! R = chol (single (A)); +%! +%! j = 3; p = [1:j-1, j+1:5]; +%! R1 = cholinsert (R, j, u2); +%! A1 = R1'*R1; +%! +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (A1(p,p) - A, Inf) < 1e1*eps ("single")); + +%!test +%! u2 = single ([ 0.35080 + 0.04298i; +%! 0.63930 + 0.23778i; +%! 3.31057 + 0.00000i; +%! -0.13825 + 0.19879i; +%! 0.45266 + 0.50020i]); +%! +%! R = chol (single (Ac)); +%! +%! j = 3; p = [1:j-1, j+1:5]; +%! R1 = cholinsert (R, j, u2); +%! A1 = R1'*R1; +%! +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (A1(p,p) - single (Ac), Inf) < 2e1*eps ("single")); + +%!test +%! cu = chol (triu (A), "upper"); +%! cl = chol (tril (A), "lower"); +%! assert (cu, cl', eps); + +%!test +%! cca = chol (Ac); +%! +%! ccal = chol (Ac, "lower"); +%! ccal2 = chol (tril (Ac), "lower"); +%! +%! ccau = chol (Ac, "upper"); +%! ccau2 = chol (triu (Ac), "upper"); +%! +%! assert (cca'*cca, Ac, eps); +%! assert (ccau'*ccau, Ac, eps); +%! assert (ccau2'*ccau2, Ac, eps); +%! +%! assert (cca, ccal', eps); +%! assert (cca, ccau, eps); +%! assert (cca, ccal2', eps); +%! assert (cca, ccau2, eps); + +%!test +%! cca = chol (single (Ac)); +%! +%! ccal = chol (single (Ac), "lower"); +%! ccal2 = chol (tril (single (Ac)), "lower"); +%! +%! ccau = chol (single (Ac), "upper"); +%! ccau2 = chol (triu (single (Ac)), "upper"); +%! +%! assert (cca'*cca, single (Ac), eps ("single")); +%! assert (ccau'*ccau, single (Ac), eps ("single")); +%! assert (ccau2'*ccau2, single (Ac), eps ("single")); +%! +%! assert (cca, ccal', eps ("single")); +%! assert (cca, ccau, eps ("single")); +%! assert (cca, ccal2', eps ("single")); +%! assert (cca, ccau2, eps ("single")); + +%!test +%! a = [12, 2, 3, 4; +%! 2, 14, 5, 3; +%! 3, 5, 16, 6; +%! 4, 3, 6, 16]; +%! +%! b = [0, 1, 2, 3; +%! -1, 0, 1, 2; +%! -2, -1, 0, 1; +%! -3, -2, -1, 0]; +%! +%! ca = a + i*b; +%! +%! cca = chol (ca); +%! +%! ccal = chol (ca, "lower"); +%! ccal2 = chol (tril (ca), "lower"); +%! +%! ccau = chol (ca, "upper"); +%! ccau2 = chol (triu (ca), "upper"); +%! +%! assert (cca'*cca, ca, 16*eps); +%! assert (ccau'*ccau, ca, 16*eps); +%! assert (ccau2'*ccau2, ca, 16*eps); +%! +%! assert (cca, ccal', 16*eps); +%! assert (cca, ccau, 16*eps); +%! assert (cca, ccal2', 16*eps); +%! assert (cca, ccau2, 16*eps); +*/ + +DEFUN_DLD (choldelete, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{R1} =} choldelete (@var{R}, @var{j})\n\ +Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ +positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ +triangular, return the Cholesky@tie{}factorization of @w{A(p,p)}, where\n\ +@w{p = [1:j-1,j+1:n+1]}.\n\ +@seealso{chol, cholupdate, cholinsert}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + + octave_value_list retval; + + if (nargin != 2) + { + print_usage (); + return retval; + } + + octave_value argr = args(0); + octave_value argj = args(1); + + if (argr.is_numeric_type () && argj.is_real_scalar ()) + { + octave_idx_type n = argr.rows (); + octave_idx_type j = argj.scalar_value (); + + if (argr.columns () == n) + { + if (j > 0 && j <= n) + { + if (argr.is_single_type ()) + { + if (argr.is_real_type ()) + { + // real case + FloatMatrix R = argr.float_matrix_value (); + + FloatCHOL fact; + fact.set (R); + fact.delete_sym (j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + FloatComplexMatrix R = argr.float_complex_matrix_value (); + + FloatComplexCHOL fact; + fact.set (R); + fact.delete_sym (j-1); + + retval(0) = get_chol_r (fact); + } + } + else + { + if (argr.is_real_type ()) + { + // real case + Matrix R = argr.matrix_value (); + + CHOL fact; + fact.set (R); + fact.delete_sym (j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + ComplexMatrix R = argr.complex_matrix_value (); + + ComplexCHOL fact; + fact.set (R); + fact.delete_sym (j-1); + + retval(0) = get_chol_r (fact); + } + } + } + else + error ("choldelete: index J out of range"); + } + else + error ("choldelete: matrix R must be square"); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! R = chol (A); +%! +%! j = 3; p = [1:j-1,j+1:4]; +%! R1 = choldelete (R, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); + +%!test +%! R = chol (Ac); +%! +%! j = 3; p = [1:j-1,j+1:4]; +%! R1 = choldelete (R, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); + +%!test +%! R = chol (single (A)); +%! +%! j = 3; p = [1:j-1,j+1:4]; +%! R1 = choldelete (R, j); +%! +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); + +%!test +%! R = chol (single (Ac)); +%! +%! j = 3; p = [1:j-1,j+1:4]; +%! R1 = choldelete (R,j); +%! +%! assert (norm (triu (R1)-R1, Inf), single (0)); +%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); +*/ + +DEFUN_DLD (cholshift, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{R1} =} cholshift (@var{R}, @var{i}, @var{j})\n\ +Given a Cholesky@tie{}factorization of a real symmetric or complex Hermitian\n\ +positive definite matrix @w{@var{A} = @var{R}'*@var{R}}, @var{R}@tie{}upper\n\ +triangular, return the Cholesky@tie{}factorization of\n\ +@w{@var{A}(p,p)}, where @w{p} is the permutation @*\n\ +@code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*\n\ + or @*\n\ +@code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*\n\ +\n\ +@seealso{chol, cholinsert, choldelete}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + + octave_value_list retval; + + if (nargin != 3) + { + print_usage (); + return retval; + } + + octave_value argr = args(0); + octave_value argi = args(1); + octave_value argj = args(2); + + if (argr.is_numeric_type () && argi.is_real_scalar () && argj.is_real_scalar ()) + { + octave_idx_type n = argr.rows (); + octave_idx_type i = argi.scalar_value (); + octave_idx_type j = argj.scalar_value (); + + if (argr.columns () == n) + { + if (j > 0 && j <= n+1 && i > 0 && i <= n+1) + { + + if (argr.is_single_type () && argi.is_single_type () && + argj.is_single_type ()) + { + if (argr.is_real_type ()) + { + // real case + FloatMatrix R = argr.float_matrix_value (); + + FloatCHOL fact; + fact.set (R); + fact.shift_sym (i-1, j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + FloatComplexMatrix R = argr.float_complex_matrix_value (); + + FloatComplexCHOL fact; + fact.set (R); + fact.shift_sym (i-1, j-1); + + retval(0) = get_chol_r (fact); + } + } + else + { + if (argr.is_real_type ()) + { + // real case + Matrix R = argr.matrix_value (); + + CHOL fact; + fact.set (R); + fact.shift_sym (i-1, j-1); + + retval(0) = get_chol_r (fact); + } + else + { + // complex case + ComplexMatrix R = argr.complex_matrix_value (); + + ComplexCHOL fact; + fact.set (R); + fact.shift_sym (i-1, j-1); + + retval(0) = get_chol_r (fact); + } + } + } + else + error ("cholshift: index I or J is out of range"); + } + else + error ("cholshift: R must be a square matrix"); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! R = chol (A); +%! +%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); +%! +%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1) - R1, Inf), 0); +%! assert (norm (R1'*R1 - A(p,p), Inf) < 1e1*eps); + +%!test +%! R = chol (Ac); +%! +%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); +%! +%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - Ac(p,p), Inf) < 1e1*eps); + +%!test +%! R = chol (single (A)); +%! +%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); +%! +%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - single (A(p,p)), Inf) < 1e1*eps ("single")); + +%!test +%! R = chol (single (Ac)); +%! +%! i = 1; j = 3; p = [1:i-1, shift(i:j,-1), j+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); +%! +%! j = 1; i = 3; p = [1:j-1, shift(j:i,+1), i+1:4]; +%! R1 = cholshift (R, i, j); +%! +%! assert (norm (triu (R1)-R1, Inf), 0); +%! assert (norm (R1'*R1 - single (Ac(p,p)), Inf) < 1e1*eps ("single")); +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/colamd.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,768 @@ +/* + +Copyright (C) 2004-2012 David Bateman +Copyright (C) 1998-2004 Andy Adler + +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/>. + +*/ + +// This is the octave interface to colamd, which bore the copyright given +// in the help of the functions. + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdlib> + +#include <string> +#include <vector> + +#include "ov.h" +#include "defun-dld.h" +#include "pager.h" +#include "ov-re-mat.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" + +#include "oct-sparse.h" +#include "oct-locbuf.h" + +#ifdef IDX_TYPE_LONG +#define COLAMD_NAME(name) colamd_l ## name +#define SYMAMD_NAME(name) symamd_l ## name +#else +#define COLAMD_NAME(name) colamd ## name +#define SYMAMD_NAME(name) symamd ## name +#endif + +// The symmetric column elimination tree code take from the Davis LDL code. +// Copyright given elsewhere in this file. +static void +symetree (const octave_idx_type *ridx, const octave_idx_type *cidx, + octave_idx_type *Parent, octave_idx_type *P, octave_idx_type n) +{ + OCTAVE_LOCAL_BUFFER (octave_idx_type, Flag, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, Pinv, (P ? n : 0)); + if (P) + // If P is present then compute Pinv, the inverse of P + for (octave_idx_type k = 0 ; k < n ; k++) + Pinv[P[k]] = k ; + + for (octave_idx_type k = 0 ; k < n ; k++) + { + // L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) + Parent[k] = n ; // parent of k is not yet known + Flag[k] = k ; // mark node k as visited + octave_idx_type kk = (P) ? (P[k]) : (k) ; // kth original, or permuted, column + octave_idx_type p2 = cidx[kk+1] ; + for (octave_idx_type p = cidx[kk] ; p < p2 ; p++) + { + // A (i,k) is nonzero (original or permuted A) + octave_idx_type i = (Pinv) ? (Pinv[ridx[p]]) : (ridx[p]) ; + if (i < k) + { + // follow path from i to root of etree, stop at flagged node + for ( ; Flag[i] != k ; i = Parent[i]) + { + // find parent of i if not yet determined + if (Parent[i] == n) + Parent[i] = k ; + Flag[i] = k ; // mark i as visited + } + } + } + } +} + +// The elimination tree post-ordering code below is taken from SuperLU +static inline octave_idx_type +make_set (octave_idx_type i, octave_idx_type *pp) +{ + pp[i] = i; + return i; +} + +static inline octave_idx_type +link (octave_idx_type s, octave_idx_type t, octave_idx_type *pp) +{ + pp[s] = t; + return t; +} + +static inline octave_idx_type +find (octave_idx_type i, octave_idx_type *pp) +{ + register octave_idx_type p, gp; + + p = pp[i]; + gp = pp[p]; + + while (gp != p) + { + pp[i] = gp; + i = gp; + p = pp[i]; + gp = pp[p]; + } + + return p; +} + +static octave_idx_type +etdfs (octave_idx_type v, octave_idx_type *first_kid, + octave_idx_type *next_kid, octave_idx_type *post, + octave_idx_type postnum) +{ + for (octave_idx_type w = first_kid[v]; w != -1; w = next_kid[w]) + postnum = etdfs (w, first_kid, next_kid, post, postnum); + + post[postnum++] = v; + + return postnum; +} + +static void +tree_postorder (octave_idx_type n, octave_idx_type *parent, + octave_idx_type *post) +{ + // Allocate storage for working arrays and results + OCTAVE_LOCAL_BUFFER (octave_idx_type, first_kid, n+1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, next_kid, n+1); + + // Set up structure describing children + for (octave_idx_type v = 0; v <= n; first_kid[v++] = -1) + /* do nothing */; + + for (octave_idx_type v = n-1; v >= 0; v--) + { + octave_idx_type dad = parent[v]; + next_kid[v] = first_kid[dad]; + first_kid[dad] = v; + } + + // Depth-first search from dummy root vertex #n + etdfs (n, first_kid, next_kid, post, 0); +} + +static void +coletree (const octave_idx_type *ridx, const octave_idx_type *colbeg, + octave_idx_type *colend, octave_idx_type *parent, + octave_idx_type nr, octave_idx_type nc) +{ + OCTAVE_LOCAL_BUFFER (octave_idx_type, root, nc); + OCTAVE_LOCAL_BUFFER (octave_idx_type, pp, nc); + OCTAVE_LOCAL_BUFFER (octave_idx_type, firstcol, nr); + + // Compute firstcol[row] = first nonzero column in row + for (octave_idx_type row = 0; row < nr; firstcol[row++] = nc) + /* do nothing */; + + for (octave_idx_type col = 0; col < nc; col++) + for (octave_idx_type p = colbeg[col]; p < colend[col]; p++) + { + octave_idx_type row = ridx[p]; + if (firstcol[row] > col) + firstcol[row] = col; + } + + // Compute etree by Liu's algorithm for symmetric matrices, + // except use (firstcol[r],c) in place of an edge (r,c) of A. + // Thus each row clique in A'*A is replaced by a star + // centered at its first vertex, which has the same fill. + for (octave_idx_type col = 0; col < nc; col++) + { + octave_idx_type cset = make_set (col, pp); + root[cset] = col; + parent[col] = nc; + for (octave_idx_type p = colbeg[col]; p < colend[col]; p++) + { + octave_idx_type row = firstcol[ridx[p]]; + if (row >= col) + continue; + octave_idx_type rset = find (row, pp); + octave_idx_type rroot = root[rset]; + if (rroot != col) + { + parent[rroot] = col; + cset = link (cset, rset, pp); + root[cset] = col; + } + } + } +} + +DEFUN_DLD (colamd, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} colamd (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} colamd (@var{S}, @var{knobs})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{S})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} colamd (@var{S}, @var{knobs})\n\ +\n\ +Column approximate minimum degree permutation.\n\ +@code{@var{p} = colamd (@var{S})} returns the column approximate minimum\n\ +degree permutation vector for the sparse matrix @var{S}. For a\n\ +non-symmetric matrix @var{S}, @code{@var{S}(:,@var{p})} tends to have\n\ +sparser LU@tie{}factors than @var{S}. The Cholesky@tie{}factorization of\n\ +@code{@var{S}(:,@var{p})' * @var{S}(:,@var{p})} also tends to be sparser\n\ +than that of @code{@var{S}' * @var{S}}.\n\ +\n\ +@var{knobs} is an optional one- to three-element input vector. If @var{S} is\n\ +m-by-n, then rows with more than @code{max(16,@var{knobs}(1)*sqrt(n))}\n\ +entries are ignored. Columns with more than\n\ +@code{max (16,@var{knobs}(2)*sqrt(min(m,n)))} entries are removed prior to\n\ +ordering, and ordered last in the output permutation @var{p}. Only\n\ +completely dense rows or columns are removed if @code{@var{knobs}(1)} and\n\ +@code{@var{knobs}(2)} are < 0, respectively. If @code{@var{knobs}(3)} is\n\ +nonzero, @var{stats} and @var{knobs} are printed. The default is\n\ +@code{@var{knobs} = [10 10 0]}. Note that @var{knobs} differs from earlier\n\ +versions of colamd.\n\ +\n\ +@var{stats} is an optional 20-element output vector that provides data\n\ +about the ordering and the validity of the input matrix @var{S}. Ordering\n\ +statistics are in @code{@var{stats}(1:3)}. @code{@var{stats}(1)} and\n\ +@code{@var{stats}(2)} are the number of dense or empty rows and columns\n\ +ignored by @sc{colamd} and @code{@var{stats}(3)} is the number of garbage\n\ +collections performed on the internal data structure used by @sc{colamd}\n\ +(roughly of size @code{2.2 * nnz(@var{S}) + 4 * @var{m} + 7 * @var{n}}\n\ +integers).\n\ +\n\ +Octave built-in functions are intended to generate valid sparse matrices,\n\ +with no duplicate entries, with ascending row indices of the nonzeros\n\ +in each column, with a non-negative number of entries in each column (!)\n\ +and so on. If a matrix is invalid, then @sc{colamd} may or may not be able\n\ +to continue. If there are duplicate entries (a row index appears two or\n\ +more times in the same column) or if the row indices in a column are out\n\ +of order, then @sc{colamd} can correct these errors by ignoring the duplicate\n\ +entries and sorting each column of its internal copy of the matrix\n\ +@var{S} (the input matrix @var{S} is not repaired, however). If a matrix\n\ +is invalid in other ways then @sc{colamd} cannot continue, an error message\n\ +is printed, and no output arguments (@var{p} or @var{stats}) are returned.\n\ +@sc{colamd} is thus a simple way to check a sparse matrix to see if it's\n\ +valid.\n\ +\n\ +@code{@var{stats}(4:7)} provide information if COLAMD was able to\n\ +continue. The matrix is OK if @code{@var{stats}(4)} is zero, or 1 if\n\ +invalid. @code{@var{stats}(5)} is the rightmost column index that is\n\ +unsorted or contains duplicate entries, or zero if no such column exists.\n\ +@code{@var{stats}(6)} is the last seen duplicate or out-of-order row\n\ +index in the column index given by @code{@var{stats}(5)}, or zero if no\n\ +such row index exists. @code{@var{stats}(7)} is the number of duplicate\n\ +or out-of-order row indices. @code{@var{stats}(8:20)} is always zero in\n\ +the current version of @sc{colamd} (reserved for future use).\n\ +\n\ +The ordering is followed by a column elimination tree post-ordering.\n\ +\n\ +The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ +Davis @email{davis@@cise.ufl.edu}, University of Florida. The algorithm was\n\ +developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ +Ng, Oak Ridge National Laboratory. (see\n\ +@url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ +@seealso{colperm, symamd, ccolamd}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_COLAMD + + int nargin = args.length (); + int spumoni = 0; + + if (nargout > 2 || nargin < 1 || nargin > 2) + print_usage (); + else + { + // Get knobs + OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); + COLAMD_NAME (_set_defaults) (knobs); + + // Check for user-passed knobs + if (nargin == 2) + { + NDArray User_knobs = args(1).array_value (); + int nel_User_knobs = User_knobs.length (); + + if (nel_User_knobs > 0) + knobs[COLAMD_DENSE_ROW] = User_knobs(0); + if (nel_User_knobs > 1) + knobs[COLAMD_DENSE_COL] = User_knobs(1) ; + if (nel_User_knobs > 2) + spumoni = static_cast<int> (User_knobs(2)); + + // print knob settings if spumoni is set + if (spumoni) + { + + octave_stdout << "\ncolamd version " << COLAMD_MAIN_VERSION << "." + << COLAMD_SUB_VERSION << ", " << COLAMD_DATE << ":\n"; + + if (knobs[COLAMD_DENSE_ROW] >= 0) + octave_stdout << "knobs(1): " << User_knobs (0) + << ", rows with > max (16," + << knobs[COLAMD_DENSE_ROW] << "*sqrt (size(A,2)))" + << " entries removed\n"; + else + octave_stdout << "knobs(1): " << User_knobs (0) + << ", only completely dense rows removed\n"; + + if (knobs[COLAMD_DENSE_COL] >= 0) + octave_stdout << "knobs(2): " << User_knobs (1) + << ", cols with > max (16," + << knobs[COLAMD_DENSE_COL] << "*sqrt (size(A)))" + << " entries removed\n"; + else + octave_stdout << "knobs(2): " << User_knobs (1) + << ", only completely dense columns removed\n"; + + octave_stdout << "knobs(3): " << User_knobs (2) + << ", statistics and knobs printed\n"; + + } + } + + octave_idx_type n_row, n_col, nnz; + octave_idx_type *ridx, *cidx; + SparseComplexMatrix scm; + SparseMatrix sm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0). sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + nnz = scm.nnz (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + + n_row = sm.rows (); + n_col = sm.cols (); + nnz = sm.nnz (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + } + else + { + if (args(0).is_complex_type ()) + sm = SparseMatrix (real (args(0).complex_matrix_value ())); + else + sm = SparseMatrix (args(0).matrix_value ()); + + n_row = sm.rows (); + n_col = sm.cols (); + nnz = sm.nnz (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + // Allocate workspace for colamd + OCTAVE_LOCAL_BUFFER (octave_idx_type, p, n_col+1); + for (octave_idx_type i = 0; i < n_col+1; i++) + p[i] = cidx[i]; + + octave_idx_type Alen = COLAMD_NAME (_recommended) (nnz, n_row, n_col); + OCTAVE_LOCAL_BUFFER (octave_idx_type, A, Alen); + for (octave_idx_type i = 0; i < nnz; i++) + A[i] = ridx[i]; + + // Order the columns (destroys A) + OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, COLAMD_STATS); + if (! COLAMD_NAME () (n_row, n_col, Alen, A, p, knobs, stats)) + { + COLAMD_NAME (_report) (stats) ; + error ("colamd: internal error!"); + return retval; + } + + // column elimination tree post-ordering (reuse variables) + OCTAVE_LOCAL_BUFFER (octave_idx_type, colbeg, n_col + 1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, colend, n_col + 1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); + + for (octave_idx_type i = 0; i < n_col; i++) + { + colbeg[i] = cidx[p[i]]; + colend[i] = cidx[p[i]+1]; + } + + coletree (ridx, colbeg, colend, etree, n_row, n_col); + + // Calculate the tree post-ordering + tree_postorder (n_col, etree, colbeg); + + // return the permutation vector + NDArray out_perm (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + out_perm(i) = p[colbeg[i]] + 1; + + retval(0) = out_perm; + + // print stats if spumoni > 0 + if (spumoni > 0) + COLAMD_NAME (_report) (stats) ; + + // Return the stats vector + if (nargout == 2) + { + NDArray out_stats (dim_vector (1, COLAMD_STATS)); + for (octave_idx_type i = 0 ; i < COLAMD_STATS ; i++) + out_stats(i) = stats[i] ; + retval(1) = out_stats; + + // fix stats (5) and (6), for 1-based information on + // jumbled matrix. note that this correction doesn't + // occur if symamd returns FALSE + out_stats (COLAMD_INFO1) ++ ; + out_stats (COLAMD_INFO2) ++ ; + } + } + +#else + + error ("colamd: not available in this version of Octave"); + +#endif + + return retval; +} + +DEFUN_DLD (symamd, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} symamd (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} symamd (@var{S}, @var{knobs})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{S})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{stats}] =} symamd (@var{S}, @var{knobs})\n\ +\n\ +For a symmetric positive definite matrix @var{S}, returns the permutation\n\ +vector p such that @code{@var{S}(@var{p}, @var{p})} tends to have a\n\ +sparser Cholesky@tie{}factor than @var{S}. Sometimes @code{symamd} works\n\ +well for symmetric indefinite matrices too. The matrix @var{S} is assumed\n\ +to be symmetric; only the strictly lower triangular part is referenced.\n\ +@var{S} must be square.\n\ +\n\ +@var{knobs} is an optional one- to two-element input vector. If @var{S} is\n\ +n-by-n, then rows and columns with more than\n\ +@code{max (16,@var{knobs}(1)*sqrt(n))} entries are removed prior to ordering,\n\ +and ordered last in the output permutation @var{p}. No rows/columns are\n\ +removed if @code{@var{knobs}(1) < 0}. If @code{@var{knobs} (2)} is nonzero,\n\ +@code{stats} and @var{knobs} are printed. The default is @code{@var{knobs}\n\ += [10 0]}. Note that @var{knobs} differs from earlier versions of symamd.\n\ +\n\ +@var{stats} is an optional 20-element output vector that provides data\n\ +about the ordering and the validity of the input matrix @var{S}. Ordering\n\ +statistics are in @code{@var{stats}(1:3)}. @code{@var{stats}(1) =\n\ +@var{stats}(2)} is the number of dense or empty rows and columns\n\ +ignored by SYMAMD and @code{@var{stats}(3)} is the number of garbage\n\ +collections performed on the internal data structure used by SYMAMD\n\ +(roughly of size @code{8.4 * nnz (tril (@var{S}, -1)) + 9 * @var{n}}\n\ +integers).\n\ +\n\ +Octave built-in functions are intended to generate valid sparse matrices,\n\ +with no duplicate entries, with ascending row indices of the nonzeros\n\ +in each column, with a non-negative number of entries in each column (!)\n\ +and so on. If a matrix is invalid, then SYMAMD may or may not be able\n\ +to continue. If there are duplicate entries (a row index appears two or\n\ +more times in the same column) or if the row indices in a column are out\n\ +of order, then SYMAMD can correct these errors by ignoring the duplicate\n\ +entries and sorting each column of its internal copy of the matrix S (the\n\ +input matrix S is not repaired, however). If a matrix is invalid in\n\ +other ways then SYMAMD cannot continue, an error message is printed, and\n\ +no output arguments (@var{p} or @var{stats}) are returned. SYMAMD is\n\ +thus a simple way to check a sparse matrix to see if it's valid.\n\ +\n\ +@code{@var{stats}(4:7)} provide information if SYMAMD was able to\n\ +continue. The matrix is OK if @code{@var{stats} (4)} is zero, or 1\n\ +if invalid. @code{@var{stats}(5)} is the rightmost column index that\n\ +is unsorted or contains duplicate entries, or zero if no such column\n\ +exists. @code{@var{stats}(6)} is the last seen duplicate or out-of-order\n\ +row index in the column index given by @code{@var{stats}(5)}, or zero\n\ +if no such row index exists. @code{@var{stats}(7)} is the number of\n\ +duplicate or out-of-order row indices. @code{@var{stats}(8:20)} is\n\ +always zero in the current version of SYMAMD (reserved for future use).\n\ +\n\ +The ordering is followed by a column elimination tree post-ordering.\n\ +\n\ +The authors of the code itself are Stefan I. Larimore and Timothy A.\n\ +Davis @email{davis@@cise.ufl.edu}, University of Florida. The algorithm was\n\ +developed in collaboration with John Gilbert, Xerox PARC, and Esmond\n\ +Ng, Oak Ridge National Laboratory. (see\n\ +@url{http://www.cise.ufl.edu/research/sparse/colamd})\n\ +@seealso{colperm, colamd}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_COLAMD + + int nargin = args.length (); + int spumoni = 0; + + if (nargout > 2 || nargin < 1 || nargin > 2) + print_usage (); + else + { + // Get knobs + OCTAVE_LOCAL_BUFFER (double, knobs, COLAMD_KNOBS); + COLAMD_NAME (_set_defaults) (knobs); + + // Check for user-passed knobs + if (nargin == 2) + { + NDArray User_knobs = args(1).array_value (); + int nel_User_knobs = User_knobs.length (); + + if (nel_User_knobs > 0) + knobs[COLAMD_DENSE_ROW] = User_knobs(COLAMD_DENSE_ROW); + if (nel_User_knobs > 1) + spumoni = static_cast<int> (User_knobs (1)); + } + + // print knob settings if spumoni is set + if (spumoni > 0) + octave_stdout << "symamd: dense row/col fraction: " + << knobs[COLAMD_DENSE_ROW] << std::endl; + + octave_idx_type n_row, n_col; + octave_idx_type *ridx, *cidx; + SparseMatrix sm; + SparseComplexMatrix scm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0).sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + } + else + { + if (args(0).is_complex_type ()) + sm = SparseMatrix (real (args(0).complex_matrix_value ())); + else + sm = SparseMatrix (args(0).matrix_value ()); + + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + if (n_row != n_col) + { + error ("symamd: matrix S must be square"); + return retval; + } + + // Allocate workspace for symamd + OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, n_col+1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, stats, COLAMD_STATS); + if (!SYMAMD_NAME () (n_col, ridx, cidx, perm, knobs, stats, &calloc, &free)) + { + SYMAMD_NAME (_report) (stats) ; + error ("symamd: internal error!") ; + return retval; + } + + // column elimination tree post-ordering + OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); + symetree (ridx, cidx, etree, perm, n_col); + + // Calculate the tree post-ordering + OCTAVE_LOCAL_BUFFER (octave_idx_type, post, n_col + 1); + tree_postorder (n_col, etree, post); + + // return the permutation vector + NDArray out_perm (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + out_perm(i) = perm[post[i]] + 1; + + retval(0) = out_perm; + + // print stats if spumoni > 0 + if (spumoni > 0) + SYMAMD_NAME (_report) (stats) ; + + // Return the stats vector + if (nargout == 2) + { + NDArray out_stats (dim_vector (1, COLAMD_STATS)); + for (octave_idx_type i = 0 ; i < COLAMD_STATS ; i++) + out_stats(i) = stats[i] ; + retval(1) = out_stats; + + // fix stats (5) and (6), for 1-based information on + // jumbled matrix. note that this correction doesn't + // occur if symamd returns FALSE + out_stats (COLAMD_INFO1) ++ ; + out_stats (COLAMD_INFO2) ++ ; + } + } + +#else + + error ("symamd: not available in this version of Octave"); + +#endif + + return retval; +} + +DEFUN_DLD (etree, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} etree (@var{S})\n\ +@deftypefnx {Loadable Function} {@var{p} =} etree (@var{S}, @var{typ})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{q}] =} etree (@var{S}, @var{typ})\n\ +\n\ +Return the elimination tree for the matrix @var{S}. By default @var{S}\n\ +is assumed to be symmetric and the symmetric elimination tree is\n\ +returned. The argument @var{typ} controls whether a symmetric or\n\ +column elimination tree is returned. Valid values of @var{typ} are\n\ +\"sym\" or \"col\", for symmetric or column elimination tree respectively\n\ +\n\ +Called with a second argument, @code{etree} also returns the postorder\n\ +permutations on the tree.\n\ +@end deftypefn") +{ + octave_value_list retval; + + int nargin = args.length (); + + if (nargout > 2 || nargin < 1 || nargin > 2) + print_usage (); + else + { + octave_idx_type n_row, n_col; + octave_idx_type *ridx, *cidx; + bool is_sym = true; + SparseMatrix sm; + SparseComplexMatrix scm; + + if (args(0).is_sparse_type ()) + { + if (args(0).is_complex_type ()) + { + scm = args(0).sparse_complex_matrix_value (); + n_row = scm.rows (); + n_col = scm.cols (); + ridx = scm.xridx (); + cidx = scm.xcidx (); + } + else + { + sm = args(0).sparse_matrix_value (); + n_row = sm.rows (); + n_col = sm.cols (); + ridx = sm.xridx (); + cidx = sm.xcidx (); + } + + } + else + { + error ("etree: S must be a sparse matrix"); + return retval; + } + + if (nargin == 2) + { + if (args(1).is_string ()) + { + std::string str = args(1).string_value (); + if (str.find ("C") == 0 || str.find ("c") == 0) + is_sym = false; + } + else + { + error ("etree: TYP must be a string"); + return retval; + } + } + + // column elimination tree post-ordering (reuse variables) + OCTAVE_LOCAL_BUFFER (octave_idx_type, etree, n_col + 1); + + if (is_sym) + { + if (n_row != n_col) + { + error ("etree: S is marked as symmetric, but is not square"); + return retval; + } + + symetree (ridx, cidx, etree, 0, n_col); + } + else + { + OCTAVE_LOCAL_BUFFER (octave_idx_type, colbeg, n_col); + OCTAVE_LOCAL_BUFFER (octave_idx_type, colend, n_col); + + for (octave_idx_type i = 0; i < n_col; i++) + { + colbeg[i] = cidx[i]; + colend[i] = cidx[i+1]; + } + + coletree (ridx, colbeg, colend, etree, n_row, n_col); + } + + NDArray tree (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + // We flag a root with n_col while Matlab does it with zero + // Convert for matlab compatiable output + if (etree[i] == n_col) + tree(i) = 0; + else + tree(i) = etree[i] + 1; + + retval(0) = tree; + + if (nargout == 2) + { + // Calculate the tree post-ordering + OCTAVE_LOCAL_BUFFER (octave_idx_type, post, n_col + 1); + tree_postorder (n_col, etree, post); + + NDArray postorder (dim_vector (1, n_col)); + for (octave_idx_type i = 0; i < n_col; i++) + postorder(i) = post[i] + 1; + + retval(1) = postorder; + } + } + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/config-module.awk Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,77 @@ +BEGIN { + FS = "|"; + nfiles = 0; + + print "## DO NOT EDIT -- generated from module-files by config-module.awk"; + print "" + print "EXTRA_DIST += \\" + print " dldfcn/config-module.sh \\" + print " dldfcn/config-module.awk \\" + print " dldfcn/module-files \\" + print " dldfcn/oct-qhull.h" + print "" +} +/^#.*/ { next; } +{ + nfiles++; + files[nfiles] = $1; + cppflags[nfiles] = $2; + ldflags[nfiles] = $3; + libraries[nfiles] = $4; +} END { + sep = " \\\n"; + print "DLDFCN_SRC = \\"; + for (i = 1; i <= nfiles; i++) { + if (i == nfiles) + sep = "\n"; + printf (" dldfcn/%s%s", files[i], sep); + } + print ""; + + sep = " \\\n"; + print "DLDFCN_LIBS = $(DLDFCN_SRC:.cc=.la)"; + print ""; + print "if AMCOND_ENABLE_DYNAMIC_LINKING"; + print ""; + print "octlib_LTLIBRARIES += $(DLDFCN_LIBS)"; + print ""; + print "## Use stamp files to avoid problems with checking timestamps"; + print "## of symbolic links"; + print ""; + for (i = 1; i <= nfiles; i++) { + basename = files[i]; + sub (/\.cc$/, "", basename); + printf ("dldfcn/$(am__leading_dot)%s.oct-stamp: dldfcn/%s.la\n", basename, basename); + print "\trm -f $(<:.la=.oct)"; + print "\tla=$(<F) && \\"; + print "\t of=$(<F:.la=.oct) && \\"; + print "\t cd dldfcn && \\"; + print "\t $(LN_S) .libs/`$(SED) -n -e \"s/dlname='\\([^']*\\)'/\\1/p\" < $$la` $$of && \\"; + print "\t touch $(@F)"; + print ""; + } + print "else"; + print ""; + print "noinst_LTLIBRARIES += $(DLDFCN_LIBS)"; + print ""; + print "endif"; + + for (i = 1; i <= nfiles; i++) { + basename = files[i]; + sub (/\.cc$/, "", basename); + print ""; + printf ("dldfcn_%s_la_SOURCES = dldfcn/%s\n", + basename, files[i]); + if (cppflags[i]) + { + printf ("dldfcn/%s.df: CPPFLAGS += %s\n", + basename, cppflags[i]); + printf ("dldfcn_%s_la_CPPFLAGS = $(AM_CPPFLAGS) %s\n", + basename, cppflags[i]); + } + printf ("dldfcn_%s_la_LDFLAGS = -avoid-version -module $(NO_UNDEFINED_LDFLAG) %s $(OCT_LINK_OPTS)\n", + basename, ldflags[i]); + printf ("dldfcn_%s_la_LIBADD = $(DLD_LIBOCTINTERP_LIBADD) ../liboctave/liboctave.la ../libcruft/libcruft.la %s $(OCT_LINK_DEPS)\n", + basename, libraries[i]); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/config-module.sh Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,19 @@ +#! /bin/sh + +set -e + +: ${AWK=awk} + +if [ $# -eq 1 ]; then + top_srcdir="$1"; +else + top_srcdir="../.." +fi + +move_if_change="$top_srcdir/build-aux/move-if-change" + +dld_dir=$top_srcdir/src/dldfcn + +$AWK -f $dld_dir/config-module.awk < $dld_dir/module-files > $dld_dir/module.mk-t + +$move_if_change $dld_dir/module.mk-t $dld_dir/module.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/convhulln.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,316 @@ +/* + +Copyright (C) 2000-2012 Kai Habel + +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/>. + +*/ + +/* +29. July 2000 - Kai Habel: first release +2002-04-22 Paul Kienzle +* Use warning(...) function rather than writing to cerr +2006-05-01 Tom Holroyd +* add support for consistent winding in all dimensions; output is +* guaranteed to be simplicial. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sstream> + +#include "Cell.h" +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "parse.h" +#include "unwind-prot.h" + +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) +char qh_version[] = "convhulln.oct 2007-07-24"; +# endif +#endif + +static void +close_fcn (FILE *f) +{ + gnulib::fclose (f); +} + +DEFUN_DLD (convhulln, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{h} =} convhulln (@var{pts})\n\ +@deftypefnx {Loadable Function} {@var{h} =} convhulln (@var{pts}, @var{options})\n\ +@deftypefnx {Loadable Function} {[@var{h}, @var{v}] =} convhulln (@dots{})\n\ +Compute the convex hull of the set of points @var{pts} which is a matrix\n\ +of size [n, dim] containing n points in a space of dimension dim.\n\ +The hull @var{h} is an index vector into the set of points and specifies\n\ +which points form the enclosing hull.\n\ +\n\ +An optional second argument, which must be a string or cell array of strings,\n\ +contains options passed to the underlying qhull command.\n\ +See the documentation for the Qhull library for details\n\ +@url{http://www.qhull.org/html/qh-quick.htm#options}.\n\ +The default options depend on the dimension of the input:\n\ +\n\ +@itemize\n\ +@item 2D, 3D, 4D: @var{options} = @code{@{\"Qt\"@}}\n\ +\n\ +@item 5D and higher: @var{options} = @code{@{\"Qt\", \"Qx\"@}}\n\ +@end itemize\n\ +\n\ +If @var{options} is not present or @code{[]} then the default arguments are\n\ +used. Otherwise, @var{options} replaces the default argument list.\n\ +To append user options to the defaults it is necessary to repeat the\n\ +default arguments in @var{options}. Use a null string to pass no arguments.\n\ +\n\ +If the second output @var{v} is requested the volume of the enclosing\n\ +convex hull is calculated.\n\n\ +@seealso{convhull, delaunayn, voronoin}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#if defined (HAVE_QHULL) + + int nargin = args.length (); + if (nargin < 1 || nargin > 2) + { + print_usage (); + return retval; + } + + Matrix points (args(0).matrix_value ()); + const octave_idx_type dim = points.columns (); + const octave_idx_type num_points = points.rows (); + + points = points.transpose (); + + std::string options; + + if (dim <= 4) + options = " Qt"; + else + options = " Qt Qx"; + + if (nargin == 2) + { + if (args(1).is_string ()) + options = " " + args(1).string_value (); + else if (args(1).is_empty ()) + ; // Use default options. + else if (args(1).is_cellstr ()) + { + options = ""; + + Array<std::string> tmp = args(1).cellstr_value (); + + for (octave_idx_type i = 0; i < tmp.numel (); i++) + options += " " + tmp(i); + } + else + { + error ("convhulln: OPTIONS must be a string, cell array of strings, or empty"); + return retval; + } + } + + boolT ismalloc = false; + + unwind_protect frame; + + // Replace the outfile pointer with stdout for debugging information. +#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) + FILE *outfile = gnulib::fopen ("NUL", "w"); +#else + FILE *outfile = gnulib::fopen ("/dev/null", "w"); +#endif + FILE *errfile = stderr; + + if (outfile) + frame.add_fcn (close_fcn, outfile); + else + { + error ("convhulln: unable to create temporary file for output"); + return retval; + } + + // qh_new_qhull command and points arguments are not const... + + std::string cmd = "qhull" + options; + + OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); + + strcpy (cmd_str, cmd.c_str ()); + + int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), + ismalloc, cmd_str, outfile, errfile); + if (! exitcode) + { + bool nonsimp_seen = false; + + octave_idx_type nf = qh num_facets; + + Matrix idx (nf, dim + 1); + + facetT *facet; + + octave_idx_type i = 0; + + FORALLfacets + { + octave_idx_type j = 0; + + if (! nonsimp_seen && ! facet->simplicial) + { + nonsimp_seen = true; + + if (cmd.find ("QJ") != std::string::npos) + { + // Should never happen with QJ. + error ("convhulln: qhull failed: option 'QJ' returned non-simplicial facet"); + return retval; + } + } + + if (dim == 3) + { + setT *vertices = qh_facet3vertex (facet); + + vertexT *vertex, **vertexp; + + FOREACHvertex_ (vertices) + idx(i, j++) = 1 + qh_pointid(vertex->point); + + qh_settempfree (&vertices); + } + else + { + if (facet->toporient ^ qh_ORIENTclock) + { + vertexT *vertex, **vertexp; + + FOREACHvertex_ (facet->vertices) + idx(i, j++) = 1 + qh_pointid(vertex->point); + } + else + { + vertexT *vertex, **vertexp; + + FOREACHvertexreverse12_ (facet->vertices) + idx(i, j++) = 1 + qh_pointid(vertex->point); + } + } + if (j < dim) + warning ("convhulln: facet %d only has %d vertices", i, j); + + i++; + } + + // Remove extra dimension if all facets were simplicial. + + if (! nonsimp_seen) + idx.resize (nf, dim, 0.0); + + if (nargout == 2) + { + // Calculate volume of convex hull, taken from qhull src/geom2.c. + + realT area; + realT dist; + + FORALLfacets + { + if (! facet->normal) + continue; + + if (facet->upperdelaunay && qh ATinfinity) + continue; + + facet->f.area = area = qh_facetarea (facet); + facet->isarea = True; + + if (qh DELAUNAY) + { + if (facet->upperdelaunay == qh UPPERdelaunay) + qh totarea += area; + } + else + { + qh totarea += area; + qh_distplane (qh interior_point, facet, &dist); + qh totvol += -dist * area/ qh hull_dim; + } + } + + retval(1) = octave_value (qh totvol); + } + + retval(0) = idx; + } + else + error ("convhulln: qhull failed"); + + // Free memory from Qhull + qh_freeqhull (! qh_ALL); + + int curlong, totlong; + qh_memfreeshort (&curlong, &totlong); + + if (curlong || totlong) + warning ("convhulln: did not free %d bytes of long memory (%d pieces)", + totlong, curlong); + +#else + error ("convhulln: not available in this version of Octave"); +#endif + + return retval; +} + +/* +%!testif HAVE_QHULL +%! cube = [0 0 0;1 0 0;1 1 0;0 1 0;0 0 1;1 0 1;1 1 1;0 1 1]; +%! [h, v] = convhulln (cube, "Qt"); +%! assert (size (h), [12 3]); +%! h = sortrows (sort (h, 2), [1:3]); +%! assert (h, [1 2 4; 1 2 6; 1 4 8; 1 5 6; 1 5 8; 2 3 4; 2 3 7; 2 6 7; 3 4 7; 4 7 8; 5 6 7; 5 7 8]); +%! assert (v, 1, 10*eps); +%! [h2, v2] = convhulln (cube); % Test defaut option = "Qt" +%! assert (size (h2), size (h)); +%! h2 = sortrows (sort (h2, 2), [1:3]); +%! assert (h2, h); +%! assert (v2, v, 10*eps); + +%!testif HAVE_QHULL +%! cube = [0 0 0;1 0 0;1 1 0;0 1 0;0 0 1;1 0 1;1 1 1;0 1 1]; +%! [h, v] = convhulln (cube, "QJ"); +%! assert (size (h), [12 3]); +%! assert (sortrows (sort (h, 2), [1:3]), [1 2 4; 1 2 5; 1 4 5; 2 3 4; 2 3 6; 2 5 6; 3 4 8; 3 6 7; 3 7 8; 4 5 8; 5 6 8; 6 7 8]); +%! assert (v, 1.0, 1e6*eps); + +%!testif HAVE_QHULL +%! tetrahedron = [1 1 1;-1 -1 1;-1 1 -1;1 -1 -1]; +%! [h, v] = convhulln (tetrahedron); +%! h = sortrows (sort (h, 2), [1 2 3]); +%! assert (h, [1 2 3;1 2 4; 1 3 4; 2 3 4]); +%! assert (v, 8/3, 10*eps); +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/dmperm.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,229 @@ +/* + +Copyright (C) 2005-2012 David Bateman +Copyright (C) 1998-2005 Andy Adler + +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> +#endif + +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +#include "oct-sparse.h" +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "SparseQR.h" +#include "SparseCmplxQR.h" + +#ifdef IDX_TYPE_LONG +#define CXSPARSE_NAME(name) cs_dl ## name +#else +#define CXSPARSE_NAME(name) cs_di ## name +#endif + +static RowVector +put_int (octave_idx_type *p, octave_idx_type n) +{ + RowVector ret (n); + for (octave_idx_type i = 0; i < n; i++) + ret.xelem (i) = p[i] + 1; + return ret; +} + +#if HAVE_CXSPARSE +static octave_value_list +dmperm_internal (bool rank, const octave_value arg, int nargout) +{ + octave_value_list retval; + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + SparseMatrix m; + SparseComplexMatrix cm; + CXSPARSE_NAME () csm; + csm.m = nr; + csm.n = nc; + csm.x = 0; + csm.nz = -1; + + if (arg.is_real_type ()) + { + m = arg.sparse_matrix_value (); + csm.nzmax = m.nnz (); + csm.p = m.xcidx (); + csm.i = m.xridx (); + } + else + { + cm = arg.sparse_complex_matrix_value (); + csm.nzmax = cm.nnz (); + csm.p = cm.xcidx (); + csm.i = cm.xridx (); + } + + if (!error_state) + { + if (nargout <= 1 || rank) + { +#if defined(CS_VER) && (CS_VER >= 2) + octave_idx_type *jmatch = CXSPARSE_NAME (_maxtrans) (&csm, 0); +#else + octave_idx_type *jmatch = CXSPARSE_NAME (_maxtrans) (&csm); +#endif + if (rank) + { + octave_idx_type r = 0; + for (octave_idx_type i = 0; i < nc; i++) + if (jmatch[nr+i] >= 0) + r++; + retval(0) = static_cast<double>(r); + } + else + retval(0) = put_int (jmatch + nr, nc); + CXSPARSE_NAME (_free) (jmatch); + } + else + { +#if defined(CS_VER) && (CS_VER >= 2) + CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm, 0); +#else + CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm); +#endif + + //retval(5) = put_int (dm->rr, 5); + //retval(4) = put_int (dm->cc, 5); +#if defined(CS_VER) && (CS_VER >= 2) + retval(3) = put_int (dm->s, dm->nb+1); + retval(2) = put_int (dm->r, dm->nb+1); + retval(1) = put_int (dm->q, nc); + retval(0) = put_int (dm->p, nr); +#else + retval(3) = put_int (dm->S, dm->nb+1); + retval(2) = put_int (dm->R, dm->nb+1); + retval(1) = put_int (dm->Q, nc); + retval(0) = put_int (dm->P, nr); +#endif + CXSPARSE_NAME (_dfree) (dm); + } + } + return retval; +} +#endif + +DEFUN_DLD (dmperm, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} dmperm (@var{S})\n\ +@deftypefnx {Loadable Function} {[@var{p}, @var{q}, @var{r}, @var{S}] =} dmperm (@var{S})\n\ +\n\ +@cindex Dulmage-Mendelsohn decomposition\n\ +Perform a Dulmage-Mendelsohn permutation of the sparse matrix @var{S}.\n\ +With a single output argument @code{dmperm} performs the row permutations\n\ +@var{p} such that @code{@var{S}(@var{p},:)} has no zero elements on the\n\ +diagonal.\n\ +\n\ +Called with two or more output arguments, returns the row and column\n\ +permutations, such that @code{@var{S}(@var{p}, @var{q})} is in block\n\ +triangular form. The values of @var{r} and @var{S} define the boundaries\n\ +of the blocks. If @var{S} is square then @code{@var{r} == @var{S}}.\n\ +\n\ +The method used is described in: A. Pothen & C.-J. Fan. @cite{Computing the\n\ +Block Triangular Form of a Sparse Matrix}. ACM Trans. Math. Software,\n\ +16(4):303-324, 1990.\n\ +@seealso{colamd, ccolamd}\n\ +@end deftypefn") +{ + int nargin = args.length (); + octave_value_list retval; + + if (nargin != 1) + { + print_usage (); + return retval; + } + +#if HAVE_CXSPARSE + retval = dmperm_internal (false, args(0), nargout); +#else + error ("dmperm: not available in this version of Octave"); +#endif + + return retval; +} + +/* +%!testif HAVE_CXSPARSE +%! n = 20; +%! a = speye (n,n); +%! a = a(randperm (n),:); +%! assert (a(dmperm (a),:), speye (n)); + +%!testif HAVE_CXSPARSE +%! n = 20; +%! d = 0.2; +%! a = tril (sprandn (n,n,d), -1) + speye (n,n); +%! a = a(randperm (n), randperm (n)); +%! [p,q,r,s] = dmperm (a); +%! assert (tril (a(p,q), -1), sparse (n, n)); +*/ + +DEFUN_DLD (sprank, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} sprank (@var{S})\n\ +@cindex structural rank\n\ +\n\ +Calculate the structural rank of the sparse matrix @var{S}. Note that\n\ +only the structure of the matrix is used in this calculation based on\n\ +a Dulmage-Mendelsohn permutation to block triangular form. As such the\n\ +numerical rank of the matrix @var{S} is bounded by\n\ +@code{sprank (@var{S}) >= rank (@var{S})}. Ignoring floating point errors\n\ +@code{sprank (@var{S}) == rank (@var{S})}.\n\ +@seealso{dmperm}\n\ +@end deftypefn") +{ + int nargin = args.length (); + octave_value_list retval; + + if (nargin != 1) + { + print_usage (); + return retval; + } + +#if HAVE_CXSPARSE + retval = dmperm_internal (true, args(0), nargout); +#else + error ("sprank: not available in this version of Octave"); +#endif + + return retval; +} + +/* +%!testif HAVE_CXSPARSE +%! assert (sprank (speye (20)), 20) +%!testif HAVE_CXSPARSE +%! assert (sprank ([1,0,2,0;2,0,4,0]), 2) + +%!error sprank (1,2) +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/eigs.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,1521 @@ +/* + +Copyright (C) 2005-2012 David Bateman + +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> +#endif + +#include "ov.h" +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "quit.h" +#include "variables.h" +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "oct-map.h" +#include "pager.h" +#include "unwind-prot.h" + +#include "eigs-base.cc" + +// Global pointer for user defined function. +static octave_function *eigs_fcn = 0; + +// Have we warned about imaginary values returned from user function? +static bool warned_imaginary = false; + +// Is this a recursive call? +static int call_depth = 0; + +ColumnVector +eigs_func (const ColumnVector &x, int &eigs_error) +{ + ColumnVector retval; + octave_value_list args; + args(0) = x; + + if (eigs_fcn) + { + octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args); + + if (error_state) + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + return retval; + } + + if (tmp.length () && tmp(0).is_defined ()) + { + if (! warned_imaginary && tmp(0).is_complex_type ()) + { + warning ("eigs: ignoring imaginary part returned from user-supplied function"); + warned_imaginary = true; + } + + retval = ColumnVector (tmp(0).vector_value ()); + + if (error_state) + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + } + } + else + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + } + } + + return retval; +} + +ComplexColumnVector +eigs_complex_func (const ComplexColumnVector &x, int &eigs_error) +{ + ComplexColumnVector retval; + octave_value_list args; + args(0) = x; + + if (eigs_fcn) + { + octave_value_list tmp = eigs_fcn->do_multi_index_op (1, args); + + if (error_state) + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + return retval; + } + + if (tmp.length () && tmp(0).is_defined ()) + { + retval = ComplexColumnVector (tmp(0).complex_vector_value ()); + + if (error_state) + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + } + } + else + { + eigs_error = 1; + gripe_user_supplied_eval ("eigs"); + } + } + + return retval; +} + +DEFUN_DLD (eigs, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{d} =} eigs (@var{A})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k}, @var{sigma})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{k}, @var{sigma}, @var{opts})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma}, @var{opts})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma}, @var{opts})\n\ +@deftypefnx {Loadable Function} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma}, @var{opts})\n\ +@deftypefnx {Loadable Function} {[@var{V}, @var{d}] =} eigs (@var{A}, @dots{})\n\ +@deftypefnx {Loadable Function} {[@var{V}, @var{d}] =} eigs (@var{af}, @var{n}, @dots{})\n\ +@deftypefnx {Loadable Function} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{A}, @dots{})\n\ +@deftypefnx {Loadable Function} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{af}, @var{n}, @dots{})\n\ +Calculate a limited number of eigenvalues and eigenvectors of @var{A},\n\ +based on a selection criteria. The number of eigenvalues and eigenvectors to\n\ +calculate is given by @var{k} and defaults to 6.\n\ +\n\ +By default, @code{eigs} solve the equation\n\ +@tex\n\ +$A \\nu = \\lambda \\nu$,\n\ +@end tex\n\ +@ifinfo\n\ +@code{A * v = lambda * v},\n\ +@end ifinfo\n\ +where\n\ +@tex\n\ +$\\lambda$ is a scalar representing one of the eigenvalues, and $\\nu$\n\ +@end tex\n\ +@ifinfo\n\ +@code{lambda} is a scalar representing one of the eigenvalues, and @code{v}\n\ +@end ifinfo\n\ +is the corresponding eigenvector. If given the positive definite matrix\n\ +@var{B} then @code{eigs} solves the general eigenvalue equation\n\ +@tex\n\ +$A \\nu = \\lambda B \\nu$.\n\ +@end tex\n\ +@ifinfo\n\ +@code{A * v = lambda * B * v}.\n\ +@end ifinfo\n\ +\n\ +The argument @var{sigma} determines which eigenvalues are returned.\n\ +@var{sigma} can be either a scalar or a string. When @var{sigma} is a\n\ +scalar, the @var{k} eigenvalues closest to @var{sigma} are returned. If\n\ +@var{sigma} is a string, it must have one of the following values.\n\ +\n\ +@table @asis\n\ +@item \"lm\"\n\ +Largest Magnitude (default).\n\ +\n\ +@item \"sm\"\n\ +Smallest Magnitude.\n\ +\n\ +@item \"la\"\n\ +Largest Algebraic (valid only for real symmetric problems).\n\ +\n\ +@item \"sa\"\n\ +Smallest Algebraic (valid only for real symmetric problems).\n\ +\n\ +@item \"be\"\n\ +Both Ends, with one more from the high-end if @var{k} is odd (valid only for\n\ +real symmetric problems).\n\ +\n\ +@item \"lr\"\n\ +Largest Real part (valid only for complex or unsymmetric problems).\n\ +\n\ +@item \"sr\"\n\ +Smallest Real part (valid only for complex or unsymmetric problems).\n\ +\n\ +@item \"li\"\n\ +Largest Imaginary part (valid only for complex or unsymmetric problems).\n\ +\n\ +@item \"si\"\n\ +Smallest Imaginary part (valid only for complex or unsymmetric problems).\n\ +@end table\n\ +\n\ +If @var{opts} is given, it is a structure defining possible options that\n\ +@code{eigs} should use. The fields of the @var{opts} structure are:\n\ +\n\ +@table @code\n\ +@item issym\n\ +If @var{af} is given, then flags whether the function @var{af} defines a\n\ +symmetric problem. It is ignored if @var{A} is given. The default is false.\n\ +\n\ +@item isreal\n\ +If @var{af} is given, then flags whether the function @var{af} defines a\n\ +real problem. It is ignored if @var{A} is given. The default is true.\n\ +\n\ +@item tol\n\ +Defines the required convergence tolerance, calculated as\n\ +@code{tol * norm (A)}. The default is @code{eps}.\n\ +\n\ +@item maxit\n\ +The maximum number of iterations. The default is 300.\n\ +\n\ +@item p\n\ +The number of Lanzcos basis vectors to use. More vectors will result in\n\ +faster convergence, but a greater use of memory. The optimal value of\n\ +@code{p} is problem dependent and should be in the range @var{k} to @var{n}.\n\ +The default value is @code{2 * @var{k}}.\n\ +\n\ +@item v0\n\ +The starting vector for the algorithm. An initial vector close to the\n\ +final vector will speed up convergence. The default is for @sc{arpack}\n\ +to randomly generate a starting vector. If specified, @code{v0} must be\n\ +an @var{n}-by-1 vector where @code{@var{n} = rows (@var{A})}\n\ +\n\ +@item disp\n\ +The level of diagnostic printout (0|1|2). If @code{disp} is 0 then\n\ +diagnostics are disabled. The default value is 0.\n\ +\n\ +@item cholB\n\ +Flag if @code{chol (@var{B})} is passed rather than @var{B}. The default is\n\ +false.\n\ +\n\ +@item permB\n\ +The permutation vector of the Cholesky@tie{}factorization of @var{B} if\n\ +@code{cholB} is true. That is @code{chol (@var{B}(permB, permB))}. The\n\ +default is @code{1:@var{n}}.\n\ +\n\ +@end table\n\ +\n\ +It is also possible to represent @var{A} by a function denoted @var{af}.\n\ +@var{af} must be followed by a scalar argument @var{n} defining the length\n\ +of the vector argument accepted by @var{af}. @var{af} can be\n\ +a function handle, an inline function, or a string. When @var{af} is a\n\ +string it holds the name of the function to use.\n\ +\n\ +@var{af} is a function of the form @code{y = af (x)}\n\ +where the required return value of @var{af} is determined by\n\ +the value of @var{sigma}. The four possible forms are\n\ +\n\ +@table @code\n\ +@item A * x\n\ +if @var{sigma} is not given or is a string other than \"sm\".\n\ +\n\ +@item A \\ x\n\ +if @var{sigma} is 0 or \"sm\".\n\ +\n\ +@item (A - sigma * I) \\ x\n\ +for the standard eigenvalue problem, where @code{I} is the identity matrix of\n\ +the same size as @var{A}.\n\ +\n\ +@item (A - sigma * B) \\ x\n\ +for the general eigenvalue problem.\n\ +@end table\n\ +\n\ +The return arguments of @code{eigs} depend on the number of return arguments\n\ +requested. With a single return argument, a vector @var{d} of length @var{k}\n\ +is returned containing the @var{k} eigenvalues that have been found. With\n\ +two return arguments, @var{V} is a @var{n}-by-@var{k} matrix whose columns\n\ +are the @var{k} eigenvectors corresponding to the returned eigenvalues. The\n\ +eigenvalues themselves are returned in @var{d} in the form of a\n\ +@var{n}-by-@var{k} matrix, where the elements on the diagonal are the\n\ +eigenvalues.\n\ +\n\ +Given a third return argument @var{flag}, @code{eigs} returns the status\n\ +of the convergence. If @var{flag} is 0 then all eigenvalues have converged.\n\ +Any other value indicates a failure to converge.\n\ +\n\ +This function is based on the @sc{arpack} package, written by R. Lehoucq,\n\ +K. Maschhoff, D. Sorensen, and C. Yang. For more information see\n\ +@url{http://www.caam.rice.edu/software/ARPACK/}.\n\ +\n\ +@seealso{eig, svds}\n\ +@end deftypefn") +{ + octave_value_list retval; +#ifdef HAVE_ARPACK + int nargin = args.length (); + std::string fcn_name; + octave_idx_type n = 0; + octave_idx_type k = 6; + Complex sigma = 0.; + double sigmar, sigmai; + bool have_sigma = false; + std::string typ = "LM"; + Matrix amm, bmm, bmt; + ComplexMatrix acm, bcm, bct; + SparseMatrix asmm, bsmm, bsmt; + SparseComplexMatrix ascm, bscm, bsct; + int b_arg = 0; + bool have_b = false; + bool have_a_fun = false; + bool a_is_complex = false; + bool b_is_complex = false; + bool symmetric = false; + bool sym_tested = false; + bool cholB = false; + bool a_is_sparse = false; + ColumnVector permB; + int arg_offset = 0; + double tol = DBL_EPSILON; + int maxit = 300; + int disp = 0; + octave_idx_type p = -1; + ColumnVector resid; + ComplexColumnVector cresid; + octave_idx_type info = 1; + + warned_imaginary = false; + + unwind_protect frame; + + frame.protect_var (call_depth); + call_depth++; + + if (call_depth > 1) + { + error ("eigs: invalid recursive call"); + if (fcn_name.length ()) + clear_function (fcn_name); + return retval; + } + + if (nargin == 0) + print_usage (); + else if (args(0).is_function_handle () || args(0).is_inline_function () + || args(0).is_string ()) + { + if (args(0).is_string ()) + { + std::string name = args(0).string_value (); + std::string fname = "function y = "; + fcn_name = unique_symbol_name ("__eigs_fcn_"); + fname.append (fcn_name); + fname.append ("(x) y = "); + eigs_fcn = extract_function (args(0), "eigs", fcn_name, fname, + "; endfunction"); + } + else + eigs_fcn = args(0).function_value (); + + if (!eigs_fcn) + { + error ("eigs: unknown function"); + return retval; + } + + if (nargin < 2) + { + error ("eigs: incorrect number of arguments"); + return retval; + } + else + { + n = args(1).nint_value (); + arg_offset = 1; + have_a_fun = true; + } + } + else + { + if (args(0).is_complex_type ()) + { + if (args(0).is_sparse_type ()) + { + ascm = (args(0).sparse_complex_matrix_value ()); + a_is_sparse = true; + } + else + acm = (args(0).complex_matrix_value ()); + a_is_complex = true; + symmetric = false; // ARPACK doesn't special case complex symmetric + sym_tested = true; + } + else + { + if (args(0).is_sparse_type ()) + { + asmm = (args(0).sparse_matrix_value ()); + a_is_sparse = true; + } + else + { + amm = (args(0).matrix_value ()); + } + } + + } + + // Note hold off reading B till later to avoid issues of double + // copies of the matrix if B is full/real while A is complex. + if (!error_state && nargin > 1 + arg_offset && + !(args(1 + arg_offset).is_real_scalar ())) + { + if (args(1+arg_offset).is_complex_type ()) + { + b_arg = 1+arg_offset; + have_b = true; + b_is_complex = true; + arg_offset++; + } + else + { + b_arg = 1+arg_offset; + have_b = true; + arg_offset++; + } + } + + if (!error_state && nargin > (1+arg_offset)) + k = args(1+arg_offset).nint_value (); + + if (!error_state && nargin > (2+arg_offset)) + { + if (args(2+arg_offset).is_string ()) + { + typ = args(2+arg_offset).string_value (); + + // Use STL function to convert to upper case + transform (typ.begin (), typ.end (), typ.begin (), toupper); + + sigma = 0.; + } + else + { + sigma = args(2+arg_offset).complex_value (); + + if (! error_state) + have_sigma = true; + else + { + error ("eigs: SIGMA must be a scalar or a string"); + return retval; + } + } + } + + sigmar = std::real (sigma); + sigmai = std::imag (sigma); + + if (!error_state && nargin > (3+arg_offset)) + { + if (args(3+arg_offset).is_map ()) + { + octave_scalar_map map = args(3+arg_offset).scalar_map_value (); + + if (! error_state) + { + octave_value tmp; + + // issym is ignored for complex matrix inputs + tmp = map.getfield ("issym"); + if (tmp.is_defined () && !sym_tested) + { + symmetric = tmp.double_value () != 0.; + sym_tested = true; + } + + // isreal is ignored if A is not a function + tmp = map.getfield ("isreal"); + if (tmp.is_defined () && have_a_fun) + a_is_complex = ! (tmp.double_value () != 0.); + + tmp = map.getfield ("tol"); + if (tmp.is_defined ()) + tol = tmp.double_value (); + + tmp = map.getfield ("maxit"); + if (tmp.is_defined ()) + maxit = tmp.nint_value (); + + tmp = map.getfield ("p"); + if (tmp.is_defined ()) + p = tmp.nint_value (); + + tmp = map.getfield ("v0"); + if (tmp.is_defined ()) + { + if (a_is_complex || b_is_complex) + cresid = ComplexColumnVector (tmp.complex_vector_value ()); + else + resid = ColumnVector (tmp.vector_value ()); + } + + tmp = map.getfield ("disp"); + if (tmp.is_defined ()) + disp = tmp.nint_value (); + + tmp = map.getfield ("cholB"); + if (tmp.is_defined ()) + cholB = tmp.double_value () != 0.; + + tmp = map.getfield ("permB"); + if (tmp.is_defined ()) + permB = ColumnVector (tmp.vector_value ()) - 1.0; + } + else + { + error ("eigs: OPTS argument must be a scalar structure"); + return retval; + } + } + else + { + error ("eigs: OPTS argument must be a structure"); + return retval; + } + } + + if (nargin > (4+arg_offset)) + { + error ("eigs: incorrect number of arguments"); + return retval; + } + + // Test undeclared (no issym) matrix inputs for symmetry + if (!sym_tested && !have_a_fun) + { + if (a_is_sparse) + symmetric = asmm.is_symmetric (); + else + symmetric = amm.is_symmetric (); + } + + if (have_b) + { + if (a_is_complex || b_is_complex) + { + if (a_is_sparse) + bscm = args(b_arg).sparse_complex_matrix_value (); + else + bcm = args(b_arg).complex_matrix_value (); + } + else + { + if (a_is_sparse) + bsmm = args(b_arg).sparse_matrix_value (); + else + bmm = args(b_arg).matrix_value (); + } + } + + // Mode 1 for SM mode seems unstable for some reason. + // Use Mode 3 instead, with sigma = 0. + if (!error_state && !have_sigma && typ == "SM") + have_sigma = true; + + if (!error_state) + { + octave_idx_type nconv; + if (a_is_complex || b_is_complex) + { + ComplexMatrix eig_vec; + ComplexColumnVector eig_val; + + + if (have_a_fun) + nconv = EigsComplexNonSymmetricFunc + (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec, eig_val, + cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + else if (have_sigma) + { + if (a_is_sparse) + nconv = EigsComplexNonSymmetricMatrixShift + (ascm, sigma, k, p, info, eig_vec, eig_val, bscm, permB, + cresid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else + nconv = EigsComplexNonSymmetricMatrixShift + (acm, sigma, k, p, info, eig_vec, eig_val, bcm, permB, cresid, + octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + } + else + { + if (a_is_sparse) + nconv = EigsComplexNonSymmetricMatrix + (ascm, typ, k, p, info, eig_vec, eig_val, bscm, permB, cresid, + octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + else + nconv = EigsComplexNonSymmetricMatrix + (acm, typ, k, p, info, eig_vec, eig_val, bcm, permB, cresid, + octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + } + + if (nargout < 2) + retval(0) = eig_val; + else + { + retval(2) = double (info); + retval(1) = ComplexDiagMatrix (eig_val); + retval(0) = eig_vec; + } + } + else if (sigmai != 0.) + { + // Promote real problem to a complex one. + ComplexMatrix eig_vec; + ComplexColumnVector eig_val; + + if (have_a_fun) + nconv = EigsComplexNonSymmetricFunc + (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec, eig_val, + cresid, octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + else + { + if (a_is_sparse) + nconv = EigsComplexNonSymmetricMatrixShift + (SparseComplexMatrix (asmm), sigma, k, p, info, eig_vec, + eig_val, SparseComplexMatrix (bsmm), permB, cresid, + octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + else + nconv = EigsComplexNonSymmetricMatrixShift + (ComplexMatrix (amm), sigma, k, p, info, eig_vec, + eig_val, ComplexMatrix (bmm), permB, cresid, + octave_stdout, tol, (nargout > 1), cholB, disp, maxit); + } + + if (nargout < 2) + retval(0) = eig_val; + else + { + retval(2) = double (info); + retval(1) = ComplexDiagMatrix (eig_val); + retval(0) = eig_vec; + } + } + else + { + if (symmetric) + { + Matrix eig_vec; + ColumnVector eig_val; + + if (have_a_fun) + nconv = EigsRealSymmetricFunc + (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else if (have_sigma) + { + if (a_is_sparse) + nconv = EigsRealSymmetricMatrixShift + (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else + nconv = EigsRealSymmetricMatrixShift + (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + } + else + { + if (a_is_sparse) + nconv = EigsRealSymmetricMatrix + (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else + nconv = EigsRealSymmetricMatrix + (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + } + + if (nargout < 2) + retval(0) = eig_val; + else + { + retval(2) = double (info); + retval(1) = DiagMatrix (eig_val); + retval(0) = eig_vec; + } + } + else + { + ComplexMatrix eig_vec; + ComplexColumnVector eig_val; + + if (have_a_fun) + nconv = EigsRealNonSymmetricFunc + (eigs_func, n, typ, sigmar, k, p, info, eig_vec, eig_val, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else if (have_sigma) + { + if (a_is_sparse) + nconv = EigsRealNonSymmetricMatrixShift + (asmm, sigmar, k, p, info, eig_vec, eig_val, bsmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else + nconv = EigsRealNonSymmetricMatrixShift + (amm, sigmar, k, p, info, eig_vec, eig_val, bmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + } + else + { + if (a_is_sparse) + nconv = EigsRealNonSymmetricMatrix + (asmm, typ, k, p, info, eig_vec, eig_val, bsmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + else + nconv = EigsRealNonSymmetricMatrix + (amm, typ, k, p, info, eig_vec, eig_val, bmm, permB, + resid, octave_stdout, tol, (nargout > 1), cholB, disp, + maxit); + } + + if (nargout < 2) + retval(0) = eig_val; + else + { + retval(2) = double (info); + retval(1) = ComplexDiagMatrix (eig_val); + retval(0) = eig_vec; + } + } + } + + if (nconv <= 0) + warning ("eigs: None of the %d requested eigenvalues converged", k); + else if (nconv < k) + warning ("eigs: Only %d of the %d requested eigenvalues converged", + nconv, k); + } + + if (! fcn_name.empty ()) + clear_function (fcn_name); +#else + error ("eigs: not available in this version of Octave"); +#endif + + return retval; +} + +/* #### SPARSE MATRIX VERSIONS #### */ + +/* +## Real positive definite tests, n must be even +%!shared n, k, A, d0, d2 +%! n = 20; +%! k = 4; +%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)]); +%! d0 = eig (A); +%! d2 = sort (d0); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); # initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (d1, d0(end:-1:(end-k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, "sm"); +%! assert (d1, d0(k:-1:1), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "la"); +%! assert (d1, d2(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sa"); +%! assert (d1, d2(1:k), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "be"); +%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1, "be"); +%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (d1(idx1), d0(idx0(1:k)), 1e-11); +%!testif HAVE_ARPACK, HAVE_CHOLMOD +%! d1 = eigs (A, speye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (eigs (A, k, 4.1), eigs (A, speye (n), k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (eigs (A, k, 4.1), eigs (A, speye (n), k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (d1, d0(k:-1:1), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (d1, eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! AA = speye (10); +%! fn = @(x) AA * x; +%! opts.issym = 1; opts.isreal = 1; +%! assert (eigs (fn, 10, AA, 3, "lm", opts), [1; 1; 1], 10*eps); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "la"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sa"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "be"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/ + +/* +## Real unsymmetric tests +%!shared n, k, A, d0 +%! n = 20; +%! k = 4; +%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)]); +%! d0 = eig (A); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); % initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, "sm"); +%! assert (abs (d1), abs (d0(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lr"); +%! [~, idx] = sort (real (d0)); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "li"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "si"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); +%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); +%!testif HAVE_ARPACK, HAVE_CHOLMOD +%! d1 = eigs (A, speye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, speye (n), k, 4.1)), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, speye (n), k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (abs (d1), d0(1:k), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "li"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "si"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/ + +/* +## Complex hermitian tests +%!shared n, k, A, d0 +%! n = 20; +%! k = 4; +%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)]); +%! d0 = eig (A); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); % initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, "sm"); +%! assert (abs (d1), abs (d0(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "li"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "si"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); +%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); +%!testif HAVE_ARPACK, HAVE_CHOLMOD +%! d1 = eigs (A, speye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! d1 = eigs (A, speye (n), k, 4.1, opts); +%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); +%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, speye (n)(q,q), k, 4.1, opts); +%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); +%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, speye (n), k, 4.1)), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, speye (n), k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (abs (d1), d0(1:k), 1e-11); +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK, HAVE_UMFPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "li"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "si"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*speye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/ + +/* #### FULL MATRIX VERSIONS #### */ + +/* +## Real positive definite tests, n must be even +%!shared n, k, A, d0, d2 +%! n = 20; +%! k = 4; +%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),4*ones(1,n),ones(1,n-2)])); +%! d0 = eig (A); +%! d2 = sort (d0); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); % initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (d1, d0(end:-1:(end-k)),1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sm"); +%! assert (d1, d0(k:-1:1), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "la"); +%! assert (d1, d2(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sa"); +%! assert (d1, d2(1:k), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "be"); +%! assert (d1, d2([1:floor(k/2), (end - ceil(k/2) + 1):end]), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1, "be"); +%! assert (d1, d2([1:floor((k+1)/2), (end - ceil((k+1)/2) + 1):end]), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (d1(idx1), d0(idx0(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, eye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! assert (eigs (A, k, 4.1), eigs (A, eye (n), k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! assert (eigs (A, k, 4.1), eigs (A, eye (n), k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (d1, d0(end:-1:(end-k+1)), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (d1, d0(k:-1:1), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 1; opts.isreal = 1; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (d1, eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "la"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sa"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "be"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/ + +/* +## Real unsymmetric tests +%!shared n, k, A, d0 +%! n = 20; +%! k = 4; +%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),1:n,-ones(1,n-2)])); +%! d0 = eig (A); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); % initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sm"); +%! assert (abs (d1), abs (d0(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lr"); +%! [~, idx] = sort (real (d0)); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "li"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "si"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); +%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, eye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, eye (n), k, 4.1)), 1e-11); +%!testif HAVE_ARPACK +%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, eye (n), k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (abs (d1), d0(1:k), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 0; opts.isreal = 1; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "li"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "si"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/ + +/* +## Complex hermitian tests +%!shared n, k, A, d0 +%! n = 20; +%! k = 4; +%! A = full (sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[1i*ones(1,n-2),4*ones(1,n),-1i*ones(1,n-2)])); +%! d0 = eig (A); +%! [~, idx] = sort (abs (d0)); +%! d0 = d0(idx); +%! rand ("state", 42); % initialize generator to make eigs behavior reproducible +%!testif HAVE_ARPACK +%! d1 = eigs (A, k); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k+1); +%! assert (abs (d1), abs (d0(end:-1:(end-k))),1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sm"); +%! assert (abs (d1), abs (d0(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "lr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "sr"); +%! [~, idx] = sort (real (abs (d0))); +%! d2 = d0(idx); +%! assert (real (d1), real (d2(1:k)), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "li"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(end:-1:(end-k+1)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, "si"); +%! [~, idx] = sort (imag (abs (d0))); +%! d2 = d0(idx); +%! assert (sort (imag (d1)), sort (imag (d2(1:k))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, k, 4.1); +%! [~, idx0] = sort (abs (d0 - 4.1)); +%! [~, idx1] = sort (abs (d1 - 4.1)); +%! assert (abs (d1(idx1)), abs (d0(idx0(1:k))), 1e-11); +%! assert (sort (imag (d1(idx1))), sort (imag (d0(idx0(1:k)))), 1e-11); +%!testif HAVE_ARPACK +%! d1 = eigs (A, eye (n), k, "lm"); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! d1 = eigs (A, eye (n), k, 4.1, opts); +%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); +%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! opts.cholB = true; +%! q = [2:n,1]; +%! opts.permB = q; +%! d1 = eigs (A, eye (n)(q,q), k, 4.1, opts); +%! assert (abs (abs (d1)), abs (eigs (A, k, 4.1)), 1e-11); +%! assert (sort (imag (abs (d1))), sort (imag (eigs (A, k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! assert (abs (eigs (A, k, 4.1)), abs (eigs (A, eye (n), k, 4.1)), 1e-11); +%!testif HAVE_ARPACK +%! assert (sort (imag (eigs (A, k, 4.1))), sort (imag (eigs (A, eye (n), k, 4.1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A * x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, "lm", opts); +%! assert (abs (d1), abs (d0(end:-1:(end-k+1))), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) A \ x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, "sm", opts); +%! assert (abs (d1), d0(1:k), 1e-11); +%!testif HAVE_ARPACK +%! fn = @(x) (A - 4.1 * eye (n)) \ x; +%! opts.issym = 0; opts.isreal = 0; +%! d1 = eigs (fn, n, k, 4.1, opts); +%! assert (abs (d1), eigs (A, k, 4.1), 1e-11); +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sm"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "lr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "sr"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "li"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "si"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/fftw.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,269 @@ +/* + +Copyright (C) 2006-2012 David Bateman + +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> +#endif + +#include <algorithm> + +#include "oct-fftw.h" + +#include "defun-dld.h" +#include "error.h" +#include "ov.h" + +DEFUN_DLD (fftw, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{method} =} fftw (\"planner\")\n\ +@deftypefnx {Loadable Function} {} fftw (\"planner\", @var{method})\n\ +@deftypefnx {Loadable Function} {@var{wisdom} =} fftw (\"dwisdom\")\n\ +@deftypefnx {Loadable Function} {} fftw (\"dwisdom\", @var{wisdom})\n\ +\n\ +Manage @sc{fftw} wisdom data. Wisdom data can be used to significantly\n\ +accelerate the calculation of the FFTs, but implies an initial cost\n\ +in its calculation. When the @sc{fftw} libraries are initialized, they read\n\ +a system wide wisdom file (typically in @file{/etc/fftw/wisdom}), allowing\n\ +wisdom to be shared between applications other than Octave. Alternatively,\n\ +the @code{fftw} function can be used to import wisdom. For example,\n\ +\n\ +@example\n\ +@var{wisdom} = fftw (\"dwisdom\")\n\ +@end example\n\ +\n\ +@noindent\n\ +will save the existing wisdom used by Octave to the string @var{wisdom}.\n\ +This string can then be saved to a file and restored using the @code{save}\n\ +and @code{load} commands respectively. This existing wisdom can be\n\ +reimported as follows\n\ +\n\ +@example\n\ +fftw (\"dwisdom\", @var{wisdom})\n\ +@end example\n\ +\n\ +If @var{wisdom} is an empty matrix, then the wisdom used is cleared.\n\ +\n\ +During the calculation of Fourier transforms further wisdom is generated.\n\ +The fashion in which this wisdom is generated is also controlled by\n\ +the @code{fftw} function. There are five different manners in which the\n\ +wisdom can be treated:\n\ +\n\ +@table @asis\n\ +@item \"estimate\"\n\ +Specifies that no run-time measurement of the optimal means of\n\ +calculating a particular is performed, and a simple heuristic is used\n\ +to pick a (probably sub-optimal) plan. The advantage of this method is\n\ +that there is little or no overhead in the generation of the plan, which\n\ +is appropriate for a Fourier transform that will be calculated once.\n\ +\n\ +@item \"measure\"\n\ +In this case a range of algorithms to perform the transform is considered\n\ +and the best is selected based on their execution time.\n\ +\n\ +@item \"patient\"\n\ +Similar to \"measure\", but a wider range of algorithms is considered.\n\ +\n\ +@item \"exhaustive\"\n\ +Like \"measure\", but all possible algorithms that may be used to\n\ +treat the transform are considered.\n\ +\n\ +@item \"hybrid\"\n\ +As run-time measurement of the algorithm can be expensive, this is a\n\ +compromise where \"measure\" is used for transforms up to the size of 8192\n\ +and beyond that the \"estimate\" method is used.\n\ +@end table\n\ +\n\ +The default method is \"estimate\". The current method can\n\ +be queried with\n\ +\n\ +@example\n\ +@var{method} = fftw (\"planner\")\n\ +@end example\n\ +\n\ +@noindent\n\ +or set by using\n\ +\n\ +@example\n\ +fftw (\"planner\", @var{method})\n\ +@end example\n\ +\n\ +Note that calculated wisdom will be lost when restarting Octave. However,\n\ +the wisdom data can be reloaded if it is saved to a file as described\n\ +above. Saved wisdom files should not be used on different platforms since\n\ +they will not be efficient and the point of calculating the wisdom is lost.\n\ +@seealso{fft, ifft, fft2, ifft2, fftn, ifftn}\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin < 1 || nargin > 2) + { + print_usage (); + return retval; + } + +#if defined (HAVE_FFTW) + if (args(0).is_string ()) + { + std::string arg0 = args(0).string_value (); + + if (!error_state) + { + // Use STL function to convert to lower case + std::transform (arg0.begin (), arg0.end (), arg0.begin (), tolower); + + if (nargin == 2) + { + std::string arg1 = args(1).string_value (); + if (!error_state) + { + if (arg0 == "planner") + { + std::transform (arg1.begin (), arg1.end (), + arg1.begin (), tolower); + octave_fftw_planner::FftwMethod meth + = octave_fftw_planner::UNKNOWN; + octave_float_fftw_planner::FftwMethod methf + = octave_float_fftw_planner::UNKNOWN; + + if (arg1 == "estimate") + { + meth = octave_fftw_planner::ESTIMATE; + methf = octave_float_fftw_planner::ESTIMATE; + } + else if (arg1 == "measure") + { + meth = octave_fftw_planner::MEASURE; + methf = octave_float_fftw_planner::MEASURE; + } + else if (arg1 == "patient") + { + meth = octave_fftw_planner::PATIENT; + methf = octave_float_fftw_planner::PATIENT; + } + else if (arg1 == "exhaustive") + { + meth = octave_fftw_planner::EXHAUSTIVE; + methf = octave_float_fftw_planner::EXHAUSTIVE; + } + else if (arg1 == "hybrid") + { + meth = octave_fftw_planner::HYBRID; + methf = octave_float_fftw_planner::HYBRID; + } + else + error ("unrecognized planner METHOD"); + + if (!error_state) + { + meth = octave_fftw_planner::method (meth); + octave_float_fftw_planner::method (methf); + + if (meth == octave_fftw_planner::MEASURE) + retval = octave_value ("measure"); + else if (meth == octave_fftw_planner::PATIENT) + retval = octave_value ("patient"); + else if (meth == octave_fftw_planner::EXHAUSTIVE) + retval = octave_value ("exhaustive"); + else if (meth == octave_fftw_planner::HYBRID) + retval = octave_value ("hybrid"); + else + retval = octave_value ("estimate"); + } + } + else if (arg0 == "dwisdom") + { + char *str = fftw_export_wisdom_to_string (); + + if (arg1.length () < 1) + fftw_forget_wisdom (); + else if (! fftw_import_wisdom_from_string (arg1.c_str ())) + error ("could not import supplied WISDOM"); + + if (!error_state) + retval = octave_value (std::string (str)); + + free (str); + } + else if (arg0 == "swisdom") + { + char *str = fftwf_export_wisdom_to_string (); + + if (arg1.length () < 1) + fftwf_forget_wisdom (); + else if (! fftwf_import_wisdom_from_string (arg1.c_str ())) + error ("could not import supplied WISDOM"); + + if (!error_state) + retval = octave_value (std::string (str)); + + free (str); + } + else + error ("unrecognized argument"); + } + } + else + { + if (arg0 == "planner") + { + octave_fftw_planner::FftwMethod meth = + octave_fftw_planner::method (); + + if (meth == octave_fftw_planner::MEASURE) + retval = octave_value ("measure"); + else if (meth == octave_fftw_planner::PATIENT) + retval = octave_value ("patient"); + else if (meth == octave_fftw_planner::EXHAUSTIVE) + retval = octave_value ("exhaustive"); + else if (meth == octave_fftw_planner::HYBRID) + retval = octave_value ("hybrid"); + else + retval = octave_value ("estimate"); + } + else if (arg0 == "dwisdom") + { + char *str = fftw_export_wisdom_to_string (); + retval = octave_value (std::string (str)); + free (str); + } + else if (arg0 == "swisdom") + { + char *str = fftwf_export_wisdom_to_string (); + retval = octave_value (std::string (str)); + free (str); + } + else + error ("unrecognized argument"); + } + } + } +#else + + warning ("fftw: this copy of Octave was not configured to use the FFTW3 planner"); + +#endif + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/module-files Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,22 @@ +# FILE|CPPFLAGS|LDFLAGS|LIBRARIES +__delaunayn__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) +__dsearchn__.cc +__fltk_uigetfile__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) +__glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS) +__init_fltk__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) +__init_gnuplot__.cc +__magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) +__voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) +amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +ccolamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +chol.cc +colamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +convhulln.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) +dmperm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +eigs.cc|$(ARPACK_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(ARPACK_LDFLAGS) $(SPARSE_XLDFLAGS)|$(ARPACK_LIBS) $(SPARSE_XLIBS) $(LAPACK_LIBS) $(BLAS_LIBS) +fftw.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) +qr.cc|$(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(QRUPDATE_LDFLAGS) $(SPARSE_XLDFLAGS)|$(QRUPDATE_LIBS) $(SPARSE_XLIBS) +symbfact.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +symrcm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +tsearch.cc +urlwrite.cc|$(CURL_CPPFLAGS)|$(CURL_LDFLAGS)|$(CURL_LIBS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/oct-qhull.h Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,60 @@ +/* + +Copyright (C) 2012 John W. Eaton + +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/>. + +*/ + +#if !defined (octave_oct_qhull_h) +#define octave_oct_qhull_h 1 + +#include <cstdio> + +extern "C" { + +#if defined (HAVE_LIBQHULL_LIBQHULL_H) +# include <libqhull/libqhull.h> +# include <libqhull/qset.h> +# include <libqhull/geom.h> +# include <libqhull/poly.h> +# include <libqhull/io.h> +#elif defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H) +# if defined (HAVE_QHULL_LIBQHULL_H) +# include <qhull/libqhull.h> +# else +# include <qhull/qhull.h> +# endif +# include <qhull/qset.h> +# include <qhull/geom.h> +# include <qhull/poly.h> +# include <qhull/io.h> +#elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H) +# if defined (HAVE_LIBQHULL_H) +# include <libqhull.h> +# else +# include <qhull.h> +# endif +# include <qset.h> +# include <geom.h> +# include <poly.h> +# include <io.h> +#endif + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/qr.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,1598 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton +Copyright (C) 2008-2009 Jaroslav Hajek +Copyright (C) 2008-2009 VZLU Prague + +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> +#endif + +#include "CmplxQR.h" +#include "CmplxQRP.h" +#include "dbleQR.h" +#include "dbleQRP.h" +#include "fCmplxQR.h" +#include "fCmplxQRP.h" +#include "floatQR.h" +#include "floatQRP.h" +#include "SparseQR.h" +#include "SparseCmplxQR.h" + + +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +template <class MT> +static octave_value +get_qr_r (const base_qr<MT>& fact) +{ + MT R = fact.R (); + if (R.is_square () && fact.regular ()) + return octave_value (R, MatrixType (MatrixType::Upper)); + else + return R; +} + +// [Q, R] = qr (X): form Q unitary and R upper triangular such +// that Q * R = X +// +// [Q, R] = qr (X, 0): form the economy decomposition such that if X is +// m by n then only the first n columns of Q are +// computed. +// +// [Q, R, P] = qr (X): form QRP factorization of X where +// P is a permutation matrix such that +// A * P = Q * R +// +// [Q, R, P] = qr (X, 0): form the economy decomposition with +// permutation vector P such that Q * R = X (:, P) +// +// qr (X) alone returns the output of the LAPACK routine dgeqrf, such +// that R = triu (qr (X)) + +DEFUN_DLD (qr, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})\n\ +@deftypefnx {Loadable Function} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A}, '0')\n\ +@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B})\n\ +@deftypefnx {Loadable Function} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B}, '0')\n\ +@cindex QR factorization\n\ +Compute the QR@tie{}factorization of @var{A}, using standard @sc{lapack}\n\ +subroutines. For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},\n\ +\n\ +@example\n\ +[@var{Q}, @var{R}] = qr (@var{A})\n\ +@end example\n\ +\n\ +@noindent\n\ +returns\n\ +\n\ +@example\n\ +@group\n\ +@var{Q} =\n\ +\n\ + -0.31623 -0.94868\n\ + -0.94868 0.31623\n\ +\n\ +@var{R} =\n\ +\n\ + -3.16228 -4.42719\n\ + 0.00000 -0.63246\n\ +@end group\n\ +@end example\n\ +\n\ +The @code{qr} factorization has applications in the solution of least\n\ +squares problems\n\ +@tex\n\ +$$\n\ +\\min_x \\left\\Vert A x - b \\right\\Vert_2\n\ +$$\n\ +@end tex\n\ +@ifnottex\n\ +\n\ +@example\n\ +min norm(A x - b)\n\ +@end example\n\ +\n\ +@end ifnottex\n\ +for overdetermined systems of equations (i.e.,\n\ +@tex\n\ +$A$\n\ +@end tex\n\ +@ifnottex\n\ +@var{A}\n\ +@end ifnottex\n\ + is a tall, thin matrix). The QR@tie{}factorization is\n\ +@tex\n\ +$QR = A$ where $Q$ is an orthogonal matrix and $R$ is upper triangular.\n\ +@end tex\n\ +@ifnottex\n\ +@code{@var{Q} * @var{Q} = @var{A}} where @var{Q} is an orthogonal matrix and\n\ +@var{R} is upper triangular.\n\ +@end ifnottex\n\ +\n\ +If given a second argument of '0', @code{qr} returns an economy-sized\n\ +QR@tie{}factorization, omitting zero rows of @var{R} and the corresponding\n\ +columns of @var{Q}.\n\ +\n\ +If the matrix @var{A} is full, the permuted QR@tie{}factorization\n\ +@code{[@var{Q}, @var{R}, @var{P}] = qr (@var{A})} forms the\n\ +QR@tie{}factorization such that the diagonal entries of @var{R} are\n\ +decreasing in magnitude order. For example, given the matrix @code{a = [1,\n\ +2; 3, 4]},\n\ +\n\ +@example\n\ +[@var{Q}, @var{R}, @var{P}] = qr (@var{A})\n\ +@end example\n\ +\n\ +@noindent\n\ +returns\n\ +\n\ +@example\n\ +@group\n\ +@var{Q} =\n\ +\n\ + -0.44721 -0.89443\n\ + -0.89443 0.44721\n\ +\n\ +@var{R} =\n\ +\n\ + -4.47214 -3.13050\n\ + 0.00000 0.44721\n\ +\n\ +@var{P} =\n\ +\n\ + 0 1\n\ + 1 0\n\ +@end group\n\ +@end example\n\ +\n\ +The permuted @code{qr} factorization @code{[@var{Q}, @var{R}, @var{P}] = qr\n\ +(@var{A})} factorization allows the construction of an orthogonal basis of\n\ +@code{span (A)}.\n\ +\n\ +If the matrix @var{A} is sparse, then compute the sparse\n\ +QR@tie{}factorization of @var{A}, using @sc{CSparse}. As the matrix @var{Q}\n\ +is in general a full matrix, this function returns the @var{Q}-less\n\ +factorization @var{R} of @var{A}, such that @code{@var{R} = chol (@var{A}' *\n\ +@var{A})}.\n\ +\n\ +If the final argument is the scalar @code{0} and the number of rows is\n\ +larger than the number of columns, then an economy factorization is\n\ +returned. That is @var{R} will have only @code{size (@var{A},1)} rows.\n\ +\n\ +If an additional matrix @var{B} is supplied, then @code{qr} returns\n\ +@var{C}, where @code{@var{C} = @var{Q}' * @var{B}}. This allows the\n\ +least squares approximation of @code{@var{A} \\ @var{B}} to be calculated\n\ +as\n\ +\n\ +@example\n\ +@group\n\ +[@var{C}, @var{R}] = qr (@var{A}, @var{B})\n\ +x = @var{R} \\ @var{C}\n\ +@end group\n\ +@end example\n\ +@end deftypefn") +{ + octave_value_list retval; + + int nargin = args.length (); + + if (nargin < 1 || nargin > (args(0).is_sparse_type () ? 3 : 2)) + { + print_usage (); + return retval; + } + + octave_value arg = args(0); + + int arg_is_empty = empty_arg ("qr", arg.rows (), arg.columns ()); + + if (arg_is_empty < 0) + return retval; + + if (arg.is_sparse_type ()) + { + bool economy = false; + bool is_cmplx = false; + int have_b = 0; + + if (arg.is_complex_type ()) + is_cmplx = true; + if (nargin > 1) + { + have_b = 1; + if (args(nargin-1).is_scalar_type ()) + { + int val = args(nargin-1).int_value (); + if (val == 0) + { + economy = true; + have_b = (nargin > 2 ? 2 : 0); + } + } + if (have_b > 0 && args(have_b).is_complex_type ()) + is_cmplx = true; + } + + if (!error_state) + { + if (have_b && nargout < 2) + error ("qr: incorrect number of output arguments"); + else if (is_cmplx) + { + SparseComplexQR q (arg.sparse_complex_matrix_value ()); + if (!error_state) + { + if (have_b > 0) + { + retval(1) = q.R (economy); + retval(0) = q.C (args(have_b).complex_matrix_value ()); + if (arg.rows () < arg.columns ()) + warning ("qr: non minimum norm solution for under-determined problem"); + } + else if (nargout > 1) + { + retval(1) = q.R (economy); + retval(0) = q.Q (); + } + else + retval(0) = q.R (economy); + } + } + else + { + SparseQR q (arg.sparse_matrix_value ()); + if (!error_state) + { + if (have_b > 0) + { + retval(1) = q.R (economy); + retval(0) = q.C (args(have_b).matrix_value ()); + if (args(0).rows () < args(0).columns ()) + warning ("qr: non minimum norm solution for under-determined problem"); + } + else if (nargout > 1) + { + retval(1) = q.R (economy); + retval(0) = q.Q (); + } + else + retval(0) = q.R (economy); + } + } + } + } + else + { + QR::type type = (nargout == 0 || nargout == 1) ? QR::raw + : (nargin == 2 ? QR::economy : QR::std); + + if (arg.is_single_type ()) + { + if (arg.is_real_type ()) + { + FloatMatrix m = arg.float_matrix_value (); + + if (! error_state) + { + switch (nargout) + { + case 0: + case 1: + { + FloatQR fact (m, type); + retval(0) = fact.R (); + } + break; + + case 2: + { + FloatQR fact (m, type); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + + default: + { + FloatQRP fact (m, type); + if (type == QR::economy) + retval(2) = fact.Pvec (); + else + retval(2) = fact.P (); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + } + } + } + else if (arg.is_complex_type ()) + { + FloatComplexMatrix m = arg.float_complex_matrix_value (); + + if (! error_state) + { + switch (nargout) + { + case 0: + case 1: + { + FloatComplexQR fact (m, type); + retval(0) = fact.R (); + } + break; + + case 2: + { + FloatComplexQR fact (m, type); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + + default: + { + FloatComplexQRP fact (m, type); + if (type == QR::economy) + retval(2) = fact.Pvec (); + else + retval(2) = fact.P (); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + } + } + } + } + else + { + if (arg.is_real_type ()) + { + Matrix m = arg.matrix_value (); + + if (! error_state) + { + switch (nargout) + { + case 0: + case 1: + { + QR fact (m, type); + retval(0) = fact.R (); + } + break; + + case 2: + { + QR fact (m, type); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + + default: + { + QRP fact (m, type); + if (type == QR::economy) + retval(2) = fact.Pvec (); + else + retval(2) = fact.P (); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + } + } + } + else if (arg.is_complex_type ()) + { + ComplexMatrix m = arg.complex_matrix_value (); + + if (! error_state) + { + switch (nargout) + { + case 0: + case 1: + { + ComplexQR fact (m, type); + retval(0) = fact.R (); + } + break; + + case 2: + { + ComplexQR fact (m, type); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + + default: + { + ComplexQRP fact (m, type); + if (type == QR::economy) + retval(2) = fact.Pvec (); + else + retval(2) = fact.P (); + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + break; + } + } + } + else + gripe_wrong_type_arg ("qr", arg); + } + } + + return retval; +} + +/* +%!test +%! a = [0, 2, 1; 2, 1, 2]; +%! +%! [q, r] = qr (a); +%! [qe, re] = qr (a, 0); +%! +%! assert (q * r, a, sqrt (eps)); +%! assert (qe * re, a, sqrt (eps)); + +%!test +%! a = [0, 2, 1; 2, 1, 2]; +%! +%! [q, r, p] = qr (a); # FIXME: not giving right dimensions. +%! [qe, re, pe] = qr (a, 0); +%! +%! assert (q * r, a * p, sqrt (eps)); +%! assert (qe * re, a(:, pe), sqrt (eps)); + +%!test +%! a = [0, 2; 2, 1; 1, 2]; +%! +%! [q, r] = qr (a); +%! [qe, re] = qr (a, 0); +%! +%! assert (q * r, a, sqrt (eps)); +%! assert (qe * re, a, sqrt (eps)); + +%!test +%! a = [0, 2; 2, 1; 1, 2]; +%! +%! [q, r, p] = qr (a); +%! [qe, re, pe] = qr (a, 0); +%! +%! assert (q * r, a * p, sqrt (eps)); +%! assert (qe * re, a(:, pe), sqrt (eps)); + +%!error qr () +%!error qr ([1, 2; 3, 4], 0, 2) + +%!function retval = __testqr (q, r, a, p) +%! tol = 100*eps (class (q)); +%! retval = 0; +%! if (nargin == 3) +%! n1 = norm (q*r - a); +%! n2 = norm (q'*q - eye (columns (q))); +%! retval = (n1 < tol && n2 < tol); +%! else +%! n1 = norm (q'*q - eye (columns (q))); +%! retval = (n1 < tol); +%! if (isvector (p)) +%! n2 = norm (q*r - a(:,p)); +%! retval = (retval && n2 < tol); +%! else +%! n2 = norm (q*r - a*p); +%! retval = (retval && n2 < tol); +%! endif +%! endif +%!endfunction + +%!test +%! t = ones (24, 1); +%! j = 1; +%! +%! if (false) # eliminate big matrix tests +%! a = rand (5000, 20); +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps; +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! endif +%! +%! a = [ ones(1,15); sqrt(eps)*eye(15) ]; +%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps; +%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); +%! +%! a = [ ones(1,15); sqrt(eps)*eye(15) ]; +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps; +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! +%! a = [ 611 196 -192 407 -8 -52 -49 29 +%! 196 899 113 -192 -71 -43 -8 -44 +%! -192 113 899 196 61 49 8 52 +%! 407 -192 196 611 8 44 59 -23 +%! -8 -71 61 8 411 -599 208 208 +%! -52 -43 49 44 -599 411 208 208 +%! -49 -8 8 59 208 208 99 -911 +%! 29 -44 52 -23 208 208 -911 99 ]; +%! [q,r] = qr (a); +%! +%! assert (all (t) && norm (q*r - a) < 5000*eps); + +%!test +%! a = single ([0, 2, 1; 2, 1, 2]); +%! +%! [q, r] = qr (a); +%! [qe, re] = qr (a, 0); +%! +%! assert (q * r, a, sqrt (eps ("single"))); +%! assert (qe * re, a, sqrt (eps ("single"))); + +%!test +%! a = single ([0, 2, 1; 2, 1, 2]); +%! +%! [q, r, p] = qr (a); # FIXME: not giving right dimensions. +%! [qe, re, pe] = qr (a, 0); +%! +%! assert (q * r, a * p, sqrt (eps ("single"))); +%! assert (qe * re, a(:, pe), sqrt (eps ("single"))); + +%!test +%! a = single ([0, 2; 2, 1; 1, 2]); +%! +%! [q, r] = qr (a); +%! [qe, re] = qr (a, 0); +%! +%! assert (q * r, a, sqrt (eps ("single"))); +%! assert (qe * re, a, sqrt (eps ("single"))); + +%!test +%! a = single ([0, 2; 2, 1; 1, 2]); +%! +%! [q, r, p] = qr (a); +%! [qe, re, pe] = qr (a, 0); +%! +%! assert (q * r, a * p, sqrt (eps ("single"))); +%! assert (qe * re, a(:, pe), sqrt (eps ("single"))); + +%!error qr () +%!error qr ([1, 2; 3, 4], 0, 2) + +%!test +%! t = ones (24, 1); +%! j = 1; +%! +%! if (false) # eliminate big matrix tests +%! a = rand (5000,20); +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps ("single"); +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! endif +%! +%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ]; +%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps ("single"); +%! [q,r] = qr (a); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a'); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a'); t(j++) = __testqr (q, r, a', p); +%! +%! a = [ ones(1,15); sqrt(eps("single"))*eye(15) ]; +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a', p); +%! +%! a = a+1i*eps ("single"); +%! [q,r] = qr (a, 0); t(j++) = __testqr (q, r, a); +%! [q,r] = qr (a',0); t(j++) = __testqr (q, r, a'); +%! [q,r,p] = qr (a, 0); t(j++) = __testqr (q, r, a, p); +%! [q,r,p] = qr (a',0); t(j++) = __testqr (q, r, a',p); +%! +%! a = [ 611 196 -192 407 -8 -52 -49 29 +%! 196 899 113 -192 -71 -43 -8 -44 +%! -192 113 899 196 61 49 8 52 +%! 407 -192 196 611 8 44 59 -23 +%! -8 -71 61 8 411 -599 208 208 +%! -52 -43 49 44 -599 411 208 208 +%! -49 -8 8 59 208 208 99 -911 +%! 29 -44 52 -23 208 208 -911 99 ]; +%! [q,r] = qr (a); +%! +%! assert (all (t) && norm (q*r-a) < 5000*eps ("single")); + +## The deactivated tests below can't be tested till rectangular back-subs is +## implemented for sparse matrices. + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = sprandn (n,n,d) + speye (n,n); +%! r = qr (a); +%! assert (r'*r, a'*a, 1e-10) + +%!testif HAVE_COLAMD +%! n = 20; d = 0.2; +%! a = sprandn (n,n,d) + speye (n,n); +%! q = symamd (a); +%! a = a(q,q); +%! r = qr (a); +%! assert (r'*r, a'*a, 1e-10) + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = sprandn (n,n,d) + speye (n,n); +%! [c,r] = qr (a, ones (n,1)); +%! assert (r\c, full (a)\ones (n,1), 10e-10) + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = sprandn (n,n,d) + speye (n,n); +%! b = randn (n,2); +%! [c,r] = qr (a, b); +%! assert (r\c, full (a)\b, 10e-10) + +%% Test under-determined systems!! +%!#testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = sprandn (n,n+1,d) + speye (n,n+1); +%! b = randn (n,2); +%! [c,r] = qr (a, b); +%! assert (r\c, full (a)\b, 10e-10) + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = 1i*sprandn (n,n,d) + speye (n,n); +%! r = qr (a); +%! assert (r'*r,a'*a,1e-10) + +%!testif HAVE_COLAMD +%! n = 20; d = 0.2; +%! a = 1i*sprandn (n,n,d) + speye (n,n); +%! q = symamd (a); +%! a = a(q,q); +%! r = qr (a); +%! assert (r'*r, a'*a, 1e-10) + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = 1i*sprandn (n,n,d) + speye (n,n); +%! [c,r] = qr (a, ones (n,1)); +%! assert (r\c, full (a)\ones (n,1), 10e-10) + +%!testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = 1i*sprandn (n,n,d) + speye (n,n); +%! b = randn (n,2); +%! [c,r] = qr (a, b); +%! assert (r\c, full (a)\b, 10e-10) + +%% Test under-determined systems!! +%!#testif HAVE_CXSPARSE +%! n = 20; d = 0.2; +%! a = 1i*sprandn (n,n+1,d) + speye (n,n+1); +%! b = randn (n,2); +%! [c,r] = qr (a, b); +%! assert (r\c, full (a)\b, 10e-10) + +%!error qr (sprandn (10,10,0.2), ones (10,1)) +*/ + +static +bool check_qr_dims (const octave_value& q, const octave_value& r, + bool allow_ecf = false) +{ + octave_idx_type m = q.rows (), k = r.rows (), n = r.columns (); + return ((q.ndims () == 2 && r.ndims () == 2 && k == q.columns ()) + && (m == k || (allow_ecf && k == n && k < m))); +} + +static +bool check_index (const octave_value& i, bool vector_allowed = false) +{ + return ((i.is_real_type () || i.is_integer_type ()) + && (i.is_scalar_type () || vector_allowed)); +} + +DEFUN_DLD (qrupdate, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrupdate (@var{Q}, @var{R}, @var{u}, @var{v})\n\ +Given a QR@tie{}factorization of a real or complex matrix\n\ +@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ +@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization\n\ +of @w{@var{A} + @var{u}*@var{v}'}, where @var{u} and @var{v} are\n\ +column vectors (rank-1 update) or matrices with equal number of columns\n\ +(rank-k update). Notice that the latter case is done as a sequence of rank-1\n\ +updates; thus, for k large enough, it will be both faster and more accurate\n\ +to recompute the factorization from scratch.\n\ +\n\ +The QR@tie{}factorization supplied may be either full\n\ +(Q is square) or economized (R is square).\n\ +\n\ +@seealso{qr, qrinsert, qrdelete}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + octave_value_list retval; + + if (nargin != 4) + { + print_usage (); + return retval; + } + + octave_value argq = args(0); + octave_value argr = args(1); + octave_value argu = args(2); + octave_value argv = args(3); + + if (argq.is_numeric_type () && argr.is_numeric_type () + && argu.is_numeric_type () && argv.is_numeric_type ()) + { + if (check_qr_dims (argq, argr, true)) + { + if (argq.is_real_type () + && argr.is_real_type () + && argu.is_real_type () + && argv.is_real_type ()) + { + // all real case + if (argq.is_single_type () + || argr.is_single_type () + || argu.is_single_type () + || argv.is_single_type ()) + { + FloatMatrix Q = argq.float_matrix_value (); + FloatMatrix R = argr.float_matrix_value (); + FloatMatrix u = argu.float_matrix_value (); + FloatMatrix v = argv.float_matrix_value (); + + FloatQR fact (Q, R); + fact.update (u, v); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + Matrix Q = argq.matrix_value (); + Matrix R = argr.matrix_value (); + Matrix u = argu.matrix_value (); + Matrix v = argv.matrix_value (); + + QR fact (Q, R); + fact.update (u, v); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + else + { + // complex case + if (argq.is_single_type () + || argr.is_single_type () + || argu.is_single_type () + || argv.is_single_type ()) + { + FloatComplexMatrix Q = argq.float_complex_matrix_value (); + FloatComplexMatrix R = argr.float_complex_matrix_value (); + FloatComplexMatrix u = argu.float_complex_matrix_value (); + FloatComplexMatrix v = argv.float_complex_matrix_value (); + + FloatComplexQR fact (Q, R); + fact.update (u, v); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + ComplexMatrix Q = argq.complex_matrix_value (); + ComplexMatrix R = argr.complex_matrix_value (); + ComplexMatrix u = argu.complex_matrix_value (); + ComplexMatrix v = argv.complex_matrix_value (); + + ComplexQR fact (Q, R); + fact.update (u, v); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + } + else + error ("qrupdate: Q and R dimensions don't match"); + } + else + error ("qrupdate: Q, R, U, and V must be numeric"); + + return retval; +} + +/* +%!shared A, u, v, Ac, uc, vc +%! A = [0.091364 0.613038 0.999083; +%! 0.594638 0.425302 0.603537; +%! 0.383594 0.291238 0.085574; +%! 0.265712 0.268003 0.238409; +%! 0.669966 0.743851 0.445057 ]; +%! +%! u = [0.85082; +%! 0.76426; +%! 0.42883; +%! 0.53010; +%! 0.80683 ]; +%! +%! v = [0.98810; +%! 0.24295; +%! 0.43167 ]; +%! +%! Ac = [0.620405 + 0.956953i 0.480013 + 0.048806i 0.402627 + 0.338171i; +%! 0.589077 + 0.658457i 0.013205 + 0.279323i 0.229284 + 0.721929i; +%! 0.092758 + 0.345687i 0.928679 + 0.241052i 0.764536 + 0.832406i; +%! 0.912098 + 0.721024i 0.049018 + 0.269452i 0.730029 + 0.796517i; +%! 0.112849 + 0.603871i 0.486352 + 0.142337i 0.355646 + 0.151496i ]; +%! +%! uc = [0.20351 + 0.05401i; +%! 0.13141 + 0.43708i; +%! 0.29808 + 0.08789i; +%! 0.69821 + 0.38844i; +%! 0.74871 + 0.25821i ]; +%! +%! vc = [0.85839 + 0.29468i; +%! 0.20820 + 0.93090i; +%! 0.86184 + 0.34689i ]; +%! + +%!test +%! [Q,R] = qr (A); +%! [Q,R] = qrupdate (Q, R, u, v); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R)-R), Inf) == 0); +%! assert (norm (vec (Q*R - A - u*v'), Inf) < norm (A)*1e1*eps); +%! +%!test +%! [Q,R] = qr (Ac); +%! [Q,R] = qrupdate (Q, R, uc, vc); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R)-R), Inf) == 0); +%! assert (norm (vec (Q*R - Ac - uc*vc'), Inf) < norm (Ac)*1e1*eps); + +%!test +%! [Q,R] = qr (single (A)); +%! [Q,R] = qrupdate (Q, R, single (u), single (v)); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R)-R), Inf) == 0); +%! assert (norm (vec (Q*R - single (A) - single (u)*single (v)'), Inf) < norm (single (A))*1e1*eps ("single")); +%! +%!test +%! [Q,R] = qr (single (Ac)); +%! [Q,R] = qrupdate (Q, R, single (uc), single (vc)); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R)-R), Inf) == 0); +%! assert (norm (vec (Q*R - single (Ac) - single (uc)*single (vc)'), Inf) < norm (single (Ac))*1e1*eps ("single")); +*/ + +DEFUN_DLD (qrinsert, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrinsert (@var{Q}, @var{R}, @var{j}, @var{x}, @var{orient})\n\ +Given a QR@tie{}factorization of a real or complex matrix\n\ +@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ +@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of\n\ +@w{[A(:,1:j-1) x A(:,j:n)]}, where @var{u} is a column vector to be\n\ +inserted into @var{A} (if @var{orient} is @code{\"col\"}), or the\n\ +QR@tie{}factorization of @w{[A(1:j-1,:);x;A(:,j:n)]}, where @var{x}\n\ +is a row vector to be inserted into @var{A} (if @var{orient} is\n\ +@code{\"row\"}).\n\ +\n\ +The default value of @var{orient} is @code{\"col\"}.\n\ +If @var{orient} is @code{\"col\"},\n\ +@var{u} may be a matrix and @var{j} an index vector\n\ +resulting in the QR@tie{}factorization of a matrix @var{B} such that\n\ +@w{B(:,@var{j})} gives @var{u} and @w{B(:,@var{j}) = []} gives @var{A}.\n\ +Notice that the latter case is done as a sequence of k insertions;\n\ +thus, for k large enough, it will be both faster and more accurate to\n\ +recompute the factorization from scratch.\n\ +\n\ +If @var{orient} is @code{\"col\"},\n\ +the QR@tie{}factorization supplied may be either full\n\ +(Q is square) or economized (R is square).\n\ +\n\ +If @var{orient} is @code{\"row\"}, full factorization is needed.\n\ +@seealso{qr, qrupdate, qrdelete}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + octave_value_list retval; + + if (nargin < 4 || nargin > 5) + { + print_usage (); + return retval; + } + + octave_value argq = args(0); + octave_value argr = args(1); + octave_value argj = args(2); + octave_value argx = args(3); + + if (argq.is_numeric_type () && argr.is_numeric_type () + && argx.is_numeric_type () + && (nargin < 5 || args(4).is_string ())) + { + std::string orient = (nargin < 5) ? "col" : args(4).string_value (); + + bool col = orient == "col"; + + if (col || orient == "row") + if (check_qr_dims (argq, argr, col) + && (col || argx.rows () == 1)) + { + if (check_index (argj, col)) + { + MArray<octave_idx_type> j + = argj.octave_idx_type_vector_value (); + + octave_idx_type one = 1; + + if (argq.is_real_type () + && argr.is_real_type () + && argx.is_real_type ()) + { + // real case + if (argq.is_single_type () + || argr.is_single_type () + || argx.is_single_type ()) + { + FloatMatrix Q = argq.float_matrix_value (); + FloatMatrix R = argr.float_matrix_value (); + FloatMatrix x = argx.float_matrix_value (); + + FloatQR fact (Q, R); + + if (col) + fact.insert_col (x, j-one); + else + fact.insert_row (x.row (0), j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + + } + else + { + Matrix Q = argq.matrix_value (); + Matrix R = argr.matrix_value (); + Matrix x = argx.matrix_value (); + + QR fact (Q, R); + + if (col) + fact.insert_col (x, j-one); + else + fact.insert_row (x.row (0), j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + + } + } + else + { + // complex case + if (argq.is_single_type () + || argr.is_single_type () + || argx.is_single_type ()) + { + FloatComplexMatrix Q = argq.float_complex_matrix_value (); + FloatComplexMatrix R = argr.float_complex_matrix_value (); + FloatComplexMatrix x = argx.float_complex_matrix_value (); + + FloatComplexQR fact (Q, R); + + if (col) + fact.insert_col (x, j-one); + else + fact.insert_row (x.row (0), j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + ComplexMatrix Q = argq.complex_matrix_value (); + ComplexMatrix R = argr.complex_matrix_value (); + ComplexMatrix x = argx.complex_matrix_value (); + + ComplexQR fact (Q, R); + + if (col) + fact.insert_col (x, j-one); + else + fact.insert_row (x.row (0), j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + + } + else + error ("qrinsert: invalid index J"); + } + else + error ("qrinsert: dimension mismatch"); + + else + error ("qrinsert: ORIENT must be \"col\" or \"row\""); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! [Q,R] = qr (A); +%! [Q,R] = qrinsert (Q, R, 3, u); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [A(:,1:2) u A(:,3)]), Inf) < norm (A)*1e1*eps); +%!test +%! [Q,R] = qr (Ac); +%! [Q,R] = qrinsert (Q, R, 3, uc); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [Ac(:,1:2) uc Ac(:,3)]), Inf) < norm (Ac)*1e1*eps); +%!test +%! x = [0.85082 0.76426 0.42883 ]; +%! +%! [Q,R] = qr (A); +%! [Q,R] = qrinsert (Q, R, 3, x, "row"); +%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [A(1:2,:);x;A(3:5,:)]), Inf) < norm (A)*1e1*eps); +%!test +%! x = [0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ]; +%! +%! [Q,R] = qr (Ac); +%! [Q,R] = qrinsert (Q, R, 3, x, "row"); +%! assert (norm (vec (Q'*Q - eye (6)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [Ac(1:2,:);x;Ac(3:5,:)]), Inf) < norm (Ac)*1e1*eps); + +%!test +%! [Q,R] = qr (single (A)); +%! [Q,R] = qrinsert (Q, R, 3, single (u)); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - single ([A(:,1:2) u A(:,3)])), Inf) < norm (single (A))*1e1*eps ("single")); +%!test +%! [Q,R] = qr (single (Ac)); +%! [Q,R] = qrinsert (Q, R, 3, single (uc)); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - single ([Ac(:,1:2) uc Ac(:,3)])), Inf) < norm (single (Ac))*1e1*eps ("single")); +%!test +%! x = single ([0.85082 0.76426 0.42883 ]); +%! +%! [Q,R] = qr (single (A)); +%! [Q,R] = qrinsert (Q, R, 3, x, "row"); +%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - single ([A(1:2,:);x;A(3:5,:)])), Inf) < norm (single (A))*1e1*eps ("single")); +%!test +%! x = single ([0.20351 + 0.05401i 0.13141 + 0.43708i 0.29808 + 0.08789i ]); +%! +%! [Q,R] = qr (single (Ac)); +%! [Q,R] = qrinsert (Q, R, 3, x, "row"); +%! assert (norm (vec (Q'*Q - eye (6,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - single ([Ac(1:2,:);x;Ac(3:5,:)])), Inf) < norm (single (Ac))*1e1*eps ("single")); +*/ + +DEFUN_DLD (qrdelete, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrdelete (@var{Q}, @var{R}, @var{j}, @var{orient})\n\ +Given a QR@tie{}factorization of a real or complex matrix\n\ +@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ +@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of\n\ +@w{[A(:,1:j-1) A(:,j+1:n)]}, i.e., @var{A} with one column deleted\n\ +(if @var{orient} is \"col\"), or the QR@tie{}factorization of\n\ +@w{[A(1:j-1,:);A(j+1:n,:)]}, i.e., @var{A} with one row deleted (if\n\ +@var{orient} is \"row\").\n\ +\n\ +The default value of @var{orient} is \"col\".\n\ +\n\ +If @var{orient} is @code{\"col\"},\n\ +@var{j} may be an index vector\n\ +resulting in the QR@tie{}factorization of a matrix @var{B} such that\n\ +@w{A(:,@var{j}) = []} gives @var{B}.\n\ +Notice that the latter case is done as a sequence of k deletions;\n\ +thus, for k large enough, it will be both faster and more accurate to\n\ +recompute the factorization from scratch.\n\ +\n\ +If @var{orient} is @code{\"col\"},\n\ +the QR@tie{}factorization supplied may be either full\n\ +(Q is square) or economized (R is square).\n\ +\n\ +If @var{orient} is @code{\"row\"}, full factorization is needed.\n\ +@seealso{qr, qrinsert, qrupdate}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + octave_value_list retval; + + if (nargin < 3 || nargin > 4) + { + print_usage (); + return retval; + } + + octave_value argq = args(0); + octave_value argr = args(1); + octave_value argj = args(2); + + if (argq.is_numeric_type () && argr.is_numeric_type () + && (nargin < 4 || args(3).is_string ())) + { + std::string orient = (nargin < 4) ? "col" : args(3).string_value (); + + bool col = orient == "col"; + + if (col || orient == "row") + if (check_qr_dims (argq, argr, col)) + { + if (check_index (argj, col)) + { + MArray<octave_idx_type> j + = argj.octave_idx_type_vector_value (); + + octave_idx_type one = 1; + + if (argq.is_real_type () + && argr.is_real_type ()) + { + // real case + if (argq.is_single_type () + || argr.is_single_type ()) + { + FloatMatrix Q = argq.float_matrix_value (); + FloatMatrix R = argr.float_matrix_value (); + + FloatQR fact (Q, R); + + if (col) + fact.delete_col (j-one); + else + fact.delete_row (j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + Matrix Q = argq.matrix_value (); + Matrix R = argr.matrix_value (); + + QR fact (Q, R); + + if (col) + fact.delete_col (j-one); + else + fact.delete_row (j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + else + { + // complex case + if (argq.is_single_type () + || argr.is_single_type ()) + { + FloatComplexMatrix Q = argq.float_complex_matrix_value (); + FloatComplexMatrix R = argr.float_complex_matrix_value (); + + FloatComplexQR fact (Q, R); + + if (col) + fact.delete_col (j-one); + else + fact.delete_row (j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + ComplexMatrix Q = argq.complex_matrix_value (); + ComplexMatrix R = argr.complex_matrix_value (); + + ComplexQR fact (Q, R); + + if (col) + fact.delete_col (j-one); + else + fact.delete_row (j(0)-one); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + } + else + error ("qrdelete: invalid index J"); + } + else + error ("qrdelete: dimension mismatch"); + + else + error ("qrdelete: ORIENT must be \"col\" or \"row\""); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! AA = [0.091364 0.613038 0.027504 0.999083; +%! 0.594638 0.425302 0.562834 0.603537; +%! 0.383594 0.291238 0.742073 0.085574; +%! 0.265712 0.268003 0.783553 0.238409; +%! 0.669966 0.743851 0.457255 0.445057 ]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps); +%! +%!test +%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; +%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; +%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; +%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; +%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3); +%! assert (norm (vec (Q'*Q - eye (5)), Inf) < 16*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps); +%! +%!test +%! AA = [0.091364 0.613038 0.027504 0.999083; +%! 0.594638 0.425302 0.562834 0.603537; +%! 0.383594 0.291238 0.742073 0.085574; +%! 0.265712 0.268003 0.783553 0.238409; +%! 0.669966 0.743851 0.457255 0.445057 ]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3, "row"); +%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps); +%! +%!test +%! AA = [0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; +%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; +%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; +%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; +%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ] * I; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3, "row"); +%! assert (norm (vec (Q'*Q - eye (4)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps); + +%!test +%! AA = single ([0.091364 0.613038 0.027504 0.999083; +%! 0.594638 0.425302 0.562834 0.603537; +%! 0.383594 0.291238 0.742073 0.085574; +%! 0.265712 0.268003 0.783553 0.238409; +%! 0.669966 0.743851 0.457255 0.445057 ]); +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single")); +%! +%!test +%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; +%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; +%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; +%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; +%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3); +%! assert (norm (vec (Q'*Q - eye (5,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(:,1:2) AA(:,4)]), Inf) < norm (AA)*1e1*eps ("single")); +%! +%!test +%! AA = single ([0.091364 0.613038 0.027504 0.999083; +%! 0.594638 0.425302 0.562834 0.603537; +%! 0.383594 0.291238 0.742073 0.085574; +%! 0.265712 0.268003 0.783553 0.238409; +%! 0.669966 0.743851 0.457255 0.445057 ]); +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3, "row"); +%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1.5e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); +%!testif HAVE_QRUPDATE +%! # Same test as above but with more precicision +%! AA = single ([0.091364 0.613038 0.027504 0.999083; +%! 0.594638 0.425302 0.562834 0.603537; +%! 0.383594 0.291238 0.742073 0.085574; +%! 0.265712 0.268003 0.783553 0.238409; +%! 0.669966 0.743851 0.457255 0.445057 ]); +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3, "row"); +%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); +%! +%!test +%! AA = single ([0.364554 + 0.993117i 0.669818 + 0.510234i 0.426568 + 0.041337i 0.847051 + 0.233291i; +%! 0.049600 + 0.242783i 0.448946 + 0.484022i 0.141155 + 0.074420i 0.446746 + 0.392706i; +%! 0.581922 + 0.657416i 0.581460 + 0.030016i 0.219909 + 0.447288i 0.201144 + 0.069132i; +%! 0.694986 + 0.000571i 0.682327 + 0.841712i 0.807537 + 0.166086i 0.192767 + 0.358098i; +%! 0.945002 + 0.066788i 0.350492 + 0.642638i 0.579629 + 0.048102i 0.600170 + 0.636938i ]) * I; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrdelete (Q, R, 3, "row"); +%! assert (norm (vec (Q'*Q - eye (4,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - [AA(1:2,:);AA(4:5,:)]), Inf) < norm (AA)*1e1*eps ("single")); +*/ + +DEFUN_DLD (qrshift, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{Q1}, @var{R1}] =} qrshift (@var{Q}, @var{R}, @var{i}, @var{j})\n\ +Given a QR@tie{}factorization of a real or complex matrix\n\ +@w{@var{A} = @var{Q}*@var{R}}, @var{Q}@tie{}unitary and\n\ +@var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization\n\ +of @w{@var{A}(:,p)}, where @w{p} is the permutation @*\n\ +@code{p = [1:i-1, shift(i:j, 1), j+1:n]} if @w{@var{i} < @var{j}} @*\n\ + or @*\n\ +@code{p = [1:j-1, shift(j:i,-1), i+1:n]} if @w{@var{j} < @var{i}}. @*\n\ +\n\ +@seealso{qr, qrinsert, qrdelete}\n\ +@end deftypefn") +{ + octave_idx_type nargin = args.length (); + octave_value_list retval; + + if (nargin != 4) + { + print_usage (); + return retval; + } + + octave_value argq = args(0); + octave_value argr = args(1); + octave_value argi = args(2); + octave_value argj = args(3); + + if (argq.is_numeric_type () && argr.is_numeric_type ()) + { + if (check_qr_dims (argq, argr, true)) + { + if (check_index (argi) && check_index (argj)) + { + octave_idx_type i = argi.int_value (); + octave_idx_type j = argj.int_value (); + + if (argq.is_real_type () + && argr.is_real_type ()) + { + // all real case + if (argq.is_single_type () + && argr.is_single_type ()) + { + FloatMatrix Q = argq.float_matrix_value (); + FloatMatrix R = argr.float_matrix_value (); + + FloatQR fact (Q, R); + fact.shift_cols (i-1, j-1); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + Matrix Q = argq.matrix_value (); + Matrix R = argr.matrix_value (); + + QR fact (Q, R); + fact.shift_cols (i-1, j-1); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + else + { + // complex case + if (argq.is_single_type () + && argr.is_single_type ()) + { + FloatComplexMatrix Q = argq.float_complex_matrix_value (); + FloatComplexMatrix R = argr.float_complex_matrix_value (); + + FloatComplexQR fact (Q, R); + fact.shift_cols (i-1, j-1); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + else + { + ComplexMatrix Q = argq.complex_matrix_value (); + ComplexMatrix R = argr.complex_matrix_value (); + + ComplexQR fact (Q, R); + fact.shift_cols (i-1, j-1); + + retval(1) = get_qr_r (fact); + retval(0) = fact.Q (); + } + } + } + else + error ("qrshift: invalid index I or J"); + } + else + error ("qrshift: dimensions mismatch"); + } + else + error ("qrshift: Q and R must be numeric"); + + return retval; +} + +/* +%!test +%! AA = A.'; +%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); +%! +%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); +%! +%!test +%! AA = Ac.'; +%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); +%! +%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3)), Inf) < 1e1*eps); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps); + +%!test +%! AA = single (A).'; +%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); +%! +%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); +%! +%!test +%! AA = single (Ac).'; +%! i = 2; j = 4; p = [1:i-1, shift(i:j,-1), j+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); +%! +%! j = 2; i = 4; p = [1:j-1, shift(j:i,+1), i+1:5]; +%! +%! [Q,R] = qr (AA); +%! [Q,R] = qrshift (Q, R, i, j); +%! assert (norm (vec (Q'*Q - eye (3,"single")), Inf) < 1e1*eps ("single")); +%! assert (norm (vec (triu (R) - R), Inf) == 0); +%! assert (norm (vec (Q*R - AA(:,p)), Inf) < norm (AA)*1e1*eps ("single")); +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/symbfact.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,363 @@ +/* + +Copyright (C) 2005-2012 David Bateman +Copyright (C) 1998-2005 Andy Adler + +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> +#endif + +#include "SparseCmplxCHOL.h" +#include "SparsedbleCHOL.h" +#include "oct-spparms.h" +#include "sparse-util.h" +#include "oct-locbuf.h" + +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +DEFUN_DLD (symbfact, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{count}, @var{h}, @var{parent}, @var{post}, @var{r}] =} symbfact (@var{S})\n\ +@deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ})\n\ +@deftypefnx {Loadable Function} {[@dots{}] =} symbfact (@var{S}, @var{typ}, @var{mode})\n\ +\n\ +Perform a symbolic factorization analysis on the sparse matrix @var{S}.\n\ +Where\n\ +\n\ +@table @var\n\ +@item S\n\ +@var{S} is a complex or real sparse matrix.\n\ +\n\ +@item typ\n\ +Is the type of the factorization and can be one of\n\ +\n\ +@table @samp\n\ +@item sym\n\ +Factorize @var{S}. This is the default.\n\ +\n\ +@item col\n\ +Factorize @code{@var{S}' * @var{S}}.\n\ +\n\ +@item row\n\ +Factorize @xcode{@var{S} * @var{S}'}.\n\ +\n\ +@item lo\n\ +Factorize @xcode{@var{S}'}\n\ +@end table\n\ +\n\ +@item mode\n\ +The default is to return the Cholesky@tie{}factorization for @var{r}, and if\n\ +@var{mode} is 'L', the conjugate transpose of the Cholesky@tie{}factorization\n\ +is returned. The conjugate transpose version is faster and uses less\n\ +memory, but returns the same values for @var{count}, @var{h}, @var{parent}\n\ +and @var{post} outputs.\n\ +@end table\n\ +\n\ +The output variables are\n\ +\n\ +@table @var\n\ +@item count\n\ +The row counts of the Cholesky@tie{}factorization as determined by @var{typ}.\n\ +\n\ +@item h\n\ +The height of the elimination tree.\n\ +\n\ +@item parent\n\ +The elimination tree itself.\n\ +\n\ +@item post\n\ +A sparse boolean matrix whose structure is that of the Cholesky\n\ +factorization as determined by @var{typ}.\n\ +@end table\n\ +@end deftypefn") +{ + octave_value_list retval; + int nargin = args.length (); + + if (nargin < 1 || nargin > 3 || nargout > 5) + { + print_usage (); + return retval; + } + +#ifdef HAVE_CHOLMOD + + cholmod_common Common; + cholmod_common *cm = &Common; + CHOLMOD_NAME(start) (cm); + + double spu = octave_sparse_params::get_key ("spumoni"); + if (spu == 0.) + { + cm->print = -1; + cm->print_function = 0; + } + else + { + cm->print = static_cast<int> (spu) + 2; + cm->print_function =&SparseCholPrint; + } + + cm->error_handler = &SparseCholError; + cm->complex_divide = CHOLMOD_NAME(divcomplex); + cm->hypotenuse = CHOLMOD_NAME(hypot); + + double dummy; + cholmod_sparse Astore; + cholmod_sparse *A = &Astore; + A->packed = true; + A->sorted = true; + A->nz = 0; +#ifdef IDX_TYPE_LONG + A->itype = CHOLMOD_LONG; +#else + A->itype = CHOLMOD_INT; +#endif + A->dtype = CHOLMOD_DOUBLE; + A->stype = 1; + A->x = &dummy; + + if (args(0).is_real_type ()) + { + const SparseMatrix a = args(0).sparse_matrix_value (); + A->nrow = a.rows (); + A->ncol = a.cols (); + A->p = a.cidx (); + A->i = a.ridx (); + A->nzmax = a.nnz (); + A->xtype = CHOLMOD_REAL; + + if (a.rows () > 0 && a.cols () > 0) + A->x = a.data (); + } + else if (args(0).is_complex_type ()) + { + const SparseComplexMatrix a = args(0).sparse_complex_matrix_value (); + A->nrow = a.rows (); + A->ncol = a.cols (); + A->p = a.cidx (); + A->i = a.ridx (); + A->nzmax = a.nnz (); + A->xtype = CHOLMOD_COMPLEX; + + if (a.rows () > 0 && a.cols () > 0) + A->x = a.data (); + } + else + gripe_wrong_type_arg ("symbfact", args(0)); + + octave_idx_type coletree = false; + octave_idx_type n = A->nrow; + + if (nargin > 1) + { + char ch; + std::string str = args(1).string_value (); + ch = tolower (str.c_str ()[0]); + if (ch == 'r') + A->stype = 0; + else if (ch == 'c') + { + n = A->ncol; + coletree = true; + A->stype = 0; + } + else if (ch == 's') + A->stype = 1; + else if (ch == 's') + A->stype = -1; + else + error ("symbfact: unrecognized TYP in symbolic factorization"); + } + + if (A->stype && A->nrow != A->ncol) + error ("symbfact: S must be a square matrix"); + + if (!error_state) + { + OCTAVE_LOCAL_BUFFER (octave_idx_type, Parent, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, Post, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, ColCount, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, First, n); + OCTAVE_LOCAL_BUFFER (octave_idx_type, Level, n); + + cholmod_sparse *F = CHOLMOD_NAME(transpose) (A, 0, cm); + cholmod_sparse *Aup, *Alo; + + if (A->stype == 1 || coletree) + { + Aup = A ; + Alo = F ; + } + else + { + Aup = F ; + Alo = A ; + } + + CHOLMOD_NAME(etree) (Aup, Parent, cm); + + if (cm->status < CHOLMOD_OK) + { + error ("matrix corrupted"); + goto symbfact_error; + } + + if (CHOLMOD_NAME(postorder) (Parent, n, 0, Post, cm) != n) + { + error ("postorder failed"); + goto symbfact_error; + } + + CHOLMOD_NAME(rowcolcounts) (Alo, 0, 0, Parent, Post, 0, + ColCount, First, Level, cm); + + if (cm->status < CHOLMOD_OK) + { + error ("matrix corrupted"); + goto symbfact_error; + } + + if (nargout > 4) + { + cholmod_sparse *A1, *A2; + + if (A->stype == 1) + { + A1 = A; + A2 = 0; + } + else if (A->stype == -1) + { + A1 = F; + A2 = 0; + } + else if (coletree) + { + A1 = F; + A2 = A; + } + else + { + A1 = A; + A2 = F; + } + + // count the total number of entries in L + octave_idx_type lnz = 0 ; + for (octave_idx_type j = 0 ; j < n ; j++) + lnz += ColCount[j]; + + + // allocate the output matrix L (pattern-only) + SparseBoolMatrix L (n, n, lnz); + + // initialize column pointers + lnz = 0; + for (octave_idx_type j = 0 ; j < n ; j++) + { + L.xcidx(j) = lnz; + lnz += ColCount[j]; + } + L.xcidx(n) = lnz; + + + /* create a copy of the column pointers */ + octave_idx_type *W = First; + for (octave_idx_type j = 0 ; j < n ; j++) + W[j] = L.xcidx (j); + + // get workspace for computing one row of L + cholmod_sparse *R = cholmod_allocate_sparse (n, 1, n, false, true, + 0, CHOLMOD_PATTERN, cm); + octave_idx_type *Rp = static_cast<octave_idx_type *>(R->p); + octave_idx_type *Ri = static_cast<octave_idx_type *>(R->i); + + // compute L one row at a time + for (octave_idx_type k = 0 ; k < n ; k++) + { + // get the kth row of L and store in the columns of L + CHOLMOD_NAME (row_subtree) (A1, A2, k, Parent, R, cm) ; + for (octave_idx_type p = 0 ; p < Rp[1] ; p++) + L.xridx (W[Ri[p]]++) = k ; + + // add the diagonal entry + L.xridx (W[k]++) = k ; + } + + // free workspace + cholmod_free_sparse (&R, cm) ; + + + // transpose L to get R, or leave as is + if (nargin < 3) + L = L.transpose (); + + // fill numerical values of L with one's + for (octave_idx_type p = 0 ; p < lnz ; p++) + L.xdata(p) = true; + + retval(4) = L; + } + + ColumnVector tmp (n); + if (nargout > 3) + { + for (octave_idx_type i = 0; i < n; i++) + tmp(i) = Post[i] + 1; + retval(3) = tmp; + } + + if (nargout > 2) + { + for (octave_idx_type i = 0; i < n; i++) + tmp(i) = Parent[i] + 1; + retval(2) = tmp; + } + + if (nargout > 1) + { + /* compute the elimination tree height */ + octave_idx_type height = 0 ; + for (int i = 0 ; i < n ; i++) + height = (height > Level[i] ? height : Level[i]); + height++ ; + retval(1) = static_cast<double> (height); + } + + for (octave_idx_type i = 0; i < n; i++) + tmp(i) = ColCount[i]; + retval(0) = tmp; + } + + symbfact_error: +#else + error ("symbfact: not available in this version of Octave"); +#endif + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/symrcm.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,702 @@ +/* + +Copyright (C) 2007-2012 Michael Weitzel + +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/>. + +*/ + +/* +An implementation of the Reverse Cuthill-McKee algorithm (symrcm) + +The implementation of this algorithm is based in the descriptions found in + +@INPROCEEDINGS{, + author = {E. Cuthill and J. McKee}, + title = {Reducing the Bandwidth of Sparse Symmetric Matrices}, + booktitle = {Proceedings of the 24th ACM National Conference}, + publisher = {Brandon Press}, + pages = {157 -- 172}, + location = {New Jersey}, + year = {1969} +} + +@BOOK{, + author = {Alan George and Joseph W. H. Liu}, + title = {Computer Solution of Large Sparse Positive Definite Systems}, + publisher = {Prentice Hall Series in Computational Mathematics}, + ISBN = {0-13-165274-5}, + year = {1981} +} + +The algorithm represents a heuristic approach to the NP-complete minimum +bandwidth problem. + +Written by Michael Weitzel <michael.weitzel@@uni-siegen.de> + <weitzel@@ldknet.org> +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ov.h" +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "utils.h" +#include "oct-locbuf.h" + +#include "ov-re-mat.h" +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "oct-sparse.h" + +// A node struct for the Cuthill-McKee algorithm +struct CMK_Node +{ + // the node's id (matrix row index) + octave_idx_type id; + // the node's degree + octave_idx_type deg; + // minimal distance to the root of the spanning tree + octave_idx_type dist; +}; + +// A simple queue. +// Queues Q have a fixed maximum size N (rows,cols of the matrix) and are +// stored in an array. qh and qt point to queue head and tail. + +// Enqueue operation (adds a node "o" at the tail) + +inline static void +Q_enq (CMK_Node *Q, octave_idx_type N, octave_idx_type& qt, const CMK_Node& o) +{ + Q[qt] = o; + qt = (qt + 1) % (N + 1); +} + +// Dequeue operation (removes a node from the head) + +inline static CMK_Node +Q_deq (CMK_Node * Q, octave_idx_type N, octave_idx_type& qh) +{ + CMK_Node r = Q[qh]; + qh = (qh + 1) % (N + 1); + return r; +} + +// Predicate (queue empty) +#define Q_empty(Q, N, qh, qt) ((qh) == (qt)) + +// A simple, array-based binary heap (used as a priority queue for nodes) + +// the left descendant of entry i +#define LEFT(i) (((i) << 1) + 1) // = (2*(i)+1) +// the right descendant of entry i +#define RIGHT(i) (((i) << 1) + 2) // = (2*(i)+2) +// the parent of entry i +#define PARENT(i) (((i) - 1) >> 1) // = floor(((i)-1)/2) + +// Builds a min-heap (the root contains the smallest element). A is an array +// with the graph's nodes, i is a starting position, size is the length of A. + +static void +H_heapify_min (CMK_Node *A, octave_idx_type i, octave_idx_type size) +{ + octave_idx_type j = i; + for (;;) + { + octave_idx_type l = LEFT(j); + octave_idx_type r = RIGHT(j); + + octave_idx_type smallest; + if (l < size && A[l].deg < A[j].deg) + smallest = l; + else + smallest = j; + + if (r < size && A[r].deg < A[smallest].deg) + smallest = r; + + if (smallest != j) + { + std::swap (A[j], A[smallest]); + j = smallest; + } + else + break; + } +} + +// Heap operation insert. Running time is O(log(n)) + +static void +H_insert (CMK_Node *H, octave_idx_type& h, const CMK_Node& o) +{ + octave_idx_type i = h++; + + H[i] = o; + + if (i == 0) + return; + do + { + octave_idx_type p = PARENT(i); + if (H[i].deg < H[p].deg) + { + std::swap (H[i], H[p]); + + i = p; + } + else + break; + } + while (i > 0); +} + +// Heap operation remove-min. Removes the smalles element in O(1) and +// reorganizes the heap optionally in O(log(n)) + +inline static CMK_Node +H_remove_min (CMK_Node *H, octave_idx_type& h, int reorg/*=1*/) +{ + CMK_Node r = H[0]; + H[0] = H[--h]; + if (reorg) + H_heapify_min (H, 0, h); + return r; +} + +// Predicate (heap empty) +#define H_empty(H, h) ((h) == 0) + +// Helper function for the Cuthill-McKee algorithm. Tries to determine a +// pseudo-peripheral node of the graph as starting node. + +static octave_idx_type +find_starting_node (octave_idx_type N, const octave_idx_type *ridx, + const octave_idx_type *cidx, const octave_idx_type *ridx2, + const octave_idx_type *cidx2, octave_idx_type *D, + octave_idx_type start) +{ + CMK_Node w; + + OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); + boolNDArray btmp (dim_vector (1, N), false); + bool *visit = btmp.fortran_vec (); + + octave_idx_type qh = 0; + octave_idx_type qt = 0; + CMK_Node x; + x.id = start; + x.deg = D[start]; + x.dist = 0; + Q_enq (Q, N, qt, x); + visit[start] = true; + + // distance level + octave_idx_type level = 0; + // current largest "eccentricity" + octave_idx_type max_dist = 0; + + for (;;) + { + while (! Q_empty (Q, N, qh, qt)) + { + CMK_Node v = Q_deq (Q, N, qh); + + if (v.dist > x.dist || (v.id != x.id && v.deg > x.deg)) + x = v; + + octave_idx_type i = v.id; + + // add all unvisited neighbors to the queue + octave_idx_type j1 = cidx[i]; + octave_idx_type j2 = cidx2[i]; + while (j1 < cidx[i+1] || j2 < cidx2[i+1]) + { + OCTAVE_QUIT; + + if (j1 == cidx[i+1]) + { + octave_idx_type r2 = ridx2[j2++]; + if (! visit[r2]) + { + // the distance of node j is dist(i)+1 + w.id = r2; + w.deg = D[r2]; + w.dist = v.dist+1; + Q_enq (Q, N, qt, w); + visit[r2] = true; + + if (w.dist > level) + level = w.dist; + } + } + else if (j2 == cidx2[i+1]) + { + octave_idx_type r1 = ridx[j1++]; + if (! visit[r1]) + { + // the distance of node j is dist(i)+1 + w.id = r1; + w.deg = D[r1]; + w.dist = v.dist+1; + Q_enq (Q, N, qt, w); + visit[r1] = true; + + if (w.dist > level) + level = w.dist; + } + } + else + { + octave_idx_type r1 = ridx[j1]; + octave_idx_type r2 = ridx2[j2]; + if (r1 <= r2) + { + if (! visit[r1]) + { + w.id = r1; + w.deg = D[r1]; + w.dist = v.dist+1; + Q_enq (Q, N, qt, w); + visit[r1] = true; + + if (w.dist > level) + level = w.dist; + } + j1++; + if (r1 == r2) + j2++; + } + else + { + if (! visit[r2]) + { + w.id = r2; + w.deg = D[r2]; + w.dist = v.dist+1; + Q_enq (Q, N, qt, w); + visit[r2] = true; + + if (w.dist > level) + level = w.dist; + } + j2++; + } + } + } + } // finish of BFS + + if (max_dist < x.dist) + { + max_dist = x.dist; + + for (octave_idx_type i = 0; i < N; i++) + visit[i] = false; + + visit[x.id] = true; + x.dist = 0; + qt = qh = 0; + Q_enq (Q, N, qt, x); + } + else + break; + } + return x.id; +} + +// Calculates the node's degrees. This means counting the non-zero elements +// in the symmetric matrix' rows. This works for non-symmetric matrices +// as well. + +static octave_idx_type +calc_degrees (octave_idx_type N, const octave_idx_type *ridx, + const octave_idx_type *cidx, octave_idx_type *D) +{ + octave_idx_type max_deg = 0; + + for (octave_idx_type i = 0; i < N; i++) + D[i] = 0; + + for (octave_idx_type j = 0; j < N; j++) + { + for (octave_idx_type i = cidx[j]; i < cidx[j+1]; i++) + { + OCTAVE_QUIT; + octave_idx_type k = ridx[i]; + // there is a non-zero element (k,j) + D[k]++; + if (D[k] > max_deg) + max_deg = D[k]; + // if there is no element (j,k) there is one in + // the symmetric matrix: + if (k != j) + { + bool found = false; + for (octave_idx_type l = cidx[k]; l < cidx[k + 1]; l++) + { + OCTAVE_QUIT; + + if (ridx[l] == j) + { + found = true; + break; + } + else if (ridx[l] > j) + break; + } + + if (! found) + { + // A(j,k) == 0 + D[j]++; + if (D[j] > max_deg) + max_deg = D[j]; + } + } + } + } + return max_deg; +} + +// Transpose of the structure of a square sparse matrix + +static void +transpose (octave_idx_type N, const octave_idx_type *ridx, + const octave_idx_type *cidx, octave_idx_type *ridx2, + octave_idx_type *cidx2) +{ + octave_idx_type nz = cidx[N]; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, w, N + 1); + for (octave_idx_type i = 0; i < N; i++) + w[i] = 0; + for (octave_idx_type i = 0; i < nz; i++) + w[ridx[i]]++; + nz = 0; + for (octave_idx_type i = 0; i < N; i++) + { + OCTAVE_QUIT; + cidx2[i] = nz; + nz += w[i]; + w[i] = cidx2[i]; + } + cidx2[N] = nz; + w[N] = nz; + + for (octave_idx_type j = 0; j < N; j++) + for (octave_idx_type k = cidx[j]; k < cidx[j + 1]; k++) + { + OCTAVE_QUIT; + octave_idx_type q = w[ridx[k]]++; + ridx2[q] = j; + } +} + +// An implementation of the Cuthill-McKee algorithm. +DEFUN_DLD (symrcm, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{p} =} symrcm (@var{S})\n\ +Return the symmetric reverse Cuthill-McKee permutation of @var{S}.\n\ +@var{p} is a permutation vector such that\n\ +@code{@var{S}(@var{p}, @var{p})} tends to have its diagonal elements\n\ +closer to the diagonal than @var{S}. This is a good preordering for LU\n\ +or Cholesky@tie{}factorization of matrices that come from ``long, skinny''\n\ +problems. It works for both symmetric and asymmetric @var{S}.\n\ +\n\ +The algorithm represents a heuristic approach to the NP-complete\n\ +bandwidth minimization problem. The implementation is based in the\n\ +descriptions found in\n\ +\n\ +E. Cuthill, J. McKee. @cite{Reducing the Bandwidth of Sparse Symmetric\n\ +Matrices}. Proceedings of the 24th ACM National Conference, 157--172\n\ +1969, Brandon Press, New Jersey.\n\ +\n\ +A. George, J.W.H. Liu. @cite{Computer Solution of Large Sparse\n\ +Positive Definite Systems}, Prentice Hall Series in Computational\n\ +Mathematics, ISBN 0-13-165274-5, 1981.\n\ +\n\ +@seealso{colperm, colamd, symamd}\n\ +@end deftypefn") +{ + octave_value retval; + int nargin = args.length (); + + if (nargin != 1) + { + print_usage (); + return retval; + } + + octave_value arg = args(0); + + // the parameter of the matrix is converted into a sparse matrix + //(if necessary) + octave_idx_type *cidx; + octave_idx_type *ridx; + SparseMatrix Ar; + SparseComplexMatrix Ac; + + if (arg.is_real_type ()) + { + Ar = arg.sparse_matrix_value (); + // Note cidx/ridx are const, so use xridx and xcidx... + cidx = Ar.xcidx (); + ridx = Ar.xridx (); + } + else + { + Ac = arg.sparse_complex_matrix_value (); + cidx = Ac.xcidx (); + ridx = Ac.xridx (); + } + + if (error_state) + return retval; + + octave_idx_type nr = arg.rows (); + octave_idx_type nc = arg.columns (); + + if (nr != nc) + { + gripe_square_matrix_required ("symrcm"); + return retval; + } + + if (nr == 0 && nc == 0) + return octave_value (NDArray (dim_vector (1, 0))); + + // sizes of the heaps + octave_idx_type s = 0; + + // head- and tail-indices for the queue + octave_idx_type qt = 0, qh = 0; + CMK_Node v, w; + // dimension of the matrix + octave_idx_type N = nr; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, cidx2, N + 1); + OCTAVE_LOCAL_BUFFER (octave_idx_type, ridx2, cidx[N]); + transpose (N, ridx, cidx, ridx2, cidx2); + + // the permutation vector + NDArray P (dim_vector (1, N)); + + // compute the node degrees + OCTAVE_LOCAL_BUFFER (octave_idx_type, D, N); + octave_idx_type max_deg = calc_degrees (N, ridx, cidx, D); + + // if none of the nodes has a degree > 0 (a matrix of zeros) + // the return value corresponds to the identity permutation + if (max_deg == 0) + { + for (octave_idx_type i = 0; i < N; i++) + P(i) = i; + return octave_value (P); + } + + // a heap for the a node's neighbors. The number of neighbors is + // limited by the maximum degree max_deg: + OCTAVE_LOCAL_BUFFER (CMK_Node, S, max_deg); + + // a queue for the BFS. The array is always one element larger than + // the number of entries that are stored. + OCTAVE_LOCAL_BUFFER (CMK_Node, Q, N+1); + + // a counter (for building the permutation) + octave_idx_type c = -1; + + // upper bound for the bandwidth (=quality of solution) + // initialize the bandwidth of the graph with 0. B contains the + // the maximum of the theoretical lower limits of the subgraphs + // bandwidths. + octave_idx_type B = 0; + + // mark all nodes as unvisited; with the exception of the nodes + // that have degree==0 and build a CC of the graph. + + boolNDArray btmp (dim_vector (1, N), false); + bool *visit = btmp.fortran_vec (); + + do + { + // locate an unvisited starting node of the graph + octave_idx_type i; + for (i = 0; i < N; i++) + if (! visit[i]) + break; + + // locate a probably better starting node + v.id = find_starting_node (N, ridx, cidx, ridx2, cidx2, D, i); + + // mark the node as visited and enqueue it (a starting node + // for the BFS). Since the node will be a root of a spanning + // tree, its dist is 0. + v.deg = D[v.id]; + v.dist = 0; + visit[v.id] = true; + Q_enq (Q, N, qt, v); + + // lower bound for the bandwidth of a subgraph + // keep a "level" in the spanning tree (= min. distance to the + // root) for determining the bandwidth of the computed + // permutation P + octave_idx_type Bsub = 0; + // min. dist. to the root is 0 + octave_idx_type level = 0; + // the root is the first/only node on level 0 + octave_idx_type level_N = 1; + + while (! Q_empty (Q, N, qh, qt)) + { + v = Q_deq (Q, N, qh); + i = v.id; + + c++; + + // for computing the inverse permutation P where + // A(inv(P),inv(P)) or P'*A*P is banded + // P(i) = c; + + // for computing permutation P where + // A(P(i),P(j)) or P*A*P' is banded + P(c) = i; + + // put all unvisited neighbors j of node i on the heap + s = 0; + octave_idx_type j1 = cidx[i]; + octave_idx_type j2 = cidx2[i]; + + OCTAVE_QUIT; + while (j1 < cidx[i+1] || j2 < cidx2[i+1]) + { + OCTAVE_QUIT; + if (j1 == cidx[i+1]) + { + octave_idx_type r2 = ridx2[j2++]; + if (! visit[r2]) + { + // the distance of node j is dist(i)+1 + w.id = r2; + w.deg = D[r2]; + w.dist = v.dist+1; + H_insert (S, s, w); + visit[r2] = true; + } + } + else if (j2 == cidx2[i+1]) + { + octave_idx_type r1 = ridx[j1++]; + if (! visit[r1]) + { + w.id = r1; + w.deg = D[r1]; + w.dist = v.dist+1; + H_insert (S, s, w); + visit[r1] = true; + } + } + else + { + octave_idx_type r1 = ridx[j1]; + octave_idx_type r2 = ridx2[j2]; + if (r1 <= r2) + { + if (! visit[r1]) + { + w.id = r1; + w.deg = D[r1]; + w.dist = v.dist+1; + H_insert (S, s, w); + visit[r1] = true; + } + j1++; + if (r1 == r2) + j2++; + } + else + { + if (! visit[r2]) + { + w.id = r2; + w.deg = D[r2]; + w.dist = v.dist+1; + H_insert (S, s, w); + visit[r2] = true; + } + j2++; + } + } + } + + // add the neighbors to the queue (sorted by node degree) + while (! H_empty (S, s)) + { + OCTAVE_QUIT; + + // locate a neighbor of i with minimal degree in O(log(N)) + v = H_remove_min (S, s, 1); + + // entered the BFS a new level? + if (v.dist > level) + { + // adjustment of bandwith: + // "[...] the minimum bandwidth that + // can be obtained [...] is the + // maximum number of nodes per level" + if (Bsub < level_N) + Bsub = level_N; + + level = v.dist; + // v is the first node on the new level + level_N = 1; + } + else + { + // there is no new level but another node on + // this level: + level_N++; + } + + // enqueue v in O(1) + Q_enq (Q, N, qt, v); + } + + // synchronize the bandwidth with level_N once again: + if (Bsub < level_N) + Bsub = level_N; + } + // finish of BFS. If there are still unvisited nodes in the graph + // then it is split into CCs. The computed bandwidth is the maximum + // of all subgraphs. Update: + if (Bsub > B) + B = Bsub; + } + // are there any nodes left? + while (c+1 < N); + + // compute the reverse-ordering + s = N / 2 - 1; + for (octave_idx_type i = 0, j = N - 1; i <= s; i++, j--) + std::swap (P.elem (i), P.elem (j)); + + // increment all indices, since Octave is not C + return octave_value (P+1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/tsearch.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,186 @@ +/* + +Copyright (C) 2002-2012 Andreas Stahel + +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/>. + +*/ + +// Author: Andreas Stahel <Andreas.Stahel@hta-bi.bfh.ch> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <fstream> +#include <string> + +#include "lo-ieee.h" +#include "lo-math.h" + +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "parse.h" + +inline double max (double a, double b, double c) +{ + if (a < b) + return (b < c ? c : b); + else + return (a < c ? c : a); +} + +inline double min (double a, double b, double c) +{ + if (a > b) + return (b > c ? c : b); + else + return (a > c ? c : a); +} + +#define REF(x,k,i) x(static_cast<octave_idx_type>(elem((k), (i))) - 1) + +// for large data set the algorithm is very slow +// one should presort (how?) either the elements of the points of evaluation +// to cut down the time needed to decide which triangle contains the +// given point + +// e.g., build up a neighbouring triangle structure and use a simplex-like +// method to traverse it + +DEFUN_DLD (tsearch, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{idx} =} tsearch (@var{x}, @var{y}, @var{t}, @var{xi}, @var{yi})\n\ +Search for the enclosing Delaunay convex hull. For @code{@var{t} =\n\ +delaunay (@var{x}, @var{y})}, finds the index in @var{t} containing the\n\ +points @code{(@var{xi}, @var{yi})}. For points outside the convex hull,\n\ +@var{idx} is NaN.\n\ +@seealso{delaunay, delaunayn}\n\ +@end deftypefn") +{ + const double eps=1.0e-12; + + octave_value_list retval; + const int nargin = args.length (); + if (nargin != 5) + { + print_usage (); + return retval; + } + + const ColumnVector x (args(0).vector_value ()); + const ColumnVector y (args(1).vector_value ()); + const Matrix elem (args(2).matrix_value ()); + const ColumnVector xi (args(3).vector_value ()); + const ColumnVector yi (args(4).vector_value ()); + + if (error_state) + return retval; + + const octave_idx_type nelem = elem.rows (); + + ColumnVector minx (nelem); + ColumnVector maxx (nelem); + ColumnVector miny (nelem); + ColumnVector maxy (nelem); + for (octave_idx_type k = 0; k < nelem; k++) + { + minx(k) = min (REF (x, k, 0), REF (x, k, 1), REF (x, k, 2)) - eps; + maxx(k) = max (REF (x, k, 0), REF (x, k, 1), REF (x, k, 2)) + eps; + miny(k) = min (REF (y, k, 0), REF (y, k, 1), REF (y, k, 2)) - eps; + maxy(k) = max (REF (y, k, 0), REF (y, k, 1), REF (y, k, 2)) + eps; + } + + const octave_idx_type np = xi.length (); + ColumnVector values (np); + + double x0 = 0.0, y0 = 0.0; + double a11 = 0.0, a12 = 0.0, a21 = 0.0, a22 = 0.0, det = 0.0; + + octave_idx_type k = nelem; // k is a counter of elements + for (octave_idx_type kp = 0; kp < np; kp++) + { + const double xt = xi(kp); + const double yt = yi(kp); + + // check if last triangle contains the next point + if (k < nelem) + { + const double dx1 = xt - x0; + const double dx2 = yt - y0; + const double c1 = (a22 * dx1 - a21 * dx2) / det; + const double c2 = (-a12 * dx1 + a11 * dx2) / det; + if (c1 >= -eps && c2 >= -eps && (c1 + c2) <= (1 + eps)) + { + values(kp) = double(k+1); + continue; + } + } + + // it doesn't, so go through all elements + for (k = 0; k < nelem; k++) + { + OCTAVE_QUIT; + if (xt >= minx(k) && xt <= maxx(k) && yt >= miny(k) && yt <= maxy(k)) + { + // element inside the minimum rectangle: examine it closely + x0 = REF (x, k, 0); + y0 = REF (y, k, 0); + a11 = REF (x, k, 1) - x0; + a12 = REF (y, k, 1) - y0; + a21 = REF (x, k, 2) - x0; + a22 = REF (y, k, 2) - y0; + det = a11 * a22 - a21 * a12; + + // solve the system + const double dx1 = xt - x0; + const double dx2 = yt - y0; + const double c1 = (a22 * dx1 - a21 * dx2) / det; + const double c2 = (-a12 * dx1 + a11 * dx2) / det; + if ((c1 >= -eps) && (c2 >= -eps) && ((c1 + c2) <= (1 + eps))) + { + values(kp) = double(k+1); + break; + } + } //endif # examine this element closely + } //endfor # each element + + if (k == nelem) + values(kp) = lo_ieee_nan_value (); + + } //endfor # kp + + retval(0) = values; + + return retval; +} + +/* +%!shared x, y, tri +%! x = [-1;-1;1]; +%! y = [-1;1;-1]; +%! tri = [1, 2, 3]; +%!assert (tsearch (x,y,tri,-1,-1), 1) +%!assert (tsearch (x,y,tri, 1,-1), 1) +%!assert (tsearch (x,y,tri,-1, 1), 1) +%!assert (tsearch (x,y,tri,-1/3, -1/3), 1) +%!assert (tsearch (x,y,tri, 1, 1), NaN) + +%!error tsearch () +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dldfcn/urlwrite.cc Tue Jul 31 21:57:58 2012 -0400 @@ -0,0 +1,1740 @@ +// urlwrite and urlread, a curl front-end for octave +/* + +Copyright (C) 2006-2012 Alexander Barth +Copyright (C) 2009 David Bateman + +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/>. + +*/ + +// Author: Alexander Barth <abarth@marine.usf.edu> +// Adapted-By: jwe + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string> +#include <fstream> +#include <iomanip> +#include <iostream> + +#include "dir-ops.h" +#include "file-ops.h" +#include "file-stat.h" +#include "oct-env.h" +#include "glob-match.h" + +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "ov-cell.h" +#include "pager.h" +#include "oct-map.h" +#include "oct-refcount.h" +#include "unwind-prot.h" + +#ifdef HAVE_CURL + +#include <curl/curl.h> +#include <curl/curlver.h> +#include <curl/easy.h> + +// Backwards compatibility for curl < 7.17.0 +#if LIBCURL_VERSION_NUM < 0x071100 +#define CURLOPT_DIRLISTONLY CURLOPT_FTPLISTONLY +#endif + +static int +write_data (void *buffer, size_t size, size_t nmemb, void *streamp) +{ + std::ostream& stream = *(static_cast<std::ostream*> (streamp)); + stream.write (static_cast<const char*> (buffer), size*nmemb); + return (stream.fail () ? 0 : size * nmemb); +} + +static int +read_data (void *buffer, size_t size, size_t nmemb, void *streamp) +{ + std::istream& stream = *(static_cast<std::istream*> (streamp)); + stream.read (static_cast<char*> (buffer), size*nmemb); + if (stream.eof ()) + return stream.gcount (); + else + return (stream.fail () ? 0 : size * nmemb); +} + +static size_t +throw_away (void *, size_t size, size_t nmemb, void *) +{ + return static_cast<size_t>(size * nmemb); +} + +class +curl_handle +{ +private: + class + curl_handle_rep + { + public: + curl_handle_rep (void) : count (1), valid (true), ascii (false) + { + curl = curl_easy_init (); + if (!curl) + error ("can not create curl handle"); + } + + ~curl_handle_rep (void) + { + if (curl) + curl_easy_cleanup (curl); + } + + bool is_valid (void) const + { + return valid; + } + + bool perform (bool curlerror) const + { + bool retval = false; + if (!error_state) + { + BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + + errnum = curl_easy_perform (curl); + if (errnum != CURLE_OK) + { + if (curlerror) + error ("%s", curl_easy_strerror (errnum)); + } + else + retval = true; + + END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + } + return retval; + } + + CURL* handle (void) const + { + return curl; + } + + bool is_ascii (void) const + { + return ascii; + } + + bool is_binary (void) const + { + return !ascii; + } + + octave_refcount<size_t> count; + std::string host; + bool valid; + bool ascii; + mutable CURLcode errnum; + + private: + CURL *curl; + + // No copying! + + curl_handle_rep (const curl_handle_rep& ov); + + curl_handle_rep& operator = (const curl_handle_rep&); + }; + +public: + +// I'd love to rewrite this as a private method of the curl_handle +// class, but you can't pass the va_list from the wrapper setopt to +// the curl_easy_setopt function. +#define setopt(option, parameter) \ + { \ + CURLcode res = curl_easy_setopt (rep->handle (), option, parameter); \ + if (res != CURLE_OK) \ + error ("%s", curl_easy_strerror (res)); \ + } + + curl_handle (void) : rep (new curl_handle_rep ()) + { + rep->valid = false; + } + + curl_handle (const std::string& _host, const std::string& user, + const std::string& passwd) : + rep (new curl_handle_rep ()) + { + rep->host = _host; + init (user, passwd, std::cin, octave_stdout); + + std::string url = "ftp://" + _host; + setopt (CURLOPT_URL, url.c_str ()); + + // Setup the link, with no transfer + if (!error_state) + perform (); + } + + curl_handle (const std::string& url, const std::string& method, + const Cell& param, std::ostream& os, bool& retval) : + rep (new curl_handle_rep ()) + { + retval = false; + + init ("", "", std::cin, os); + + setopt (CURLOPT_NOBODY, 0); + + // Don't need to store the parameters here as we can't change + // the URL after the handle is created + std::string query_string = form_query_string (param); + + if (method == "get") + { + query_string = url + "?" + query_string; + setopt (CURLOPT_URL, query_string.c_str ()); + } + else if (method == "post") + { + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_POSTFIELDS, query_string.c_str ()); + } + else + setopt (CURLOPT_URL, url.c_str ()); + + if (!error_state) + retval = perform (false); + } + + curl_handle (const curl_handle& h) : rep (h.rep) + { + rep->count++; + } + + ~curl_handle (void) + { + if (--rep->count == 0) + delete rep; + } + + curl_handle& operator = (const curl_handle& h) + { + if (this != &h) + { + if (--rep->count == 0) + delete rep; + + rep = h.rep; + rep->count++; + } + return *this; + } + + bool is_valid (void) const + { + return rep->is_valid (); + } + + std::string lasterror (void) const + { + return std::string (curl_easy_strerror (rep->errnum)); + } + + void set_ostream (std::ostream& os) const + { + setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os)); + } + + void set_istream (std::istream& is) const + { + setopt (CURLOPT_READDATA, static_cast<void*> (&is)); + } + + void ascii (void) const + { + setopt (CURLOPT_TRANSFERTEXT, 1); + rep->ascii = true; + } + + void binary (void) const + { + setopt (CURLOPT_TRANSFERTEXT, 0); + rep->ascii = false; + } + + bool is_ascii (void) const + { + return rep->is_ascii (); + } + + bool is_binary (void) const + { + return rep->is_binary (); + } + + void cwd (const std::string& path) const + { + struct curl_slist *slist = 0; + std::string cmd = "cwd " + path; + slist = curl_slist_append (slist, cmd.c_str ()); + setopt (CURLOPT_POSTQUOTE, slist); + if (! error_state) + perform (); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + } + + void del (const std::string& file) const + { + struct curl_slist *slist = 0; + std::string cmd = "dele " + file; + slist = curl_slist_append (slist, cmd.c_str ()); + setopt (CURLOPT_POSTQUOTE, slist); + if (! error_state) + perform (); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + } + + void rmdir (const std::string& path) const + { + struct curl_slist *slist = 0; + std::string cmd = "rmd " + path; + slist = curl_slist_append (slist, cmd.c_str ()); + setopt (CURLOPT_POSTQUOTE, slist); + if (! error_state) + perform (); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + } + + bool mkdir (const std::string& path, bool curlerror = true) const + { + bool retval = false; + struct curl_slist *slist = 0; + std::string cmd = "mkd " + path; + slist = curl_slist_append (slist, cmd.c_str ()); + setopt (CURLOPT_POSTQUOTE, slist); + if (! error_state) + retval = perform (curlerror); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + return retval; + } + + void rename (const std::string& oldname, const std::string& newname) const + { + struct curl_slist *slist = 0; + std::string cmd = "rnfr " + oldname; + slist = curl_slist_append (slist, cmd.c_str ()); + cmd = "rnto " + newname; + slist = curl_slist_append (slist, cmd.c_str ()); + setopt (CURLOPT_POSTQUOTE, slist); + if (! error_state) + perform (); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + } + + void put (const std::string& file, std::istream& is) const + { + std::string url = "ftp://" + rep->host + "/" + file; + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_UPLOAD, 1); + setopt (CURLOPT_NOBODY, 0); + set_istream (is); + if (! error_state) + perform (); + set_istream (std::cin); + setopt (CURLOPT_NOBODY, 1); + setopt (CURLOPT_UPLOAD, 0); + url = "ftp://" + rep->host; + setopt (CURLOPT_URL, url.c_str ()); + } + + void get (const std::string& file, std::ostream& os) const + { + std::string url = "ftp://" + rep->host + "/" + file; + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_NOBODY, 0); + set_ostream (os); + if (! error_state) + perform (); + set_ostream (octave_stdout); + setopt (CURLOPT_NOBODY, 1); + url = "ftp://" + rep->host; + setopt (CURLOPT_URL, url.c_str ()); + } + + void dir (void) const + { + std::string url = "ftp://" + rep->host + "/"; + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_NOBODY, 0); + if (! error_state) + perform (); + setopt (CURLOPT_NOBODY, 1); + url = "ftp://" + rep->host; + setopt (CURLOPT_URL, url.c_str ()); + } + + string_vector list (void) const + { + std::ostringstream buf; + std::string url = "ftp://" + rep->host + "/"; + setopt (CURLOPT_WRITEDATA, static_cast<void*> (&buf)); + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_DIRLISTONLY, 1); + setopt (CURLOPT_NOBODY, 0); + if (! error_state) + perform (); + setopt (CURLOPT_NOBODY, 1); + url = "ftp://" + rep->host; + setopt (CURLOPT_WRITEDATA, static_cast<void*> (&octave_stdout)); + setopt (CURLOPT_DIRLISTONLY, 0); + setopt (CURLOPT_URL, url.c_str ()); + + // Count number of directory entries + std::string str = buf.str (); + octave_idx_type n = 0; + size_t pos = 0; + while (true) + { + pos = str.find_first_of ('\n', pos); + if (pos == std::string::npos) + break; + pos++; + n++; + } + string_vector retval (n); + pos = 0; + for (octave_idx_type i = 0; i < n; i++) + { + size_t newpos = str.find_first_of ('\n', pos); + if (newpos == std::string::npos) + break; + + retval(i) = str.substr(pos, newpos - pos); + pos = newpos + 1; + } + return retval; + } + + void get_fileinfo (const std::string& filename, double& filesize, + time_t& filetime, bool& fileisdir) const + { + std::string path = pwd (); + + std::string url = "ftp://" + rep->host + "/" + path + "/" + filename; + setopt (CURLOPT_URL, url.c_str ()); + setopt (CURLOPT_FILETIME, 1); + setopt (CURLOPT_HEADERFUNCTION, throw_away); + setopt (CURLOPT_WRITEFUNCTION, throw_away); + + // FIXME + // The MDTM command fails for a directory on the servers I tested + // so this is a means of testing for directories. It also means + // I can't get the date of directories! + if (! error_state) + { + if (! perform (false)) + { + fileisdir = true; + filetime = -1; + filesize = 0; + } + else + { + fileisdir = false; + time_t ft; + curl_easy_getinfo (rep->handle (), CURLINFO_FILETIME, &ft); + filetime = ft; + double fs; + curl_easy_getinfo (rep->handle (), + CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs); + filesize = fs; + } + } + + setopt (CURLOPT_WRITEFUNCTION, write_data); + setopt (CURLOPT_HEADERFUNCTION, 0); + setopt (CURLOPT_FILETIME, 0); + url = "ftp://" + rep->host; + setopt (CURLOPT_URL, url.c_str ()); + + // The MDTM command seems to reset the path to the root with the + // servers I tested with, so cd again into the correct path. Make + // the path absolute so that this will work even with servers that + // don't end up in the root after an MDTM command. + cwd ("/" + path); + } + + std::string pwd (void) const + { + struct curl_slist *slist = 0; + std::string retval; + std::ostringstream buf; + + slist = curl_slist_append (slist, "pwd"); + setopt (CURLOPT_POSTQUOTE, slist); + setopt (CURLOPT_HEADERFUNCTION, write_data); + setopt (CURLOPT_WRITEHEADER, static_cast<void *>(&buf)); + + if (! error_state) + { + perform (); + retval = buf.str (); + + // Can I assume that the path is alway in "" on the last line + size_t pos2 = retval.rfind ('"'); + size_t pos1 = retval.rfind ('"', pos2 - 1); + retval = retval.substr (pos1 + 1, pos2 - pos1 - 1); + } + setopt (CURLOPT_HEADERFUNCTION, 0); + setopt (CURLOPT_WRITEHEADER, 0); + setopt (CURLOPT_POSTQUOTE, 0); + curl_slist_free_all (slist); + + return retval; + } + + bool perform (bool curlerror = true) const + { + return rep->perform (curlerror); + } + +private: + curl_handle_rep *rep; + + std::string form_query_string (const Cell& param) + { + std::ostringstream query; + + for (int i = 0; i < param.numel (); i += 2) + { + std::string name = param(i).string_value (); + std::string text = param(i+1).string_value (); + + // Encode strings. + char *enc_name = curl_easy_escape (rep->handle (), name.c_str (), + name.length ()); + char *enc_text = curl_easy_escape (rep->handle (), text.c_str (), + text.length ()); + + query << enc_name << "=" << enc_text; + + curl_free (enc_name); + curl_free (enc_text); + + if (i < param.numel ()-1) + query << "&"; + } + + query.flush (); + + return query.str (); + } + + void init (const std::string& user, const std::string& passwd, + std::istream& is, std::ostream& os) + { + // No data transfer by default + setopt (CURLOPT_NOBODY, 1); + + // Set the username and password + std::string userpwd = user; + if (! passwd.empty ()) + userpwd += ":" + passwd; + if (! userpwd.empty ()) + setopt (CURLOPT_USERPWD, userpwd.c_str ()); + + // Define our callback to get called when there's data to be written. + setopt (CURLOPT_WRITEFUNCTION, write_data); + + // Set a pointer to our struct to pass to the callback. + setopt (CURLOPT_WRITEDATA, static_cast<void*> (&os)); + + // Define our callback to get called when there's data to be read + setopt (CURLOPT_READFUNCTION, read_data); + + // Set a pointer to our struct to pass to the callback. + setopt (CURLOPT_READDATA, static_cast<void*> (&is)); + + // Follow redirects. + setopt (CURLOPT_FOLLOWLOCATION, true); + + // Don't use EPSV since connecting to sites that don't support it + // will hang for some time (3 minutes?) before moving on to try PASV + // instead. + setopt (CURLOPT_FTP_USE_EPSV, false); + + setopt (CURLOPT_NOPROGRESS, true); + setopt (CURLOPT_FAILONERROR, true); + + setopt (CURLOPT_POSTQUOTE, 0); + setopt (CURLOPT_QUOTE, 0); + } + +#undef setopt +}; + +class +curl_handles +{ +public: + + typedef std::map<std::string, curl_handle>::iterator iterator; + typedef std::map<std::string, curl_handle>::const_iterator const_iterator; + + curl_handles (void) : map () + { + curl_global_init (CURL_GLOBAL_DEFAULT); + } + + ~curl_handles (void) + { + // Remove the elements of the map explicitly as they should + // be deleted before the call to curl_global_cleanup + map.erase (begin (), end ()); + + curl_global_cleanup (); + } + + iterator begin (void) { return iterator (map.begin ()); } + const_iterator begin (void) const { return const_iterator (map.begin ()); } + + iterator end (void) { return iterator (map.end ()); } + const_iterator end (void) const { return const_iterator (map.end ()); } + + iterator seek (const std::string& k) { return map.find (k); } + const_iterator seek (const std::string& k) const { return map.find (k); } + + std::string key (const_iterator p) const { return p->first; } + + curl_handle& contents (const std::string& k) + { + return map[k]; + } + + curl_handle contents (const std::string& k) const + { + const_iterator p = seek (k); + return p != end () ? p->second : curl_handle (); + } + + curl_handle& contents (iterator p) + { return p->second; } + + curl_handle contents (const_iterator p) const + { return p->second; } + + void del (const std::string& k) + { + iterator p = map.find (k); + + if (p != map.end ()) + map.erase (p); + } + +private: + std::map<std::string, curl_handle> map; +}; + +static curl_handles handles; + +static void +cleanup_urlwrite (std::string filename) +{ + octave_unlink (filename); +} + +static void +reset_path (const curl_handle curl) +{ + curl.cwd (".."); +} + +static void +delete_file (std::string file) +{ + octave_unlink (file); +} +#endif + +DEFUN_DLD (urlwrite, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} urlwrite (@var{url}, @var{localfile})\n\ +@deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\ +@deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\ +@deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\ +Download a remote file specified by its @var{url} and save it as\n\ +@var{localfile}. For example:\n\ +\n\ +@example\n\ +@group\n\ +urlwrite (\"ftp://ftp.octave.org/pub/octave/README\",\n\ + \"README.txt\");\n\ +@end group\n\ +@end example\n\ +\n\ +The full path of the downloaded file is returned in @var{f}. The\n\ +variable @var{success} is 1 if the download was successful,\n\ +otherwise it is 0 in which case @var{message} contains an error\n\ +message. If no output argument is specified and an error occurs,\n\ +then the error is signaled through Octave's error handling mechanism.\n\ +\n\ +This function uses libcurl. Curl supports, among others, the HTTP,\n\ +FTP and FILE protocols. Username and password may be specified in\n\ +the URL, for example:\n\ +\n\ +@example\n\ +@group\n\ +urlwrite (\"http://username:password@@example.com/file.txt\",\n\ + \"file.txt\");\n\ +@end group\n\ +@end example\n\ +\n\ +GET and POST requests can be specified by @var{method} and @var{param}.\n\ +The parameter @var{method} is either @samp{get} or @samp{post}\n\ +and @var{param} is a cell array of parameter and value pairs.\n\ +For example:\n\ +\n\ +@example\n\ +@group\n\ +urlwrite (\"http://www.google.com/search\", \"search.html\",\n\ + \"get\", @{\"query\", \"octave\"@});\n\ +@end group\n\ +@end example\n\ +@seealso{urlread}\n\ +@end deftypefn") +{ + octave_value_list retval; + +#ifdef HAVE_CURL + + int nargin = args.length (); + + // verify arguments + if (nargin != 2 && nargin != 4) + { + print_usage (); + return retval; + } + + std::string url = args(0).string_value (); + + if (error_state) + { + error ("urlwrite: URL must be a character string"); + return retval; + } + + // name to store the file if download is succesful + std::string filename = args(1).string_value (); + + if (error_state) + { + error ("urlwrite: LOCALFILE must be a character string"); + return retval; + } + + std::string method; + Cell param; // empty cell array + + if (nargin == 4) + { + method = args(2).string_value (); + + if (error_state) + { + error ("urlwrite: METHOD must be \"get\" or \"post\""); + return retval; + } + + if (method != "get" && method != "post") + { + error ("urlwrite: METHOD must be \"get\" or \"post\""); + return retval; + } + + param = args(3).cell_value (); + + if (error_state) + { + error ("urlwrite: parameters (PARAM) for get and post requests must be given as a cell"); + return retval; + } + + + if (param.numel () % 2 == 1 ) + { + error ("urlwrite: number of elements in PARAM must be even"); + return retval; + } + } + + // The file should only be deleted if it doesn't initially exist, we + // create it, and the download fails. We use unwind_protect to do + // it so that the deletion happens no matter how we exit the function. + + file_stat fs (filename); + + std::ofstream ofile (filename.c_str (), std::ios::out | std::ios::binary); + + if (! ofile.is_open ()) + { + error ("urlwrite: unable to open file"); + return retval; + } + + unwind_protect_safe frame; + + frame.add_fcn (cleanup_urlwrite, filename); + + bool ok; + curl_handle curl = curl_handle (url, method, param, ofile, ok); + + ofile.close (); + + if (!error_state) + frame.discard (); + else + frame.run (); + + if (nargout > 0) + { + if (ok) + { + retval(2) = std::string (); + retval(1) = true; + retval(0) = octave_env::make_absolute (filename); + } + else + { + retval(2) = curl.lasterror (); + retval(1) = false; + retval(0) = std::string (); + } + } + + if (nargout < 2 && ! ok) + error ("urlwrite: curl: %s", curl.lasterror ().c_str ()); + +#else + error ("urlwrite: not available in this version of Octave"); +#endif + + return retval; +} + +DEFUN_DLD (urlread, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{s} =} urlread (@var{url})\n\ +@deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\ +@deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})\n\ +@deftypefnx {Loadable Function} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})\n\ +Download a remote file specified by its @var{url} and return its content\n\ +in string @var{s}. For example:\n\ +\n\ +@example\n\ +s = urlread (\"ftp://ftp.octave.org/pub/octave/README\");\n\ +@end example\n\ +\n\ +The variable @var{success} is 1 if the download was successful,\n\ +otherwise it is 0 in which case @var{message} contains an error\n\ +message. If no output argument is specified and an error occurs,\n\ +then the error is signaled through Octave's error handling mechanism.\n\ +\n\ +This function uses libcurl. Curl supports, among others, the HTTP,\n\ +FTP and FILE protocols. Username and password may be specified in the\n\ +URL@. For example:\n\ +\n\ +@example\n\ +s = urlread (\"http://user:password@@example.com/file.txt\");\n\ +@end example\n\ +\n\ +GET and POST requests can be specified by @var{method} and @var{param}.\n\ +The parameter @var{method} is either @samp{get} or @samp{post}\n\ +and @var{param} is a cell array of parameter and value pairs.\n\ +For example:\n\ +\n\ +@example\n\ +@group\n\ +s = urlread (\"http://www.google.com/search\", \"get\",\n\ + @{\"query\", \"octave\"@});\n\ +@end group\n\ +@end example\n\ +@seealso{urlwrite}\n\ +@end deftypefn") +{ + // Octave's return value + octave_value_list retval; + +#ifdef HAVE_CURL + + int nargin = args.length (); + + // verify arguments + if (nargin != 1 && nargin != 3) + { + print_usage (); + return retval; + } + + std::string url = args(0).string_value (); + + if (error_state) + { + error ("urlread: URL must be a character string"); + return retval; + } + + std::string method; + Cell param; // empty cell array + + if (nargin == 3) + { + method = args(1).string_value (); + + if (error_state) + { + error ("urlread: METHOD must be \"get\" or \"post\""); + return retval; + } + + if (method != "get" && method != "post") + { + error ("urlread: METHOD must be \"get\" or \"post\""); + return retval; + } + + param = args(2).cell_value (); + + if (error_state) + { + error ("urlread: parameters (PARAM) for get and post requests must be given as a cell"); + return retval; + } + + if (param.numel () % 2 == 1 ) + { + error ("urlread: number of elements in PARAM must be even"); + return retval; + } + } + + std::ostringstream buf; + + bool ok; + curl_handle curl = curl_handle (url, method, param, buf, ok); + + if (nargout > 0) + { + // Return empty string if no error occured. + retval(2) = ok ? "" : curl.lasterror (); + retval(1) = ok; + retval(0) = buf.str (); + } + + if (nargout < 2 && ! ok) + error ("urlread: curl: %s", curl.lasterror().c_str()); + +#else + error ("urlread: not available in this version of Octave"); +#endif + + return retval; +} + +DEFUN_DLD (__ftp__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp__ (@var{handle}, @var{host})\n\ +@deftypefnx {Loadable Function} {} __ftp__ (@var{handle}, @var{host}, @var{username}, @var{password})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + std::string handle; + std::string host; + std::string user = "anonymous"; + std::string passwd = ""; + + if (nargin < 2 || nargin > 4) + error ("incorrect number of arguments"); + else + { + handle = args(0).string_value (); + host = args(1).string_value (); + + if (nargin > 1) + user = args(2).string_value (); + + if (nargin > 2) + passwd = args(3).string_value (); + + if (!error_state) + { + handles.contents (handle) = curl_handle (host, user, passwd); + + if (error_state) + handles.del (handle); + } + } +#else + error ("__ftp__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_pwd__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_pwd__ (@var{handle})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ + octave_value retval; +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_pwd__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + retval = curl.pwd (); + else + error ("__ftp_pwd__: invalid ftp handle"); + } + } +#else + error ("__ftp_pwd__: not available in this version of Octave"); +#endif + + return retval; +} + +DEFUN_DLD (__ftp_cwd__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_cwd__ (@var{handle}, @var{path})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1 && nargin != 2) + error ("__ftp_cwd__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string path = ""; + + if (nargin > 1) + path = args(1).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.cwd (path); + else + error ("__ftp_cwd__: invalid ftp handle"); + } + } +#else + error ("__ftp_cwd__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_dir__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_dir__ (@var{handle})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ + octave_value retval; +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_dir__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + { + if (nargout == 0) + curl.dir (); + else + { + string_vector sv = curl.list (); + octave_idx_type n = sv.length (); + if (n == 0) + { + string_vector flds (5); + flds(0) = "name"; + flds(1) = "date"; + flds(2) = "bytes"; + flds(3) = "isdir"; + flds(4) = "datenum"; + retval = octave_map (flds); + } + else + { + octave_map st; + Cell filectime (dim_vector (n, 1)); + Cell filesize (dim_vector (n, 1)); + Cell fileisdir (dim_vector (n, 1)); + Cell filedatenum (dim_vector (n, 1)); + + st.assign ("name", Cell (sv)); + + for (octave_idx_type i = 0; i < n; i++) + { + time_t ftime; + bool fisdir; + double fsize; + + curl.get_fileinfo (sv(i), fsize, ftime, fisdir); + + fileisdir (i) = fisdir; + filectime (i) = ctime (&ftime); + filesize (i) = fsize; + filedatenum (i) = double (ftime); + } + st.assign ("date", filectime); + st.assign ("bytes", filesize); + st.assign ("isdir", fileisdir); + st.assign ("datenum", filedatenum); + retval = st; + } + } + } + else + error ("__ftp_dir__: invalid ftp handle"); + } + } +#else + error ("__ftp_dir__: not available in this version of Octave"); +#endif + + return retval; +} + +DEFUN_DLD (__ftp_ascii__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_ascii__ (@var{handle})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_ascii__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.ascii (); + else + error ("__ftp_ascii__: invalid ftp handle"); + } + } +#else + error ("__ftp_ascii__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_binary__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_binary__ (@var{handle})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_binary__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.binary (); + else + error ("__ftp_binary__: invalid ftp handle"); + } + } +#else + error ("__ftp_binary__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_close__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_close__ (@var{handle})\n\ + Undocumented internal function\n\ + @end deftypefn") + { + #ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_close__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + if (!error_state) + handles.del (handle); + } + #else + error ("__ftp_close__: not available in this version of Octave"); + #endif + + return octave_value (); + } + +DEFUN_DLD (__ftp_mode__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_mode__ (@var{handle})\n\ + Undocumented internal function\n\ + @end deftypefn") + { + octave_value retval; + #ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 1) + error ("__ftp_mode__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + retval = (curl.is_ascii () ? "ascii" : "binary"); + else + error ("__ftp_binary__: invalid ftp handle"); + } + } + #else + error ("__ftp_mode__: not available in this version of Octave"); + #endif + + return retval; + } + +DEFUN_DLD (__ftp_delete__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_delete__ (@var{handle}, @var{path})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 2) + error ("__ftp_delete__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string file = args(1).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.del (file); + else + error ("__ftp_delete__: invalid ftp handle"); + } + } +#else + error ("__ftp_delete__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_rmdir__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_rmdir__ (@var{handle}, @var{path})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 2) + error ("__ftp_rmdir__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string dir = args(1).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.rmdir (dir); + else + error ("__ftp_rmdir__: invalid ftp handle"); + } + } +#else + error ("__ftp_rmdir__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_mkdir__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_mkdir__ (@var{handle}, @var{path})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 2) + error ("__ftp_mkdir__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string dir = args(1).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.mkdir (dir); + else + error ("__ftp_mkdir__: invalid ftp handle"); + } + } +#else + error ("__ftp_mkdir__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +DEFUN_DLD (__ftp_rename__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_rename__ (@var{handle}, @var{path})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 3) + error ("__ftp_rename__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string oldname = args(1).string_value (); + std::string newname = args(2).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + curl.rename (oldname, newname); + else + error ("__ftp_rename__: invalid ftp handle"); + } + } +#else + error ("__ftp_rename__: not available in this version of Octave"); +#endif + + return octave_value (); +} + +#ifdef HAVE_CURL +static string_vector +mput_directory (const curl_handle& curl, const std::string& base, + const std::string& dir) +{ + string_vector retval; + + if (! curl.mkdir (dir, false)) + warning ("__ftp_mput__: can not create the remote directory ""%s""", + (base.length () == 0 ? dir : base + + file_ops::dir_sep_str () + dir).c_str ()); + + curl.cwd (dir); + + if (! error_state) + { + unwind_protect_safe frame; + + frame.add_fcn (reset_path, curl); + + std::string realdir = base.length () == 0 ? dir : base + + file_ops::dir_sep_str () + dir; + + dir_entry dirlist (realdir); + + if (dirlist) + { + string_vector files = dirlist.read (); + + for (octave_idx_type i = 0; i < files.length (); i++) + { + std::string file = files (i); + + if (file == "." || file == "..") + continue; + + std::string realfile = realdir + file_ops::dir_sep_str () + file; + file_stat fs (realfile); + + if (! fs.exists ()) + { + error ("__ftp__mput: file ""%s"" does not exist", + realfile.c_str ()); + break; + } + + if (fs.is_dir ()) + { + retval.append (mput_directory (curl, realdir, file)); + + if (error_state) + break; + } + else + { + // FIXME Does ascii mode need to be flagged here? + std::ifstream ifile (realfile.c_str (), std::ios::in | + std::ios::binary); + + if (! ifile.is_open ()) + { + error ("__ftp_mput__: unable to open file ""%s""", + realfile.c_str ()); + break; + } + + curl.put (file, ifile); + + ifile.close (); + + if (error_state) + break; + + retval.append (realfile); + } + } + } + else + error ("__ftp_mput__: can not read the directory ""%s""", + realdir.c_str ()); + } + + return retval; +} +#endif + +DEFUN_DLD (__ftp_mput__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_mput__ (@var{handle}, @var{files})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ + string_vector retval; + +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 2) + error ("__ftp_mput__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string pat = args(1).string_value (); + + if (!error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + { + glob_match pattern (file_ops::tilde_expand (pat)); + string_vector files = pattern.glob (); + + for (octave_idx_type i = 0; i < files.length (); i++) + { + std::string file = files (i); + + file_stat fs (file); + + if (! fs.exists ()) + { + error ("__ftp__mput: file does not exist"); + break; + } + + if (fs.is_dir ()) + { + retval.append (mput_directory (curl, "", file)); + if (error_state) + break; + } + else + { + // FIXME Does ascii mode need to be flagged here? + std::ifstream ifile (file.c_str (), std::ios::in | + std::ios::binary); + + if (! ifile.is_open ()) + { + error ("__ftp_mput__: unable to open file"); + break; + } + + curl.put (file, ifile); + + ifile.close (); + + if (error_state) + break; + + retval.append (file); + } + } + } + else + error ("__ftp_mput__: invalid ftp handle"); + } + } +#else + error ("__ftp_mput__: not available in this version of Octave"); +#endif + + return (nargout > 0 ? octave_value (retval) : octave_value ()); +} + +#ifdef HAVE_CURL +static void +getallfiles (const curl_handle& curl, const std::string& dir, + const std::string& target) +{ + std::string sep = file_ops::dir_sep_str (); + file_stat fs (dir); + + if (!fs || !fs.is_dir ()) + { + std::string msg; + int status = octave_mkdir (dir, 0777, msg); + + if (status < 0) + error ("__ftp_mget__: can't create directory %s%s%s. %s", + target.c_str (), sep.c_str (), dir.c_str (), msg.c_str ()); + } + + if (! error_state) + { + curl.cwd (dir); + + if (! error_state) + { + unwind_protect_safe frame; + + frame.add_fcn (reset_path, curl); + + string_vector sv = curl.list (); + + for (octave_idx_type i = 0; i < sv.length (); i++) + { + time_t ftime; + bool fisdir; + double fsize; + + curl.get_fileinfo (sv(i), fsize, ftime, fisdir); + + if (fisdir) + getallfiles (curl, sv(i), target + dir + sep); + else + { + std::string realfile = target + dir + sep + sv(i); + std::ofstream ofile (realfile.c_str (), + std::ios::out | + std::ios::binary); + + if (! ofile.is_open ()) + { + error ("__ftp_mget__: unable to open file"); + break; + } + + unwind_protect_safe frame2; + + frame2.add_fcn (delete_file, realfile); + + curl.get (sv(i), ofile); + + ofile.close (); + + if (!error_state) + frame2.discard (); + else + frame2.run (); + } + + if (error_state) + break; + } + } + } +} +#endif + +DEFUN_DLD (__ftp_mget__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {} __ftp_mget__ (@var{handle}, @var{files})\n\ +Undocumented internal function\n\ +@end deftypefn") +{ +#ifdef HAVE_CURL + int nargin = args.length (); + + if (nargin != 2 && nargin != 3) + error ("__ftp_mget__: incorrect number of arguments"); + else + { + std::string handle = args(0).string_value (); + std::string file = args(1).string_value (); + std::string target; + + if (nargin == 3) + target = args(2).string_value () + file_ops::dir_sep_str (); + + if (! error_state) + { + const curl_handle curl = handles.contents (handle); + + if (curl.is_valid ()) + { + string_vector sv = curl.list (); + octave_idx_type n = 0; + glob_match pattern (file); + + for (octave_idx_type i = 0; i < sv.length (); i++) + { + if (pattern.match (sv(i))) + { + n++; + + time_t ftime; + bool fisdir; + double fsize; + + curl.get_fileinfo (sv(i), fsize, ftime, fisdir); + + if (fisdir) + getallfiles (curl, sv(i), target); + else + { + std::ofstream ofile ((target + sv(i)).c_str (), + std::ios::out | + std::ios::binary); + + if (! ofile.is_open ()) + { + error ("__ftp_mget__: unable to open file"); + break; + } + + unwind_protect_safe frame; + + frame.add_fcn (delete_file, target + sv(i)); + + curl.get (sv(i), ofile); + + ofile.close (); + + if (!error_state) + frame.discard (); + else + frame.run (); + } + + if (error_state) + break; + } + } + if (n == 0) + error ("__ftp_mget__: file not found"); + } + } + } +#else + error ("__ftp_mget__: not available in this version of Octave"); +#endif + + return octave_value (); +}
--- a/src/link-deps.mk Tue Jul 31 20:46:47 2012 -0400 +++ b/src/link-deps.mk Tue Jul 31 21:57:58 2012 -0400 @@ -3,7 +3,7 @@ if AMCOND_ENABLE_DYNAMIC_LINKING LIBOCTINTERP_LINK_DEPS = else - LIBOCTINTERP_LINK_DEPS = $(DLD_FUNCTIONS_LIBS) + LIBOCTINTERP_LINK_DEPS = $(DLDFCN_LIBS) endif LIBOCTINTERP_LINK_DEPS += \