Jaroslav,

Since you are listed as maintainer of the octave-forge linear-algebra package:
Would you mind if I commit the attached updated funm and thfm functions?


Long explanation below:

Inspired by the recent discussion about matrix functions and funm.m (see thread here: https://mailman.cae.wisc.edu/pipermail/help-octave/2010-December/043907.html), and because I could use a better funm.m myself, I've looked a bit into:

(1) augmenting the current, primitive (some say: naive) funm.m in octave-forge that I contributed 11 years ago and that has been untouched since then, with some very basic improvements;

(2) incorporating N. Higham's funm stuff from http://www.maths.manchester.ac.uk/~higham/NAMF/ (funm_files.tar.gz).

(3) alternatively, incorporating (parts of) N. Higham's Matrix Function Toolbox (GPL v3) at
  http://www.maths.manchester.ac.uk/~higham/mftoolbox/
especially funm_simple.m

DISCLAIMER: I'm not a mathematician and I'm no expert in linear algebra.
Yet funm.m is fairly vital for some of my applications.


Anyway, as to (1):
------------------
The existing funm.m can be improved by:
- Allowing function handles as input arg
- Checking whether the function-to-be-applied is one included in octave-forge's thfm.m and if so, invoke thfm() (which resorts to expm() for some functions); except for logm which has recently been improved in octave-core.

The "trick" suggested by Davies (2007), as indicated by Higham (i.e., adding noise, see bottom of https://mailman.cae.wisc.edu/pipermail/help-octave/2010-December/044012.html) is easy to incorporate too.

I've attached the resulting funm.m for review. An improved thfm.m is attached too as the old one called funm in turn (which would imply an endless loop). If you don't object, I'll commit this version to octave-forge next or following week, as a first update and place holder until (hopefully) a much better version becomes available. I know funm.m is still ultra-basic, but it's better than what's presently available.


As to (2):
----------
As far as I understand, Higham's (and current Matlab's) funm.m can only invoke functions that have Taylor expansion, or an easily coded series of successive/recursive derivatives. Helper function files built for this have to be supplied by the user. TMW site has an example using (exp() + sin()). In my case I invoke a.o. (modified) Bessel functions for which simple relations exist between successive derivatives (and they can easily be written as Taylor expansions anyway).
But in case of other functions, Higham's funm version may pose a problem.
Moreover, I have the impression that for small, diagonizable matrices, Higham's (and Matlab's) funm.m may be unduly demanding and expensive.


As to (3):
----------
The funm_simple.m mentioned in there is only marginally better than the old one in octave-forge.


Philip




%USAGE  y = thfm ( x, MODE )
%
%       trigonometric/hyperbolic functions of square matrix x
%
%MODE   cos   sin   tan   sec   csc   cot
%       cosh  sinh  tanh  sech  csch  coth
%       acos  asin  atan  asec  acsc  acot
%       acosh asinh atanh asech acsch acoth
%       sqrt  log   exp
%
%NOTE		--- IMPORTANT ---
%	This algorithm does  NOT USE an eigensystem
%	similarity transformation. It maps the MODE
%	functions to functions of expm, logm and sqrtm, 
%       which are known to be robust with respect to
%	non-diagonalizable ('defective') x
%
%EXA	thfm( x ,'cos' )  calculates  matrix cosinus
%	EVEN IF input matrix x IS NOT DIAGONALIZABLE
%
%ASSOC	expm, sqrtm, logm, funm
% Copyright	(C) 2001 Rolf Fabian <fab...@tu-cottbus.de>
% 010213
%	published under current GNU GENERAL PUBLIC LICENSE

% 2001-03-15 Paul Kienzle
%     * extend with inverse functions and power functions
%     * optimize handling of real input
% 2011-03-27 Philip Nienhuis
%     * Dropped call to funm at bottom (as funm calls thfm...)

function y=thfm(x,M)
				#% minimal arg check only
  if	nargin~=2||~ischar(M)||ischar(x)	
    usage ("y = thfm (x, MODE)");
  endif

  ## look for known functions of sqrt, log, exp
  I = eye(size(x));
  match = 1;
  len =  length(M);
  if	len==3
    
    if	M=='cos',  
      if (isreal(x))     y = real( expm( i*x ) );
      else               y = ( expm( i*x ) + expm( -i*x ) ) / 2;
      endif
      
    elseif	M=='sin',
      if (isreal(x))     y = imag( expm( i*x ) );
      else               y = ( expm( i*x ) - expm( -i*x ) ) / (2*i);
      endif
      
    elseif	M=='tan',
      if (isreal(x))     t = expm( i*x );    y = imag(t)/real(t);
      else     	         t = expm( -2*i*x ); y = -i*(I-t)/(I+t);
      endif
      
    elseif	M=='cot',		% == cos/sin
      if (isreal(x))     t = expm( i*x );    y = real(t)/imag(t);
      else	         t = expm( -2*i*x ); y = i*(I+t)/(I-t);
      endif
      
    elseif	M=='sec',  
      if (isreal(x))     y = inv( real(expm(i*x)) );
      else               y = inv( expm(i*x)+expm(-i*x) )*2 ;
      endif
      
    elseif	M=='csc',  
      if (isreal(x))     y = inv( imag(expm(i*x)) );
      else               y = inv( expm(i*x)-expm(-i*x) )*2i;
      endif

    elseif    M=='log',  y = logm(x);
      
    elseif    M=='exp',  y = expm(x);
      
    else match = 0;

    endif
    
  elseif	len==4
    
    if      M=='cosh',   y = ( expm(x)+expm(-x) )/2;
      
    elseif  M=='sinh',   y = ( expm(x)-expm(-x) )/2;
      
    elseif  M=='tanh'    t = expm( -2*x ); y = (I - t)/(I + t);
     
    elseif  M=='coth', 	 t = expm( -2*x ); y = (I + t)/(I - t);
      
    elseif  M=='sech',   y = 2 * inv( expm(x) + expm(-x) );
      
    elseif  M=='csch',   y = 2 * inv( expm(x) - expm(-x) );
      
    elseif  M=='asin',   y = -i * logm( i*x + sqrtm(I - x*x) );
      
    elseif  M=='acos',   y =  i * logm( x - i*sqrtm(I - x*x) );

    elseif  M=='atan',   y = -i/2 * logm( (I + i*x)/(I - i*x) );

    elseif  M=='acot',   y =  i/2 * logm( (I + i*x)/(i*x - I) );

    elseif  M=='asec',   y = i * logm( ( I - sqrtm(I - x*x) ) / x );

    elseif  M=='acsc',   y = -i * logm( i*( I + sqrtm(I - x*x) ) / x );

    elseif  M=='sqrt',   y = sqrtm(x);

    else match = 0;

    end

  elseif   len==5

    if      M=='asinh',  y = logm( x + sqrtm (x*x + I) );
      
    elseif  M=='acosh',  y = logm( x + sqrtm (x*x - I) );
      
    elseif  M=='atanh',  y = logm( (I + x)/(I - x) ) / 2;
      
    elseif  M=='acoth',  y = logm( (I + x)/(x - I) ) / 2;

    elseif  M=='asech',  y = logm( (I + sqrtm (I - x*x)) / x );

    elseif  M=='acsch',  y = logm( (I + sqrtm (I + x*x)) / x );

    else match = 0;

    endif

  else match = 0;

  endif

  ## if no known function found, issue warning
  if (match == 0)
    warning ("thfm doesn't support function M");
  endif
endfunction
## Copyright (C) 2000, 2011 P.R. Nienhuis
##
## This program 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 2 of the License, or
## (at your option) any later version.
##
## This program 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/>.

## -*- texinfo -*-
## @deftypefn {Function File} [ @var{B} ] = funm (@var{A}, @var{F})
## Compute matrix equivalent of function F; F can be a function name or
## a function handle.
##
## For trigonometric and hyperbolic functions, thfm() is automatically
## invoked as that is based on expm() and diagonalization is avoided.
## For other functions diagonalization is invoked, which implies that
## -depending on the properties of input matrix @var{A}- the results
## can be very inaccurate WITHOUT ANY WARNING. For easy diagonizable and
## stable matrices results of funm will be sufficiently accurate.
##
## Note that you should not use funm for 'sqrt', 'log' or 'exp'; instead
## use sqrtm, logm and expm as these are more robust.
##
## Examples:
##
## @example
##   B = funm (A, sin);
##   (Compute matrix equivalent of sin() )
## @end example
##
## @example
##   function bk1 = besselk1 (x)
##      bk1 = besselk(x, 1);
##   endfunction 
##   B = funm (A, besselk1);
##   (Compute matrix equivalent of bessel function K1(); a helper function
##    is needed here to convey extra args for besselk() )
## @end example
##
## @seealso thfm, expm, logm, sqrtm
##
## @end deftypefn

## Author: P.R. Nienhuis <prnienh...@users.sf.net>
## Additions by P. Kienzle, .........
## 2001-03-01 Paul Kienzle
##            * Many code improvements
## 2011-03-27 Philip Nienhuis
##            * Function handles
##            * Texinfo header
##            * Fallback to thfm for trig & hyperb funcs to avoid diagonalization

function B = funm (A, name)

persistent thfuncs  = {"cos",   "sin",   "tan",   "sec",   "csc",   "cot",   \
                       "cosh",  "sinh",  "tanh",  "sech",  "csch",  "coth",  \
                       "acos",  "asin",  "atan",  "asec",  "acsc",  "acot",  \
                       "acosh", "asinh", "atanh", "asech", "acsch", "acoth", \
                      }

  # Function handle supplied? 
  try 
    ishndl = isstruct (functions (name));
	fname = functions (name).function;
  catch
    ishdnl = 0;
	fname = ' '
  end_try_catch

  if (nargin < 2 || (!(ischar (name) || ishndl)) || ischar (A))
    usage ("B = funm (A, 'f'");
  endif
  
  if (~isempty (find (ismember (thfuncs, fname))))
    # Use more robust thfm ()
	if (ishndl), name = fname; endif
    B = thfm (A, name);
  else
    # Simply invoke eigenvalues. Note: risk for repeated eigenvalues!!
	# Modeled after suggestion by N. Higham (based on R. Davis, 2007)
	## FIXME  Do we need automatic setting of TOL?
	tol = 1.e-15;
    [V, D] = eig (A + tol * randn (size(A)));
    D = diag (feval (name, diag(D)));
    B = V * D / V;
  endif  
  
endfunction

------------------------------------------------------------------------------
Enable your software for Intel(R) Active Management Technology to meet the
growing manageability and security demands of your customers. Businesses
are taking advantage of Intel(R) vPro (TM) technology - will your software 
be a part of the solution? Download the Intel(R) Manageability Checker 
today! http://p.sf.net/sfu/intel-dev2devmar
_______________________________________________
Octave-dev mailing list
Octave-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/octave-dev

Reply via email to