Code covered by the BSD License  

Highlights from
Chebfun V4

image thumbnail

Chebfun V4

by

 

30 Apr 2009 (Updated )

Numerical computation with functions instead of numbers.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

chebtest(dirname)
function varargout = chebtest(dirname)
%CHEBTEST Probe Chebfun against standard test files.
% CHEBTEST DIRNAME runs each M-file in the directory DIRNAME. Each M-file
% should be a function that takes no inputs and returns a logical scalar
% value. If this value is true, the function is deemed to have 'passed'. 
% If its result is false, the function 'failed'. If the function threw an
% error, it is considered to have 'crashed'. A report is generated in the
% command window, and in a file 'chebtestreport' in the chebfun directory.
%
% CHEBTEST by itself tries to find a directory named 'chebtests' in the
% directory in which chebtest.m resides.
%
% FAILED = CHEBTEST returns a cell array of all functions that either 
% failed or crashed. A report is also generated in the file
%   <chebfun_directory>/chebtests/chebtest_report.txt
%
% CHEBTEST RESTORE restores user preferences prior to CHEBTEST execution.
% CHEBTEST modifies path, warning state, and chebfunpref during execution.
% If a CHEBTEST execution is interrupted, the RESTORE option can be used to
% reset these values. 
%
% Chebtest looks first for the subdirectories below, and executes the tests
% therein in alphabetical order. The tests should be assigned to different
% directories according to the following scheme:
%
%   basic:    Tests of the basic Chebfun routines such as arithmetic
%             operators, constructors, preferences, etc...
%   advanced: Tests for more complex operations of a single chebfun, e.g.
%             norm, max, roots, diff, sum, etc...
%   quasimatrices: Tests involving systems of chebfuns (quasimatrices).
%   linops:   Tests involving linear operators (linops).
%   chebop:   Tests involving non-linear chebops (chebops)
%   ad:       Tests involving automatic differentiation (AD).
%   misc:     Tests that don't fit elsewhere (BVP and IVP solvers, etc).

% Copyright 2011 by The University of Oxford and The Chebfun Developers. 
% See http://www.maths.ox.ac.uk/chebfun/ for Chebfun information.

persistent userpref

if nargin == 1 && ischar(dirname) && strcmpi(dirname,'restore')
    if isempty(userpref)
%         disp('First execution of chebtests (or information has been cleared), preferences unchanged.')
        return
    end
    warning(userpref.warnstate)
    rmpath(userpref.dirname)
    path(path,userpref.path)
    chebfunpref(userpref.pref);
    cheboppref(userpref.oppref);
    disp('Restored values of warning, path, and chebfunpref.')
    return
end

% init some local data
pref = chebfunpref;
tol = pref.eps;
createreport = true;
avgtimes = false; % If turning off, remember to remove line from help comments.
nr_tests = 0;
tests = struct('fun','','path','','funptr',[]);

if verLessThan('matlab','7.6')
    matlabver = ver('matlab');
    disp(['MATLAB version: ',matlabver.Version, ' ', matlabver.Release])
    error('CHEBFUN:chebtest:version',['Chebfun is compatible' ...
        ' with MATLAB 7.6 (R2008a) or above.'])
end

% Chebfun directory
chbfundir = fileparts(which('chebtest.m'));

if nargin < 1
    % Attempt to find "chebtests" directory.
    dirname = fullfile(chbfundir,'chebtests');
end

% Deal with levelX input
if ischar(dirname)
    if ~isempty(str2num(dirname))
        dirname = str2num(dirname);
    elseif strncmpi(dirname,'level',5)
        dirname = fullfile(chbfundir,'chebtests',lower(dirname));
    end
end

if ~exist(dirname,'dir')
    tmpdirname = fullfile(chbfundir,'chebtests',dirname);
    if ~exist(tmpdirname,'dir')
          msg = ['The name "' dirname '" does not appear to be a directory on the path.'];
          error('CHEBFUN:chebtest:nodir',msg)
    else
        dirname = tmpdirname;
    end
end


% Store user preferences for warning and chebfunpref
warnstate = warning;
userpref.warnstate = warnstate;
userpref.path = path;
userpref.pref = pref;
userpref.oppref = cheboppref;
userpref.dirname = dirname;

% Add chebtests directory to the path
addpath(dirname)

% Get the chebtest directory names
subdirlist = dir( fullfile(dirname) );
subdirnames = { subdirlist.name };
numdirs = length(subdirnames);

% Assign an order
defaultOrder = {'basic','advanced','quasimatrices','linops','chebops','ad','misc'};
order = 1:numdirs;
for i = 1:numdirs
    idx = find(strcmp(subdirnames(i),defaultOrder));
    if ~isempty(idx)
        order(order == idx) = order(i);
        order(i) = idx;
    end
end
% Order is stored in inverse format. Flip.
[ignored order] = sort(order);

% loop over the level directories (first)
for i=order

    % is this really a directory?
    if ~subdirlist(i).isdir, continue; end;
    if any(strcmp(subdirnames(i),{,'.','..'})), continue; end;
    
    % add it to the path
    addpath( fullfile(dirname,subdirnames{i}) );

    % Get the names of the tests for this level
    dirlist = dir(fullfile(dirname,subdirnames{i},'*.m'));
    for j=1:length(dirlist)
        nr_tests = nr_tests + 1;
        tests(nr_tests).fun = dirlist(j).name(1:end-2);
        tests(nr_tests).path = [ dirname filesep subdirnames{i} filesep dirlist(j).name ];
        tests(nr_tests).funptr = str2func( dirlist(j).name(1:end-2) );
    end;
    
    % remove the path
    rmpath( fullfile(dirname,subdirnames{i}) )
    
end

% Get the names of any un-sorted tests
dirlist = dir( fullfile(dirname,'*.m') );
for j=1:length(dirlist)
    nr_tests = nr_tests + 1;
    tests(nr_tests).fun = dirlist(j).name(1:end-2);
    tests(nr_tests).path = [ dirname filesep dirlist(j).name ];
    tests(nr_tests).funptr = str2func( dirlist(j).name(1:end-2) );
end

% restore the original path names
path( userpref.path );

% check for duplicate chebtest names
um = unique( { tests(:).fun } , 'first' );
if numel(um) < nr_tests
    warning('CHEBFUN:chebtest:unique','Nonunique chebtest names detected.');
end

% Find the length of the names (for pretty display later).
namelen = 0;
for k = 1:nr_tests
    namelen = max(namelen,length(tests(k).fun));
end
    
% Initialise some storage
failed = zeros(nr_tests,1);  % Pass/fail
t = failed;                        % Vector to store times

% Clear the report file (and check we can open file)
report = fullfile(chbfundir,'chebtests','chebtest_report.txt');
[fid message] = fopen(report,'w+');
if fid < 0
    warning('CHEBFUN:chebtest:fopenfail', ...
        ['Cannot create chebtest report: ', message]);
    createreport = false;
    avgtimes = false;
else
    fclose(fid);
end

% For looking at average time performance.
if avgtimes
    avgfile = fullfile(chbfundir,'chebtests','chebtest_avgs.txt');
    if ~exist(avgfile,'file')
        fclose(fopen(avgfile,'w+'));
    end
    avgfid = fopen(avgfile,'r');    
    avgt = fscanf(avgfid,'%f',inf);
    fclose(avgfid);
    if length(t) ~= length(avgt)-1
        % Number of chebtests has changed, so scrap averages.
        fclose(fopen(avgfile,'w+'));
        avgt = 0*t;
    end
    avgN = avgt(end);
    avgTot = sum(avgt(1:end-1));
else
    avgN = 0; avgt = 0*t;
end

% If java is not enabled, don't display html links.
javacheck = true;
if ~usejava('jvm') || ~usejava('desktop')
    javacheck = false;
end

prevdir = 'bogus';

% Turn off warnings for the test
warning off

% loop through the tests
for j = 1:nr_tests
  fun = tests(j).fun;
  % Print the test directory (if new)
  whichfun = tests(j).path;
  fparts = fileparts(whichfun);
  curdir = fparts(find(fparts==filesep,1,'last')+1:end);
  if ~strcmp(curdir,prevdir)
      prevdir = curdir;
      fprintf('%s tests:\n',curdir);
  end
  % Print the test name
  if javacheck
      link = ['<a href="matlab: edit ''' whichfun '''">' fun '</a>'];
  else
      link = fun;
  end
  ws = repmat(' ',1,namelen+3-length(fun)-length(num2str(j)));
  msg = ['  Function #' num2str(j) ' (' link ')... ', ws ];
  msg = strrep(msg,'\','\\');  % escape \ for fprintf
  numchar = fprintf(msg);
  % Execute the test
  try
    close all
    chebfunpref('factory');
    cheboppref('factory');
    chebfunpref('eps',tol);
    tic
    pass = feval( tests(j).funptr );
    t(j) = toc;
    failed(j) = ~ all(pass);
    if failed(j)
      fprintf('FAILED\n')
      
      % Create an error report entry for a failure
      if createreport
        fid = fopen(report,'a');
        fprintf(fid,[fun '  (failed) \n']);
        fprintf(fid,['pass: ''' int2str(pass) '''\n\n']);
        fclose(fid);
      end

    else
        avgt(j) = (avgN*avgt(j)+t(j))/(avgN+1);
        if avgN == 0
          fprintf('passed in %2.3fs \n',t(j))
        else
          fprintf('passed in %2.3fs (avg %2.3fs)\n',t(j),avgt(j))
        end
      %pause(0.1)
      %fprintf( repmat('\b',1,numchar) )
    end
  catch ME
    failed(j) = -1;
    fprintf('CRASHED: ')
    msg = ME;
    lf = findstr(sprintf('\n'),msg.message); 
    if ~isempty(lf), msg.message(1:lf(end))=[]; end
    fprintf([msg.message '\n'])
   
    % Create an error report entry for a crash
    if createreport
        fid = fopen(report,'a');
        fprintf(fid,[fun '  (crashed) \n']);
        fprintf(fid,['identifier: ''' msg.identifier '''\n']);
        fprintf(fid,['message: ''' msg.message '''\n']);
        for k = 1:size(msg.stack,1)
            fprintf(fid,[msg.stack(k).file ' \tline ' int2str(msg.stack(k).line) '\n']);
        end
    fprintf(fid,'\n');
    fclose(fid);
    end

  end
  
end
warning(warnstate)
chebfunpref(pref);
cheboppref(userpref.oppref);

% Final output
ts = sum(t); tm = ts/60;
if avgN == 0
    fprintf('Total time: %1.1f seconds = %1.1f minutes \n',ts,tm)
else
    fprintf('Total time: %1.1f seconds (Lifetime Avg: %1.1f seconds)\n',ts,avgTot)
end

if all(~failed)
  fprintf('\nAll tests passed!\n')
  failfun = [];
else
  fprintf('\n%i failed and %i crashed\n',sum(failed>0),sum(failed<0))
  failfun = tests(failed~=0);
  if createreport
      if javacheck
          link = ['<a href="matlab: edit ''' report '''">chebtest_report.txt</a>'];
      else
          link = report;
      end
      msg = [' Error report available here: ' link '. ' ];
      msg = strrep(msg,'\','\\');  % escape \ for fprintf
      numchar = fprintf(msg); fprintf('\n')
  end
end

% Update average times (if enabled and no failures)
if avgtimes && all(~failed)
    avgfid = fopen(avgfile,'w+');    
    for k = 1:size(t,1)
        fprintf(avgfid,'%f\n',avgt(k));
    end
    fprintf(avgfid,'%d \n',avgN+1);
    fclose(avgfid);
end

% Output args
if nargout > 0
    if isempty(failfun)
        varargout{1} = [];
    else
        varargout{1} = { failfun(:).fun }; 
    end
else
    fprintf('    ');
    for k = 1:sum(abs(failed))
        fun = failfun(k).fun;
        whichfun = failfun(k).path;
        if javacheck         
            link = ['<a href="matlab: edit ''' whichfun '''">' fun '</a>    '];
            link = strrep(link,'\','\\');  % maintain fprintf compatability in MSwin
        else
            link = fun;
        end
        fprintf([ link '    ' ])
    end
    fprintf('\n');
end
if nargout > 0, varargout{2} = t; end

if createreport && any(failed)
    fid = fopen(report,'a');

    % GET SYSTEM INFORMATION
    % find platform OS
    if ispc
        platform = [system_dependent('getos'),' ',system_dependent('getwinsys')];
    elseif ismac
        [fail, input] = unix('sw_vers');
        if ~fail
            platform = strrep(input, 'ProductName:', '');
            platform = strrep(platform, sprintf('\t'), '');
            platform = strrep(platform, sprintf('\n'), ' ');
            platform = strrep(platform, 'ProductVersion:', ' Version: ');
            platform = strrep(platform, 'BuildVersion:', 'Build: ');
        else
            platform = system_dependent('getos');
        end
    else    
        platform = system_dependent('getos');
    end
    % display platform type
    fprintf(fid,['MATLAB Version ',version,'\n']);
    % display operating system
    fprintf(fid,['Operating System: ',  platform,'\n']);
    % display first line of Java VM version info
    fprintf(fid,['Java VM Version: ',...
    char(strread(version('-java'),'%s',1,'delimiter','\n'))]);

    fclose(fid);
elseif createreport && ~any(failed)
    delete(report);
end

Contact us