Mercurial > hg > octave-max
changeset 13029:50db905c3cf1
maint: periodic merge of stable to default
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 30 Aug 2011 14:37:25 -0400 |
parents | b9a89ca0fb75 (diff) 9b191d0e547f (current diff) |
children | b646413c3d0e |
files | doc/interpreter/matrix.txi scripts/plot/private/__print_parse_opts__.m src/DLD-FUNCTIONS/__magick_read__.cc src/data.cc src/oct-parse.yy |
diffstat | 418 files changed, 8900 insertions(+), 5842 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS +++ b/NEWS @@ -1,3 +1,67 @@ +Summary of important user-visible changes for version 3.6: +--------------------------------------------------------- + + ** The PCRE library is now required to build Octave. + + ** Octave now features a profiler, thanks to the work of Daniel Kraft + under the Google Summer of Code mentorship program. The manual has + been updated to reflect this addition. + + ** strread, textscan, and textread have been completely revamped. + + They now support nearly all Matlab functionality including: + + * ML-compatible whitespace and delimiter defaults + + * ML-compatible options: 'whitespace', treatasempty', + format string repeat count, user-specified comment style, uneven-length + output arrays, %n and %u conversion specifiers (provisionally) + + ** Certain string functions have been modified for greater Matlab compatibility + and for 15X greater performance when operating on cell array of strings. + + deblank : Now requires character or cellstr input + strtrim : Now requires character or cellstr input. + No longer trims nulls ("\0") from string for ML compatibility. + strmatch: Follows documentation precisely and ignores trailing spaces + in pattern and in string. Note that Matlab documents this + behavior but the implementation does *not* always follow it. + + ** New functions added. + + iscolumn + issrow + zscore + profile + profshow + + ** Deprecated functions. + + The following functions were deprecated in Octave 3.2 and have been + removed from Octave 3.6. + + create_set spcholinv splu + dmult spcumprod spmax + iscommand spcumsum spmin + israwcommand spdet spprod + lchol spdiag spqr + loadimage spfind spsum + mark_as_command sphcat spsumsq + mark_as_rawcommand spinv spvcat + spatan2 spkron str2mat + spchol splchol unmark_command + spchol2inv split unmark_rawcommand + + The following functions have been deprecated in Octave 3.6 and will + be removed from Octave 3.10 (or whatever version is the second major + release after 3.6): + + cut is_duplicate_entry + cor polyderiv + corrcoef studentize + __error_text__ sylvester_matrix + error_text + Summary of important user-visible changes for version 3.4.2: -----------------------------------------------------------
--- a/build-aux/common.mk +++ b/build-aux/common.mk @@ -162,8 +162,6 @@ RDYNAMIC_FLAG = @RDYNAMIC_FLAG@ -RLD_FLAG = @RLD_FLAG@ - FLIBS = @FLIBS@ LIBOCTINTERP = @LIBOCTINTERP@ @@ -535,8 +533,12 @@ -e "s|%OCTAVE_CONF_MAGICK_LDFLAGS%|\"${MAGICK_LDFLAGS}\"|" \ -e "s|%OCTAVE_CONF_MAGICK_LIBS%|\"${MAGICK_LIBS}\"|" \ -e 's|%OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%|\"@MKOCTFILE_DL_LDFLAGS@\"|' \ + -e "s|%OCTAVE_CONF_OCTAVE_LINK_DEPS%|\"${OCTAVE_LINK_DEPS}\"|" \ + -e "s|%OCTAVE_CONF_OCTAVE_LINK_OPTS%|\"${OCTAVE_LINK_OPTS}\"|" \ -e "s|%OCTAVE_CONF_OCTINCLUDEDIR%|\"${octincludedir}\"|" \ -e "s|%OCTAVE_CONF_OCTLIBDIR%|\"${octlibdir}\"|" \ + -e "s|%OCTAVE_CONF_OCT_LINK_DEPS%|\"${OCT_LINK_DEPS}\"|" \ + -e "s|%OCTAVE_CONF_OCT_LINK_OPTS%|\"${OCT_LINK_OPTS}\"|" \ -e "s|%OCTAVE_CONF_OPENGL_LIBS%|\"${OPENGL_LIBS}\"|" \ -e "s|%OCTAVE_CONF_PREFIX%|\"${prefix}\"|" \ -e "s|%OCTAVE_CONF_PTHREAD_CFLAGS%|\"${PTHREAD_CFLAGS}\"|" \ @@ -551,7 +553,6 @@ -e "s|%OCTAVE_CONF_RDYNAMIC_FLAG%|\"${RDYNAMIC_FLAG}\"|" \ -e "s|%OCTAVE_CONF_READLINE_LIBS%|\"${READLINE_LIBS}\"|" \ -e "s|%OCTAVE_CONF_REGEX_LIBS%|\"${REGEX_LIBS}\"|" \ - -e "s|%OCTAVE_CONF_RLD_FLAG%|\"${RLD_FLAG}\"|" \ -e "s|%OCTAVE_CONF_SED%|\"${SED}\"|" \ -e "s|%OCTAVE_CONF_SHARED_LIBS%|\"${SHARED_LIBS}\"|" \ -e "s|%OCTAVE_CONF_SHLEXT%|\"${SHLEXT}\"|" \
--- a/configure.ac +++ b/configure.ac @@ -27,13 +27,13 @@ EXTERN_CFLAGS="$CFLAGS" EXTERN_CXXFLAGS="$CXXFLAGS" -AC_INIT([GNU Octave], [3.4.2], [http://octave.org/bugs.html], [octave]) +AC_INIT([GNU Octave], [3.5.0+], [http://octave.org/bugs.html], [octave]) dnl PACKAGE_VERSION is set by the AC_INIT VERSION arg OCTAVE_VERSION="$PACKAGE_VERSION" -OCTAVE_API_VERSION_NUMBER="45" +OCTAVE_API_VERSION_NUMBER="44" OCTAVE_API_VERSION="api-v$OCTAVE_API_VERSION_NUMBER+" -OCTAVE_RELEASE_DATE="2011-06-24" +OCTAVE_RELEASE_DATE="2011-01-22" OCTAVE_COPYRIGHT="Copyright (C) 2011 John W. Eaton and others." AC_SUBST(OCTAVE_VERSION) AC_SUBST(OCTAVE_API_VERSION_NUMBER) @@ -1157,7 +1157,7 @@ AC_ARG_ENABLE([dl], [AS_HELP_STRING([--enable-dl], - [create shared libraries (not all systems)])], [ + [allow loading of dynamically linked modules (not all systems)])], [ case "${enableval}" in yes) ENABLE_DYNAMIC_LINKING=true ;; no) ENABLE_DYNAMIC_LINKING=false ;; @@ -1170,16 +1170,6 @@ AC_MSG_ERROR([You can't disable building static AND shared libraries!]) fi -AC_ARG_ENABLE(rpath, - [AS_HELP_STRING([--enable-rpath], - [override the default link options for rpath; e.g., --enable-rpath='-rpath $(octlibdir)'])], - [ if test "$enableval" = no; then use_rpath=false; - else - use_rpath=true - if test "$enableval" = yes; then true; - else enable_rpath_arg="$enableval"; fi - fi], [use_rpath=true]) - CPICFLAG=-fPIC CXXPICFLAG=-fPIC FPICFLAG=-fPIC @@ -1200,7 +1190,6 @@ DL_LDFLAGS='$(SH_LDFLAGS)' MKOCTFILE_DL_LDFLAGS='$(DL_LDFLAGS)' SONAME_FLAGS= -RLD_FLAG= NO_OCT_FILE_STRIP=false TEMPLATE_AR='$(AR)' TEMPLATE_ARFLAGS="$ARFLAGS" @@ -1221,14 +1210,12 @@ ;; *-*-freebsd*) SH_LDFLAGS="-shared -Wl,-x" - RLD_FLAG='-Wl,-rpath -Wl,$(octlibdir)' ;; alpha*-dec-osf*) CPICFLAG= CXXPICFLAG= FPICFLAG= SH_LDFLAGS="-shared -Wl,-expect_unresolved -Wl,'*'" - RLD_FLAG='-Wl,-rpath -Wl,$(octlibdir)' ;; *-*-darwin*) DL_LDFLAGS='-bundle -bundle_loader $(top_builddir)/src/octave $(LDFLAGS)' @@ -1335,11 +1322,9 @@ *-*-linux* | *-*-gnu*) MKOCTFILE_DL_LDFLAGS="-shared -Wl,-Bsymbolic" SONAME_FLAGS='-Wl,-soname -Wl,$@' - RLD_FLAG='-Wl,-rpath -Wl,$(octlibdir)' ;; i[[3456]]86-*-sco3.2v5*) SONAME_FLAGS='-Wl,-h -Wl,$@' - RLD_FLAG= SH_LDFLAGS=-G ;; rs6000-ibm-aix* | powerpc-ibm-aix*) @@ -1356,7 +1341,6 @@ fi SHLEXT=sl SH_LDFLAGS="-shared -fPIC" - RLD_FLAG='-Wl,+b -Wl,$(octlibdir)' library_path_var=SHLIB_PATH ;; ia64*-hp-hpux*) @@ -1366,13 +1350,11 @@ FPICFLAG=+Z fi SH_LDFLAGS="-shared -fPIC" - RLD_FLAG='-Wl,+b -Wl,$(octlibdir)' ;; *-sgi-*) CPICFLAG= CXXPICFLAG= FPICFLAG= - RLD_FLAG='-rpath $(octlibdir)' ;; sparc-sun-sunos4*) if test "$ac_cv_f77_compiler_gnu" = yes; then @@ -1382,7 +1364,6 @@ fi SH_LD=ld SH_LDFLAGS="-assert nodefinitions" - RLD_FLAG='-L$(octlibdir)' ;; sparc-sun-solaris2* | i386-pc-solaris2*) if test "$ac_cv_f77_compiler_gnu" = yes; then @@ -1402,7 +1383,6 @@ CXXPICFLAG=-KPIC SH_LDFLAGS=-G fi - RLD_FLAG='-R $(octlibdir)' ## Template closures in archive libraries need a different mechanism. if test "$GXX" = yes; then true @@ -1416,14 +1396,6 @@ AM_CONDITIONAL([AMCOND_BUILD_COMPILED_AUX_PROGRAMS], [test x$BUILD_COMPILED_AUX_PROGRAMS = xtrue]) -if $use_rpath; then - if test -n "$enable_rpath_arg"; then - RLD_FLAG="$enable_rpath_arg" - fi -else - RLD_FLAG="" -fi - AC_MSG_NOTICE([defining FPICFLAG to be $FPICFLAG]) AC_MSG_NOTICE([defining CPICFLAG to be $CPICFLAG]) AC_MSG_NOTICE([defining CXXPICFLAG to be $CXXPICFLAG]) @@ -1445,7 +1417,6 @@ AC_MSG_NOTICE([defining MKOCTFILE_DL_LDFLAGS to be $MKOCTFILE_DL_LDFLAGS]) AC_MSG_NOTICE([defining SONAME_FLAGS to be $SONAME_FLAGS]) AC_MSG_NOTICE([defining NO_OCT_FILE_STRIP to be $NO_OCT_FILE_STRIP]) -AC_MSG_NOTICE([defining RLD_FLAG to be $RLD_FLAG]) AC_MSG_NOTICE([defining TEMPLATE_AR to be $TEMPLATE_AR]) AC_MSG_NOTICE([defining TEMPLATE_ARFLAGS to be $TEMPLATE_ARFLAGS]) AC_MSG_NOTICE([defining CRUFT_DLL_DEFS to be $CRUFT_DLL_DEFS]) @@ -1474,7 +1445,6 @@ AC_SUBST(MKOCTFILE_DL_LDFLAGS) AC_SUBST(SONAME_FLAGS) AC_SUBST(NO_OCT_FILE_STRIP) -AC_SUBST(RLD_FLAG) AC_SUBST(TEMPLATE_AR) AC_SUBST(TEMPLATE_ARFLAGS) AC_SUBST(CRUFT_DLL_DEFS) @@ -1488,28 +1458,42 @@ AC_CHECK_FUNCS(getpwnam, [], [AC_CHECK_LIB(sun, getpwnam)]) -NO_UNDEFINED_LDFLAG= case "$canonical_host_type" in *-*-mingw*) if test "$have_msvc" = "yes"; then AC_CHECK_LIB(dirent, opendir) LIBS="$LIBS -ladvapi32 -lgdi32 -lws2_32 -luser32 -lkernel32" - NO_UNDEFINED_LDFLAG=-no-undefined else LIBS="$LIBS -lgdi32 -lws2_32 -luser32 -lkernel32" - NO_UNDEFINED_LDFLAG=-no-undefined fi LIBS="$LIBS -lgdi32 -lws2_32 -luser32 -lkernel32" - NO_UNDEFINED_LDFLAG=-no-undefined ;; *-*-msdosmsvc*) AC_CHECK_LIB(dirent, opendir) LIBS="$LIBS -ladvapi32 -lgdi32 -lws2_32 -luser32 -lkernel32" - NO_UNDEFINED_LDFLAG=-no-undefined ;; esac + +AC_ARG_ENABLE([no-undefined], + [AS_HELP_STRING([--enable-no-undefined], + [pass -no-undefined to libtool when linking linking Octave and its shared libraries (on by default)])], + [case "${enableval}" in + yes) NO_UNDEFINED_LDFLAG="-no-undefined" ;; + no) NO_UNDEFINED_LDFLAG="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-link-all-depenencies]) ;; + esac], [NO_UNDEFINED_LDFLAG="-no-undefined"]) AC_SUBST(NO_UNDEFINED_LDFLAG) +AC_ARG_ENABLE([link-all-dependencies], + [AS_HELP_STRING([--enable-link-all-dependencies], + [link Octave and its shared libraries with all dependencies, not just those immediately referenced (should not be needed on most systems)])], + [case "${enableval}" in + yes) link_all_deps=true ;; + no) link_all_deps=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-link-all-depenencies]) ;; + esac], [link_all_deps=false]) +AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS], [test x$link_all_deps = xtrue]) + ### Type stuff. AC_TYPE_MODE_T @@ -1685,7 +1669,7 @@ OCTAVE_CXX_FLAG(-rdynamic, [RDYNAMIC_FLAG=-rdynamic]) ;; shl_load) - shl_load_api=true + shl_load_api=truenn DL_API_MSG="(shl_load)" AC_DEFINE(HAVE_SHL_LOAD_API, 1, [Define if your system has shl_load and shl_findsym for dynamic linking]) ;; @@ -1704,12 +1688,18 @@ DL_LIBS="$lt_cv_dlopen_libs" AC_SUBST(DL_LIBS) + ## Disable dynamic linking if capability is not present. if $dlopen_api || $shl_load_api || $loadlibrary_api || $dyld_api; then - ENABLE_DYNAMIC_LINKING=true - AC_DEFINE(ENABLE_DYNAMIC_LINKING, 1, [Define if using dynamic linking]) + true + else + ENABLE_DYNAMIC_LINKING=false fi fi +if $ENABLE_DYNAMIC_LINKING; then + AC_DEFINE(ENABLE_DYNAMIC_LINKING, 1, [Define if using dynamic linking]) +fi + AM_CONDITIONAL([AMCOND_ENABLE_DYNAMIC_LINKING], [test x$ENABLE_DYNAMIC_LINKING = xtrue])
--- a/doc/faq/OctaveFAQ.texi +++ b/doc/faq/OctaveFAQ.texi @@ -63,7 +63,7 @@ * Getting Octave:: * Installation:: * Common problems:: -* How do I ...?:: +* Using Octave:: * @sc{Matlab} compatibility:: * Index:: @end menu @@ -780,15 +780,16 @@ @end itemize @end itemize -@node How do I ...? -@chapter How do I ...? +@node Using Octave +@chapter Using Octave @menu * How do I set the number of displayed decimals?:: +* How does Octave solve linear systems?:: @end menu @cindex Tips and tricks -@cindex How do I @dots{} ? +@cindex Using Octave @node How do I set the number of displayed decimals? @section How do I set the number of displayed decimals? @@ -804,6 +805,18 @@ @end group @end example +@node How does Octave solve linear systems? +@section How does Octave solve linear systems? + +@cindex backslash operator + +In addition to consulting Octave's source for the precise details, the +Octave manual contains a complete high-level description of the +algorithm that Octave uses to decide how to solve a particular linear +system, e.g. how the backslash operator @code{A\x} will be interpreted. +Sections ``Techniques Used for Linear Algebra'' and ``Linear Algebra on +Sparse Matrices'' from the manual describe this procedure. + @node @sc{Matlab} compatibility @chapter Porting programs from @sc{Matlab} to Octave
--- a/doc/interpreter/container.txi +++ b/doc/interpreter/container.txi @@ -563,16 +563,11 @@ @example @group c@{1:2@} + @result{} ans = a string @result{} ans = - (, - [1] = a string - [2] = - 0.593993 0.627732 0.377037 0.033643 - - ,) @end group @end example
--- a/doc/interpreter/contributors.in +++ b/doc/interpreter/contributors.in @@ -1,5 +1,6 @@ Ben Abbott Andy Adler +Giles Anderson Joel Andersson Muthiah Annamalai Shai Ayal @@ -148,9 +149,11 @@ Stefan Monnier Antoine Moreau Kai P. Mueller +Hannes Müller Victor Munoz Carmen Navarrete Todd Neal +Philip Nienhuis Al Niessner Rick Niles Takuji Nishimura @@ -206,6 +209,7 @@ Daniel J. Sebald Dmitri A. Sergatskov Baylis Shanks +Andriy Shinkarchuck Joseph P. Skudlarek John Smith Julius Smith @@ -232,6 +236,7 @@ Frederick Umminger Utkarsh Upadhyay Stefan van der Walt +David Wells Peter Van Wieren James R. Van Zandt Gregory Vanuxem @@ -244,6 +249,7 @@ Andreas Weingessel Michael Weitzel Fook Fah Yap +Sean Young Michael Zeising Federico Zenith Alex Zvoleff
--- a/doc/interpreter/debug.txi +++ b/doc/interpreter/debug.txi @@ -35,6 +35,8 @@ * Breakpoints:: * Debug Mode:: * Call Stack:: +* Profiling:: +* Profiler Example:: @end menu @node Entering Debug Mode @@ -182,3 +184,256 @@ @DOCSTRING(dbup) @DOCSTRING(dbdown) + +@node Profiling +@section Profiling +@cindex profiler +@cindex code profiling + +Octave supports profiling of code execution on a per-function level. If +profiling is enabled, each call to a function (supporting built-ins, +operators, functions in oct- and mex-files, user-defined functions in +Octave code and anonymous functions) is recorded while running Octave +code. After that, this data can aid in analyzing the code behaviour, and +is in particular helpful for finding ``hot spots'' in the code which use +up a lot of computation time and are the best targets to spend +optimization efforts on. + +The main command for profiling is @code{profile}, which can be used to +start or stop the profiler and also to query collected data afterwards. +The data is returned in an Octave data structure which can then be +examined or further processed by other routines or tools. + +@DOCSTRING(profile) + +An easy way to get an overview over the collected data is +@code{profshow}. This function takes the profiler data returned by +@code{profile} as input and prints a flat profile, for instance: + +@example +@group + Function Attr Time (s) Calls +---------------------------------------- + >myfib R 2.195 13529 +binary <= 0.061 13529 + binary - 0.050 13528 + binary + 0.026 6764 +@end group +@end example + +This shows that most of the runtime was spent executing the function +@samp{myfib}, and some minor proportion evaluating the listed binary +operators. Furthermore, it is shown how often the function was called +and the profiler also records that it is recursive. + +@DOCSTRING(profshow) + +@node Profiler Example +@section Profiler Example + +Below, we will give a short example of a profiler session. See also +@ref{Profiling} for the documentation of the profiler functions in +detail. Consider the code: + +@example +@group +global N A; + +N = 300; +A = rand (N, N); + +function xt = timesteps (steps, x0, expM) + global N; + + if (steps == 0) + xt = NA (N, 0); + else + xt = NA (N, steps); + x1 = expM * x0; + xt(:, 1) = x1; + xt(:, 2 : end) = timesteps (steps - 1, x1, expM); + endif +endfunction + +function foo () + global N A; + + initial = @@(x) sin (x); + x0 = (initial (linspace (0, 2 * pi, N)))'; + + expA = expm (A); + xt = timesteps (100, x0, expA); +endfunction + +function fib = bar (N) + if (N <= 2) + fib = 1; + else + fib = bar (N - 1) + bar (N - 2); + endif +endfunction +@end group +@end example + +If we execute the two main functions, we get: + +@example +@group +tic; foo; toc; +@result{} Elapsed time is 2.37338 seconds. + +tic; bar (20); toc; +@result{} Elapsed time is 2.04952 seconds. +@end group +@end example + +But this does not give much information about where this time is spent; +for instance, whether the single call to @code{expm} is more expensive +or the recursive time-stepping itself. To get a more detailed picture, +we can use the profiler. + +@example +@group +profile on; +foo; +profile off; + +data = profile ('info'); +profshow (data, 10); +@end group +@end example + +This prints a table like: + +@example +@group + # Function Attr Time (s) Calls +--------------------------------------------- + 7 expm 1.034 1 + 3 binary * 0.823 117 + 41 binary \ 0.188 1 + 38 binary ^ 0.126 2 + 43 timesteps R 0.111 101 + 44 NA 0.029 101 + 39 binary + 0.024 8 + 34 norm 0.011 1 + 40 binary - 0.004 101 + 33 balance 0.003 1 +@end group +@end example + +The entries are the individual functions which have been executed (only +the 10 most important ones), together with some information for each of +them. The entries like @samp{binary *} denote operators, while other +entries are ordinary functions. They include both built-ins like +@code{expm} and our own routines (for instance @code{timesteps}). From +this profile, we can immediately deduce that @code{expm} uses up the +largest proportion of the processing time, even though it is only called +once. The second expensive operation is the matrix-vector product in the +routine @code{timesteps}. @footnote{We only know it is the binary +multiplication operator, but fortunately this operator appears only at +one place in the code and thus we know which occurence takes so much +time. If there were multiple places, we would have to use the +hierarchical profile to find out the exact place which uses up the time +which is not covered in this example.} + +Timing, however, is not the only information available from the profile. +The attribute column shows us that @code{timesteps} calls itself +recursively. This may not be that remarkable in this example (since it's +clear anyway), but could be helpful in a more complex setting. As to the +question of why is there a @samp{binary \} in the output, we can easily +shed some light on that too. Note that @code{data} is a structure array +(@ref{Structure Arrays}) which contains the field @code{FunctionTable}. +This stores the raw data for the profile shown. The number in the first +column of the table gives the index under which the shown function can +be found there. Looking up @code{data.FunctionTable(41)} gives: + +@example +@group + scalar structure containing the fields: + + FunctionName = binary \ + TotalTime = 0.18765 + NumCalls = 1 + IsRecursive = 0 + Parents = 7 + Children = [](1x0) +@end group +@end example + +Here we see the information from the table again, but have additional +fields @code{Parents} and @code{Children}. Those are both arrays, which +contain the indices of functions which have directly called the function +in question (which is entry 7, @code{expm}, in this case) or been called +by it (no functions). Hence, the backslash operator has been used +internally by @code{expm}. + +Now let's take a look at @code{bar}. For this, we start a fresh +profiling session (@code{profile on} does this; the old data is removed +before the profiler is restarted): + +@example +@group +profile on; +bar (20); +profile off; + +profshow (profile ('info')); +@end group +@end example + +This gives: + +@example + # Function Attr Time (s) Calls +------------------------------------------------------- + 1 bar R 2.091 13529 + 2 binary <= 0.062 13529 + 3 binary - 0.042 13528 + 4 binary + 0.023 6764 + 5 profile 0.000 1 + 8 false 0.000 1 + 6 nargin 0.000 1 + 7 binary != 0.000 1 + 9 __profiler_enable__ 0.000 1 +@end example + +Unsurprisingly, @code{bar} is also recursive. It has been called 13,529 +times in the course of recursively calculating the Fibonacci number in a +suboptimal way, and most of the time was spent in @code{bar} itself. + +Finally, let's say we want to profile the execution of both @code{foo} +and @code{bar} together. Since we already have the runtime data +collected for @code{bar}, we can restart the profiler without clearing +the existing data and collect the missing statistics about @code{foo}. +This is done by: + +@example +@group +profile resume; +foo; +profile off; + +profshow (profile ('info'), 10); +@end group +@end example + +As you can see in the table below, now we have both profiles mixed +together. + +@example +@group + # Function Attr Time (s) Calls +--------------------------------------------- + 1 bar R 2.091 13529 + 16 expm 1.122 1 + 12 binary * 0.798 117 + 46 binary \ 0.185 1 + 45 binary ^ 0.124 2 + 48 timesteps R 0.115 101 + 2 binary <= 0.062 13529 + 3 binary - 0.045 13629 + 4 binary + 0.041 6772 + 49 NA 0.036 101 +@end group +@end example
deleted file mode 100644 --- a/doc/interpreter/dir +++ /dev/null @@ -1,14 +0,0 @@ --*- Text -*- -This is the file .../info/dir, which contains the topmost node of the -Info hierarchy. The first time you invoke Info you start off -looking at that node, which is (dir)Top. - -File: dir Node: Top This is the top of the INFO tree - This (the Directory node) gives a menu of major topics. - Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h" - gives a primer for first-timers, "mItem<Return>" visits the menu - item named `Item', etc. - -* Menu: The list of major topics begins on the next line. - -* Octave: (octave). Interactive language for numerical computations.
--- a/doc/interpreter/doccheck/mk_undocumented_list +++ b/doc/interpreter/doccheck/mk_undocumented_list @@ -82,7 +82,6 @@ comma debug dbnext -error_text exit F_DUPFD F_GETFD
deleted file mode 100644 --- a/doc/interpreter/eos.txi +++ /dev/null @@ -1,515 +0,0 @@ -@c Copyright (C) 1996-2011 Kurt Hornik -@c -@c This file is part of Octave. -@c -@c Octave is free software; you can redistribute it and/or modify it -@c under the terms of the GNU General Public License as published by the -@c Free Software Foundation; either version 3 of the License, or (at -@c your option) any later version. -@c -@c Octave is distributed in the hope that it will be useful, but WITHOUT -@c ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -@c FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -@c for more details. -@c -@c You should have received a copy of the GNU General Public License -@c along with Octave; see the file COPYING. If not, see -@c <http://www.gnu.org/licenses/>. - -@c Written by Kurt Hornik <Kurt.Hornik@wu-wien.ac.at> on 1996/05/17. -@c Last updated by KH on 1997/07/31. - -@node Emacs -@chapter Emacs Octave Support - -The development of Octave code can greatly be facilitated using Emacs -with Octave mode -automatically indent the code, do some of the typing (with Abbrev mode) -and show keywords, comments, strings, etc.@: in different faces (with -Font-lock mode on devices that support it). - -It is also possible to run Octave from within Emacs, either by directly -entering commands at the prompt in a buffer in Inferior Octave mode, or -by interacting with Octave from within a file with Octave code. This is -useful in particular for debugging Octave code. - -Finally, you can convince Octave to use the Emacs info reader for -@kbd{help -i}. - -All functionality is provided by the Emacs Lisp package EOS (for ``Emacs -Octave Support''). This chapter describes how to set up and use this -package. - -Please contact @email{Kurt.Hornik@@wu-wien.ac.at} if you have any questions -or suggestions on using EOS. - -@menu -* Installing EOS:: -* Using Octave Mode:: -* Running Octave From Within Emacs:: -* Using the Emacs Info Reader for Octave:: -@end menu - -@node Installing EOS -@section Installing EOS - -The Emacs package EOS consists of the three files @file{octave-mod.el}, -@file{octave-inf.el}, and @file{octave-hlp.el}. These files, or better -yet their byte-compiled versions, should be somewhere in your Emacs -load-path. - -If you have GNU Emacs with a version number at least as high as 19.35, -you are all set up, because EOS is respectively will be part of GNU -Emacs as of version 19.35. - -Otherwise, copy the three files from the @file{emacs} subdirectory of -the Octave distribution to a place where Emacs can find them (this -depends on how your Emacs was installed). Byte-compile them for speed -if you want. - -@node Using Octave Mode -@section Using Octave Mode - -If you are lucky, your sysadmins have already arranged everything so -that Emacs automatically goes into Octave mode whenever you visit an -Octave code file as characterized by its extension @file{.m}. If not, -proceed as follows. - -@enumerate -@item -To begin using Octave mode for all @file{.m} files you visit, add the -following lines to a file loaded by Emacs at startup time, typically -your @file{~/.emacs} file: - -@lisp -(autoload 'octave-mode "octave-mod" nil t) -(setq auto-mode-alist - (cons '(\"\\\\.m$\" . octave-mode) auto-mode-alist)) -@end lisp - -@item -Finally, to turn on the abbrevs, auto-fill and font-lock features -automatically, also add the following lines to one of the Emacs startup -files: -@lisp -(add-hook 'octave-mode-hook - (lambda () - (abbrev-mode 1) - (auto-fill-mode 1) - (if (eq window-system 'x) - (font-lock-mode 1)))) -@end lisp -See the Emacs manual for more information about how to customize -Font-lock mode. -@end enumerate - -In Octave mode, the following special Emacs commands can be used in -addition to the standard Emacs commands. - -@table @kbd -@item C-h m -Describe the features of Octave mode. - -@item LFD -Reindent the current Octave line, insert a newline and indent the new -line (@code{octave-reindent-then-newline-and-indent}). An abbrev before -point is expanded if @code{abbrev-mode} is non-@code{nil}. - -@item TAB -Indents current Octave line based on its contents and on previous -lines (@code{indent-according-to-mode}). - -@item ; -Insert an ``electric'' semicolon (@code{octave-electric-semi}). If -@code{octave-auto-indent} is non-@code{nil}, reindent the current line. -If @code{octave-auto-newline} is non-@code{nil}, automagically insert a -newline and indent the new line. - -@item ` -Start entering an abbreviation (@code{octave-abbrev-start}). If Abbrev -mode is turned on, typing @kbd{`C-h} or @kbd{`?} lists all abbrevs. -Any other key combination is executed normally. Note that all Octave -abbrevs start with a grave accent. - -@item M-LFD -Break line at point and insert continuation marker and alignment -(@code{octave-split-line}). - -@item M-TAB -Perform completion on Octave symbol preceding point, comparing that -symbol against Octave's reserved words and built-in variables -(@code{octave-complete-symbol}). - -@item M-C-a -Move backward to the beginning of a function -(@code{octave-beginning-of-defun}). -With prefix argument @var{N}, do it that many times if @var{N} is -positive; otherwise, move forward to the @var{N}-th following beginning -of a function. - -@item M-C-e -Move forward to the end of a function (@code{octave-end-of-defun}). -With prefix argument @var{N}, do it that many times if @var{N} is -positive; otherwise, move back to the @var{N}-th preceding end of a -function. - -@item M-C-h -Puts point at beginning and mark at the end of the current Octave -function, i.e., the one containing point or following point -(@code{octave-mark-defun}). - -@item M-C-q -Properly indents the Octave function which contains point -(@code{octave-indent-defun}). - -@item M-; -If there is no comment already on this line, create a code-level comment -(started by two comment characters) if the line is empty, or an in-line -comment (started by one comment character) otherwise -(@code{octave-indent-for-comment}). -Point is left after the start of the comment which is properly aligned. - -@item C-c ; -Puts the comment character @samp{#} (more precisely, the string value of -@code{octave-comment-start}) at the beginning of every line in the -region (@code{octave-comment-region}). With just @kbd{C-u} prefix -argument, uncomment each line in the region. A numeric prefix argument -@var{N} means use @var{N} comment characters. - -@item C-c : -Uncomments every line in the region (@code{octave-uncomment-region}). - -@item C-c C-p -Move one line of Octave code backward, skipping empty and comment lines -(@code{octave-previous-code-line}). With numeric prefix argument -@var{N}, move that many code lines backward (forward if @var{N} is -negative). - -@item C-c C-n -Move one line of Octave code forward, skipping empty and comment lines -(@code{octave-next-code-line}). With numeric prefix argument @var{N}, -move that many code lines forward (backward if @var{N} is negative). - -@item C-c C-a -Move to the `real' beginning of the current line -(@code{octave-beginning-of-line}). If point is in an empty or comment -line, simply go to its beginning; otherwise, move backwards to the -beginning of the first code line which is not inside a continuation -statement, i.e., which does not follow a code line ending in @samp{...} -or @samp{\}, or is inside an open parenthesis list. - -@item C-c C-e -Move to the `real' end of the current line (@code{octave-end-of-line}). -If point is in a code line, move forward to the end of the first Octave -code line which does not end in @samp{...} or @samp{\} or is inside an -open parenthesis list. Otherwise, simply go to the end of the current -line. - -@item C-c M-C-n -Move forward across one balanced begin-end block of Octave code -(@code{octave-forward-block}). With numeric prefix argument @var{N}, -move forward across @var{n} such blocks (backward if @var{N} is -negative). - -@item C-c M-C-p -Move back across one balanced begin-end block of Octave code -(@code{octave-backward-block}). With numeric prefix argument @var{N}, -move backward across @var{N} such blocks (forward if @var{N} is -negative). - -@item C-c M-C-d -Move forward down one begin-end block level of Octave code -(@code{octave-down-block}). With numeric prefix argument, do it that -many times; a negative argument means move backward, but still go down -one level. - -@item C-c M-C-u -Move backward out of one begin-end block level of Octave code -(@code{octave-backward-up-block}). With numeric prefix argument, do it -that many times; a negative argument means move forward, but still to a -less deep spot. - -@item C-c M-C-h -Put point at the beginning of this block, mark at the end -(@code{octave-mark-block}). -The block marked is the one that contains point or follows point. - -@item C-c ] -Close the current block on a separate line (@code{octave-close-block}). -An error is signaled if no block to close is found. - -@item C-c f -Insert a function skeleton, prompting for the function's name, arguments -and return values which have to be entered without parentheses -(@code{octave-insert-defun}). - -@item C-c C-h -Search the function, operator and variable indices of all info files -with documentation for Octave for entries (@code{octave-help}). If used -interactively, the entry is prompted for with completion. If multiple -matches are found, one can cycle through them using the standard -@samp{,} (@code{Info-index-next}) command of the Info reader. - -The variable @code{octave-help-files} is a list of files to search -through and defaults to @code{'("octave")}. If there is also an Octave -Local Guide with corresponding info file, say, @file{octave-LG}, you can -have @code{octave-help} search both files by -@lisp -(setq octave-help-files '("octave" "octave-LG")) -@end lisp -@noindent -in one of your Emacs startup files. - -@end table - -A common problem is that the @key{RET} key does @emph{not} indent the -line to where the new text should go after inserting the newline. This -is because the standard Emacs convention is that @key{RET} (aka -@kbd{C-m}) just adds a newline, whereas @key{LFD} (aka @kbd{C-j}) adds a -newline and indents it. This is particularly inconvenient for users with -keyboards which do not have a special @key{LFD} key at all; in such -cases, it is typically more convenient to use @key{RET} as the @key{LFD} -key (rather than typing @kbd{C-j}). - -You can make @key{RET} do this by adding -@lisp -(define-key octave-mode-map "\C-m" - 'octave-reindent-then-newline-and-indent) -@end lisp -@noindent -to one of your Emacs startup files. Another, more generally applicable -solution is -@lisp -(defun RET-behaves-as-LFD () - (let ((x (key-binding "\C-j"))) - (local-set-key "\C-m" x))) -(add-hook 'octave-mode-hook 'RET-behaves-as-LFD) -@end lisp -@noindent -(this works for all modes by adding to the startup hooks, without having -to know the particular binding of @key{RET} in that mode!). Similar -considerations apply for using @key{M-RET} as @key{M-LFD}. As Barry -A. Warsaw @email{bwarsaw@@cnri.reston.va.us} says in the documentation for his -@code{cc-mode}, ``This is a very common question. @code{:-)} If you want -this to be the default behavior, don't lobby me, lobby RMS!'' - -The following variables can be used to customize Octave mode. - -@table @code -@item octave-auto-indent -Non-@code{nil} means auto-indent the current line after a semicolon or -space. Default is @code{nil}. - -@item octave-auto-newline -Non-@code{nil} means auto-insert a newline and indent after semicolons -are typed. The default value is @code{nil}. - -@item octave-blink-matching-block -Non-@code{nil} means show matching begin of block when inserting a space, -newline or @samp{;} after an else or end keyword. Default is @code{t}. -This is an extremely useful feature for automatically verifying that the -keywords match---if they don't, an error message is displayed. - -@item octave-block-offset -Extra indentation applied to statements in block structures. -Default is 2. - -@item octave-continuation-offset -Extra indentation applied to Octave continuation lines. -Default is 4. - -@item octave-continuation-string -String used for Octave continuation lines. -Normally @samp{\}. - -@item octave-mode-startup-message -If @code{t} (default), a startup message is displayed when Octave mode -is called. - -@end table - -If Font Lock mode is enabled, Octave mode will display -@itemize @bullet -@item -strings in @code{font-lock-string-face} - -@item -comments in @code{font-lock-comment-face} - -@item -the Octave reserved words (such as all block keywords) and the text -functions (such as @samp{cd} or @samp{who}) which are also reserved -using @code{font-lock-keyword-face} - -@item -the built-in operators (@samp{&&}, @samp{==}, @dots{}) using -@code{font-lock-reference-face} - -@item -and the function names in function declarations in -@code{font-lock-function-name-face}. -@end itemize - -There is also rudimentary support for Imenu (currently, function names -can be indexed). - -Customization of Octave mode can be performed by modification of the -variable @code{octave-mode-hook}. It the value of this variable is -non-@code{nil}, turning on Octave mode calls its value. - -If you discover a problem with Octave mode, you can conveniently send a -bug report using @kbd{C-c C-b} (@code{octave-submit-bug-report}). This -automatically sets up a mail buffer with version information already -added. You just need to add a description of the problem, including a -reproducible test case and send the message. - -@node Running Octave From Within Emacs -@section Running Octave From Within Emacs - -The package @file{octave} provides commands for running an inferior -Octave process in a special Emacs buffer. Use -@lisp -M-x run-octave -@end lisp -@noindent -to directly start an inferior Octave process. If Emacs does not know -about this command, add the line -@lisp -(autoload 'run-octave "octave-inf" nil t) -@end lisp -@noindent -to your @file{.emacs} file. - -This will start Octave in a special buffer the name of which is -specified by the variable @code{inferior-octave-buffer} and defaults to -@code{"*Inferior Octave*"}. From within this buffer, you can -interact with the inferior Octave process `as usual', i.e., by entering -Octave commands at the prompt. The buffer is in Inferior Octave mode, -which is derived from the standard Comint mode, a major mode for -interacting with an inferior interpreter. See the documentation for -@code{comint-mode} for more details, and use @kbd{C-h b} to find out -about available special keybindings. - -You can also communicate with an inferior Octave process from within -files with Octave code (i.e., buffers in Octave mode), using the -following commands. - -@table @kbd -@item C-c i l -Send the current line to the inferior Octave process -(@code{octave-send-line}). -With positive prefix argument @var{N}, send that many lines. -If @code{octave-send-line-auto-forward} is non-@code{nil}, go to the -next unsent code line. - -@item C-c i b -Send the current block to the inferior Octave process -(@code{octave-send-block}). - -@item C-c i f -Send the current function to the inferior Octave process -(@code{octave-send-defun}). - -@item C-c i r -Send the region to the inferior Octave process -(@code{octave-send-region}). - -@item C-c i s -Make sure that `inferior-octave-buffer' is displayed -(@code{octave-show-process-buffer}). - -@item C-c i h -Delete all windows that display the inferior Octave buffer -(@code{octave-hide-process-buffer}). - -@item C-c i k -Kill the inferior Octave process and its buffer -(@code{octave-kill-process}). -@end table - -The effect of the commands which send code to the Octave process can be -customized by the following variables. -@table @code -@item octave-send-echo-input -Non-@code{nil} means echo input sent to the inferior Octave process. -Default is @code{t}. - -@item octave-send-show-buffer -Non-@code{nil} means display the buffer running the Octave process after -sending a command (but without selecting it). -Default is @code{t}. -@end table - -If you send code and there is no inferior Octave process yet, it will be -started automatically. - -The startup of the inferior Octave process is highly customizable. -The variable @code{inferior-octave-startup-args} can be used for -specifying command lines arguments to be passed to Octave on startup -as a list of strings. For example, to suppress the startup message and -use `traditional' mode, set this to @code{'("-q" "--traditional")}. -You can also specify a startup file of Octave commands to be loaded on -startup; note that these commands will not produce any visible output -in the process buffer. Which file to use is controlled by the variable -@code{inferior-octave-startup-file}. If this is @code{nil}, the file -@file{~/.emacs-octave} is used if it exists. - -And finally, @code{inferior-octave-mode-hook} is run after starting the -process and putting its buffer into Inferior Octave mode. Hence, if you -like the up and down arrow keys to behave in the interaction buffer as -in the shell, and you want this buffer to use nice colors, add -@lisp -(add-hook 'inferior-octave-mode-hook - (lambda () - (turn-on-font-lock) - (define-key inferior-octave-mode-map [up] - 'comint-previous-input) - (define-key inferior-octave-mode-map [down] - 'comint-next-input))) -@end lisp -@noindent -to your @file{.emacs} file. You could also swap the roles of @kbd{C-a} -(@code{beginning-of-line}) and @code{C-c C-a} (@code{comint-bol}) using -this hook. - -@quotation -@strong{Note:} -If you set your Octave prompts to something different from the defaults, -make sure that @code{inferior-octave-prompt} matches them. -Otherwise, @emph{nothing} will work, because Emacs will have no idea -when Octave is waiting for input, or done sending output. -@end quotation - -@node Using the Emacs Info Reader for Octave -@section Using the Emacs Info Reader for Octave - -You can also set up the Emacs Info reader for dealing with the results -of Octave's @samp{help -i}. For this, the package @file{gnuserv} needs -to be installed, which unfortunately still does not come with GNU Emacs -(it does with XEmacs). It can be retrieved from any GNU Emacs Lisp Code -Directory archive, e.g.@: -@url{ftp://ftp.cis.ohio-state.edu/pub/gnu/emacs/elisp-archive}, -in the @file{packages} subdirectory. The alpha version of an enhanced -version of gnuserv is available at -@url{ftp://ftp.wellfleet.com/netman/psmith/emacs/gnuserv-2.1alpha.tar.gz}. - -If @file{gnuserv} is installed, add the lines -@lisp -(autoload 'octave-help "octave-hlp" nil t) -(require 'gnuserv) -(gnuserv-start) -@end lisp -@noindent -to your @file{.emacs} file. - -You can use either `plain' Emacs Info or the function @code{octave-help} -as your Octave info reader (for @samp{help -i}). In the former case, -set the Octave variable @w{@env{INFO_PROGRAM}} to @code{"info-emacs-info"}. -The latter is perhaps more attractive because it allows to look up keys -in the indices of @emph{several} info files related to Octave (provided -that the Emacs variable @code{octave-help-files} is set correctly). In -this case, set @w{@env{INFO_PROGRAM}} to @code{"info-emacs-octave-help"}. - -If you use Octave from within Emacs, these settings are best done in the -@file{~/.emacs-octave} startup file (or the file pointed to by the Emacs -variable @code{inferior-octave-startup-file}).
--- a/doc/interpreter/expr.txi +++ b/doc/interpreter/expr.txi @@ -1239,51 +1239,62 @@ any such mistake. When operators of equal precedence are used together, the leftmost -operator groups first, except for the assignment and exponentiation -operators, which group in the opposite order. Thus, the expression -@code{a - b + c} groups as @code{(a - b) + c}, but the expression -@code{a = b = c} groups as @code{a = (b = c)}. +operator groups first, except for the assignment operators, which group +in the opposite order. Thus, the expression @code{a - b + c} groups as +@code{(a - b) + c}, but the expression @code{a = b = c} groups as +@code{a = (b = c)}. The precedence of prefix unary operators is important when another operator follows the operand. For example, @code{-x^2} means @code{-(x^2)}, because @samp{-} has lower precedence than @samp{^}. -Here is a table of the operators in Octave, in order of increasing -precedence. +Here is a table of the operators in Octave, in order of decreasing +precedence. Unless noted, all operators group left to right. @table @code -@item statement separators -@samp{;}, @samp{,}. +@item function call and array indexing, cell array indexing, and structure element indexing +@samp{()} @samp{@{@}} @samp{.} + +@item postfix increment, and postfix decrement +@samp{++} @samp{--} + +These operators group right to left. + +@item transpose and exponentiation +@samp{'} @samp{.'} @samp{^} @samp{**} @samp{.^} @samp{.**} -@item assignment -@samp{=}, @samp{+=}, @samp{-=}, @samp{*=},@samp{/=}. This operator -groups right to left. +@item unary plus, unary minus, prefix increment, prefix decrement, and logical "not" +@samp{+} @samp{-} @samp{++} @samp{--} @samp{~} @samp{!} + +@item multiply and divide +@samp{*} @samp{/} @samp{\} @samp{.\} @samp{.*} @samp{./} -@item logical "or" and "and" -@samp{||}, @samp{&&}. +@item add, subtract +@samp{+} @samp{-} -@item element-wise "or" and "and" -@samp{|}, @samp{&}. +@item colon +@samp{:} @item relational -@samp{<}, @samp{<=}, @samp{==}, @samp{>=}, @samp{>}, @samp{!=}, -@samp{~=}. +@samp{<} @samp{<=} @samp{==} @samp{>=} @samp{>} @samp{!=} +@samp{~=} -@item colon -@samp{:}. +@item element-wise "and" +@samp{&} -@item add, subtract -@samp{+}, @samp{-}. +@item element-wise "or" +@samp{|} -@item multiply, divide -@samp{*}, @samp{/}, @samp{\}, @samp{.\}, @samp{.*}, @samp{./}. +@item logical "and" +@samp{&&} -@item transpose -@samp{'}, @samp{.'} +@item logical "or" +@samp{||} -@item unary plus, minus, increment, decrement, and ``not'' -@samp{+}, @samp{-}, @samp{++}, @samp{--}, @samp{!}, @samp{~}. +@item assignment +@samp{=} @samp{+=} @samp{-=} @samp{*=} @samp{/=} @samp{\=} +@samp{^=} @samp{.*=} @samp{./=} @samp{.\=} @samp{.^=} @samp{|=} +@samp{&=} -@item exponentiation -@samp{^}, @samp{**}, @samp{.^}, @samp{.**}. +These operators group right to left. @end table
--- a/doc/interpreter/install.txi +++ b/doc/interpreter/install.txi @@ -32,7 +32,7 @@ under the terms of the GNU General Public License as published by the Free Software Foundation. -@strong{Note:} This file is automatically generated from +@strong{Note}: This file is automatically generated from @file{doc/interpreter/install.txi} in the Octave sources. To update the documentation make changes to the .txi source file rather than this derived file.
--- a/doc/interpreter/linalg.txi +++ b/doc/interpreter/linalg.txi @@ -187,6 +187,8 @@ @node Specialized Solvers @section Specialized Solvers +@DOCSTRING(bicg) + @DOCSTRING(bicgstab) @DOCSTRING(cgs)
--- a/doc/interpreter/matrix.txi +++ b/doc/interpreter/matrix.txi @@ -257,8 +257,6 @@ @DOCSTRING(rosser) -@DOCSTRING(sylvester_matrix) - @DOCSTRING(toeplitz) @DOCSTRING(vander)
--- a/doc/interpreter/mkoctfile.1 +++ b/doc/interpreter/mkoctfile.1 @@ -95,28 +95,29 @@ Print configuration variable \fIVAR\fP. Recognized variables are: .RS .Vb - ALL_CFLAGS FFTW3F_LDFLAGS - ALL_CXXFLAGS FFTW3F_LIBS - ALL_FFLAGS FLIBS - ALL_LDFLAGS FPICFLAG - BLAS_LIBS INCFLAGS - CC LAPACK_LIBS - CFLAGS LDFLAGS - CPICFLAG LD_CXX - CPPFLAGS LD_STATIC_FLAG - CXX LFLAGS - CXXFLAGS LIBCRUFT - CXXPICFLAG LIBOCTAVE - DEPEND_EXTRA_SED_PATTERN LIBOCTINTERP - DEPEND_FLAGS LIBS - DL_LD OCTAVE_LIBS - DL_LDFLAGS RDYNAMIC_FLAG - EXEEXT READLINE_LIBS - F77 RLD_FLAG - F77_INTEGER_8_FLAG SED - FFLAGS XTRA_CFLAGS - FFTW3_LDFLAGS XTRA_CXXFLAGS - FFTW3_LIBS + ALL_CFLAGS FFTW3F_LIBS + ALL_CXXFLAGS FLIBS + ALL_FFLAGS FPICFLAG + ALL_LDFLAGS INCFLAGS + BLAS_LIBS LAPACK_LIBS + CC LDFLAGS + CFLAGS LD_CXX + CPICFLAG LD_STATIC_FLAG + CPPFLAGS LFLAGS + CXX LIBCRUFT + CXXFLAGS LIBOCTAVE + CXXPICFLAG LIBOCTINTERP + DEPEND_EXTRA_SED_PATTERN LIBS + DEPEND_FLAGS OCTAVE_LIBS + DL_LD OCTAVE_LINK_DEPS + DL_LDFLAGS OCT_LINK_DEPS + EXEEXT RDYNAMIC_FLAG + F77 READLINE_LIBS + F77_INTEGER_8_FLAG SED + FFLAGS XTRA_CFLAGS + FFTW3_LDFLAGS XTRA_CXXFLAGS + FFTW3_LIBS + FFTW3F_LDFLAGS .Ve .RE .TP
--- a/doc/interpreter/plot.txi +++ b/doc/interpreter/plot.txi @@ -2396,7 +2396,11 @@ may override the factory defaults. Although default values may be set for any object, they are set in -parent objects and apply to child objects. For example, +parent objects and apply to child objects, of the specified object type. +For example, seeting the default @code{color} property of @code{line} +objects to "green", for the @code{root} object, will result in all +@code{line} objects inheriting the @code{color} "green" as the default +value. @example set (0, "defaultlinecolor", "green");
--- a/doc/interpreter/stats.txi +++ b/doc/interpreter/stats.txi @@ -114,7 +114,7 @@ @DOCSTRING(center) -@DOCSTRING(studentize) +@DOCSTRING(zscore) @DOCSTRING(histc) @@ -168,9 +168,7 @@ @DOCSTRING(cov) -@DOCSTRING(cor) - -@DOCSTRING(corrcoef) +@DOCSTRING(corr) @DOCSTRING(spearman)
--- a/doc/refcard/refcard.tex +++ b/doc/refcard/refcard.tex @@ -863,14 +863,14 @@ gray2ind ({\it i}, {\it n})&convert gray scale to Octave image\cr image ({\it img}, {\it zoom})&display an Octave image matrix\cr imagesc ({\it img}, {\it zoom})&display scaled matrix as image\cr +imread ({\it file})&load an image file\cr imshow ({\it img}, {\it map})&display Octave image\cr imshow ({\it i}, {\it n})&display gray scale image\cr imshow ({\it r}, {\it g}, {\it b})&display RGB image\cr +imwrite ({\it img}, {\it file})&write images in various file formats\cr ind2gray ({\it img}, {\it map})&convert Octave image to gray scale\cr ind2rgb ({\it img}, {\it map})&convert indexed image to RGB\cr -loadimage ({\it file})&load an image file\cr rgb2ind ({\it r}, {\it g}, {\it b})&convert RGB to Octave image\cr -\omit\tt saveimage ({\it file}, {\it img}, {\it fmt}, {\it map})\quad\rm save a matrix to {\it file}\span\cr \endsec
--- a/etc/OLD-ChangeLogs/ChangeLog +++ b/etc/OLD-ChangeLogs/ChangeLog @@ -2,6 +2,10 @@ * NEWS: Add colstyle to list of new functions for 3.4 +2011-04-08 Rik <octave@nomad.inbox5.com> + + * NEWS: Deprecate studentize(), add new function zscore(). + 2011-04-04 Rik <octave@nomad.inbox5.com> * NEWS: Add perror, strerror to list of functions deprecated in 3.4 @@ -88,6 +92,11 @@ * NEWS: Use indentation of 2 spaces rather than 3 in code examples. +2011-02-08 John W. Eaton <jwe@octave.org> + + * NEWS: New section for 3.6. List deprecated functions that + have been removed for 3.6. + 2011-02-08 Ben Abbott <bpabbott@mac.com> * README.MacOS: Add detail.
--- a/etc/OLD-ChangeLogs/doc-ChangeLog +++ b/etc/OLD-ChangeLogs/doc-ChangeLog @@ -1,3 +1,7 @@ +2011-04-16 Ben Abbott <bpabbott@mac.com> + + * interpreter/plot.txi: Clarify that inheritance of default property + values only applies to the named object type. 2011-04-14 Rik <octave@nomad.inbox5.com> * interpreter/plot.txi: Add colstyle function to documentation. @@ -16,6 +20,11 @@ * interpreter/func.txi: Add discussion of isargout to Ignoring Arguments section of documentation. +2011-04-08 Rik <octave@nomad.inbox5.com> + + * interpreter/stats.txi: Deprecate studentize(), replace with + zscore(). + 2011-04-07 Rik <octave@nomad.inbox5.com> * interpreter/Makefile.am: Add spellcheck target to documentation @@ -42,7 +51,7 @@ 2011-04-04 Rik <octave@nomad.inbox5.com> - * interpreter/doccheck/aspell-octave.en.pws, interpreter/nonlin.txi, + * interpreter/doccheck/aspell-octave.en.pws, interpreter/nonlin.txi, interpreter/tips.txi: Spellcheck documentation for 3.4.1 release. 2011-04-04 Rik <octave@nomad.inbox5.com>
--- a/etc/OLD-ChangeLogs/liboctave-ChangeLog +++ b/etc/OLD-ChangeLogs/liboctave-ChangeLog @@ -1,3 +1,7 @@ +2011-04-12 Rik <octave@nomad.inbox5.com> + + * LSODE.cc: Add semicolon to error messages to prevent run-together text. + 2011-04-01 Jordi Gutiérrez Hermoso <jordigh@gmail.com> * MatrixType (MatrixType::operator =): Plug memory leak due to
--- a/etc/OLD-ChangeLogs/scripts-ChangeLog +++ b/etc/OLD-ChangeLogs/scripts-ChangeLog @@ -1,8 +1,47 @@ +2011-04-18 Paul Boven <p.boven@xs4all.nl> + + * image/image.m: Fixed naming of variables in texinfo + +2011-04-17 Patrick Häcker <magicmuscleman> + + * strings/mat2str.m: Limit the number of digits to one less than + available for double. + +2011-04-15 Kai Habel <kai.habel@gmx.de> + + * general/interp1.m, polynomial/mkpp.m, polynomial/pchip.m, + polynomial/ppder.m, polynomial/ppint.m, polynomial/ppjumps.m, + polynomial/ppval.m, polynomial/spline.m, polynomial/unmkpp.m: + Make functions more compatible with respect to handling of + picewise polynoms (pp). Rename pp-struct elements. + Handle nD-arguments correctly. Tests added. + (bugs #32040, #32045) + 2011-04-13 David Bateman <dbateman@free.fr> * plot/colstyle.m : New function. * plot/module.mk plot_FCN_FILES) : Add it here. +2011-04-13 Rik <octave@nomad.inbox5.com> + + * help/__makeinfo__.m: Simplify function by using regular expressions. + Eliminate third input argument see_also function. + +2011-04-13 Rik <octave@nomad.inbox5.com> + + * general/isdir.m, general/isequal.m, general/isequalwithequalnans.m, + general/isscalar.m, general/issquare.m, general/isvector.m: Refactor + code to put input validation first. + + * general/iscolumn.m, general/isrow.m : Remove useless initialization + of output variable. + + * general/isa.m: Add additional tests for various classes. + +2011-04-13 Rik <octave@nomad.inbox5.com> + + * ChangeLog: Remove results of bad merge in ChangeLog. + 2011-04-12 Ben Abbott <bpabbott@mac.com> * miscellaneous/getappdata.m: If no property name is provided, return @@ -20,10 +59,21 @@ 2011-04-08 Rik <octave@nomad.inbox5.com> + * deprecated/module.mk, statistics/base/center.m, + statistics/base/module.mk: Deprecate studentize(), replace with + zscore(). + +2011-04-08 Rik <octave@nomad.inbox5.com> + * linear-algebra/cond.m, linear-algebra/expm.m, linear-algebra/logm.m, linear-algebra/null.m, linear-algebra/orth.m, linear-algebra/rank.m, linear-algebra/rref.m: Improve docstrings. +2011-04-08 Rik <octave@nomad.inbox5.com> + + * statistics/base/mode.m, statistics/base/quantile.m: Return output + of same class as input. + 2011-04-06 Rik <octave@nomad.inbox5.com> * miscellaneous/pack.m: Improve docstring. @@ -397,6 +447,25 @@ * plot/__go_draw_axes__.m: Properly set fontspec for legends. +2011-02-08 John W. Eaton <jwe@octave.org> + + * deprecated/complement.m, deprecated/create_set.m, + deprecated/dmult.m, deprecated/iscommand.m, + deprecated/israwcommand.m, deprecated/lchol.m, + deprecated/loadimage.m, deprecated/mark_as_command.m, + deprecated/mark_as_rawcommand.m, deprecated/spatan2.m, + deprecated/spchol2inv.m, deprecated/spcholinv.m, + deprecated/spchol.m, deprecated/spcumprod.m, + deprecated/spcumsum.m, deprecated/spdet.m, deprecated/spdiag.m, + deprecated/spfind.m, deprecated/spinv.m, deprecated/spkron.m, + deprecated/splchol.m, deprecated/split.m, deprecated/splu.m, + deprecated/spmax.m, deprecated/spmin.m, deprecated/spprod.m, + deprecated/spqr.m, deprecated/spsum.m, deprecated/spsumsq.m, + deprecated/str2mat.m, deprecated/unmark_command.m, + deprecated/unmark_rawcommand.m: + Remove functions deprecated in version 3.2. + * module.mk (deprecated_FCN_FILES): Remove them from the list. + 2011-02-05 David Bateman <dbateman@free.fr> * plot/legend.m: Allow the location and orientation to be set
--- a/etc/OLD-ChangeLogs/src-ChangeLog +++ b/etc/OLD-ChangeLogs/src-ChangeLog @@ -1,10 +1,15 @@ +2011-04-19 Kai Habel <kai.habel@gmx.de> + + * src/DLD-FUNCTIONS/__init_fltk__.cc(plot_window::plot_window): + Instantiate canvas before uimenu. + 2011-04-13 Rik <octave@nomad.inbox5.com> * help.cc: Add spaces after commas in @seealso blocks. 2011-04-12 Rik <octave@nomad.inbox5.com> - * load-path.cc (restoredefaultpath): Correct use of it's -> its in + * load-path.cc (restoredefaultpath): Correct use of it's -> its in documentation. 2011-04-10 John Eaton <jwe@octave.org> @@ -90,7 +95,7 @@ * DLD-FUNCTIONS/inv.cc (inv, inverse), DLD-FUNCTIONS/tril.cc (tril), data.cc (cumsum, szie), file-io.cc (fgets), ov-typeinfo.cc (typeinfo), - ov-usr-fcn.cc (nargout), utils.cc (make_absolute_filename), + ov-usr-fcn.cc (nargout), utils.cc (make_absolute_filename), variables.cc (who): Improve docstrings 2011-03-25 John W. Eaton <jwe@octave.org> @@ -342,6 +347,10 @@ 2011-02-08 John W. Eaton <jwe@octave.org> + * DLD-FUNCTIONS/chol.cc: Delete obsolete test of spcholinv. + +2011-02-08 John W. Eaton <jwe@octave.org> + * oct-parse.yy (parse_fcn_file): Don't warn about coercing nested functions to subfunctions if yyparse failed.
--- a/etc/OLD-ChangeLogs/test-ChangeLog +++ b/etc/OLD-ChangeLogs/test-ChangeLog @@ -1,3 +1,9 @@ +2011-04-11 Rik <octave@nomad.inbox5.com> + + * fntests.m: Remove deprecated and private functions from list of + functions requiring tests. Count functions with %!demo blocks as + having tests. + 2011-04-03 Rik <octave@nomad.inbox5.com> * test_diag_perm.m: Reverse previous changeset. Return 3-input form
--- a/etc/README.MacOS +++ b/etc/README.MacOS @@ -334,67 +334,83 @@ includes a port file for octave-devel. To build and run the most recent development snapshots, enter the commands below. - sudo port selfupdate - sudo port install octave-devel + sudo port selfupdate + sudo port install octave-devel To build the developers sources in one's own way, or if MacPorts' version is outdated, a custom port file can be added. This requires setting up a local port file repository (link below). - http://guide.macports.org/#development.local-repositories + http://guide.macports.org/#development.local-repositories The octave-devel port file may be used as an initial starting point. The port file is accessible from the web at the link below. - http://trac.macports.org/browser/trunk/dports/math/octave-devel/Portfile + http://trac.macports.org/browser/trunk/dports/math/octave-devel/Portfile It is also available locally at the location below. The parameter ${prefix} is corresponds to where MacPorts is install, which by default is "/opt/local". - ${prefix}/var/macports/sources/rsync.macports.org/release/ports/math/octave-devel/Portfile + ${prefix}/var/macports/sources/rsync.macports.org/release/ports/math/octave-devel/Portfile + +If the Portfile is missing the dependencies, epstools, epstoedit, and transfig, +those should be installed manually or added to the Portfile. To install +manually, type the command below. + + sudo port install epstools epstoedit transfig The local source tarball must be placed in the location below, where ${name} and ${distname} are each specified in the port file. - ${prefix}/var/macports/distfiles/${name}/${disname}.tar.gz + ${prefix}/var/macports/distfiles/${name}/${disname}.tar.gz 2.4.2 Building for Active Development of Octave ----------------------------------------------- -To satisfy Octave's dependencies, first install the octave-devel port. - - sudo port selfupdate - sudo port install octave-devel +To satisfy most of Octave's dependencies, first install the octave-devel port. -Next run octave to determine the configure options needed to build Octave -using MacPorts. At Octave's prompt type the command below and make note of -the result, ${config_opts}. - - octave:1> octave_config_info.config_opts + sudo port selfupdate + sudo port install octave-devel Now uninstall the Octave port. - sudo port deactivate octave-devel + sudo port deactivate octave-devel + +This will remove Octave and leave its dependencies in place. Some additional +dependencies may be needed. + + sudo port install epstools epstoedit transfig + +Octave may now be built from a local mercurial archive by typing the commands +below (these assume gcc-4.4 is installed by macports). -This will remove Octave and leave its dependencies in place. Now Octave may -be built from the local mercurial archive by typing the commands below, where -the configure options mentioned above are substituted for the parameter -${config_opts}. If the sources being built are from the mercurial archive, -then ./autogen.sh must be run prior to ./configure. - - ./configure ${config_opts} - make + ./autogen.sh + export PREFIX=/opt/local + export CC=/opt/local/bin/gcc-mp-4.4 + export CXX=/opt/local/bin/g++-mp-4.4 + export CXXCPP="/opt/local/bin/g++-mp-4.4 -E" + export F77=/opt/local/bin/gfortran-mp-4.4 + export FC=/opt/local/bin/gfortran-mp-4.4 + export CXXFLAGS="-pipe -O2 -m64" + export FFLAGS="$CXXFLAGS -D_THREAD_SAFE -pthread" + export CFLAGS="$FFLAGS -lstdc++" + export LDFLAGS=-L$PREFIX/lib + export CPPFLAGS=-I$PREFIX/include + export BLAS_LIBS="-lcblas -lf77blas -latlas" + export LAPACK_LIBS=-llapack + ./configure --prefix="/opt/local" --without-framework-carbon --with-x + make Octave's integrated tests may be run. - make check + make check -However, "make install" should not be run as it may damage or corrupt the -MacPorts installation. To run Octave, type the command below from the root of -the mercurial archive. +"make install" should not be run as it will bypass the macports package +management. To run Octave, type the command below from the root of the +mercurial archive. - ./run-octave + ./run-octave John W. Eaton
--- a/libcruft/Makefile.am +++ b/libcruft/Makefile.am @@ -34,6 +34,13 @@ @CRUFT_DLL_DEFS@ \ $(AM_CPPFLAGS) +include link-deps.mk + +libcruft_la_LIBADD = \ + libranlib.la \ + ../libgnu/libgnu.la \ + $(LIBCRUFT_LINK_DEPS) + # Increment these as needed and according to the rules in the libtool # manual: libcruft_current = 0 @@ -46,13 +53,8 @@ -version-info $(libcruft_version_info) \ $(NO_UNDEFINED_LDFLAG) \ @XTRA_CRUFT_SH_LDFLAGS@ \ - -bindir $(bindir) - -libcruft_la_LIBADD = \ - ../libgnu/libgnu.la \ - libranlib.la \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(FLIBS) + -bindir $(bindir) \ + $(LIBCRUFT_LINK_OPTS) libcruft_la_DEPENDENCIES = cruft.def
new file mode 100644 --- /dev/null +++ b/libcruft/link-deps.mk @@ -0,0 +1,30 @@ +## The following libraries may be needed to satisfy gnulib dependencies: +## +## $(COPYSIGN_LIBM) +## $(FLOOR_LIBM) +## $(GETHOSTNAME_LIB) +## $(LIBSOCKET) +## $(LIB_NANOSLEEP) +## $(LTLIBINTL) +## $(ROUNDF_LIBM) +## $(ROUND_LIBM) +## $(TRUNCF_LIBM) +## $(TRUNC_LIBM) + +LIBCRUFT_LINK_DEPS = \ + $(COPYSIGN_LIBM) \ + $(FLOOR_LIBM) \ + $(GETHOSTNAME_LIB) \ + $(LIBSOCKET) \ + $(LIB_NANOSLEEP) \ + $(LTLIBINTL) \ + $(ROUNDF_LIBM) \ + $(ROUND_LIBM) \ + $(TRUNCF_LIBM) \ + $(TRUNC_LIBM) \ + $(LAPACK_LIBS) \ + $(BLAS_LIBS) \ + $(FLIBS) \ + $(LIBS) + +LIBCRUFT_LINK_OPTS =
--- a/liboctave/LSODE.cc +++ b/liboctave/LSODE.cc @@ -292,7 +292,7 @@ case -2: // excess accuracy requested (tolerances too small). case -3: // invalid input detected (see printed message). case -4: // repeated error test failures (check all inputs). - case -5: // repeated convergence failures (perhaps bad jacobian + case -5: // repeated convergence failures (perhaps bad Jacobian // supplied or wrong choice of mf or tolerances). case -6: // error weight became zero during problem. (solution // component i vanished, and atol or atol(i) = 0.) @@ -349,13 +349,13 @@ case -4: retval = std::string ("repeated error test failures (t = ") - + t_curr + "check all inputs)"; + + t_curr + "; check all inputs)"; break; case -5: retval = std::string ("repeated convergence failures (t = ") + t_curr - + "perhaps bad jacobian supplied or wrong choice of integration method or tolerances)"; + + "; perhaps bad Jacobian supplied or wrong choice of integration method or tolerances)"; break; case -6:
--- a/liboctave/MArray.cc +++ b/liboctave/MArray.cc @@ -339,7 +339,7 @@ MArray<T> \ FCN (const MArray<T>& a, const MArray<T>& b) \ { \ - return do_mm_binary_op<T, T, T> (a, b, FN, #FCN); \ + return do_mm_binary_op<T, T, T> (a, b, FN, FN, FN, #FCN); \ } MARRAY_NDND_OP (operator +, +, mx_inline_add)
--- a/liboctave/MDiagArray2.cc +++ b/liboctave/MDiagArray2.cc @@ -82,7 +82,7 @@ { \ if (a.d1 != b.d1 || a.d2 != b.d2) \ gripe_nonconformant (#FCN, a.d1, a.d2, b.d1, b.d2); \ - return MDiagArray2<T> (do_mm_binary_op<T, T, T> (a, b, FN, #FCN), a.d1, a.d2); \ + return MDiagArray2<T> (do_mm_binary_op<T, T, T> (a, b, FN, FN, FN, #FCN), a.d1, a.d2); \ } MARRAY_DADA_OP (operator +, +, mx_inline_add)
--- a/liboctave/Makefile.am +++ b/liboctave/Makefile.am @@ -188,6 +188,7 @@ base-dae.h \ base-de.h \ base-min.h \ + bsxfun.h \ byte-swap.h \ caseless-str.h \ cmd-edit.h \ @@ -491,21 +492,6 @@ LIBOCT_READLINE_SOURCES = $(LIBOCT_READLINE_CXX_SOURCES) $(LIBOCT_READLINE_C_SOURCES) -LINK_DEPS = \ - $(RLD_FLAG) \ - ../libcruft/libcruft.la \ - ../libcruft/libranlib.la \ - ../libgnu/libgnu.la \ - $(SPARSE_XLIBS) \ - $(ARPACK_LIBS) \ - $(QRUPDATE_LIBS) \ - $(FFTW_XLIBS) \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(READLINE_LIBS) $(TERM_LIBS) \ - $(LIBGLOB) $(REGEX_LIBS) $(DL_LIBS) \ - $(FLIBS) \ - $(PTHREAD_LIBS) $(LIBS) - liboctave_la_SOURCES = \ $(LIBOCTAVE_CXX_SOURCES) \ $(LIBOCTAVE_C_SOURCES) \ @@ -516,7 +502,11 @@ nodist_liboctave_la_SOURCES = \ $(BUILT_LIBOCTAVE_CXX_SOURCES) -liboctave_la_LIBADD = $(LINK_DEPS) +include link-deps.mk + +liboctave_la_LIBADD = \ + ../libcruft/libcruft.la \ + $(LIBOCTAVE_LINK_DEPS) liboctave_la_CPPFLAGS = \ @OCTAVE_DLL_DEFS@ \ @@ -537,10 +527,7 @@ -version-info $(liboctave_version_info) \ $(NO_UNDEFINED_LDFLAG) \ -bindir $(bindir) \ - $(SPARSE_XLDFLAGS) \ - $(ARPACK_LDFLAGS) \ - $(QRUPDATE_LDFLAGS) \ - $(FFTW_XLDFLAGS) + $(LIBOCTAVE_LINK_OPTS) octinclude_HEADERS = \ $(INCS) \
--- a/liboctave/bsxfun-decl.h +++ b/liboctave/bsxfun-decl.h @@ -42,6 +42,12 @@ BSXFUN_OP_DECL (min, ARRAY, API) \ BSXFUN_OP_DECL (max, ARRAY, API) +#define BSXFUN_MIXED_INT_DECLS(INT_TYPE, API) \ + BSXFUN_OP2_DECL (pow, INT_TYPE, INT_TYPE, NDArray, API) \ + BSXFUN_OP2_DECL (pow, INT_TYPE, INT_TYPE, FloatNDArray, API) \ + BSXFUN_OP2_DECL (pow, INT_TYPE, NDArray, INT_TYPE, API) \ + BSXFUN_OP2_DECL (pow, INT_TYPE, FloatNDArray, INT_TYPE, API) + #define BSXFUN_STDREL_DECLS(ARRAY, API) \ BSXFUN_REL_DECL (eq, ARRAY, API) \ BSXFUN_REL_DECL (ne, ARRAY, API) \
--- a/liboctave/bsxfun-defs.cc +++ b/liboctave/bsxfun-defs.cc @@ -174,4 +174,11 @@ BSXFUN_REL_DEF_MXLOOP (gt, ARRAY, mx_inline_gt) \ BSXFUN_REL_DEF_MXLOOP (ge, ARRAY, mx_inline_ge) +//For bsxfun power with mixed integer/float types +#define BSXFUN_POW_MIXED_MXLOOP(INT_TYPE) \ + BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, INT_TYPE, NDArray, mx_inline_pow) \ + BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, INT_TYPE, FloatNDArray, mx_inline_pow)\ + BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, NDArray, INT_TYPE, mx_inline_pow) \ + BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, FloatNDArray, INT_TYPE, mx_inline_pow) + #endif
new file mode 100644 --- /dev/null +++ b/liboctave/bsxfun.h @@ -0,0 +1,44 @@ +/* + +Copyright (C) 2011 Jordi Gutiérrez Hermoso <jordigh@octave.org> + +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 (bsxfun_h) +#define bsxfun_h 1 + +#include <algorithm> + +#include "Array.h" +#include "dim-vector.h" + +inline +bool +is_valid_bsxfun (const dim_vector& dx, const dim_vector& dy) +{ + for (int i = 0; i < std::min (dx.length (), dy.length ()); i++) + { + if ( dx(i) > 1 && dy(i) > 1 && dx(i) != dy(i)) + return false; + } + return true; +} + +#include "bsxfun-defs.cc" + +#endif
--- a/liboctave/chMatrix.cc +++ b/liboctave/chMatrix.cc @@ -74,8 +74,8 @@ elem (0, i) = s[i]; } -charMatrix::charMatrix (const string_vector& s) - : Array<char> (dim_vector (s.length (), s.max_length ()), 0) +charMatrix::charMatrix (const string_vector& s, char fill_value) + : Array<char> (dim_vector (s.length (), s.max_length ()), fill_value) { octave_idx_type nr = rows ();
--- a/liboctave/chMatrix.h +++ b/liboctave/chMatrix.h @@ -62,7 +62,7 @@ charMatrix (const std::string& s); - charMatrix (const string_vector& s); + charMatrix (const string_vector& s, char fill_value = '\0'); charMatrix& operator = (const charMatrix& a) {
--- a/liboctave/dNDArray.cc +++ b/liboctave/dNDArray.cc @@ -925,3 +925,5 @@ BSXFUN_OP_DEF_MXLOOP (pow, NDArray, mx_inline_pow) BSXFUN_OP2_DEF_MXLOOP (pow, ComplexNDArray, ComplexNDArray, NDArray, mx_inline_pow) +BSXFUN_OP2_DEF_MXLOOP (pow, ComplexNDArray, NDArray, + ComplexNDArray, mx_inline_pow)
--- a/liboctave/dNDArray.h +++ b/liboctave/dNDArray.h @@ -185,5 +185,7 @@ BSXFUN_OP_DECL (pow, NDArray, OCTAVE_API) BSXFUN_OP2_DECL (pow, ComplexNDArray, ComplexNDArray, NDArray, OCTAVE_API) +BSXFUN_OP2_DECL (pow, ComplexNDArray, NDArray, + ComplexNDArray, OCTAVE_API) #endif
--- a/liboctave/fNDArray.cc +++ b/liboctave/fNDArray.cc @@ -885,3 +885,5 @@ BSXFUN_OP_DEF_MXLOOP (pow, FloatNDArray, mx_inline_pow) BSXFUN_OP2_DEF_MXLOOP (pow, FloatComplexNDArray, FloatComplexNDArray, FloatNDArray, mx_inline_pow) +BSXFUN_OP2_DEF_MXLOOP (pow, FloatComplexNDArray, FloatNDArray, + FloatComplexNDArray, mx_inline_pow)
--- a/liboctave/fNDArray.h +++ b/liboctave/fNDArray.h @@ -182,5 +182,7 @@ BSXFUN_OP_DECL (pow, FloatNDArray, OCTAVE_API) BSXFUN_OP2_DECL (pow, FloatComplexNDArray, FloatComplexNDArray, FloatNDArray, OCTAVE_API) +BSXFUN_OP2_DECL (pow, FloatComplexNDArray, FloatNDArray, + FloatComplexNDArray, OCTAVE_API) #endif
--- a/liboctave/int16NDArray.cc +++ b/liboctave/int16NDArray.cc @@ -54,3 +54,7 @@ BSXFUN_STDOP_DEFS_MXLOOP (int16NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int16NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int16NDArray, mx_inline_pow) + +BSXFUN_POW_MIXED_MXLOOP (int16NDArray)
--- a/liboctave/int16NDArray.h +++ b/liboctave/int16NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (int16NDArray, octave_int16, OCTAVE_API) BSXFUN_STDOP_DECLS (int16NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(int16NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (int16NDArray, OCTAVE_API) #endif
--- a/liboctave/int32NDArray.cc +++ b/liboctave/int32NDArray.cc @@ -54,3 +54,6 @@ BSXFUN_STDOP_DEFS_MXLOOP (int32NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int32NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int32NDArray, mx_inline_pow) +BSXFUN_POW_MIXED_MXLOOP (int32NDArray)
--- a/liboctave/int32NDArray.h +++ b/liboctave/int32NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (int32NDArray, octave_int32, OCTAVE_API) BSXFUN_STDOP_DECLS (int32NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(int32NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (int32NDArray, OCTAVE_API) #endif
--- a/liboctave/int64NDArray.cc +++ b/liboctave/int64NDArray.cc @@ -54,3 +54,7 @@ BSXFUN_STDOP_DEFS_MXLOOP (int64NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int64NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int64NDArray, mx_inline_pow) + +BSXFUN_POW_MIXED_MXLOOP (int64NDArray)
--- a/liboctave/int64NDArray.h +++ b/liboctave/int64NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (int64NDArray, octave_int64, OCTAVE_API) BSXFUN_STDOP_DECLS (int64NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(int64NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (int64NDArray, OCTAVE_API) #endif
--- a/liboctave/int8NDArray.cc +++ b/liboctave/int8NDArray.cc @@ -54,3 +54,6 @@ BSXFUN_STDOP_DEFS_MXLOOP (int8NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int8NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int8NDArray, mx_inline_pow) +BSXFUN_POW_MIXED_MXLOOP (int8NDArray)
--- a/liboctave/int8NDArray.h +++ b/liboctave/int8NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (int8NDArray, octave_int8, OCTAVE_API) BSXFUN_STDOP_DECLS (int8NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(int8NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (int8NDArray, OCTAVE_API) #endif
new file mode 100644 --- /dev/null +++ b/liboctave/link-deps.mk @@ -0,0 +1,27 @@ +include ../libcruft/link-deps.mk + +LIBOCTAVE_LINK_DEPS = \ + $(SPARSE_XLIBS) \ + $(ARPACK_LIBS) \ + $(QRUPDATE_LIBS) \ + $(FFTW_XLIBS) \ + $(LAPACK_LIBS) \ + $(BLAS_LIBS) \ + $(READLINE_LIBS) \ + $(TERM_LIBS) \ + $(LIBGLOB) \ + $(REGEX_LIBS) \ + $(DL_LIBS) \ + $(PTHREAD_LIBS) \ + $(LIBS) + +LIBOCTAVE_LINK_OPTS = \ + $(SPARSE_XLDFLAGS) \ + $(ARPACK_LDFLAGS) \ + $(QRUPDATE_LDFLAGS) \ + $(FFTW_XLDFLAGS) + +if AMCOND_LINK_ALL_DEPS + LIBOCTAVE_LINK_DEPS += $(LIBCRUFT_LINK_DEPS) + LIBOCTAVE_LINK_OPTS += $(LIBCRUFT_LINK_OPTS) +endif
--- a/liboctave/lo-utils.cc +++ b/liboctave/lo-utils.cc @@ -196,44 +196,57 @@ } static inline double -read_inf_nan_na (std::istream& is, char c, char sign = '+') +read_inf_nan_na (std::istream& is, char c0, char sign = '+') { double d = 0.0; - switch (c) + switch (c0) { case 'i': case 'I': { - c = is.get (); - if (c == 'n' || c == 'N') + char c1 = is.get (); + if (c1 == 'n' || c1 == 'N') { - c = is.get (); - if (c == 'f' || c == 'F') + char c2 = is.get (); + if (c2 == 'f' || c2 == 'F') d = sign == '-' ? -octave_Inf : octave_Inf; else - is.putback (c); + { + is.putback (c2); + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; case 'n': case 'N': { - c = is.get (); - if (c == 'a' || c == 'A') + char c1 = is.get (); + if (c1 == 'a' || c1 == 'A') { - c = is.get (); - if (c == 'n' || c == 'N') + char c2 = is.get (); + if (c2 == 'n' || c2 == 'N') d = octave_NaN; else { - is.putback (c); + is.putback (c2); d = octave_NA; } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; @@ -244,6 +257,8 @@ return d; } +// Read a double value. Discard any sign on NaN and NA. + template <> double octave_read_value (std::istream& is) @@ -261,7 +276,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_inf_nan_na (is, c2, c1); else { @@ -276,7 +291,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_inf_nan_na (is, c2, c1); else { @@ -344,44 +359,57 @@ } static inline float -read_float_inf_nan_na (std::istream& is, char c, char sign = '+') +read_float_inf_nan_na (std::istream& is, char c0, char sign = '+') { float d = 0.0; - switch (c) + switch (c0) { case 'i': case 'I': { - c = is.get (); - if (c == 'n' || c == 'N') + char c1 = is.get (); + if (c1 == 'n' || c1 == 'N') { - c = is.get (); - if (c == 'f' || c == 'F') - d = sign == '-' ? -octave_Inf : octave_Inf; + char c2 = is.get (); + if (c2 == 'f' || c2 == 'F') + d = sign == '-' ? -octave_Float_Inf : octave_Float_Inf; else - is.putback (c); + { + is.putback (c2); + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; case 'n': case 'N': { - c = is.get (); - if (c == 'a' || c == 'A') + char c1 = is.get (); + if (c1 == 'a' || c1 == 'A') { - c = is.get (); - if (c == 'n' || c == 'N') - d = octave_NaN; + char c2 = is.get (); + if (c2 == 'n' || c2 == 'N') + d = octave_Float_NaN; else { - is.putback (c); - d = octave_NA; + is.putback (c2); + d = octave_Float_NA; } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; @@ -392,6 +420,8 @@ return d; } +// Read a float value. Discard any sign on NaN and NA. + template <> float octave_read_value (std::istream& is) @@ -409,7 +439,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_float_inf_nan_na (is, c2, c1); else { @@ -424,7 +454,7 @@ { char c2 = 0; c2 = is.get (); - if (c2 == 'i' || c2 == 'I') + if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') d = read_float_inf_nan_na (is, c2, c1); else {
--- a/liboctave/mx-inlines.cc +++ b/liboctave/mx-inlines.cc @@ -37,6 +37,8 @@ #include "Array.h" #include "Array-util.h" +#include "bsxfun.h" + // Provides some commonly repeated, basic loop templates. template <class R, class S> @@ -286,7 +288,10 @@ inline void F (size_t n, R *r, X x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); } -DEFMXMAPPER2X (mx_inline_pow, std::pow) +// Let the compiler decide which pow to use, whichever best matches the +// arguments provided. +using std::pow; +DEFMXMAPPER2X (mx_inline_pow, pow) // Arbitrary function appliers. The function is a template parameter to enable // inlining. @@ -336,11 +341,12 @@ return r; } - template <class R, class X, class Y> inline Array<R> do_mm_binary_op (const Array<X>& x, const Array<Y>& y, void (*op) (size_t, R *, const X *, const Y *) throw (), + void (*op1) (size_t, R *, X, const Y *) throw (), + void (*op2) (size_t, R *, const X *, Y) throw (), const char *opname) { dim_vector dx = x.dims (), dy = y.dims (); @@ -350,6 +356,10 @@ op (r.length (), r.fortran_vec (), x.data (), y.data ()); return r; } + else if (is_valid_bsxfun (dx, dy)) + { + return do_bsxfun_op (x, y, op, op1, op2); + } else { gripe_nonconformant (opname, dx, dy);
--- a/liboctave/mx-op-defs.h +++ b/liboctave/mx-op-defs.h @@ -72,7 +72,7 @@ R \ F (const V1& v1, const V2& v2) \ { \ - return do_mm_binary_op<R::element_type, V1::element_type, V2::element_type> (v1, v2, OP, #F); \ + return do_mm_binary_op<R::element_type, V1::element_type, V2::element_type> (v1, v2, OP, OP, OP, #F); \ } #define VV_BIN_OPS(R, V1, V2) \ @@ -173,7 +173,7 @@ R \ OP (const M1& m1, const M2& m2) \ { \ - return do_mm_binary_op<R::element_type, M1::element_type, M2::element_type> (m1, m2, F, #OP); \ + return do_mm_binary_op<R::element_type, M1::element_type, M2::element_type> (m1, m2, F, F, F, #OP); \ } #define MM_BIN_OPS(R, M1, M2) \ @@ -186,7 +186,7 @@ boolMatrix \ F (const M1& m1, const M2& m2) \ { \ - return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, #F); \ + return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, OP, OP, #F); \ } #define MM_CMP_OPS(M1, M2) \ @@ -203,7 +203,7 @@ { \ MNANCHK (m1, M1::element_type); \ MNANCHK (m2, M2::element_type); \ - return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, #F); \ + return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, OP, OP, #F); \ } #define MM_BOOL_OPS(M1, M2) \ @@ -310,7 +310,7 @@ R \ OP (const ND1& m1, const ND2& m2) \ { \ - return do_mm_binary_op<R::element_type, ND1::element_type, ND2::element_type> (m1, m2, F, #OP); \ + return do_mm_binary_op<R::element_type, ND1::element_type, ND2::element_type> (m1, m2, F, F, F, #OP); \ } #define NDND_BIN_OPS(R, ND1, ND2) \ @@ -323,7 +323,7 @@ boolNDArray \ F (const ND1& m1, const ND2& m2) \ { \ - return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, #F); \ + return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, OP, OP, #F); \ } #define NDND_CMP_OPS(ND1, ND2) \ @@ -340,7 +340,7 @@ { \ MNANCHK (m1, ND1::element_type); \ MNANCHK (m2, ND2::element_type); \ - return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, #F); \ + return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, OP, OP, #F); \ } #define NDND_BOOL_OPS(ND1, ND2) \ @@ -583,7 +583,7 @@ T \ FCN (const T& a, const T& b) \ { \ - return do_mm_binary_op<T::element_type, T::element_type, T::element_type> (a, b, mx_inline_x##FCN, #FCN); \ + return do_mm_binary_op<T::element_type, T::element_type, T::element_type> (a, b, mx_inline_x##FCN, mx_inline_x##FCN, mx_inline_x##FCN, #FCN); \ } #define MINMAX_FCNS(T, S) \
--- a/liboctave/oct-binmap.h +++ b/liboctave/oct-binmap.h @@ -27,9 +27,13 @@ #include "Sparse.h" #include "Array-util.h" -// This source implements a general binary maping function for arrays. -// The syntax is binmap<type> (a, b, f, [name]). type denotes the expected -// return type of the operation. a, b, should be one of the 6 combinations: +#include "bsxfun.h" + +// This source file implements a general binary maping function for +// arrays. The syntax is binmap<type> (a, b, f, [name]). type denotes +// the expected return type of the operation. a, b, should be one of +// the 6 combinations: +// // Array-Array // Array-scalar // scalar-Array @@ -37,11 +41,12 @@ // Sparse-scalar // scalar-Sparse // -// If both operands are nonscalar, name must be supplied. It is used as the base for error message -// when operands are nonconforming. +// If both operands are nonscalar, name must be supplied. It is used +// as the base for error message when operands are nonconforming. // -// The operation needs not be homogeneous, i.e. a, b and the result may be of distinct types. -// f can have any of the four signatures: +// The operation needs not be homogeneous, i.e. a, b and the result +// may be of distinct types. f can have any of the four signatures: +// // U f (T, R) // U f (const T&, R) // U f (T, const R&) @@ -49,7 +54,51 @@ // // Additionally, f can be an arbitrary functor object. // -// octave_quit() is called at appropriate places, hence the operation is breakable. +// octave_quit() is called at appropriate places, hence the operation +// is breakable. + +// The following template wrappers are provided for automatic bsxfun +// calls (see the function signature for do_bsxfun_op). + +template<typename R, typename X, typename Y, typename F> +class bsxfun_wrapper +{ +private: + static F f; + +public: + static void + set_f (const F& f_in) + { + f = f_in; + } + + static void + op_mm (size_t n, R* r, const X* x , const Y* y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x[i], y[i]); + } + + static void + op_sm (size_t n, R* r, X x, const Y* y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x, y[i]); + } + + static void + op_ms (size_t n , R* r, const X* x, Y y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x[i], y); + } +}; + +// Static init +template<typename R, typename X, typename Y, typename F> +F bsxfun_wrapper<R, X, Y, F>::f; + // scalar-Array template <class U, class T, class R, class F> @@ -118,12 +167,24 @@ Array<U> binmap (const Array<T>& xa, const Array<R>& ya, F fcn, const char *name) { + dim_vector xad = xa.dims (), yad = ya.dims (); if (xa.numel () == 1) return binmap<U, T, R, F> (xa(0), ya, fcn); else if (ya.numel () == 1) return binmap<U, T, R, F> (xa, ya(0), fcn); - else if (xa.dims () != ya.dims ()) - gripe_nonconformant (name, xa.dims (), ya.dims ()); + else if (xad != yad) + { + if (is_valid_bsxfun (xad, yad)) + { + bsxfun_wrapper<U, T, R, F>::set_f(fcn); + return do_bsxfun_op (xa, ya, + bsxfun_wrapper<U, T, R, F>::op_mm, + bsxfun_wrapper<U, T, R, F>::op_sm, + bsxfun_wrapper<U, T, R, F>::op_ms); + } + else + gripe_nonconformant (name, xad, yad); + } octave_idx_type len = xa.numel (); @@ -273,134 +334,134 @@ fcn, name)); } -// Overloads for function references. +// Overloads for function pointers. // Signature (T, R) template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (T, R), const char *name) -{ return binmap<U, T, R, U (&) (T, R)> (xa, ya, fcn, name); } +binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, R), const char *name) +{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Array<U> -binmap (const T& x, const Array<R>& ya, U (&fcn) (T, R)) -{ return binmap<U, T, R, U (&) (T, R)> (x, ya, fcn); } +binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R)) +{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); } template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const R& y, U (&fcn) (T, R)) -{ return binmap<U, T, R, U (&) (T, R)> (xa, y, fcn); } +binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R)) +{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (T, R), const char *name) -{ return binmap<U, T, R, U (&) (T, R)> (xa, ya, fcn, name); } +binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, R), const char *name) +{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Sparse<U> -binmap (const T& x, const Sparse<R>& ya, U (&fcn) (T, R)) -{ return binmap<U, T, R, U (&) (T, R)> (x, ya, fcn); } +binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R)) +{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const R& y, U (&fcn) (T, R)) -{ return binmap<U, T, R, U (&) (T, R)> (xa, y, fcn); } +binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, R)) +{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); } // Signature (const T&, const R&) template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (const T&, const R&), const char *name) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, ya, fcn, name); } +binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, const R&), const char *name) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Array<U> -binmap (const T& x, const Array<R>& ya, U (&fcn) (const T&, const R&)) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (x, ya, fcn); } +binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, const R&)) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); } template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const R& y, U (&fcn) (const T&, const R&)) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, y, fcn); } +binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, const R&)) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (const T&, const R&), const char *name) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, ya, fcn, name); } +binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, const R&), const char *name) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Sparse<U> -binmap (const T& x, const Sparse<R>& ya, U (&fcn) (const T&, const R&)) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (x, ya, fcn); } +binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, const R&)) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const R& y, U (&fcn) (const T&, const R&)) -{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, y, fcn); } +binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, const R&)) +{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); } // Signature (const T&, R) template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (const T&, R), const char *name) -{ return binmap<U, T, R, U (&) (const T&, R)> (xa, ya, fcn, name); } +binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, R), const char *name) +{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Array<U> -binmap (const T& x, const Array<R>& ya, U (&fcn) (const T&, R)) -{ return binmap<U, T, R, U (&) (const T&, R)> (x, ya, fcn); } +binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, R)) +{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); } template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const R& y, U (&fcn) (const T&, R)) -{ return binmap<U, T, R, U (&) (const T&, R)> (xa, y, fcn); } +binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, R)) +{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (const T&, R), const char *name) -{ return binmap<U, T, R, U (&) (const T&, R)> (xa, ya, fcn, name); } +binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, R), const char *name) +{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Sparse<U> -binmap (const T& x, const Sparse<R>& ya, U (&fcn) (const T&, R)) -{ return binmap<U, T, R, U (&) (const T&, R)> (x, ya, fcn); } +binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, R)) +{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const R& y, U (&fcn) (const T&, R)) -{ return binmap<U, T, R, U (&) (const T&, R)> (xa, y, fcn); } +binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, R)) +{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); } // Signature (T, const R&) template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (T, const R&), const char *name) -{ return binmap<U, T, R, U (&) (T, const R&)> (xa, ya, fcn, name); } +binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, const R&), const char *name) +{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Array<U> -binmap (const T& x, const Array<R>& ya, U (&fcn) (T, const R&)) -{ return binmap<U, T, R, U (&) (T, const R&)> (x, ya, fcn); } +binmap (const T& x, const Array<R>& ya, U (*fcn) (T, const R&)) +{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); } template <class U, class T, class R> inline Array<U> -binmap (const Array<T>& xa, const R& y, U (&fcn) (T, const R&)) -{ return binmap<U, T, R, U (&) (T, const R&)> (xa, y, fcn); } +binmap (const Array<T>& xa, const R& y, U (*fcn) (T, const R&)) +{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (T, const R&), const char *name) -{ return binmap<U, T, R, U (&) (T, const R&)> (xa, ya, fcn, name); } +binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, const R&), const char *name) +{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); } template <class U, class T, class R> inline Sparse<U> -binmap (const T& x, const Sparse<R>& ya, U (&fcn) (T, const R&)) -{ return binmap<U, T, R, U (&) (T, const R&)> (x, ya, fcn); } +binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, const R&)) +{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); } template <class U, class T, class R> inline Sparse<U> -binmap (const Sparse<T>& xa, const R& y, U (&fcn) (T, const R&)) -{ return binmap<U, T, R, U (&) (T, const R&)> (xa, y, fcn); } +binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, const R&)) +{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); } #endif
--- a/liboctave/oct-inttypes.cc +++ b/liboctave/oct-inttypes.cc @@ -578,6 +578,23 @@ template <class T> octave_int<T> +pow (const float& a, const octave_int<T>& b) +{ return octave_int<T> (pow (a, b.float_value ())); } + +template <class T> +octave_int<T> +pow (const octave_int<T>& a, const float& b) +{ + return ((b >= 0 && b < std::numeric_limits<T>::digits && b == xround (b)) + ? pow (a, octave_int<T> (static_cast<T> (b))) + : octave_int<T> (pow (a.double_value (), static_cast<double> (b)))); +} + +// FIXME: Do we really need a differently named single-precision +// function integer power function here instead of an overloaded +// one? +template <class T> +octave_int<T> powf (const float& a, const octave_int<T>& b) { return octave_int<T> (pow (a, b.float_value ())); } @@ -595,6 +612,8 @@ template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const octave_int<T>&); \ template OCTAVE_API octave_int<T> pow (const double&, const octave_int<T>&); \ template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const double&); \ + template OCTAVE_API octave_int<T> pow (const float&, const octave_int<T>&); \ + template OCTAVE_API octave_int<T> pow (const octave_int<T>&, const float&); \ template OCTAVE_API octave_int<T> powf (const float&, const octave_int<T>&); \ template OCTAVE_API octave_int<T> powf (const octave_int<T>&, const float&); \ template OCTAVE_API octave_int<T> \
--- a/liboctave/oct-inttypes.h +++ b/liboctave/oct-inttypes.h @@ -874,6 +874,17 @@ template <class T> extern OCTAVE_API octave_int<T> +pow (const float& a, const octave_int<T>& b); + +template <class T> +extern OCTAVE_API octave_int<T> +pow (const octave_int<T>& a, const float& b); + +// FIXME: Do we really need a differently named single-precision +// function integer power function here instead of an overloaded +// one? +template <class T> +extern OCTAVE_API octave_int<T> powf (const float& a, const octave_int<T>& b); template <class T>
--- a/liboctave/str-vec.cc +++ b/liboctave/str-vec.cc @@ -163,6 +163,26 @@ return *this; } +std::string +string_vector::join (const std::string& sep) const +{ + std::string retval; + + octave_idx_type len = length (); + + if (len > 0) + { + octave_idx_type i; + + for (i = 0; i < len - 1; i++) + retval += elem(i) + sep; + + retval += elem(i); + } + + return retval; +} + char ** string_vector::c_str_vec (void) const {
--- a/liboctave/str-vec.h +++ b/liboctave/str-vec.h @@ -105,6 +105,8 @@ string_vector& append (const string_vector& sv); + std::string join (const std::string& sep = std::string ()) const; + char **c_str_vec (void) const; static void delete_c_str_vec (const char * const*);
--- a/liboctave/uint16NDArray.cc +++ b/liboctave/uint16NDArray.cc @@ -54,3 +54,6 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint16NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint16NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint16NDArray, mx_inline_pow) +BSXFUN_POW_MIXED_MXLOOP (uint16NDArray)
--- a/liboctave/uint16NDArray.h +++ b/liboctave/uint16NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (uint16NDArray, octave_uint16, OCTAVE_API) BSXFUN_STDOP_DECLS (uint16NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(uint16NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (uint16NDArray, OCTAVE_API) #endif
--- a/liboctave/uint32NDArray.cc +++ b/liboctave/uint32NDArray.cc @@ -54,3 +54,6 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint32NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint32NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint32NDArray, mx_inline_pow) +BSXFUN_POW_MIXED_MXLOOP (uint32NDArray)
--- a/liboctave/uint32NDArray.h +++ b/liboctave/uint32NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (uint32NDArray, octave_uint32, OCTAVE_API) BSXFUN_STDOP_DECLS (uint32NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(uint32NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (uint32NDArray, OCTAVE_API) #endif
--- a/liboctave/uint64NDArray.cc +++ b/liboctave/uint64NDArray.cc @@ -54,3 +54,7 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint64NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint64NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint64NDArray, mx_inline_pow) +BSXFUN_POW_MIXED_MXLOOP (uint64NDArray) +
--- a/liboctave/uint64NDArray.h +++ b/liboctave/uint64NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (uint64NDArray, octave_uint64, OCTAVE_API) BSXFUN_STDOP_DECLS (uint64NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(uint64NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (uint64NDArray, OCTAVE_API) #endif
--- a/liboctave/uint8NDArray.cc +++ b/liboctave/uint8NDArray.cc @@ -54,3 +54,7 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint8NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint8NDArray) + +BSXFUN_POW_MIXED_MXLOOP (uint8NDArray) +BSXFUN_OP_DEF_MXLOOP (pow, uint8NDArray, mx_inline_pow) +
--- a/liboctave/uint8NDArray.h +++ b/liboctave/uint8NDArray.h @@ -44,6 +44,7 @@ MINMAX_DECLS (uint8NDArray, octave_uint8, OCTAVE_API) BSXFUN_STDOP_DECLS (uint8NDArray, OCTAVE_API) +BSXFUN_MIXED_INT_DECLS(uint8NDArray, OCTAVE_API) BSXFUN_STDREL_DECLS (uint8NDArray, OCTAVE_API) #endif
--- a/scripts/audio/playaudio.m +++ b/scripts/audio/playaudio.m @@ -47,7 +47,10 @@ num = fopen (file, "wb"); c = fwrite (num, X, "uchar"); fclose (num); - system (sprintf ("cat \"%s\" > /dev/dsp", file)); + [status, out] = system (sprintf ("cat \"%s\" > /dev/dsp", file)); + if (status != 0) + system (sprintf ("paplay --raw \"%s\"", file)) + endif unwind_protect_cleanup unlink (file); end_unwind_protect @@ -61,10 +64,16 @@ print_usage (); endif if (strcmp (ext, "lin") || strcmp (ext, "raw")) - system (sprintf ("cat \"%s\" > /dev/dsp", name)); + [status, out] = system (sprintf ("cat \"%s\" > /dev/dsp", name)); + if (status != 0) + system (sprintf ("paplay --raw \"%s\"", name)) + endif elseif (strcmp (ext, "mu") || strcmp (ext, "au") || strcmp (ext, "snd") || strcmp (ext, "ul")) - system (sprintf ("cat \"%s\" > /dev/audio", name)); + [status, out] = system (sprintf ("cat \"%s\" > /dev/audio", name)); + if (status != 0) + system (sprintf ("paplay \"%s\"", name)) + endif else error ("playaudio: unsupported extension"); endif
--- a/scripts/audio/wavread.m +++ b/scripts/audio/wavread.m @@ -55,135 +55,139 @@ error ("wavread: FILENAME must be a character string"); endif - # Open file for binary reading. - [fid, msg] = fopen (filename, "rb"); - if (fid < 0) - error ("wavread: %s", msg); - endif + fid = -1; + + unwind_protect - ## Get file size. - fseek (fid, 0, "eof"); - file_size = ftell (fid); - fseek (fid, 0, "bof"); + [fid, msg] = fopen (filename, "rb"); + + if (fid < 0) + error ("wavread: %s", msg); + endif - ## Find RIFF chunk. - riff_size = find_chunk (fid, "RIFF", file_size); - riff_pos = ftell (fid); - if (riff_size == -1) - fclose (fid); - error ("wavread: file contains no RIFF chunk"); - endif + ## Get file size. + fseek (fid, 0, "eof"); + file_size = ftell (fid); + fseek (fid, 0, "bof"); - riff_type = char (fread (fid, 4))'; - if (! strcmp (riff_type, "WAVE")) - fclose (fid); - error ("wavread: file contains no WAVE signature"); - endif - riff_pos = riff_pos + 4; - riff_size = riff_size - 4; + ## Find RIFF chunk. + riff_size = find_chunk (fid, "RIFF", file_size); + riff_pos = ftell (fid); + if (riff_size == -1) + error ("wavread: file contains no RIFF chunk"); + endif + + riff_type = char (fread (fid, 4))'; + if (! strcmp (riff_type, "WAVE")) + error ("wavread: file contains no WAVE signature"); + endif + riff_pos = riff_pos + 4; + riff_size = riff_size - 4; - ## Find format chunk inside the RIFF chunk. - fseek (fid, riff_pos, "bof"); - fmt_size = find_chunk (fid, "fmt ", riff_size); - fmt_pos = ftell(fid); - if (fmt_size == -1) - fclose (fid); - error ("wavread: file contains no format chunk"); - endif + ## Find format chunk inside the RIFF chunk. + fseek (fid, riff_pos, "bof"); + fmt_size = find_chunk (fid, "fmt ", riff_size); + fmt_pos = ftell(fid); + if (fmt_size == -1) + error ("wavread: file contains no format chunk"); + endif + + ## Find data chunk inside the RIFF chunk. + ## We don't assume that it comes after the format chunk. + fseek (fid, riff_pos, "bof"); + data_size = find_chunk (fid, "data", riff_size); + data_pos = ftell (fid); + if (data_size == -1) + error ("wavread: file contains no data chunk"); + endif - ## Find data chunk inside the RIFF chunk. - ## We don't assume that it comes after the format chunk. - fseek (fid, riff_pos, "bof"); - data_size = find_chunk (fid, "data", riff_size); - data_pos = ftell (fid); - if (data_size == -1) - fclose (fid); - error ("wavread: file contains no data chunk"); - endif + ### Read format chunk. + fseek (fid, fmt_pos, "bof"); - ### Read format chunk. - fseek (fid, fmt_pos, "bof"); + ## Sample format code. + format_tag = fread (fid, 1, "uint16", 0, BYTEORDER); + if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) + error ("wavread: sample format %#x is not supported", format_tag); + endif - ## Sample format code. - format_tag = fread (fid, 1, "uint16", 0, BYTEORDER); - if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) - fclose (fid); - error ("wavread: sample format %#x is not supported", format_tag); - endif + ## Number of interleaved channels. + channels = fread (fid, 1, "uint16", 0, BYTEORDER); - ## Number of interleaved channels. - channels = fread (fid, 1, "uint16", 0, BYTEORDER); + ## Sample rate. + samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER); - ## Sample rate. - samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER); + ## Bits per sample. + fseek (fid, 6, "cof"); + bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER); - ## Bits per sample. - fseek (fid, 6, "cof"); - bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER); + ### Read data chunk. + fseek (fid, data_pos, "bof"); - ### Read data chunk. - fseek (fid, data_pos, "bof"); + ## Determine sample data type. + if (format_tag == FORMAT_PCM) + switch (bits_per_sample) + case 8 + format = "uint8"; + case 16 + format = "int16"; + case 24 + format = "uint8"; + case 32 + format = "int32"; + otherwise + error ("wavread: %d bits sample resolution is not supported with PCM", + bits_per_sample); + endswitch + else + switch (bits_per_sample) + case 32 + format = "float32"; + case 64 + format = "float64"; + otherwise + error ("wavread: %d bits sample resolution is not supported with IEEE float", + bits_per_sample); + endswitch + endif - ## Determine sample data type. - if (format_tag == FORMAT_PCM) - switch (bits_per_sample) - case 8 - format = "uint8"; - case 16 - format = "int16"; - case 24 - format = "uint8"; - case 32 - format = "int32"; - otherwise - fclose (fid); - error ("wavread: %d bits sample resolution is not supported with PCM", - bits_per_sample); - endswitch - else - switch (bits_per_sample) - case 32 - format = "float32"; - case 64 - format = "float64"; - otherwise - fclose (fid); - error ("wavread: %d bits sample resolution is not supported with IEEE float", - bits_per_sample); - endswitch - endif + ## Parse arguments. + if (nargin == 1) + length = idivide (8 * data_size, bits_per_sample); + else + nparams = numel (param); + if (nparams == 1) + ## Number of samples is given. + length = param * channels; + elseif (nparams == 2) + ## Sample range is given. + if (fseek (fid, (param(1)-1) * channels * (bits_per_sample/8), "cof") < 0) + warning ("wavread: seeking failed"); + endif + length = (param(2)-param(1)+1) * channels; + elseif (nparams == 4 && char (param) == "size") + ## Size of the file is requested. + tmp = idivide (8 * data_size, channels * bits_per_sample); + y = [tmp, channels]; + return; + else + error ("wavread: invalid PARAM argument"); + endif + endif - ## Parse arguments. - if (nargin == 1) - length = 8 * data_size / bits_per_sample; - else - nparams = numel (param); - if (nparams == 1) - ## Number of samples is given. - length = param * channels; - elseif (nparams == 2) - ## Sample range is given. - if (fseek (fid, (param(1)-1) * channels * (bits_per_sample/8), "cof") < 0) - warning ("wavread: seeking failed"); - endif - length = (param(2)-param(1)+1) * channels; - elseif (nparams == 4 && char (param) == "size") - ## Size of the file is requested. + ## Read samples and close file. + if (bits_per_sample == 24) + length *= 3; + endif + + [yi, n] = fread (fid, length, format, 0, BYTEORDER); + + unwind_protect_cleanup + + if (fid >= 0) fclose (fid); - y = [data_size/channels/(bits_per_sample/8), channels]; - return; - else - fclose (fid); - error ("wavread: invalid PARAM argument"); endif - endif - ## Read samples and close file. - if (bits_per_sample == 24) - length *= 3; - endif - [yi, n] = fread (fid, length, format, 0, BYTEORDER); - fclose (fid); + end_unwind_protect ## Check data. if (mod (numel (yi), channels) != 0) @@ -240,7 +244,6 @@ endif endfunction - -%% Tests for wavread/wavwrite pair are in wavrite.m -%!assert(1) # stop fntests.m from reporting no tests for wavread - +## Mark file as being tested. Tests for wavread/wavwrite pair are in +## wavwrite.m +%!assert(1)
new file mode 100644 --- /dev/null +++ b/scripts/deprecated/__error_text__.m @@ -0,0 +1,36 @@ +## Copyright (C) 2011 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/>. + +## -*- texinfo -*- +## @deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} __error_text__ (@var{msg}, @var{msgid}) +## This function has been deprecated. Use @code{lasterr} instead. +## @seealso{lasterr} +## @end deftypefn + +function [msg, msgid] = __error_text__ (varargin) + + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "__error_text__ is obsolete and will be removed from a future version of Octave, please use lasterr instead"); + endif + + [msg, msgid] = lasterr (varargin{:}); + +endfunction
deleted file mode 100644 --- a/scripts/deprecated/complement.m +++ /dev/null @@ -1,78 +0,0 @@ -## Copyright (C) 1994-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} complement (@var{x}, @var{y}) -## Return the elements of set @var{y} that are not in set @var{x}. For -## example: -## -## @example -## @group -## complement ([ 1, 2, 3 ], [ 2, 3, 5 ]) -## @result{} 5 -## @end group -## @end example -## @seealso{union, intersect, unique} -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function y = complement (a, b) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "complement is obsolete and will be removed from a future version of Octave, please use setdiff instead"); - endif - - if (nargin != 2) - print_usage (); - endif - - if (isempty (a)) - y = unique (b); - elseif (isempty (b)) - y = []; - else - a = unique (a); - b = unique (b); - yindex = 1; - y = zeros (1, length (b)); - for index = 1:length (b) - if (all (a != b (index))) - y(yindex++) = b(index); - endif - endfor - y = y(1:(yindex-1)); - endif - -endfunction - -%!assert(all (all (complement ([1, 2, 3], [3; 4; 5; 6]) == [4, 5, 6]))); - -%!assert(all (all (complement ([1, 2, 3], [3, 4, 5, 6]) == [4, 5, 6]))); - -%!assert(isempty (complement ([1, 2, 3], [3, 2, 1]))); - -%!error complement (1); - -%!error complement (1, 2, 3); -
rename from scripts/statistics/base/cor.m rename to scripts/deprecated/cor.m --- a/scripts/statistics/base/cor.m +++ b/scripts/deprecated/cor.m @@ -27,6 +27,13 @@ function retval = cor (x, y = x) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "cor is obsolete and will be removed from a future version of Octave; please use corr instead"); + endif + if (nargin < 1 || nargin > 2) print_usage (); endif @@ -35,6 +42,7 @@ endfunction + %!test %! x = rand (10, 2); %! assert (cor (x), corrcoef (x), 5*eps);
rename from scripts/statistics/base/corrcoef.m rename to scripts/deprecated/corrcoef.m --- a/scripts/statistics/base/corrcoef.m +++ b/scripts/deprecated/corrcoef.m @@ -48,20 +48,26 @@ function retval = corrcoef (x, y = []) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "corrcoef is not equivalent to Matlab and will be removed from a future version of Octave; for similar functionality see corr"); + endif + if (nargin < 1 || nargin > 2) print_usage (); endif - if (! (isnumeric (x) && isnumeric (y))) - error ("corrcoef: X and Y must be numeric matrices or vectors"); - endif + ## Input validation is done by cov.m. Don't repeat tests here - if (ndims (x) != 2 || ndims (y) != 2) - error ("corrcoef: X and Y must be 2-D matrices or vectors"); - endif - + ## Special case, scalar is always 100% correlated with itself if (isscalar (x)) - retval = 1; + if (isa (x, 'single')) + retval = single (1); + else + retval = 1; + endif return; endif @@ -79,20 +85,35 @@ endfunction + %!test %! x = rand (10); %! cc1 = corrcoef (x); %! cc2 = corrcoef (x, x); -%! assert((size (cc1) == [10, 10] && size (cc2) == [10, 10] -%! && abs (cc1 - cc2) < sqrt (eps))); +%! assert (size (cc1) == [10, 10] && size (cc2) == [10, 10]); +%! assert (cc1, cc2, sqrt (eps)); + +%!test +%! x = [1:3]'; +%! y = [3:-1:1]'; +%! assert (corrcoef (x,y), -1, 5*eps) +%! assert (corrcoef (x,flipud (y)), 1, 5*eps) +%! assert (corrcoef ([x, y]), [1 -1; -1 1], 5*eps) -%!assert(corrcoef (5), 1); +%!test +%! x = single ([1:3]'); +%! y = single ([3:-1:1]'); +%! assert (corrcoef (x,y), single (-1), 5*eps) +%! assert (corrcoef (x,flipud (y)), single (1), 5*eps) +%! assert (corrcoef ([x, y]), single ([1 -1; -1 1]), 5*eps) + +%!assert (corrcoef (5), 1); +%!assert (corrcoef (single(5)), single(1)); %% Test input validation %!error corrcoef (); %!error corrcoef (1, 2, 3); -%!error corrcoef ([true, true]); -%!error corrcoef ([1, 2], [true, true]); +%!error corrcoef ([1; 2], ["A", "B"]); %!error corrcoef (ones (2,2,2)); %!error corrcoef (ones (2,2), ones (2,2,2));
deleted file mode 100644 --- a/scripts/deprecated/create_set.m +++ /dev/null @@ -1,79 +0,0 @@ -## Copyright (C) 1994-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} create_set (@var{x}) -## @deftypefnx {Function File} {} create_set (@var{x}, "rows") -## This function has been deprecated. Use unique instead. -## @end deftypefn - -## Return a row vector containing the unique values in @var{x}, sorted in -## ascending order. For example, -## -## @example -## @group -## create_set ([ 1, 2; 3, 4; 4, 2; 1, 2 ]) -## @result{} [ 1, 2, 3, 4 ] -## @end group -## @end example -## -## If the optional second input argument is the string "rows" each row of -## the matrix @var{x} will be considered an element of set. For example, -## @example -## @group -## create_set ([ 1, 2; 3, 4; 4, 2; 1, 2 ], "rows") -## @result{} 1 2 -## 3 4 -## 4 2 -## @end group -## @end example -## @seealso{union, intersect, complement, unique} - -## Author: jwe - -## Deprecated in version 3.2 - -function y = create_set (x, rows_opt) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "create_set is obsolete and will be removed from a future version of Octave, please use unique instead"); - endif - - if (nargin < 1 || nargin > 2) - print_usage (); - endif - - if (nargin == 1) - y = unique (x)(:)'; - elseif (strcmpi (rows_opt, "rows")) - y = unique (x, "rows"); - else - error ("create_set: expecting \"rows\" as second argument"); - endif - -endfunction - -%!assert(all (all (create_set ([1, 2, 3, 4, 2, 4]) == [1, 2, 3, 4]))); -%!assert(all (all (create_set ([1, 2; 3, 4; 2, 4]) == [1, 2, 3, 4]))); -%!assert(all (all (create_set ([1; 2; 3; 4; 2; 4]) == [1, 2, 3, 4]))); -%!assert(isempty (create_set ([]))); -%!error create_set (1, 2); -
rename from scripts/statistics/base/cut.m rename to scripts/deprecated/cut.m --- a/scripts/statistics/base/cut.m +++ b/scripts/deprecated/cut.m @@ -37,6 +37,13 @@ function group = cut (x, breaks) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "cut is obsolete and will be removed from a future version of Octave; please use histc instead"); + endif + if (nargin != 2) print_usage (); endif
deleted file mode 100644 --- a/scripts/deprecated/dmult.m +++ /dev/null @@ -1,49 +0,0 @@ -## Copyright (C) 1995-2011 Kurt Hornik -## -## 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} dmult (@var{a}, @var{b}) -## This function has been deprecated. Use the direct syntax @code{diag(A)*B} -## which is more readable and now also more efficient. -## @end deftypefn - -## Author: KH <Kurt.Hornik@wu-wien.ac.at> -## Description: Rescale the rows of a matrix - -## Deprecated in version 3.2 - -function M = dmult (a, B) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "dmult is obsolete and will be removed from a future version of Octave; please use the straightforward (and now efficient) syntax \"diag(A)*B\""); - endif - - if (nargin != 2) - print_usage (); - endif - if (! isvector (a)) - error ("dmult: a must be a vector of length rows (B)"); - endif - a = a(:); - sb = size (B); - sb(1) = 1; - M = repmat (a(:), sb) .* B; -endfunction
new file mode 100644 --- /dev/null +++ b/scripts/deprecated/error_text.m @@ -0,0 +1,36 @@ +## Copyright (C) 2011 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/>. + +## -*- texinfo -*- +## @deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} error_text (@var{msg}, @var{msgid}) +## This function has been deprecated. Use @code{lasterr} instead. +## @seealso{lasterr} +## @end deftypefn + +function [msg, msgid] = error_text (varargin) + + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "error_text is obsolete and will be removed from a future version of Octave, please use lasterr instead"); + endif + + [msg, msgid] = lasterr (varargin{:}); + +endfunction
deleted file mode 100644 --- a/scripts/deprecated/iscommand.m +++ /dev/null @@ -1,44 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} iscommand (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function retval = iscommand () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "iscommand is obsolete and will be removed from a future version of Octave"); - endif - - if (nargin == 0) - retval = {}; - else - retval = true; - endif - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/israwcommand.m +++ /dev/null @@ -1,44 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} israwcommand (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function retval = israwcommand () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "israwcommand is obsolete and will be removed from a future version of Octave"); - endif - - if (nargin == 0) - retval = {}; - else - retval = true; - endif - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/lchol.m +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{l} =} lchol (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{p}] =} lchol (@var{a}) -## This function has been deprecated. Use @code{chol (@dots{},'lower')} -## instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = lchol (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spfind is obsolete and will be removed from a future version of Octave; please use find instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = chol (varargin{:}, "lower"); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/loadimage.m +++ /dev/null @@ -1,43 +0,0 @@ -## Copyright (C) 1994-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{x}, @var{map}] =} loadimage (@var{file}) -## Load an image file and its associated color map from the specified -## @var{file}. The image must be stored in Octave's image format. -## @seealso{saveimage, load, save} -## @end deftypefn - -## Author: Tony Richardson <arichard@stark.cc.oh.us> -## Created: July 1994 -## Adapted-By: jwe - -## Deprecated in version 3.2 - -function [img_retval, map_retval] = loadimage (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "loadimage is obsolete and will be removed from a future version of Octave; please use imread instead"); - endif - - [img_retval, map_retval] = imread (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/mark_as_command.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} mark_as_command (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function mark_as_command () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "mark_as_command is obsolete and will be removed from a future version of Octave"); - endif - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/mark_as_rawcommand.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} mark_as_rawcommand (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function mark_as_rawcommand () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "mark_as_rawcommand is obsolete and will be removed from a future version of Octave"); - endif - -endfunction
--- a/scripts/deprecated/module.mk +++ b/scripts/deprecated/module.mk @@ -6,55 +6,29 @@ deprecated/betai.m \ deprecated/cellidx.m \ deprecated/clg.m \ - deprecated/complement.m \ - deprecated/create_set.m \ + deprecated/cor.m \ + deprecated/corrcoef.m \ deprecated/cquad.m \ + deprecated/cut.m \ deprecated/dispatch.m \ - deprecated/dmult.m \ deprecated/fstat.m \ deprecated/gammai.m \ deprecated/glpkmex.m \ deprecated/intwarning.m \ - deprecated/iscommand.m \ deprecated/is_duplicate_entry.m \ deprecated/is_global.m \ - deprecated/israwcommand.m \ deprecated/isstr.m \ - deprecated/lchol.m \ - deprecated/loadimage.m \ deprecated/krylovb.m \ - deprecated/mark_as_command.m \ - deprecated/mark_as_rawcommand.m \ deprecated/perror.m \ + deprecated/polyderiv.m \ deprecated/replot.m \ deprecated/saveimage.m \ deprecated/setstr.m \ - deprecated/spatan2.m \ - deprecated/spchol2inv.m \ - deprecated/spcholinv.m \ - deprecated/spchol.m \ - deprecated/spcumprod.m \ - deprecated/spcumsum.m \ - deprecated/spdet.m \ - deprecated/spdiag.m \ - deprecated/spfind.m \ deprecated/sphcat.m \ - deprecated/spinv.m \ - deprecated/spkron.m \ - deprecated/splchol.m \ - deprecated/split.m \ - deprecated/splu.m \ - deprecated/spmax.m \ - deprecated/spmin.m \ - deprecated/spprod.m \ - deprecated/spqr.m \ - deprecated/spsum.m \ - deprecated/spsumsq.m \ deprecated/spvcat.m \ - deprecated/str2mat.m \ deprecated/strerror.m \ - deprecated/unmark_command.m \ - deprecated/unmark_rawcommand.m \ + deprecated/studentize.m \ + deprecated/sylvester_matrix.m \ deprecated/values.m \ deprecated/weibcdf.m \ deprecated/weibinv.m \
rename from scripts/polynomial/polyderiv.m rename to scripts/deprecated/polyderiv.m --- a/scripts/polynomial/polyderiv.m +++ b/scripts/deprecated/polyderiv.m @@ -36,6 +36,13 @@ function [q, d] = polyderiv (p, a) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "polyderiv is obsolete and will be removed from a future version of Octave; please use polyder instead"); + endif + if (nargin == 1 || nargin == 2) if (! isvector (p)) error ("polyderiv: argument must be a vector");
--- a/scripts/deprecated/saveimage.m +++ b/scripts/deprecated/saveimage.m @@ -30,8 +30,7 @@ ## Portable pixmap format. ## ## @item "ps" -## PostScript format. Note that images saved in PostScript format cannot -## be read back into Octave with loadimage. +## PostScript format. ## @end table ## ## If the fourth argument is supplied, the specified colormap will also be @@ -42,7 +41,7 @@ ## image is a gray scale image (the entries within each row of the colormap ## are equal) the gray scale ppm and PostScript image formats are used, ## otherwise the full color formats are used. -## @seealso{loadimage, save, load, colormap} +## @seealso{imread, save, load, colormap} ## @end deftypefn ## The conversion to PostScript is based on pbmtolps.c, which was
deleted file mode 100644 --- a/scripts/deprecated/spatan2.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spatan2 (@var{y}, @var{x}) -## This function has been deprecated. Use @code{atan2} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spatan2 (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spatan2 is obsolete and will be removed from a future version of Octave; please use atan2 instead"); - endif - - retval = atan2 (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spchol.m +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{r} =} spchol (@var{a}) -## @deftypefnx {Loadable Function} {[@var{r}, @var{p}] =} spchol (@var{a}) -## @deftypefnx {Loadable Function} {[@var{r}, @var{p}, @var{q}] =} spchol (@var{a}) -## This function has been deprecated. Use @code{chol} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spchol (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spchol is obsolete and will be removed from a future version of Octave; please use chol instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = chol (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spchol2inv.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spchol2inv (@var{u}) -## This function has been deprecated. Use @code{chol2inv} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spchol2inv (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spchol2inv is obsolete and will be removed from a future version of Octave; please use chol2inv instead"); - endif - - retval = chol2inv (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spcholinv.m +++ /dev/null @@ -1,35 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spcholinv (@var{u}) -## This function has been deprecated. Use @code{cholinv} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spcholinv (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spcholinv is obsolete and will be removed from a future version of Octave; please use cholinv instead"); - endif - retval = cholinv (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spcumprod.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spcumprod (@var{x}, @var{dim}) -## This function has been deprecated. Use @code{cumprod} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spcumprod (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spcumprod is obsolete and will be removed from a future version of Octave; please use cumprod instead"); - endif - - retval = cumprod (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spcumsum.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spcumsum (@var{x}, @var{dim}) -## This function has been deprecated. Use @code{cumsum} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spcumsum (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spcumsum is obsolete and will be removed from a future version of Octave; please use cumsum instead"); - endif - - retval = cumsum (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spdet.m +++ /dev/null @@ -1,37 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {[@var{d}, @var{rcond}] =} spdet (@var{a}) -## This function has been deprecated. Use @code{det} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spdet (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spdet is obsolete and will be removed from a future version of Octave; please use det instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = det (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spdiag.m +++ /dev/null @@ -1,37 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spdiag (@var{v}, @var{k}) -## This function has been deprecated. Use @code{sparse (diag (@dots{}))} -## instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spdiag (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spdiag is obsolete and will be removed from a future version of Octave; please use sparse (diag (...)) instead"); - endif - - retval = sparse (diag (varargin{:})); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spfind.m +++ /dev/null @@ -1,40 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {} spfind (@var{x}) -## @deftypefnx {Loadable Function} {} spfind (@var{x}, @var{n}) -## @deftypefnx {Loadable Function} {} spfind (@var{x}, @var{n}, @var{direction}) -## @deftypefnx {Loadable Function} {[@var{i}, @var{j}, @var{v}} spfind (@dots{}) -## This function has been deprecated. Use @code{find} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spfind (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spfind is obsolete and will be removed from a future version of Octave; please use find instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = find (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spinv.m +++ /dev/null @@ -1,37 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{x}, @var{rcond}] =} spinv (@var{a}) -## This function has been deprecated. Use @code{inv} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spinv (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spinv is obsolete and will be removed from a future version of Octave; please use inv instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = inv (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spkron.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spkron (@var{a}, @var{b}) -## This function has been deprecated. Use @code{kron} instead. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function retval = spkron (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spkron is obsolete and will be removed from a future version of Octave; please use kron instead"); - endif - - retval = kron (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/splchol.m +++ /dev/null @@ -1,40 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{l} =} splchol (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{p}] =} splchol (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{p}, @var{q}] =} splchol (@var{a}) -## This function has been deprecated. Use @code{chol (@dots{},'lower')} -## instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = splchol (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "splchol is obsolete and will be removed from a future version of Octave; please use chol instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = chol (varargin{:}, "lower"); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/split.m +++ /dev/null @@ -1,130 +0,0 @@ -## Copyright (C) 1996-2011 Kurt Hornik -## -## 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} split (@var{s}, @var{t}, @var{n}) -## This function has been deprecated. Use @code{char (strsplit (s, t))} -## instead. -## @end deftypefn - -## Divides the string @var{s} into pieces separated by @var{t}, returning -## the result in a string array (padded with blanks to form a valid -## matrix). If the optional input @var{n} is supplied, split @var{s} -## into at most @var{n} different pieces. -## -## For example, -## -## @example -## split ("Test string", "t") -## @result{} -## "Tes " -## " s " -## "ring" -## @end example -## -## @example -## split ("Test string", "t s", 2) -## @result{} -## "Tes " -## "tring" -## @end example -## @seealso{strtok, index} -## @end deftypefn - -## Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at> -## Adapted-By: jwe - -## Deprecated in version 3.2 - -function m = split (s, t, n) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "split is obsolete and will be removed from a future version of Octave; please use strsplit instead"); - endif - - if (nargin == 2 || nargin == 3) - if (nargin == 2) - n = length (s); - endif - - if (ischar (s) && ischar (t)) - - l_s = length (s); - l_t = length (t); - - if (l_s == 0) - m = ""; - return; - elseif (l_t == 0) - m = s'; - return; - elseif (l_s < l_t) - error ("split: S must not be shorter than T"); - endif - - if (min (size (s)) != 1 || min (size (t)) != 1) - error("split: multi-line strings are not supported"); - endif - - ind = findstr (s, t, 0); - if (length (ind) == 0) - m = s; - return; - elseif (n - 1 < length(ind)) - ind = ind(1:n-1); - endif - ind2 = [1, ind+l_t]; - ind = [ind, l_s+1]; - - ind_diff = ind-ind2; - - ## Create a matrix of the correct size that's filled with spaces. - m_rows = length (ind); - m_cols = max (ind_diff); - m = repmat (" ", m_rows, m_cols); - - ## Copy the strings to the matrix. - for i = 1:length (ind) - tmp = ind2(i):(ind(i)-1); - m(i,1:length(tmp)) = s(tmp); - endfor - else - error ("split: both S and T must be strings"); - endif - else - print_usage (); - endif - -endfunction - -%!assert(all (all (split ("Test string", "t") == ["Tes "; " s "; "ring"]))); - -%!error split (); - -%!assert(all (strcmp (split ("foo bar baz", " ", 2), ["foo"; "bar baz"]))); - -%!error split ("foo", "bar", 3, 4); - -%!assert (all (strcmp (split("road//to/hell","/"), ["road"; " "; "to "; "hell"]))) - -%!assert (all (strcmp (split("/road/to/hell/","/"), [" "; "road"; "to "; "hell"; " "]))) - -
deleted file mode 100644 --- a/scripts/deprecated/splu.m +++ /dev/null @@ -1,48 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {[@var{l}, @var{u}] =} splu (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{u}, @var{P}] =} splu (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{u}, @var{P}, @var{Q}] =} splu (@var{a}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{u}, @var{P}, @var{Q}] =} splu (@dots{}, @var{thres}) -## @deftypefnx {Loadable Function} {[@var{l}, @var{u}, @var{P}] =} splu (@dots{}, @var{Q}) -## This function has been deprecated. Use @code{lu} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = splu (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "splu is obsolete and will be removed from a future version of Octave; please use lu instead"); - endif - - for i = 2 : nargin - arg = varargin {i}; - if (! isscalar (arg)) - error ("splu: Can no longer treat input column permutations"); - endif - endfor - - varargout = cell (nargout, 1); - [ varargout{:} ] = lu (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spmax.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Mapping Function} {} spmax (@var{x}, @var{y}, @var{dim}) -## @deftypefnx {Mapping Function} {[@var{w}, @var{iw}] =} spmax (@var{x}) -## This function has been deprecated. Use @code{max} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spmax (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spmax is obsolete and will be removed from a future version of Octave; please use max instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = max (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spmin.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Mapping Function} {} spmin (@var{x}, @var{y}, @var{dim}) -## @deftypefnx {Mapping Function} {[@var{w}, @var{iw}] =} spmin (@var{x}) -## This function has been deprecated. Use @code{min} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spmin (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spmin is obsolete and will be removed from a future version of Octave; please use min instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = min (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spprod.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spprod (@var{x}, @var{dim}) -## This function has been deprecated. Use @code{prod} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spprod (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spprod is obsolete and will be removed from a future version of Octave; please use prod instead"); - endif - - retval = prod (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spqr.m +++ /dev/null @@ -1,40 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{r} =} spqr (@var{a}) -## @deftypefnx {Loadable Function} {@var{r} =} spqr (@var{a}, 0) -## @deftypefnx {Loadable Function} {[@var{c}, @var{r}] =} spqr (@var{a}, @var{b}) -## @deftypefnx {Loadable Function} {[@var{c}, @var{r}] =} spqr (@var{a}, @var{b}, 0) -## This function has been deprecated. Use @code{qr} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function varargout = spqr (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spqr is obsolete and will be removed from a future version of Octave; please use qr instead"); - endif - - varargout = cell (nargout, 1); - [ varargout{:} ] = qr (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spsum.m +++ /dev/null @@ -1,36 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spsum (@var{x}, @var{dim}) -## This function has been deprecated. Use @code{sum} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spsum (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spsum is obsolete and will be removed from a future version of Octave; please use sum instead"); - endif - - retval = sum (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/spsumsq.m +++ /dev/null @@ -1,35 +0,0 @@ -## Copyright (C) 2008-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} spsumsq (@var{x}, @var{dim}) -## This function has been deprecated. Use @code{sumsq} instead. -## @end deftypefn - -## Deprecated in version 3.2 - -function retval = spsumsq (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "spsumsq is obsolete and will be removed from a future version of Octave; please use sumsq instead"); - endif - retval = sumsq (varargin{:}); - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/str2mat.m +++ /dev/null @@ -1,45 +0,0 @@ -## Copyright (C) 1996-2011 Kurt Hornik -## -## 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/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} str2mat (@var{s_1}, @dots{}, @var{s_n}) -## Return a matrix containing the strings @var{s_1}, @dots{}, @var{s_n} as -## its rows. Each string is padded with blanks in order to form a valid -## matrix. -## -## This function is modelled after @sc{matlab}. In Octave, you can create -## a matrix of strings by @code{[@var{s_1}; @dots{}; @var{s_n}]} even if -## the strings are not all the same length. -## @end deftypefn - -## Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at> -## Adapted-By: jwe - -## Deprecated in version 3.2 - -function retval = str2mat (varargin) - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "str2mat is obsolete and will be removed from a future version of Octave; please use char instead"); - endif - - retval = char (varargin{:}); - -endfunction
rename from scripts/statistics/base/studentize.m rename to scripts/deprecated/studentize.m --- a/scripts/statistics/base/studentize.m +++ b/scripts/deprecated/studentize.m @@ -32,6 +32,12 @@ ## Description: Subtract mean and divide by standard deviation function t = studentize (x, dim) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "studentize is obsolete and will be removed from a future version of Octave; please use zscore instead"); + endif if (nargin != 1 && nargin != 2) print_usage ();
rename from scripts/special-matrix/sylvester_matrix.m rename to scripts/deprecated/sylvester_matrix.m --- a/scripts/special-matrix/sylvester_matrix.m +++ b/scripts/deprecated/sylvester_matrix.m @@ -33,6 +33,13 @@ function retval = sylvester_matrix (k) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "sylvester_matrix is obsolete and will be removed from a future version of Octave; please use hadamard(2^k) instead"); + endif + if (nargin != 1) print_usage (); endif
deleted file mode 100644 --- a/scripts/deprecated/unmark_command.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} unmark_command (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function unmark_command () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "unmark_command is obsolete and will be removed from a future version of Octave"); - endif - -endfunction
deleted file mode 100644 --- a/scripts/deprecated/unmark_rawcommand.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2009-2011 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/>. - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} unmark_rawcommand (@var{name}) -## This function is obsolete and will be removed from a future -## version of Octave. -## @end deftypefn - -## Author: jwe - -## Deprecated in version 3.2 - -function unmark_rawcommand () - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "unmark_rawcommand is obsolete and will be removed from a future version of Octave"); - endif - -endfunction
--- a/scripts/elfun/module.mk +++ b/scripts/elfun/module.mk @@ -20,7 +20,6 @@ elfun/csc.m \ elfun/cscd.m \ elfun/csch.m \ - elfun/lcm.m \ elfun/sec.m \ elfun/secd.m \ elfun/sech.m \
--- a/scripts/general/accumarray.m +++ b/scripts/general/accumarray.m @@ -72,7 +72,7 @@ endif if (iscell (subs)) - subs = cellfun (@vec, subs, "uniformoutput", false); + subs = cellfun ("vec", subs, "uniformoutput", false); ndims = numel (subs); if (ndims == 1) subs = subs{1}; @@ -149,7 +149,7 @@ if (ndims > 1) if (isempty (sz)) if (iscell (subs)) - sz = cellfun (@max, subs); + sz = cellfun ("max", subs); else sz = max (subs, [], 1); endif
--- a/scripts/general/accumdim.m +++ b/scripts/general/accumdim.m @@ -42,12 +42,12 @@ ## ## An example of the use of @code{accumdim} is: ## -## @example +## @smallexample ## @group ## accumdim ([1, 2, 1, 2, 1], [7,-10,4;-5,-12,8;-12,2,8;-10,9,-3;-5,-3,-13]) ## @result{} ans = [-10,-11,-1;-15,-3,5] ## @end group -## @end example +## @end smallexample ## ## @seealso{accumarray} ## @end deftypefn
--- a/scripts/general/arrayfun.m +++ b/scripts/general/arrayfun.m @@ -154,7 +154,7 @@ args = varargin(1:nargs); opts = varargin(nargs+1:end); - args = cellfun (@num2cell, args, "UniformOutput", false, + args = cellfun ("num2cell", args, "UniformOutput", false, "ErrorHandler", @arg_class_error); [varargout{1:max(1, nargout)}] = cellfun (func, args{:}, opts{:});
--- a/scripts/general/bitget.m +++ b/scripts/general/bitget.m @@ -79,3 +79,31 @@ C = bitand (A, bitshift (_conv (1), uint8 (n) - uint8 (1))) != _conv (0); endfunction + +%!error bitget (1); +%!error bitget (1, 2, 3); + +%!test +%! assert (bitget ([4, 14], [3, 3]), logical ([1, 1])); +%! pfx = {"", "u"}; +%! for i = 1:2 +%! for prec = [8, 16, 32, 64] +%! fcn = str2func (sprintf ("%sint%d", pfx{i}, prec)); +%! assert (bitget (fcn ([4, 14]), [3, 3]), logical ([1, 1])); +%! endfor +%! endfor + +%!error bitget (0, 0); +%!error bitget (0, 55); + +%!error bitget (int8 (0), 9); +%!error bitget (uint8 (0), 9); + +%!error bitget (int16 (0), 17); +%!error bitget (uint16 (0), 17); + +%!error bitget (int32 (0), 33); +%!error bitget (uint32 (0), 33); + +%!error bitget (int64 (0), 65); +%!error bitget (uint64 (0), 65);
--- a/scripts/general/bitset.m +++ b/scripts/general/bitset.m @@ -92,3 +92,31 @@ endif endfunction + +%!error bitset (1); +%!error bitset (1, 2, 3, 4); + +%!test +%! assert (bitset ([0, 10], [3, 3]), [4, 14]); +%! pfx = {"", "u"}; +%! for i = 1:2 +%! for prec = [8, 16, 32, 64] +%! fcn = str2func (sprintf ("%sint%d", pfx{i}, prec)); +%! assert (bitset (fcn ([0, 10]), [3, 3]), fcn ([4, 14])); +%! endfor +%! endfor + +%!error bitset (0, 0); +%!error bitset (0, 55); + +%!error bitset (int8 (0), 9); +%!error bitset (uint8 (0), 9); + +%!error bitset (int16 (0), 17); +%!error bitset (uint16 (0), 17); + +%!error bitset (int32 (0), 33); +%!error bitset (uint32 (0), 33); + +%!error bitset (int64 (0), 65); +%!error bitset (uint64 (0), 65);
--- a/scripts/general/blkdiag.m +++ b/scripts/general/blkdiag.m @@ -33,7 +33,7 @@ print_usage (); endif - if (! all (cellfun (@isnumeric, varargin))) + if (! all (cellfun ("isnumeric", varargin))) error ("blkdiag: all arguments must be numeric"); endif
--- a/scripts/general/cell2mat.m +++ b/scripts/general/cell2mat.m @@ -43,11 +43,11 @@ else ## We only want numeric, logical, and char matrices. - valid = cellfun (@isnumeric, c); - valid |= cellfun (@islogical, c); - valid |= cellfun (@ischar, c); - validc = cellfun (@iscell, c); - valids = cellfun (@isstruct, c); + valid = cellfun ("isnumeric", c); + valid |= cellfun ("islogical", c); + valid |= cellfun ("isclass", c, "char"); + validc = cellfun ("isclass", c, "cell"); + valids = cellfun ("isclass", c, "struct"); if (! all (valid(:)) && ! all (validc(:)) && ! all (valids(:))) error ("cell2mat: wrong type elements or mixed cells, structs and matrices"); @@ -71,7 +71,7 @@ endif xdim = [1:idim-1, idim+1:nd]; cc = num2cell (c, xdim); - c = cellfun (@cat, {idim}, cc{:}, "uniformoutput", false); + c = cellfun ("cat", {idim}, cc{:}, "uniformoutput", false); endfor m = c{1}; endif
--- a/scripts/general/colon.m +++ b/scripts/general/colon.m @@ -38,3 +38,7 @@ error ("colon: not defined for class \"%s\"", class(varargin{1})); endif endfunction + +%!error colon (1) + +## FIXME -- what does colon () mean since it doesn't set a return value?
--- a/scripts/general/common_size.m +++ b/scripts/general/common_size.m @@ -52,7 +52,7 @@ endif ## Find scalar args. - nscal = cellfun (@numel, varargin) != 1; + nscal = cellfun ("numel", varargin) != 1; i = find (nscal, 1); @@ -60,7 +60,7 @@ errorcode = 0; varargout = varargin; else - match = cellfun (@size_equal, varargin, varargin(i)); + match = cellfun ("size_equal", varargin, varargin(i)); if (any (nscal &! match)) errorcode = 1; varargout = varargin; @@ -78,3 +78,13 @@ endif endif endfunction + +%!error common_size (); + +%!test +%! m = [1,2;3,4]; +%! [err, a, b, c] = common_size (m, 3, 5); +%! assert (err, 0); +%! assert (a, m); +%! assert (b, [3,3;3,3]); +%! assert (c, [5,5;5,5]);
--- a/scripts/general/dblquad.m +++ b/scripts/general/dblquad.m @@ -37,22 +37,23 @@ ## ## The optional argument @var{quadf} specifies which underlying integrator ## function to use. Any choice but @code{quad} is available and the default -## is @code{quadgk}. +## is @code{quadcc}. ## ## Additional arguments, are passed directly to @var{f}. To use the default -## value for @var{tol} or @var{quadf} one may pass an empty matrix ([]). +## value for @var{tol} or @var{quadf} one may pass ':' or an empty matrix ([]). ## @seealso{triplequad, quad, quadv, quadl, quadgk, quadcc, trapz} ## @end deftypefn -function q = dblquad(f, xa, xb, ya, yb, tol, quadf, varargin) +function q = dblquad (f, xa, xb, ya, yb, tol = 1e-6, quadf = @quadcc, varargin) + if (nargin < 5) print_usage (); endif - if (nargin < 6 || isempty (tol)) + if (isempty (tol)) tol = 1e-6; endif - if (nargin < 7 || isempty (quadf)) - quadf = @quadgk; + if (isempty (quadf)) + quadf = @quadcc; endif inner = @__dblquad_inner__; @@ -72,10 +73,10 @@ endfor endfunction -%% Nasty integrand to show quadgk off +%% Nasty integrand to show quadcc off %!assert (dblquad (@(x,y) 1 ./ (x+y), 0, 1, 0, 1), 2*log(2), 1e-6) -%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, [], @quadgk), pi * erf(1).^2, 1e-6) -%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, [], @quadl), pi * erf(1).^2, 1e-6) -%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, [], @quadv), pi * erf(1).^2, 1e-6) +%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, 1e-6, @quadgk), pi * erf(1).^2, 1e-6) +%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, 1e-6, @quadl), pi * erf(1).^2, 1e-6) +%!assert (dblquad (@(x,y) exp(-x.^2 - y.^2) , -1, 1, -1, 1, 1e-6, @quadv), pi * erf(1).^2, 1e-6)
--- a/scripts/general/flipdim.m +++ b/scripts/general/flipdim.m @@ -43,9 +43,10 @@ endif nd = ndims (x); + sz = size (x); if (nargin == 1) ## Find the first non-singleton dimension. - [~, dim] = min (size (x) != 1); + (dim = find (sz > 1, 1)) || (dim = 1); elseif (! (isscalar (dim) && isindex (dim))) error ("flipdim: DIM must be a positive integer"); endif @@ -55,3 +56,12 @@ y = x(idx{:}); endfunction + +%!error flipdim (); +%!error flipdim (1, 2, 3); + +%!assert (flipdim ([1,2;3,4]), flipdim ([1,2 ; 3,4], 1)); +%!assert (flipdim ([1,2;3,4], 2), [2,1;4,3]); +%!assert (flipdim ([1,2;3,4], 3), [1,2;3,4]); + +## FIXME -- we need tests for multidimensional arrays.
--- a/scripts/general/int2str.m +++ b/scripts/general/int2str.m @@ -49,31 +49,33 @@ function retval = int2str (n) - if (nargin == 1) - n = round (real(n)); - sz = size(n); - nd = ndims (n); - nc = columns (n); - if (nc > 1) - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor - idx(2) = 1; - ifmt = get_fmt (n(idx{:}), 0); - idx(2) = 2:sz(2); - rfmt = get_fmt (n(idx{:}), 2); - fmt = cstrcat (ifmt, repmat (rfmt, 1, nc-1), "\n"); - else - fmt = cstrcat (get_fmt (n, 0), "\n"); - endif - tmp = sprintf (fmt, permute (n, [2, 1, 3 : nd])); - tmp(end) = ""; - retval = char (strsplit (tmp, "\n")); - else + if (nargin != 1) print_usage (); endif + if (isempty (n)) + retval = ''; + return; + endif + + n = round (real(n)); + sz = size(n); + nd = ndims (n); + nc = columns (n); + if (nc > 1) + idx = repmat ({':'}, nd, 1); + idx(2) = 1; + ifmt = get_fmt (n(idx{:}), 0); + idx(2) = 2:sz(2); + rfmt = get_fmt (n(idx{:}), 2); + fmt = cstrcat (ifmt, repmat (rfmt, 1, nc-1), "\n"); + else + fmt = cstrcat (get_fmt (n, 0), "\n"); + endif + tmp = sprintf (fmt, permute (n, [2, 1, 3 : nd])); + tmp(end) = ""; + retval = char (strsplit (tmp, "\n")); + endfunction function fmt = get_fmt (x, sep) @@ -112,8 +114,10 @@ endfunction -%!assert(strcmp (int2str (-123), "-123") && strcmp (int2str (1.2), "1")); +%!assert (strcmp (int2str (-123), "-123") && strcmp (int2str (1.2), "1")); %!assert (all (int2str ([1, 2, 3; 4, 5, 6]) == ["1 2 3";"4 5 6"])); +%!assert (int2str([]), ""); + %!error int2str (); %!error int2str (1, 2);
--- a/scripts/general/interp1.m +++ b/scripts/general/interp1.m @@ -43,7 +43,7 @@ ## Piecewise cubic Hermite interpolating polynomial ## ## @item 'cubic' -## Cubic interpolation from four nearest neighbors +## Cubic interpolation (same as @code{pchip}) ## ## @item 'spline' ## Cubic spline interpolation---smooth first and second derivatives @@ -112,7 +112,7 @@ method = "linear"; extrap = NA; xi = []; - pp = false; + ispp = false; firstnumeric = true; if (nargin > 2) @@ -123,7 +123,7 @@ if (strcmp ("extrap", arg)) extrap = "extrap"; elseif (strcmp ("pp", arg)) - pp = true; + ispp = true; else method = arg; endif @@ -138,7 +138,7 @@ endfor endif - if (isempty (xi) && firstnumeric && ! pp) + if (isempty (xi) && firstnumeric && ! ispp) xi = y; y = x; x = 1:numel(y); @@ -150,9 +150,8 @@ szx = size (xi); if (isvector (y)) y = y(:); - elseif (isvector (xi)) - szx = length (xi); endif + szy = size (y); y = y(:,:); [ny, nc] = size (y); @@ -191,147 +190,85 @@ switch (method) case "nearest" - if (pp) - yi = mkpp ([x(1); (x(1:nx-1)+x(2:nx))/2; x(nx)], y, szy(2:end)); + pp = mkpp ([x(1); (x(1:nx-1)+x(2:nx))/2; x(nx)], shiftdim (y, 1), szy(2:end)); + pp.orient = "first"; + + if (ispp) + yi = pp; else - idx = lookup (0.5*(x(1:nx-1)+x(2:nx)), xi) + 1; - yi = y(idx,:); + yi = ppval (pp, reshape (xi, szx)); endif case "*nearest" - if (pp) - yi = mkpp ([x(1); x(1)+[0.5:(nx-1)]'*dx; x(nx)], y, szy(2:end)); + pp = mkpp ([x(1), x(1)+[0.5:(nx-1)]*dx, x(nx)], shiftdim (y, 1), szy(2:end)); + pp.orient = "first"; + if (ispp) + yi = pp; else - idx = max (1, min (ny, floor((xi-x(1))/dx+1.5))); - yi = y(idx,:); + yi = ppval(pp, reshape (xi, szx)); endif case "linear" dy = diff (y); - dx = diff (x); - if (pp) - coefs = [dy./dx, y(1:nx-1)]; - xx = x; - if (have_jumps) - ## Omit zero-size intervals. - coefs(jumps) = []; - xx(jumps) = []; - endif - yi = mkpp (xx, coefs, szy(2:end)); + dx = diff (x); + dx = repmat (dx, [1 size(dy)(2:end)]); + coefs = [(dy./dx).'(:), y(1:nx-1, :).'(:)]; + xx = x; + + if (have_jumps) + ## Omit zero-size intervals. + coefs(jumps, :) = []; + xx(jumps) = []; + endif + + pp = mkpp (xx, coefs, szy(2:end)); + pp.orient = "first"; + + if (ispp) + yi = pp; else - ## find the interval containing the test point - idx = lookup (x, xi, "lr"); - ## use the endpoints of the interval to define a line - s = (xi - x(idx))./dx(idx); - yi = bsxfun (@times, s, dy(idx,:)) + y(idx,:); - if (have_jumps) - ## Fix the corner cases of discontinuities at boundaries. - ## Internal discontinuities already handled correctly. - if (jumps (1)) - mask = xi < x(1); - yi(mask,:) = y(1*ones (1, sum (mask)),:); - endif - if (jumps(nx-1)) - mask = xi >= x(nx); - yi(mask,:) = y(nx*ones (1, sum (mask)),:); - endif - endif + yi = ppval(pp, reshape (xi, szx)); endif + case "*linear" dy = diff (y); - if (pp) - yi = mkpp (x(1) + [0:ny-1]*dx, [dy./dx, y(1:end-1)], szy(2:end)); + coefs = [(dy/dx).'(:), y(1:nx-1, :).'(:)]; + pp = mkpp (x, coefs, szy(2:end)); + pp.orient = "first"; + + if (ispp) + yi = pp; else - ## find the interval containing the test point - t = (xi - x(1))/dx + 1; - idx = max (1, min (ny - 1, floor (t))); + yi = ppval(pp, reshape (xi, szx)); + endif - ## use the endpoints of the interval to define a line - s = t - idx; - yi = bsxfun (@times, s, dy(idx,:)) + y(idx,:); - endif - case {"pchip", "*pchip"} + case {"pchip", "*pchip", "cubic", "*cubic"} if (nx == 2 || starmethod) x = linspace (x(1), x(nx), ny); endif - ## Note that pchip's arguments are transposed relative to interp1 - if (pp) - yi = pchip (x.', y.'); - yi.d = szy(2:end); - else - yi = pchip (x.', y.', xi.').'; - endif - - case {"cubic", "*cubic"} - if (nx < 4 || ny < 4) - error ("interp1: table too short"); - endif - - ## FIXME Is there a better way to treat pp return and *cubic - if (starmethod && ! pp) - ## From: Miloje Makivic - ## http://www.npac.syr.edu/projects/nasa/MILOJE/final/node36.html - t = (xi - x(1))/dx + 1; - idx = max (min (floor (t), ny-2), 2); - t = t - idx; - t2 = t.*t; - tp = 1 - 0.5*t; - a = (1 - t2).*tp; - b = (t2 + t).*tp; - c = (t2 - t).*tp/3; - d = (t2 - 1).*t/6; - J = ones (1, nc); - - yi = a(:,J) .* y(idx,:) + b(:,J) .* y(idx+1,:) ... - + c(:,J) .* y(idx-1,:) + d(:,J) .* y(idx+2,:); + + if (ispp) + y = shiftdim (reshape (y, szy), 1); + yi = pchip (x, y); else - if (starmethod) - x = linspace (x(1), x(nx), ny).'; - nx = ny; - endif - - idx = lookup (x(2:nx-1), xi, "lr"); - - ## Construct cubic equations for each interval using divided - ## differences (computation of c and d don't use divided differences - ## but instead solve 2 equations for 2 unknowns). Perhaps - ## reformulating this as a lagrange polynomial would be more efficient. - i = 1:nx-3; - J = ones (1, nc); - dx = diff (x); - dx2 = x(i+1).^2 - x(i).^2; - dx3 = x(i+1).^3 - x(i).^3; - a = diff (y, 3)./dx(i,J).^3/6; - b = (diff (y(1:nx-1,:), 2)./dx(i,J).^2 - 6*a.*x(i+1,J))/2; - c = (diff (y(1:nx-2,:), 1) - a.*dx3(:,J) - b.*dx2(:,J))./dx(i,J); - d = y(i,:) - ((a.*x(i,J) + b).*x(i,J) + c).*x(i,J); - - if (pp) - xs = [x(1);x(3:nx-2)]; - yi = mkpp ([x(1);x(3:nx-2);x(nx)], - [a(:), (b(:) + 3.*xs(:,J).*a(:)), ... - (c(:) + 2.*xs(:,J).*b(:) + 3.*xs(:,J)(:).^2.*a(:)), ... - (d(:) + xs(:,J).*c(:) + xs(:,J).^2.*b(:) + ... - xs(:,J).^3.*a(:))], szy(2:end)); - else - yi = ((a(idx,:).*xi(:,J) + b(idx,:)).*xi(:,J) ... - + c(idx,:)).*xi(:,J) + d(idx,:); - endif + y = shiftdim (y, 1); + yi = pchip (x, y, reshape (xi, szx)); endif case {"spline", "*spline"} if (nx == 2 || starmethod) x = linspace(x(1), x(nx), ny); endif - ## Note that spline's arguments are transposed relative to interp1 - if (pp) - yi = spline (x.', y.'); - yi.d = szy(2:end); + + if (ispp) + y = shiftdim (reshape (y, szy), 1); + yi = spline (x, y); else - yi = spline (x.', y.', xi.').'; + y = shiftdim (y, 1); + yi = spline (x, y, reshape (xi, szx)); endif otherwise error ("interp1: invalid method '%s'", method); endswitch - if (! pp) + if (! ispp) if (! ischar (extrap)) ## determine which values are out of range and set them to extrap, ## unless extrap == "extrap". @@ -339,10 +276,24 @@ maxx = max (x(1), x(nx)); outliers = xi < minx | ! (xi <= maxx); # this catches even NaNs - yi(outliers, :) = extrap; + if (size_equal (outliers, yi)) + yi(outliers) = extrap; + yi = reshape (yi, szx); + elseif (!isvector (yi)) + if (strcmp (method, "pchip") || strcmp (method, "*pchip") + ||strcmp (method, "cubic") || strcmp (method, "*cubic") + ||strcmp (method, "spline") || strcmp (method, "*spline")) + yi(:, outliers) = extrap; + yi = shiftdim(yi, 1); + else + yi(outliers, :) = extrap; + endif + else + yi(outliers.') = extrap; + endif endif - - yi = reshape (yi, [szx, szy(2:end)]); + else + yi.orient = "first"; endif endfunction @@ -394,6 +345,7 @@ %! %-------------------------------------------------------- %! % confirm that interpolated function matches the original +##FIXME: add test for n-d arguments here ## For each type of interpolated test, confirm that the interpolated ## value at the knots match the values at the knots. Points away @@ -595,7 +547,6 @@ %!assert (interp1(1:2,1:2,1.4,"nearest"),1); %!error interp1(1,1,1, "linear"); %!assert (interp1(1:2,1:2,1.4,"linear"),1.4); -%!error interp1(1:3,1:3,1, "cubic"); %!assert (interp1(1:4,1:4,1.4,"cubic"),1.4); %!assert (interp1(1:2,1:2,1.1, "spline"), 1.1); %!assert (interp1(1:3,1:3,1.4,"spline"),1.4); @@ -604,7 +555,6 @@ %!assert (interp1(1:2:4,1:2:4,1.4,"*nearest"),1); %!error interp1(1,1,1, "*linear"); %!assert (interp1(1:2:4,1:2:4,[0,1,1.4,3,4],"*linear"),[NA,1,1.4,3,NA]); -%!error interp1(1:3,1:3,1, "*cubic"); %!assert (interp1(1:2:8,1:2:8,1.4,"*cubic"),1.4); %!assert (interp1(1:2,1:2,1.3, "*spline"), 1.3); %!assert (interp1(1:2:6,1:2:6,1.4,"*spline"),1.4); @@ -612,5 +562,5 @@ %!assert (interp1([3,2,1],[3,2,2],2.5),2.5) %!assert (interp1 ([1,2,2,3,4],[0,1,4,2,1],[-1,1.5,2,2.5,3.5], "linear", "extrap"), [-2,0.5,4,3,1.5]) -%!assert (interp1 ([4,4,3,2,0],[0,1,4,2,1],[1.5,4,4.5], "linear"), [0,1,NA]) +%!assert (interp1 ([4,4,3,2,0],[0,1,4,2,1],[1.5,4,4.5], "linear"), [1.75,1,NA]) %!assert (interp1 (0:4, 2.5), 1.5)
--- a/scripts/general/interp3.m +++ b/scripts/general/interp3.m @@ -92,7 +92,7 @@ error ("interp3: expect 3-dimensional array of values"); endif x = varargin (2:4); - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : 3 if (! size_equal (x{1}, x{i})) error ("interp3: dimensional mismatch"); @@ -109,7 +109,7 @@ error ("interp3: expect 3-dimensional array of values"); endif x = varargin (1:3); - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : 3 if (! size_equal (x{1}, x{i}) || ! size_equal (x{i}, v)) error ("interp3: dimensional mismatch"); @@ -119,7 +119,7 @@ x{1} = permute (x{1}, [2, 1, 3]); endif y = varargin (5:7); - if (any (! cellfun (@isvector, y))) + if (any (! cellfun ("isvector", y))) for i = 2 : 3 if (! size_equal (y{1}, y{i})) error ("interp3: dimensional mismatch");
--- a/scripts/general/interpft.m +++ b/scripts/general/interpft.m @@ -76,10 +76,8 @@ k = floor (m / 2); sz = size (x); sz(1) = n * inc - m; - idx = cell (nd, 1); - for i = 2:nd - idx{i} = 1:sz(i); - endfor + + idx = repmat ({':'}, nd, 1); idx{1} = 1:k; z = cat (1, y(idx{:}), zeros (sz)); idx{1} = k+1:m;
--- a/scripts/general/interpn.m +++ b/scripts/general/interpn.m @@ -124,7 +124,7 @@ error ("interpn: wrong number or incorrectly formatted input arguments"); endif - if (any (! cellfun (@isvector, x))) + if (any (! cellfun ("isvector", x))) for i = 2 : nd if (! size_equal (x{1}, x{i}) || ! size_equal (x{i}, v)) error ("interpn: dimensional mismatch"); @@ -140,8 +140,8 @@ method = tolower (method); - all_vectors = all (cellfun (@isvector, y)); - different_lengths = numel (unique (cellfun (@numel, y))) > 1; + all_vectors = all (cellfun ("isvector", y)); + different_lengths = numel (unique (cellfun ("numel", y))) > 1; if (all_vectors && different_lengths) [foobar(1:numel(y)).y] = ndgrid (y{:}); y = {foobar.y}; @@ -169,7 +169,7 @@ vi(idx) = extrapval; vi = reshape (vi, yshape); elseif (strcmp (method, "spline")) - if (any (! cellfun (@isvector, y))) + if (any (! cellfun ("isvector", y))) for i = 2 : nd if (! size_equal (y{1}, y{i})) error ("interpn: dimensional mismatch");
--- a/scripts/general/isa.m +++ b/scripts/general/isa.m @@ -75,3 +75,22 @@ %!assert (isa (uint16 (13), "numeric"), true) %!assert (isa (uint32 (13), "numeric"), true) %!assert (isa (uint64 (13), "numeric"), true) + +%!assert (isa (double (13), "double")); +%!assert (isa (single (13), "single")); +%!assert (isa (int8 (13), "int8")); +%!assert (isa (int16 (13), "int16")); +%!assert (isa (int32 (13), "int32")); +%!assert (isa (int64 (13), "int64")); +%!assert (isa (uint8 (13), "uint8")); +%!assert (isa (uint16 (13), "uint16")); +%!assert (isa (uint32 (13), "uint32")); +%!assert (isa (uint64 (13), "uint64")); +%!assert (isa ("string", "char")); +%!assert (isa (true, "logical")); +%!assert (isa (false, "logical")); +%!assert (isa ({1, 2}, "cell")); +%!test +%! a.b = 1; +%! assert (isa (a, "struct")); +
--- a/scripts/general/iscolumn.m +++ b/scripts/general/iscolumn.m @@ -26,8 +26,6 @@ function retval = iscolumn (x) - retval = false; - if (nargin != 1) print_usage (); endif
--- a/scripts/general/isdir.m +++ b/scripts/general/isdir.m @@ -23,10 +23,17 @@ ## @end deftypefn function retval = isdir (f) - if (nargin == 1) - ## Exist returns an integer but isdir should return a logical. - retval = (exist (f, "dir") == 7); - else + if (nargin != 1) print_usage ("isdir"); endif + + ## Exist returns an integer but isdir should return a logical. + retval = (exist (f, "dir") == 7); + endfunction + +%!error isdir (); +%!error isdir (1, 2); + +%!assert (isdir (pwd ())); +%!assert (! isdir ("this is highly unlikely to be a directory name"));
--- a/scripts/general/isequal.m +++ b/scripts/general/isequal.m @@ -24,12 +24,12 @@ function retval = isequal (x1, varargin) - if (nargin > 1) - retval = __isequal__ (false, x1, varargin{:}); - else + if (nargin < 2) print_usage (); endif + retval = __isequal__ (false, x1, varargin{:}); + endfunction ## test size and shape
--- a/scripts/general/isequalwithequalnans.m +++ b/scripts/general/isequalwithequalnans.m @@ -25,12 +25,12 @@ function retval = isequalwithequalnans (x1, varargin) - if (nargin > 1) - retval = __isequal__ (true, x1, varargin{:}); - else + if (nargin < 2) print_usage (); endif + retval = __isequal__ (true, x1, varargin{:}); + endfunction ## test for equality
--- a/scripts/general/isrow.m +++ b/scripts/general/isrow.m @@ -26,8 +26,6 @@ function retval = isrow (x) - retval = false; - if (nargin != 1) print_usage (); endif
--- a/scripts/general/isscalar.m +++ b/scripts/general/isscalar.m @@ -26,12 +26,12 @@ function retval = isscalar (x) - if (nargin == 1) - retval = numel (x) == 1; - else + if (nargin != 1) print_usage (); endif + retval = numel (x) == 1; + endfunction %!assert(isscalar (1));
--- a/scripts/general/issquare.m +++ b/scripts/general/issquare.m @@ -28,42 +28,35 @@ function retval = issquare (x) - if (nargin == 1) - if (ndims (x) == 2) - [r, c] = size (x); - retval = r == c; - else - retval = false; - endif + if (nargin != 1) + print_usage (); + endif + + if (ndims (x) == 2) + [r, c] = size (x); + retval = r == c; else - print_usage (); + retval = false; endif endfunction +%!assert(issquare ([])); %!assert(issquare (1)); - %!assert(!(issquare ([1, 2]))); - -%!assert(issquare ([])); - %!assert(issquare ([1, 2; 3, 4])); - -%!test -%! assert(issquare ("t")); - +%!assert(!(issquare ([1, 2; 3, 4; 5, 6]))); +%!assert(!(issquare (ones (3,3,3)))); +%!assert(issquare ("t")); %!assert(!(issquare ("test"))); - -%!test -%! assert(issquare (["test"; "ing"; "1"; "2"])); - +%!assert(issquare (["test"; "ing"; "1"; "2"])); %!test %! s.a = 1; %! assert(issquare (s)); - -%!assert(!(issquare ([1, 2; 3, 4; 5, 6]))); +%!assert(issquare ({1, 2; 3, 4})); +%!assert(sparse (([1, 2; 3, 4]))); +%% Test input validation %!error issquare (); - %!error issquare ([1, 2; 3, 4], 2);
--- a/scripts/general/isvector.m +++ b/scripts/general/isvector.m @@ -28,15 +28,13 @@ function retval = isvector (x) - retval = 0; - - if (nargin == 1) - sz = size (x); - retval = (ndims (x) == 2 && (sz(1) == 1 || sz(2) == 1)); - else + if (nargin != 1) print_usage (); endif + sz = size (x); + retval = (ndims (x) == 2 && (sz(1) == 1 || sz(2) == 1)); + endfunction %!assert(isvector (1));
--- a/scripts/general/module.mk +++ b/scripts/general/module.mk @@ -61,6 +61,8 @@ general/polyarea.m \ general/postpad.m \ general/prepad.m \ + general/profile.m \ + general/profshow.m \ general/quadgk.m \ general/quadl.m \ general/quadv.m \
--- a/scripts/general/nargchk.m +++ b/scripts/general/nargchk.m @@ -30,16 +30,14 @@ ## Author: Bill Denney <bill@denney.ws> -function msg = nargchk (minargs, maxargs, nargs, outtype) +function msg = nargchk (minargs, maxargs, nargs, outtype = "string") if (nargin < 3 || nargin > 4) print_usage (); elseif (minargs > maxargs) error ("nargchk: MINARGS must be <= MAXARGS"); - elseif (nargin == 3) - outtype = "string"; elseif (! any (strcmpi (outtype, {"string", "struct"}))) - error ("nargchk: output type must be either string or struct"); + error ('nargchk: output type must be either "string" or "struct"'); elseif (! (isscalar (minargs) && isscalar (maxargs) && isscalar (nargs))) error ("nargchk: MINARGS, MAXARGS, and NARGS must be scalars"); endif @@ -56,13 +54,16 @@ if (strcmpi (outtype, "string")) msg = msg.message; elseif (isempty (msg.message)) - msg = struct ([]); + ## Compatability: Matlab returns a 0x1 empty struct when nargchk passes + msg = resize (msg, 0, 1); endif endfunction + ## Tests -%!shared stmin, stmax +%!shared stnul, stmin, stmax +%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1); %! stmin = struct ("message", "not enough input arguments", %! "identifier", "Octave:nargchk:not-enough-inputs"); %! stmax = struct ("message", "too many input arguments", @@ -73,7 +74,7 @@ %!assert (nargchk (0, 1, 2), "too many input arguments") %!assert (nargchk (0, 1, 2, "string"), "too many input arguments") ## Struct outputs -%!assert (nargchk (0, 1, 0, "struct"), struct([])) -%!assert (nargchk (0, 1, 1, "struct"), struct([])) +%!assert (isequal (nargchk (0, 1, 0, "struct"), stnul)) +%!assert (isequal (nargchk (0, 1, 1, "struct"), stnul)) %!assert (nargchk (1, 1, 0, "struct"), stmin) %!assert (nargchk (0, 1, 2, "struct"), stmax)
--- a/scripts/general/nargoutchk.m +++ b/scripts/general/nargoutchk.m @@ -55,19 +55,17 @@ if (strcmpi (outtype, "string")) msg = msg.message; - else - if (isempty (msg.message)) - msg = struct ([]); - endif - ## FIXME: remove the error below if error is modified to accept - ## struct inputs - error ("nargoutchk: error does not yet support struct inputs"); + elseif (isempty (msg.message)) + ## Compatability: Matlab returns a 0x1 empty struct when nargchk passes + msg = resize (msg, 0, 1); endif endfunction + ## Tests -%!shared stmin, stmax +%!shared stnul, stmin, stmax +%! stnul = resize (struct ("message", "", "identifier", ""), 0, 1); %! stmin = struct ("message", "not enough output arguments", %! "identifier", "Octave:nargoutchk:not-enough-outputs"); %! stmax = struct ("message", "too many output arguments", @@ -78,7 +76,8 @@ %!assert (nargoutchk (0, 1, 2), "too many output arguments") %!assert (nargoutchk (0, 1, 2, "string"), "too many output arguments") ## Struct outputs -#%!assert (nargoutchk (0, 1, 0, "struct"), struct([])) -#%!assert (nargoutchk (0, 1, 1, "struct"), struct([])) -#%!assert (nargoutchk (1, 1, 0, "struct"), stmin) -#%!assert (nargoutchk (0, 1, 2, "struct"), stmax) +%!assert (isequal (nargoutchk (0, 1, 0, "struct"), stnul)) +%!assert (isequal (nargoutchk (0, 1, 1, "struct"), stnul)) +%!assert (nargoutchk (1, 1, 0, "struct"), stmin) +%!assert (nargoutchk (0, 1, 2, "struct"), stmax) +
--- a/scripts/general/nextpow2.m +++ b/scripts/general/nextpow2.m @@ -55,3 +55,14 @@ endif endfunction + +%!error nexpow2 (); +%!error nexpow2 (1, 2); + +%!assert (nextpow2 (16), 4); +%!assert (nextpow2 (17), 5); +%!assert (nextpow2 (31), 5); +%!assert (nextpow2 (-16), 4); +%!assert (nextpow2 (-17), 5); +%!assert (nextpow2 (-31), 5); +%!assert (nextpow2 (1:17), 5);
--- a/scripts/general/num2str.m +++ b/scripts/general/num2str.m @@ -111,10 +111,7 @@ nd = ndims (x); perm = fix ([1:0.5:nc+0.5]); perm(2:2:2*nc) = perm(2:2:2*nc) + nc; - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{2} = perm; x = horzcat (real (x), imag (x)); x = x(idx{:});
--- a/scripts/general/postpad.m +++ b/scripts/general/postpad.m @@ -53,11 +53,8 @@ nd = ndims (x); sz = size (x); if (nargin < 4) - ## Find the first non-singleton dimension - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + ## Find the first non-singleton dimension. + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -76,10 +73,7 @@ d = sz (dim); if (d >= l) - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{dim} = 1:l; y = x(idx{:}); else @@ -88,3 +82,16 @@ endif endfunction + +%!error postpad (); +%!error postpad (1); +%!error postpad (1,2,3,4,5); +%!error postpad ([1,2], 2, 2,3); + +%!assert (postpad ([1,2], 4), [1,2,0,0]); +%!assert (postpad ([1;2], 4), [1;2;0;0]); + +%!assert (postpad ([1,2], 4, 2), [1,2,2,2]); +%!assert (postpad ([1;2], 4, 2), [1;2;2;2]); + +%!assert (postpad ([1,2], 2, 2, 1), [1,2;2,2]);
--- a/scripts/general/prepad.m +++ b/scripts/general/prepad.m @@ -53,11 +53,8 @@ nd = ndims (x); sz = size (x); if (nargin < 4) - ## Find the first non-singleton dimension - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + ## Find the first non-singleton dimension. + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -76,10 +73,7 @@ d = sz (dim); if (d >= l) - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{dim} = d-l+1:d; y = x(idx{:}); else @@ -88,3 +82,18 @@ endif endfunction + +%!error prepad (); +%!error prepad (1); +%!error prepad (1,2,3,4,5); +%!error prepad ([1,2], 2, 2,3); + +%!assert (prepad ([1,2], 4), [0,0,1,2]); +%!assert (prepad ([1;2], 4), [0;0;1;2]); + +%!assert (prepad ([1,2], 4, 2), [2,2,1,2]); +%!assert (prepad ([1;2], 4, 2), [2;2;1;2]); + +%!assert (prepad ([1,2], 2, 2, 1), [2,2;1,2]); + +## FIXME -- we need tests for multidimensional arrays.
--- a/scripts/general/private/__isequal__.m +++ b/scripts/general/private/__isequal__.m @@ -59,16 +59,16 @@ ## All arguments must either be of the same class or they must be ## numeric values. t = (all (strcmp (class(x), - cellfun (@class, varargin, "uniformoutput", false))) + cellfun ("class", varargin, "uniformoutput", false))) || ((isnumeric (x) || islogical (x)) - && all (cellfun (@isnumeric, varargin) - | cellfun (@islogical, varargin)))); + && all (cellfun ("isnumeric", varargin) + | cellfun ("islogical", varargin)))); if (t) ## Test that everything has the same number of dimensions. s_x = size (x); s_v = cellfun (@size, varargin, "uniformoutput", false); - t = all (length (s_x) == cellfun (@length, s_v)); + t = all (length (s_x) == cellfun ("length", s_v)); endif if (t) @@ -96,8 +96,8 @@ ## Test the number of fields. fn_x = fieldnames (x); l_fn_x = length (fn_x); - fn_v = cellfun (@fieldnames, varargin, "uniformoutput", false); - t = all (l_fn_x == cellfun (@length, fn_v)); + fn_v = cellfun ("fieldnames", varargin, "uniformoutput", false); + t = all (l_fn_x == cellfun ("length", fn_v)); ## Test that all the names are equal. idx = 0; @@ -146,7 +146,7 @@ elseif (isa (x, "function_handle")) ## The == operator is overloaded for handles. - t = all (cellfun (@eq, {x}, varargin)); + t = all (cellfun ("eq", {x}, varargin)); else ## Check the numeric types.
new file mode 100644 --- /dev/null +++ b/scripts/general/profile.m @@ -0,0 +1,115 @@ +## Copyright (C) 2011 Daniel Kraft +## +## 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/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} profile on +## @deftypefnx {Function File} {} profile off +## @deftypefnx {Function File} {} profile resume +## @deftypefnx {Function File} {} profile clear +## @deftypefnx {Function File} {@var{S} =} profile ('status') +## @deftypefnx {Function File} {@var{T} =} profile ('info') +## Control the built-in profiler. +## +## @table @code +## @item profile on +## Start the profiler, clearing all previously collected data if there +## is any. +## +## @item profile off +## Stop profiling. The collected data can later be retrieved and examined +## with calls like @code{S = profile ('info')}. +## +## @item profile clear +## Clear all collected profiler data. +## +## @item profile resume +## Restart profiling without cleaning up the old data and instead +## all newly collected statistics are added to the already existing ones. +## +## @item @var{S} = profile ('status') +## Return a structure filled with certain information about the current status +## of the profiler. At the moment, the only field is @code{ProfilerStatus} +## which is either 'on' or 'off'. +## +## @item @var{T} = profile ('info') +## Return the collected profiling statistics in the structure @var{T}. +## The flat profile is returned in the field @code{FunctionTable} which is an +## array of structures, each entry corresponding to a function which was called +## and for which profiling statistics are present. Furthermore, the field +## @code{Hierarchical} contains the hierarchical call-tree. Each node +## has an index into the @code{FunctionTable} identifying the function it +## corresponds to as well as data fields for number of calls and time spent +## at this level in the call-tree. +## @end table +## @end deftypefn + +## Built-in profiler. +## Author: Daniel Kraft <d@domob.eu> + +function retval = profile (option) + + if (nargin != 1) + print_usage (); + endif + + switch (option) + case 'on' + __profiler_reset__ (); + __profiler_enable__ (true); + + case 'off' + __profiler_enable__ (false); + + case 'clear' + __profiler_reset__ (); + + case 'resume' + __profiler_enable__ (true); + + case 'status' + enabled = __profiler_enable__ (); + if (enabled) + enabled = 'on'; + else + enabled = 'off'; + endif + retval = struct ('ProfilerStatus', enabled); + + case 'info' + [flat, tree] = __profiler_data__ (); + retval = struct ('FunctionTable', flat, 'Hierarchical', tree); + + otherwise + warning ("profile: Unrecognized option '%s'", option); + print_usage (); + + endswitch + +endfunction + + +%!demo +%! profile ('on'); +%! A = rand (100); +%! B = expm (A); +%! profile ('off'); +%! profile ('resume'); +%! C = sqrtm (A); +%! profile ('off'); +%! T = profile ('info'); +%! profshow (T);
new file mode 100644 --- /dev/null +++ b/scripts/general/profshow.m @@ -0,0 +1,102 @@ +## Copyright (C) 2011 Daniel Kraft +## +## 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/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} profshow (@var{data}) +## @deftypefnx {Function File} {} profshow (@var{data}, @var{n}) +## Show flat profiler results. +## +## This command prints out profiler data as a flat profile. @var{data} is the +## structure returned by @code{profile ('info')}. If @var{n} is given, it +## specifies the number of functions to show in the profile; functions are +## sorted in descending order by total time spent in them. If there are more +## than @var{n} included in the profile, those will not be shown. @var{n} +## defaults to 20. +## +## The attribute column shows @samp{R} for recursive functions and nothing +## otherwise. +## @end deftypefn + +## Built-in profiler. +## Author: Daniel Kraft <d@domob.eu> + +function profshow (data, n = 20) + + if (nargin < 1 || nargin > 2) + print_usage (); + endif + + n = fix (n); + if (! isscalar (n) || ! isreal (n) || ! (n > 0)) + error ("profile: N must be a positive integer"); + endif + + m = length (data.FunctionTable); + n = min (n, m); + + ## We want to sort by times in descending order. For this, extract the + ## times to an array, then sort this, and use the resulting index permutation + ## to print out our table. + times = -[ data.FunctionTable.TotalTime ]; + + [~, p] = sort (times); + + ## For printing the table, find out the maximum length of a function name + ## so that we can proportion the table accordingly. Based on this, + ## we can build the format used for printing table rows. + nameLen = length ("Function"); + for i = 1 : n + nameLen = max (nameLen, length (data.FunctionTable(p(i)).FunctionName)); + endfor + headerFormat = sprintf ("%%4s %%%ds %%4s %%12s %%12s\n", nameLen); + rowFormat = sprintf ("%%4d %%%ds %%4s %%12.3f %%12d\n", nameLen); + + printf (headerFormat, "#", "Function", "Attr", "Time (s)", "Calls"); + printf ("%s\n", repmat ("-", 1, nameLen + 2 * 5 + 2 * 13)); + for i = 1 : n + row = data.FunctionTable(p(i)); + attr = ""; + if (row.IsRecursive) + attr = "R"; + endif + printf (rowFormat, p(i), row.FunctionName, attr, ... + row.TotalTime, row.NumCalls); + endfor + +endfunction + +%!demo +%! profile ("on"); +%! A = rand (100); +%! B = expm (A); +%! profile ("off"); +%! T = profile ("info"); +%! profshow (T, 10); + +%!demo +%! function f = myfib (n) +%! if (n <= 2) +%! f = 1; +%! else +%! f = myfib (n - 1) + myfib (n - 2); +%! endif +%! endfunction +%! profile ("on"); +%! myfib (20); +%! profile ("off"); +%! profshow (profile ("info"), 5);
--- a/scripts/general/quadl.m +++ b/scripts/general/quadl.m @@ -62,14 +62,12 @@ ## * replace global variable terminate2 with local function need_warning ## * add paper ref to docs -function q = quadl (f, a, b, tol, trace, varargin) - need_warning (1); - if (nargin < 4) - tol = []; +function q = quadl (f, a, b, tol = [], trace = false, varargin) + + if (nargin < 3) + print_usage (); endif - if (nargin < 5) - trace = []; - endif + if (isa (a, "single") || isa (b, "single")) myeps = eps ("single"); else @@ -79,16 +77,23 @@ tol = myeps; endif if (isempty (trace)) - trace = 0; + trace = false; endif if (tol < myeps) tol = myeps; endif + ## Track whether recursion has occurred + global __quadl_recurse_done__; + __quadl_recurse_done__ = false; + ## Track whether warning about machine precision has been issued + global __quadl_need_warning__; + __quadl_need_warning__ = true; + m = (a+b)/2; h = (b-a)/2; - alpha = sqrt(2/3); - beta = 1/sqrt(5); + alpha = sqrt (2/3); + beta = 1/sqrt (5); x1 = .942882415695480; x2 = .641853342345781; @@ -104,12 +109,12 @@ i2 = (h/6)*(y(1) + y(13) + 5*(y(5)+y(9))); - i1 = (h/1470)*(77*(y(1)+y(13)) + i1 = (h/1470)*( 77*(y(1)+y(13)) + 432*(y(3)+y(11)) + 625*(y(5)+y(9)) + 672*y(7)); - is = h*(.0158271919734802*(y(1)+y(13)) + is = h*( .0158271919734802*(y(1)+y(13)) +.0942738402188500*(y(2)+y(12)) + .155071987336585*(y(3)+y(11)) + .188821573960182*(y(4)+y(10)) @@ -117,80 +122,96 @@ + .224926465333340*(y(6)+y(8)) + .242611071901408*y(7)); - s = sign(is); - + s = sign (is); if (s == 0) s = 1; endif - erri1 = abs(i1-is); - erri2 = abs(i2-is); - R = 1; + erri1 = abs (i1-is); + erri2 = abs (i2-is); if (erri2 != 0) R = erri1/erri2; + else + R = 1; endif if (R > 0 && R < 1) tol = tol/R; endif - is = s*abs(is)*tol/myeps; + is = s * abs(is) * tol/myeps; if (is == 0) is = b-a; endif + q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin{:}); + endfunction ## ADAPTLOBSTP Recursive function used by QUADL. ## ## Q = ADAPTLOBSTP('F', A, B, FA, FB, IS, TRACE) tries to ## approximate the integral of F(X) from A to B to -## an appropriate relative error. The argument 'F' is +## an appropriate relative error. The argument 'F' is ## a string containing the name of f. The remaining ## arguments are generated by ADAPTLOB or by recursion. ## ## Walter Gautschi, 08/03/98 function q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin) + global __quadl_recurse_done__; + global __quadl_need_warning__; + h = (b-a)/2; m = (a+b)/2; - alpha = sqrt(2/3); - beta = 1/sqrt(5); + alpha = sqrt (2/3); + beta = 1 / sqrt(5); mll = m-alpha*h; - ml = m-beta*h; - mr = m+beta*h; + ml = m-beta*h; + mr = m+beta*h; mrr = m+alpha*h; x = [mll, ml, m, mr, mrr]; - y = feval(f, x, varargin{:}); + y = feval (f, x, varargin{:}); fmll = y(1); - fml = y(2); - fm = y(3); - fmr = y(4); + fml = y(2); + fm = y(3); + fmr = y(4); fmrr = y(5); i2 = (h/6)*(fa + fb + 5*(fml+fmr)); i1 = (h/1470)*(77*(fa+fb) + 432*(fmll+fmrr) + 625*(fml+fmr) + 672*fm); - if (is+(i1-i2) == is || mll <= a || b <= mrr) - if ((m <= a || b <= m) && need_warning ()) + if ((is+(i1-i2) == is || mll <= a || b <= mrr) && __quadl_recurse_done__) + if ((m <= a || b <= m) && __quadl_need_warning__) warning ("quadl: interval contains no more machine number"); warning ("quadl: required tolerance may not be met"); - need_warning (0); + __quadl_need_warning__ = false; endif q = i1; if (trace) disp ([a, b-a, q]); endif else - q = (adaptlobstp (f, a, mll, fa, fmll, is, trace, varargin{:}) - + adaptlobstp (f, mll, ml, fmll, fml, is, trace, varargin{:}) - + adaptlobstp (f, ml, m, fml, fm, is, trace, varargin{:}) - + adaptlobstp (f, m, mr, fm, fmr, is, trace, varargin{:}) - + adaptlobstp (f, mr, mrr, fmr, fmrr, is, trace, varargin{:}) - + adaptlobstp (f, mrr, b, fmrr, fb, is, trace, varargin{:})); + __quadl_recurse_done__ = true; + q = ( adaptlobstp (f, a , mll, fa , fmll, is, trace, varargin{:}) + + adaptlobstp (f, mll, ml , fmll, fml , is, trace, varargin{:}) + + adaptlobstp (f, ml , m , fml , fm , is, trace, varargin{:}) + + adaptlobstp (f, m , mr , fm , fmr , is, trace, varargin{:}) + + adaptlobstp (f, mr , mrr, fmr , fmrr, is, trace, varargin{:}) + + adaptlobstp (f, mrr, b , fmrr, fb , is, trace, varargin{:})); endif endfunction -function r = need_warning (v) - persistent w = []; - if (nargin == 0) - r = w; - else - w = v; - endif -endfunction + +## basic functionality +%!assert (quadl (@(x) sin (x), 0, pi, [], []), 2, -3e-16) + +## the values here are very high so it may be unavoidable that this fails +%!assert (quadl (@(x) sin (3*x).*cosh (x).*sinh (x),10,15), +%! 2.588424538641647e+10, -9e-15) + +## extra parameters +%!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3), +%! cos(2)/3 - cos(5)/3, - 3e-16) + +## test different tolerances. +%!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []), +%! (60 + sin(4) - sin(64))/12, -0.3) +%!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []), +%! (60 + sin(4) - sin(64))/12, -0.1) +
--- a/scripts/general/rat.m +++ b/scripts/general/rat.m @@ -150,3 +150,11 @@ endif endfunction + +%!error rat (); +%!error rat (1, 2, 3); + +%!test +%! [n, d] = rat ([0.5, 0.3, 1/3]); +%! assert (n, [1, 3, 1]); +%! assert (d, [2, 10, 3]);
--- a/scripts/general/rot90.m +++ b/scripts/general/rot90.m @@ -52,44 +52,41 @@ ## Author: jwe -function B = rot90 (A, k) - - if (nargin == 1 || nargin == 2) - if (nargin < 2) - k = 1; - endif - - if (ndims (A) > 2) - error ("rot90: Only works with 2-D arrays"); - endif - - if (imag (k) != 0 || fix (k) != k) - error ("rot90: K must be an integer"); - endif - - k = rem (k, 4); +function B = rot90 (A, k = 1) - if (k < 0) - k = k + 4; - endif - - if (k == 0) - B = A; - elseif (k == 1) - B = flipud (A.'); - elseif (k == 2) - B = flipud (fliplr (A)); - elseif (k == 3) - B = (flipud (A)).'; - else - error ("rot90: internal error!"); - endif - else + if (nargin < 1 || nargin > 2) print_usage (); endif + if (ndims (A) > 2) + error ("rot90: A must be a 2-D array"); + endif + + if (! (isscalar (k) && isreal (k) && fix (k) == k)) + error ("rot90: K must be a single real integer"); + endif + + k = rem (k, 4); + + if (k < 0) + k = k + 4; + endif + + if (k == 0) + B = A; + elseif (k == 1) + B = flipud (A.'); + elseif (k == 2) + B = flipud (fliplr (A)); + elseif (k == 3) + B = (flipud (A)).'; + else + error ("rot90: internal error!"); + endif + endfunction + %!test %! x1 = [1, 2; 3, 4]; %! x2 = [2, 4; 1, 3]; @@ -106,4 +103,6 @@ %% Test input validation %!error rot90 (); %!error rot90 (1, 2, 3); - +%!error rot90 (1, ones(2)); +%!error rot90 (1, 1.5); +%!error rot90 (1, 1+i);
--- a/scripts/general/rotdim.m +++ b/scripts/general/rotdim.m @@ -71,22 +71,26 @@ nd = ndims (x); sz = size (x); if (nargin < 3) - ## Find the first two non-singleton dimension. - plane = []; - dim = 0; - while (dim < nd) - dim = dim + 1; - if (sz (dim) != 1) - plane = [plane, dim]; - if (length (plane) == 2) - break; + if (nd > 2) + ## Find the first two non-singleton dimension. + plane = []; + dim = 0; + while (dim < nd) + dim = dim + 1; + if (sz (dim) != 1) + plane = [plane, dim]; + if (length (plane) == 2) + break; + endif endif + endwhile + if (length (plane) < 1) + plane = [1, 2]; + elseif (length (plane) < 2) + plane = [1, plane]; endif - endwhile - if (length (plane) < 1) + else plane = [1, 2]; - elseif (length (plane) < 2) - plane = [1, plane]; endif else if (! (isvector (plane) && length (plane) == 2 @@ -119,3 +123,36 @@ endif endfunction + +%!error rotdim (); +%!error rotdim (1, 2, 3, 4); + +%!shared r, rr +%! r = [1,2,3]; rr = [3,2,1]; +%!assert (rotdim (r, 0), r); +%!assert (rotdim (r, 1), rr'); +%!assert (rotdim (r, 2), rr); +%!assert (rotdim (r, 3), r'); +%!assert (rotdim (r, 3), rotdim (r, -1)); +%!assert (rotdim (r, 1), rotdim (r)); + +%!shared c, cr +%! c = [1;2;3]; cr = [3;2;1]; +%!assert (rotdim (c, 0), c); +%!assert (rotdim (c, 1), c'); +%!assert (rotdim (c, 2), cr); +%!assert (rotdim (c, 3), cr'); +%!assert (rotdim (c, 3), rotdim (c, -1)); +%!assert (rotdim (c, 1), rotdim (c)); + +%!shared m +%! m = [1,2;3,4]; +%!assert (rotdim (m, 0), m); +%!assert (rotdim (m, 1), [2,4;1,3]); +%!assert (rotdim (m, 2), [4,3;2,1]); +%!assert (rotdim (m, 3), [3,1;4,2]); +%!assert (rotdim (m, 3), rotdim (m, -1)); +%!assert (rotdim (m, 1), rotdim (m)); + +## FIXME -- we need tests for multidimensional arrays and different +## values of PLANE.
--- a/scripts/general/shift.m +++ b/scripts/general/shift.m @@ -51,10 +51,7 @@ endif else ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); endif if (numel (x) < 1) @@ -63,10 +60,7 @@ d = sz (dim); - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); if (b >= 0) b = rem (b, d); idx{dim} = [d-b+1:d, 1:d-b];
--- a/scripts/general/shiftdim.m +++ b/scripts/general/shiftdim.m @@ -57,14 +57,9 @@ orig_dims = size (x); if (nargin == 1) - ## Find the first singleton dimension. - n = 0; - while (n < nd && orig_dims(n+1) == 1) - n++; - endwhile - endif - - if (! isscalar (n) || floor (n) != n) + ## Find the first non-singleton dimension. + (n = find (orig_dims != 1, 1) - 1) || (n = nd); + elseif (! (isscalar (n) && n == fix (n))) error ("shiftdim: N must be a scalar integer"); endif @@ -78,7 +73,7 @@ elseif (n > 0) ## We need permute here instead of reshape to shift values in a ## compatible way. - y = permute (x, [n+1:ndims(x) 1:n]); + y = permute (x, [n+1:nd 1:n]); else y = x; endif @@ -86,3 +81,20 @@ ns = n; endfunction + + +%!test +%! x = rand (1, 1, 4, 2); +%! [y, ns] = shiftdim (x); +%! assert (size (y), [4 2]); +%! assert (ns, 2); +%! assert (shiftdim (y, -2), x); +%! assert (size (shiftdim (x, 2)), [4 2]); +%!assert (size (shiftdim (rand (0, 1, 2))), [0 1 2]); + +%% Test input validation +%!error(shiftdim ()); +%!error(shiftdim (1,2,3)); +%!error(shiftdim (1, ones (2))); +%!error(shiftdim (1, 1.5)); +
--- a/scripts/general/structfun.m +++ b/scripts/general/structfun.m @@ -106,7 +106,7 @@ [varargout{:}] = cellfun (func, struct2cell (S), varargin{:}); if (! uniform_output) - varargout = cellfun (@cell2struct, varargout, {fieldnames(S)}, {1}, uo_str, false); + varargout = cellfun ("cell2struct", varargout, {fieldnames(S)}, {1}, uo_str, false); endif endfunction
--- a/scripts/general/triplequad.m +++ b/scripts/general/triplequad.m @@ -37,22 +37,25 @@ ## ## The optional argument @var{quadf} specifies which underlying integrator ## function to use. Any choice but @code{quad} is available and the default -## is @code{quadgk}. +## is @code{quadcc}. ## ## Additional arguments, are passed directly to @var{f}. To use the default -## value for @var{tol} or @var{quadf} one may pass an empty matrix ([]). +## value for @var{tol} or @var{quadf} one may pass ':' or an empty matrix ([]). ## @seealso{dblquad, quad, quadv, quadl, quadgk, quadcc, trapz} ## @end deftypefn -function q = triplequad(f, xa, xb, ya, yb, za, zb, tol, quadf, varargin) +function q = triplequad (f, xa, xb, ya, yb, za, zb, tol = 1e-6, quadf = @quadcc, varargin) + if (nargin < 7) print_usage (); endif - if (nargin < 8 || isempty (tol)) + + ## Allow use of empty matrix ([]) to indicate default + if (isempty (tol)) tol = 1e-6; endif - if (nargin < 9 || isempty (quadf)) - quadf = @quadgk; + if (isempty (quadf)) + quadf = @quadcc; endif inner = @__triplequad_inner__; @@ -61,7 +64,8 @@ varargin = {}; endif - q = dblquad(@(y, z) inner (y, z, f, xa, xb, tol, quadf, varargin{:}),ya, yb, za, zb, tol); + q = dblquad (@(y, z) inner (y, z, f, xa, xb, tol, quadf, varargin{:}), ya, yb, za, zb, tol); + endfunction function q = __triplequad_inner__ (y, z, f, xa, xb, tol, quadf, varargin) @@ -71,8 +75,11 @@ endfor endfunction -%% These tests are too expensive to run normally. Disable them -% !#assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadgk), pi ^ (3/2) * erf(1).^3, 1e-6) -% !#assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadl), pi ^ (3/2) * erf(1).^3, 1e-6) -% !#assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadv), pi ^ (3/2) * erf(1).^3, 1e-6) + +%!assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadcc), pi ^ (3/2) * erf(1).^3, 1e-6) +%% These tests are too expensive to run normally (~30 sec each). Disable them +#%!assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadgk), pi ^ (3/2) * erf(1).^3, 1e-6) +#%!#assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadl), pi ^ (3/2) * erf(1).^3, 1e-6) +#%!#assert (triplequad (@(x,y,z) exp(-x.^2 - y.^2 - z.^2) , -1, 1, -1, 1, -1, 1, [], @quadv), pi ^ (3/2) * erf(1).^3, 1e-6) +
--- a/scripts/geometry/module.mk +++ b/scripts/geometry/module.mk @@ -12,9 +12,6 @@ geometry/griddatan.m \ geometry/inpolygon.m \ geometry/rectint.m \ - geometry/trimesh.m \ - geometry/triplot.m \ - geometry/trisurf.m \ geometry/tsearchn.m \ geometry/voronoi.m \ geometry/voronoin.m
--- a/scripts/geometry/voronoi.m +++ b/scripts/geometry/voronoi.m @@ -129,7 +129,7 @@ idx = find (!infi); ll = length (idx); c = c(idx).'; - k = sum (cellfun ('length', c)); + k = sum (cellfun ("length", c)); edges = cell2mat(cellfun (@(x) [x ; [x(end), x(1:end-1)]], c, "uniformoutput", false)); @@ -166,3 +166,13 @@ endif endfunction + +%!testif HAVE_QHULL +%! phi=linspace(-pi,3/4*pi,8); +%! [x,y]=pol2cart(phi,1); +%! [vx,vy]=voronoi(x,y); +%! assert(vx(2,:),zeros(1,size(vx,2)),eps); +%! assert(vy(2,:),zeros(1,size(vy,2)),eps); + +%!demo +%! voronoi (rand(10,1), rand(10,1));
--- a/scripts/help/__makeinfo__.m +++ b/scripts/help/__makeinfo__.m @@ -17,8 +17,8 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{retval}, @var{status}] =} __makeinfo__ (@var{text}, @var{output_type}) -## @deftypefnx {Function File} {[@var{retval}, @var{status}] =} __makeinfo__ (@var{text}, @var{output_type}, @var{see_also}) +## @deftypefn {Function File} {[@var{retval}, @var{status}] =} __makeinfo__ (@var{text}) +## @deftypefnx {Function File} {[@var{retval}, @var{status}] =} __makeinfo__ (@var{text}, @var{output_type}) ## Undocumented internal function. ## @end deftypefn @@ -33,13 +33,6 @@ ## @t{"plain text"}. If @var{output_type} is @t{"texinfo"}, the @t{@@seealso} ## macro is expanded, but otherwise the text is unaltered. ## -## If the optional argument @var{see_also} is present, it is used to expand the -## Octave specific @t{@@seealso} macro. This argument must be a function handle, -## that accepts a cell array of strings as input argument (each elements of the -## array corresponds to the arguments to the @t{@@seealso} macro), and return -## the expanded string. If this argument is not given, the @t{@@seealso} macro -## will be expanded to the text -## ## @example ## See also: arg1, arg2@, ... ## @end example @@ -60,7 +53,7 @@ function [retval, status] = __makeinfo__ (text, output_type = "plain text", see_also = []) ## Check input - if (nargin == 0) + if (nargin < 1 || nargin > 2) print_usage (); endif @@ -72,72 +65,18 @@ error ("__makeinfo__: second input argument must be a string"); endif - ## Define the function which expands @seealso macro - if (isempty (see_also)) - if (strcmpi (output_type, "plain text")) - see_also = @simple_see_also; - else - see_also = @simple_see_also_with_refs; - endif - endif - - if (!isa (see_also, "function_handle")) - error ("__makeinfo__: third input argument must be the empty matrix, or a function handle"); - endif - ## It seems like makeinfo sometimes gets angry if the first character ## on a line is a space, so we remove these. text = strrep (text, "\n ", "\n"); ## Handle @seealso macro - SEE_ALSO = "@seealso"; - starts = strfind (text, SEE_ALSO); - for start = fliplr (starts) - if (start == 1 || (text (start-1) != "@")) - bracket_start = find (text (start:end) == "{", 1); - stop = find (text (start:end) == "}", 1); - if (!isempty (stop) && !isempty (bracket_start)) - stop += start - 1; - bracket_start += start - 1; - else - bracket_start = start + length (SEE_ALSO); - stop = find (text (start:end) == "\n", 1); - if (isempty (stop)) - stop = length (text); - else - stop += start - 1; - endif - endif - see_also_args = text (bracket_start+1:(stop-1)); - see_also_args = strtrim (strsplit (see_also_args, ",")); - expanded = see_also (see_also_args); - text = strcat (text (1:start-1), expanded, text (stop+1:end)); - endif - endfor - + if (strcmpi (output_type, "plain text")) + text = regexprep (text, '@seealso *\{([^}]*)\}', "\nSee also: $1.\n\n"); + else + text = regexprep (text, '@seealso *\{([^}]*)\}', "\nSee also: @ref{$1}.\n\n"); + endif ## Handle @nospell macro - NOSPELL = "@nospell"; - starts = strfind (text, NOSPELL); - for start = fliplr (starts) - if (start == 1 || (text (start-1) != "@")) - bracket_start = find (text (start:end) == "{", 1); - stop = find (text (start:end) == "}", 1); - if (!isempty (stop) && !isempty (bracket_start)) - stop += start - 1; - bracket_start += start - 1; - else - bracket_start = start + length (NOSPELL); - stop = find (text (start:end) == "\n", 1); - if (isempty (stop)) - stop = length (text); - else - stop += start - 1; - endif - endif - text(stop) = []; - text(start:bracket_start) = []; - endif - endfor + text = regexprep (text, '@nospell *\{([^}]*)\}', "$1"); if (strcmpi (output_type, "texinfo")) status = 0; @@ -180,12 +119,3 @@ end_unwind_protect endfunction -function expanded = simple_see_also (args) - expanded = strcat ("\nSee also:", sprintf (" %s,", args {:})); - expanded = strcat (expanded (1:end-1), "\n\n"); -endfunction - -function expanded = simple_see_also_with_refs (args) - expanded = strcat ("\nSee also:", sprintf (" @ref{%s},", args {:})); - expanded = strcat (expanded (1:end-1), "\n\n"); -endfunction
--- a/scripts/help/module.mk +++ b/scripts/help/module.mk @@ -1,11 +1,11 @@ FCN_FILE_DIRS += help help_PRIVATE_FCN_FILES = \ - help/private/__additional_help_message__.m + help/private/__additional_help_message__.m \ + help/private/__strip_html_tags__.m help_FCN_FILES = \ help/__makeinfo__.m \ - help/__strip_html_tags__.m \ help/doc.m \ help/gen_doc_cache.m \ help/get_first_help_sentence.m \ @@ -13,6 +13,7 @@ help/lookfor.m \ help/print_usage.m \ help/type.m \ + help/unimplemented.m \ help/which.m \ $(help_PRIVATE_FCN_FILES)
--- a/scripts/help/print_usage.m +++ b/scripts/help/print_usage.m @@ -136,3 +136,7 @@ retval = get_usage_plain_text (help_text, max_len); endfunction + +## Stop reporting function as missing tests. No good tests possible. +%!assert (1) +
--- a/scripts/help/type.m +++ b/scripts/help/type.m @@ -111,4 +111,14 @@ endfor endfunction +%!test +%! var = 1; +%! typestr = type ("var"); +%! typestr = typestr{1}(1:17); +%! assert (typestr, "var is a variable"); +%!assert (type ('dot'){1}, "dot is a dynamically-linked function") +%!assert (type ('cat'){1}, "cat is a built-in function") +%!assert (type ('+'){1}, "+ is an operator") +%!assert (type ('end'){1}, "end is a keyword") +%!error (type ('NO_NAME'))
rename from scripts/miscellaneous/unimplemented.m rename to scripts/help/unimplemented.m --- a/scripts/miscellaneous/unimplemented.m +++ b/scripts/help/unimplemented.m @@ -333,13 +333,11 @@ "reducepatch", "reducevolume", "resample", - "reset", "rgbplot", "rmpref", "root", "rotate", "rotate3d", - "rsf2csf", "selectmoveresize", "sendmail", "serial", @@ -428,3 +426,14 @@ "zoom", }; endfunction + + +%!test +%! str = unimplemented ("no_name_function"); +%! assert (isempty (str)); +%! str = unimplemented ("quad2d"); +%! assert (str(1:51), "quad2d is not implemented. Consider using dblquad."); +%! str = unimplemented ("MException"); +%! assert (str(1:58), "the `MException' function is not yet implemented in Octave"); + +
--- a/scripts/help/which.m +++ b/scripts/help/which.m @@ -53,3 +53,13 @@ endif endfunction + + +%!test +%! str = which ("ls"); +%! assert (str(end-17:end), strcat ("miscellaneous", filesep(), "ls.m")); +%!test +%! str = which ("dot"); +%! assert (str(end-6:end), "dot.oct"); + +%!assert (which ("NO_NAME"), "");
--- a/scripts/image/image.m +++ b/scripts/image/image.m @@ -19,9 +19,9 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} image (@var{img}) ## @deftypefnx {Function File} {} image (@var{x}, @var{y}, @var{img}) -## Display a matrix as a color image. The elements of @var{x} are indices +## Display a matrix as a color image. The elements of @var{img} are indices ## into the current colormap, and the colormap will be scaled so that the -## extremes of @var{x} are mapped to the extremes of the colormap. +## extremes of @var{img} are mapped to the extremes of the colormap. ## ## The axis values corresponding to the matrix elements are specified in ## @var{x} and @var{y}. If you're not using gnuplot 4.2 or later, these
--- a/scripts/io/strread.m +++ b/scripts/io/strread.m @@ -19,15 +19,16 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @dots{}] =} strread (@var{str}) ## @deftypefnx {Function File} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}) +## @deftypefnx {Function File} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat}) ## @deftypefnx {Function File} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{prop1}, @var{value1}, @dots{}) +## @deftypefnx {Function File} {[@var{a}, @dots{}] =} strread (@var{str}, @var{format}, @var{format_repeat}, @var{prop1}, @var{value1}, @dots{}) ## Read data from a string. ## ## The string @var{str} is split into words that are repeatedly matched to the ## specifiers in @var{format}. The first word is matched to the first -## specifier, -## the second to the second specifier and so forth. If there are more words -## than -## specifiers, the process is repeated until all words have been processed. +## specifier, the second to the second specifier and so forth. If there are +## more words than specifiers, the process is repeated until all words have +## been processed. ## ## The string @var{format} describes how the words in @var{str} should be ## parsed. @@ -36,19 +37,31 @@ ## @item %s ## The word is parsed as a string. ## -## @item %d ## @itemx %f -## The word is parsed as a number. +## @itemx %n +## The word is parsed as a number and converted to double. +## +## @item %d +## @itemx %u +## The word is parsed as a number and converted to int32. ## -## @item %* +## @item %*', '%*f', '%*s ## The word is skipped. +## +## For %s and %d, %f, %n, %u and the associated %*s @dots{} specifiers an +## optional width can be specified as %Ns, etc. where N is an integer > 1. +## For %f, format specifiers like %N.Mf are allowed. +## +## @item literals +## In addition the format may contain literal character strings; these will be +## skipped during reading. ## @end table ## ## Parsed word corresponding to the first specifier are returned in the first ## output argument and likewise for the rest of the specifiers. ## ## By default, @var{format} is @t{"%f"}, meaning that numbers are read from -## @var{str}. +## @var{str}. This will do if @var{str} contains only numeric fields. ## ## For example, the string ## @@ -68,6 +81,18 @@ ## [@var{a}, @var{b}, @var{c}] = strread (@var{str}, "%s %s %f"); ## @end example ## +## Optional numeric argument @var{format_repeat} can be used for +## limiting the number of items read: +## @table @asis +## @item -1 +## (default) read all of the string until the end. +## +## @item N +## Read N times @var{nargout} items. 0 (zero) is an acceptable +## value for @var{format_repeat}. +## +## @end table +## ## The behavior of @code{strread} can be changed via property-value ## pairs. The following properties are recognized: ## @@ -77,94 +102,202 @@ ## @var{value} is the comment style and can be any of the following. ## @itemize ## @item "shell" -## Everything from @code{#} characters to the nearest end-line is skipped. +## Everything from @code{#} characters to the nearest end-of-line is skipped. ## ## @item "c" ## Everything between @code{/*} and @code{*/} is skipped. ## ## @item "c++" -## Everything from @code{//} characters to the nearest end-line is skipped. +## Everything from @code{//} characters to the nearest end-of-line is skipped. ## ## @item "matlab" -## Everything from @code{%} characters to the nearest end-line is skipped. +## Everything from @code{%} characters to the nearest end-of-line is skipped. +## +## @item user-supplied. Two options: +## (1) One string, or 1x1 cell string: Skip everything to the right of it; +## (2) 2x1 cell string array: Everything between the left and right strings +## is skipped. ## @end itemize ## ## @item "delimiter" -## Any character in @var{value} will be used to split @var{str} into words. +## Any character in @var{value} will be used to split @var{str} into words +## (default value = any whitespace). ## ## @item "emptyvalue" ## Parts of the output where no word is available is filled with @var{value}. +## +## @item "multipledelimsasone" +## Treat a series of consecutive delimiters, without whitespace in between, +## as a single delimiter. Consecutive delimiter series need not be vertically +## "aligned". +## +## @item "treatasempty" +## Treat single occurrences (surrounded by delimiters or whitespace) of the +## string(s) in @var{value} as missing values. +## +## @item "returnonerror" +## If @var{value} true (1, default), ignore read errors and return normally. +## If false (0), return an error. +## +## @item "whitespace" +## Any character in @var{value} will be interpreted as whitespace and +## trimmed; the string defining whitespace must be enclosed in double +## quotes for proper processing of special characters like \t. +## The default value for whitespace = " \b\r\n\t" (note the space). +## ## @end table ## -## @seealso{textread, load, dlmread, fscanf} +## @seealso{textscan, textread, load, dlmread, fscanf} ## @end deftypefn function varargout = strread (str, format = "%f", varargin) + ## Check input if (nargin < 1) print_usage (); endif - if (!ischar (str) || !ischar (format)) + if (isempty (format)) + format = "%f"; + endif + + if (! ischar (str) || ! ischar (format)) error ("strread: STR and FORMAT arguments must be strings"); endif - ## Parse options + ## Parse format string to compare number of conversion fields and nargout + nfields = length (strfind (format, "%")) - length (strfind (format, "%*")); + ## If str only has numeric fields, a (default) format ("%f") will do. + ## Otherwise: + if ((max (nargout, 1) != nfields) && ! strcmp (format, "%f")) + error ("strread: the number of output variables must match that specified by FORMAT"); + endif + + ## Check for format string repeat count + format_repeat_count = -1; + if (nargin > 2 && isnumeric (varargin{1})) + if (varargin{1} >= 0) + format_repeat_count = varargin{1}; + endif + if (nargin > 3) + varargin = varargin(2:end); + else + varargin = {}; + endif + endif + + ## Parse options. First initialize defaults comment_flag = false; - numeric_fill_value = 0; - white_spaces = " \n\r\t\b"; delimiter_str = ""; + empty_str = ""; + eol_char = ""; + err_action = 0; + mult_dlms_s1 = false; + numeric_fill_value = NaN; + white_spaces = " \b\r\n\t"; for n = 1:2:length (varargin) - switch (lower (varargin {n})) + switch (lower (varargin{n})) + case "bufsize" + ## We could synthesize this, but that just seems weird... + warning ('strread: property "bufsize" is not implemented'); case "commentstyle" comment_flag = true; - switch (lower (varargin {n+1})) + switch (lower (varargin{n+1})) case "c" - comment_specif = {"/*", "*/"}; + [comment_start, comment_end] = deal ("/*", "*/"); case "c++" - comment_specif = {"//", "\n"}; + [comment_start, comment_end] = deal ("//", "eol_char"); case "shell" - comment_specif = {"#", "\n"}; + [comment_start, comment_end] = deal ("#" , "eol_char"); case "matlab" - comment_specif = {"%", "\n"}; + [comment_start, comment_end] = deal ("%" , "eol_char"); otherwise - warning ("strread: unknown comment style '%s'", val); + if (ischar (varargin{n+1}) || + (numel (varargin{n+1}) == 1 && iscellstr (varargin{n+1}))) + [comment_start, comment_end] = deal (char (varargin{n+1}), "eol_char"); + elseif (iscellstr (varargin{n+1}) && numel (varargin{n+1}) == 2) + [comment_start, comment_end] = deal (varargin{n+1}{:}); + else + ## FIXME - a user may have numeric values specified: {'//', 7} + ## this will lead to an error in the warning message + error ("strread: unknown or unrecognized comment style '%s'", + varargin{n+1}); + endif endswitch case "delimiter" - delimiter_str = varargin {n+1}; + delimiter_str = varargin{n+1}; case "emptyvalue" - numeric_fill_value = varargin {n+1}; - case "bufsize" - ## XXX: We could synthesize this, but that just seems weird... - warning ("strread: property \"bufsize\" is not implemented"); + numeric_fill_value = varargin{n+1}; + case "expchars" + warning ('strread: property "expchars" is not implemented'); case "whitespace" - white_spaces = varargin {n+1}; - case "expchars" - warning ("strread: property \"expchars\" is not implemented"); + white_spaces = varargin{n+1}; + ## The following parameters are specific to textscan and textread + case "endofline" + eol_char = varargin{n+1}; + case "returnonerror" + err_action = varargin{n+1}; + case "multipledelimsasone" + mult_dlms_s1 = varargin{n+1}; + case "treatasempty" + if (iscellstr (varargin{n+1})) + empty_str = varargin{n+1}; + elseif (ischar (varargin{n+1})) + empty_str = varargin(n+1); + else + error ('strread: "treatasempty" value must be string or cellstr'); + endif otherwise - warning ("strread: unknown property \"%s\"", varargin {n}); + warning ('strread: unknown property "%s"', varargin{n}); endswitch endfor - if (isempty (delimiter_str)) - delimiter_str = white_spaces; + + ## First parse of FORMAT + if (strcmpi (strtrim (format), "%f")) + ## Default format specified. Expand it (to desired nargout) + fmt_words = cell (nargout, 1); + fmt_words (1:nargout) = format; + else + ## Determine the number of words per line as a first guess. Forms + ## like %f<literal>) (w/o delimiter in between) are fixed further on + format = strrep (format, "%", " %"); + fmt_words = regexp (format, '[^ ]+', 'match'); + ## Format conversion specifiers following literals w/o space/delim + ## in between are separate now. Separate those w trailing literals + idy2 = find (! cellfun ("isempty", strfind (fmt_words, "%"))); + a = strfind (fmt_words(idy2), "%"); + b = regexp (fmt_words(idy2), '[nfdus]', 'end'); + for jj = 1:numel (a) + ii = numel (a) - jj + 1; + if (! (length (fmt_words{idy2(ii)}) == b{ii}(1))) + ## Fix format_words + fmt_words(idy2(ii)+1 : end+1) = fmt_words(idy2(ii) : end); + fmt_words{idy2(ii)} = fmt_words{idy2(ii)}(a{ii} : b{ii}(1)); + fmt_words{idy2(ii)+1} = fmt_words{idy2(ii)+1}(b{ii}+1:end); + endif + endfor + endif + num_words_per_line = numel (fmt_words); + + ## Special handling for CRLF EOL character in str + if (! isempty (eol_char) && strcmp (eol_char, "\r\n")) + ## Strip CR from CRLF sequences + str = strrep (str, "\r\n", "\n"); + ## CR serves no further purpose in function + eol_char = "\n"; endif - ## Parse format string - idx = strfind (format, "%")'; - specif = format ([idx, idx+1]); - nspecif = length (idx); - idx_star = strfind (format, "%*"); - nfields = length (idx) - length (idx_star); - - if (max (nargout, 1) != nfields) - error ("strread: the number of output variables must match that specified byFORMAT"); - endif - - ## Remove comments + ## Remove comments in str if (comment_flag) - cstart = strfind (str, comment_specif{1}); - cstop = strfind (str, comment_specif{2}); - if (length (cstart) > 0) + ## Expand 'eol_char' here, after option processing which may have set value + comment_end = regexprep (comment_end, 'eol_char', eol_char); + cstart = strfind (str, comment_start); + cstop = strfind (str, comment_end); + ## Treat end of string as additional comment stop + if (isempty (cstop) || cstop(end) != length (str)) + cstop(end+1) = length (str); + endif + if (! isempty (cstart)) ## Ignore nested openers. [idx, cidx] = unique (lookup (cstop, cstart), "first"); if (idx(end) == length (cstop)) @@ -172,7 +305,7 @@ endif cstart = cstart(cidx); endif - if (length (cstop) > 0) + if (! isempty (cstop)) ## Ignore nested closers. [idx, cidx] = unique (lookup (cstart, cstop), "first"); if (idx(1) == 0) @@ -181,101 +314,406 @@ cstop = cstop(cidx); endif len = length (str); - c2len = length (comment_specif{2}); + c2len = length (comment_end); str = cellslices (str, [1, cstop + c2len], [cstart - 1, len]); str = [str{:}]; endif - ## Determine the number of words per line - format = strrep (format, "%", " %"); - [~, ~, ~, fmt_words] = regexp (format, '[^ ]+'); + if (! isempty (white_spaces)) + ## Remove any delimiter chars from white_spaces list + white_spaces = setdiff (white_spaces, delimiter_str); + endif + if (isempty (delimiter_str)) + delimiter_str = " "; + endif + if (! isempty (eol_char)) + ## Add eol_char to delimiter collection + delimiter_str = unique ([delimiter_str eol_char]); + ## .. and remove it from whitespace collection + white_spaces = strrep (white_spaces, eol_char, ''); + endif - num_words_per_line = numel (fmt_words); - for m = 1:numel(fmt_words) - ## Convert formats such as "%Ns" to "%s" (see the FIXME below) - if (length (fmt_words{m}) > 2) - if (strcmp (fmt_words{m}(1:2), "%*")) - fmt_words{m} = "%*"; - elseif (fmt_words{m}(1) == "%") - fmt_words{m} = fmt_words{m}([1, end]); - endif + pad_out = 0; + ## Trim whitespace if needed + ## FIXME: This is very complicated. Can this be simplified with regexprep? + if (! isempty (white_spaces)) + ## Check if trailing "\n" might signal padding output arrays to equal size + ## before it is trimmed away below + if ((str(end) == 10) && (nargout > 1)) + pad_out = 1; endif - endfor + ## Remove repeated white_space chars. First find white_space positions + idx = strchr (str, white_spaces); + ## Find repeated white_spaces + idx2 = ! (idx(2:end) - idx(1:end-1) - 1); + ## Set all whitespace chars to spaces + ## FIXME: this implies real spaces are always part of white_spaces + str(idx) = ' '; + ## Set all repeated white_space to \0 + str(idx(idx2)) = "\0"; + str = strsplit (str, "\0"); + ## Reconstruct trimmed str + str = cell2mat (str); + ## Remove leading & trailing space, but preserve delimiters. + str = strtrim (str); + ## FIXME: Double strrep on str is enormously expensive of CPU time. + ## Can this be eliminated + ## Wipe leading and trailing whitespace on each line (it may be delimiter too) + if (! isempty (eol_char)) + str = strrep (str, [eol_char " "], eol_char); + str = strrep (str, [" " eol_char], eol_char); + endif + endif ## Split 'str' into words - words = split_by (str, delimiter_str); + words = split_by (str, delimiter_str, mult_dlms_s1, eol_char); + if (! isempty (white_spaces)) + ## Trim leading and trailing white_spaces + ## FIXME: Is this correct? strtrim clears what matches isspace(), not + ## necessarily what is in white_spaces. + words = strtrim (words); + endif num_words = numel (words); + ## First guess at number of lines in file (ignoring leading/trailing literals) num_lines = ceil (num_words / num_words_per_line); - ## For each specifier + ## Replace TreatAsEmpty char sequences by empty strings + if (! isempty (empty_str)) + for ii = 1:numel (empty_str) + idz = strmatch (empty_str{ii}, words, "exact"); + words(idz) = {""}; + endfor + endif + + ## We now may have to cope with 3 cases: + ## A: Trailing literals (%f<literal>) w/o delimiter in between. + ## B: Leading literals (<literal>%f) w/o delimiter in between. + ## C. Skipping leftover parts of specified skip fields (%*N ) + ## fmt_words has been split properly now, but words{} has only been split on + ## delimiter positions. Some words columns may have to be split further. + ## We also don't know the number of lines (as EndOfLine may have been set to + ## "" (empty) by the caller). + + ## Find indices and pointers to possible literals in fmt_words + idf = cellfun ("isempty", strfind (fmt_words, "%")); + ## Find indices and pointers to conversion specifiers with fixed width + idg = ! cellfun ("isempty", regexp (fmt_words, '%\*?\d')); + idy = find (idf | idg); + + ## If needed, split up columns in three steps: + if (! isempty (idy)) + ## Try-catch because complexity of strings to read can be infinite + #try + + ## 1. Assess "period" in the split-up words array ( < num_words_per_line). + ## Could be done using EndOfLine but that prohibits EndOfLine = "" option. + ## Alternative below goes by simply parsing a first grab of words + ## and counting words until the fmt_words array is exhausted: + iwrd = 1; iwrdp = 0; iwrdl = length (words{iwrd}); + for ii = 1:numel (fmt_words) + + if (idf(ii)) + ## Literal expected + if (isempty (strfind (fmt_words{ii}, words(iwrd)))) + ## Not found in current word; supposed to be in next word + ++iwrd; iwrdp = 0; + if (ii < numel (fmt_words)) + iwrdl = length (words{iwrd}); + endif + else + ## Found it in current word. Subtract literal length + iwrdp += length (fmt_words{ii}); + if (iwrdp > iwrdl) + ## Parse error. Literal extends beyond delimiter (word boundary) + error ("strread: Literal '%s' (fmt spec # %d) does not match data", fmt_words{ii}, ii); + elseif (iwrdp == iwrdl) + ## Word completely "used up". Next word + ++iwrd; iwrdp = 0; + if (ii < numel (fmt_words)) + iwrdl = length (words{iwrd}); + endif + endif + endif + + elseif (idg(ii)) + ## Fixed width specifier (%N or %*N): read just a part of word + iwrdp += floor ... + (str2double (fmt_words{ii}(regexp(fmt_words{ii}, '\d') : end-1))); + if (iwrdp > iwrdl) + ## Error. Field extends beyond word boundary. + error ("strread: Field width '%s' (fmt spec # %d) extends beyond word limit", fmt_words{ii}, ii); + elseif (iwrdp == iwrdl) + ## Word completely "used up". Next word + ++iwrd; iwrdp = 0; iwrdl = length (words{iwrd}); + endif + + else + ## A simple format conv. specifier. Either (1) uses rest of word, or + ## (2) is squeezed between current iwrdp and next literal, or (3) uses + ## next word. (3) is already taken care of. So just check (1) & (2) + if (ii < numel (fmt_words) && idf(ii+1)) + ## Next fmt_word is a literal... + if (! index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1})) + ## ...but not found in current word => field uses rest of word + ++iwrd; iwrdp = 0; iwrdl = length (words{iwrd}); + else + ## ..or it IS found. Add inferred width of current conversion field + iwrdp += index (words{iwrd}(iwrdp+1:end), fmt_words{ii+1}) - 1; + endif + elseif (iwrdp < iwrdl) + ## No bordering literal to the right => field occupies (rest of) word + ++iwrd; iwrdp = 0; + if (ii < numel (fmt_words)) + iwrdl = length (words{iwrd}); + endif + endif + + endif + endfor + ## Done + words_period = max (iwrd - 1, 1); + num_lines = ceil (num_words / words_period); + + ## 2. Pad words array so that it can be reshaped + tmp_lines = ceil (num_words / words_period); + num_words_padded = tmp_lines * words_period - num_words; + if (num_words_padded) + words = [words'; cell(num_words_padded, 1)]; + endif + words = reshape (words, words_period, tmp_lines); + + ## 3. Do the column splitting on rectangular words array + icol = 1; ii = 1; # icol = current column, ii = current fmt_word + while (ii <= num_words_per_line) + + ## Check if fmt_words(ii) contains a literal or fixed-width + if ((idf(ii) || idg(ii)) && (rows(words) < num_words_per_line)) + if (idf(ii)) + s = strfind (words(icol, 1), fmt_words{ii}); + if (isempty (s{:})) + error ("strread: Literal '%s' not found in column %d", fmt_words{ii}, icol); + endif + s = s{:}(1); + e = s(1) + length (fmt_words{ii}) - 1; + endif + if (! strcmp (fmt_words{ii}, words{icol, 1})) + ## Column doesn't exactly match literal => split needed. Insert a column + words(icol+1:end+1, :) = words(icol:end, :); + ## Watch out for empty cells + jptr = find (! cellfun ("isempty", words(icol, :))); + + ## Distinguish leading or trailing literals + if (! idg(ii) && ! isempty (s) && s(1) == 1) + ## Leading literal. Assign literal to icol, paste rest in icol + 1 + ## Apply only to those cells that do have something beyond literal + jptr = find (cellfun("length", words(icol+1, jptr), ... + "UniformOutput", false) > e(1)); + words(icol+1, :) = {""}; + words(icol+1, jptr) = cellfun ... + (@(x) substr(x, e(1)+1, length(x)-e(1)), words(icol, jptr), ... + "UniformOutput", false); + words(icol, jptr) = fmt_words{ii}; + + else + if (! idg(ii) && ! isempty (strfind (fmt_words{ii-1}, "%s"))) + ## Trailing literal. If preceding format == '%s' this is an error + warning ("Ambiguous '%s' specifier next to literal in column %d", icol); + elseif (idg(ii)) + ## Current field = fixed width. Strip into icol, rest in icol+1 + wdth = floor (str2double (fmt_words{ii}(regexp(fmt_words{ii}, ... + '\d') : end-1))); + words(icol+1, jptr) = cellfun (@(x) x(wdth+1:end), + words(icol,jptr), "UniformOutput", false); + words(icol, jptr) = strtrunc (words(icol, jptr), wdth); + else + ## FIXME: this assumes char(254)/char(255) won't occur in input! + clear wrds; + wrds(1:2:2*numel (words(icol, jptr))) = ... + strrep (words(icol, jptr), fmt_words{ii}, ... + [char(255) char(254)]); + wrds(2:2:2*numel (words(icol, jptr))-1) = char(255); + wrds = strsplit ([wrds{:}], char(255)); + words(icol, jptr) = ... + wrds(find (cellfun ("isempty", strfind (wrds, char(254))))); + wrds(find (cellfun ("isempty", strfind (wrds, char(254))))) ... + = char(255); + words(icol+1, jptr) = strsplit (strrep ([wrds{2:end}], ... + char(254), fmt_words{ii}), char(255)); + ## Former trailing literal may now be leading for next specifier + --ii; + endif + endif + endif + + else + ## Conv. specifier. Peek if next fmt_word needs split from current column + if (ii < num_words_per_line && idf(ii+1)) + if (! isempty (strfind (words{icol, 1}, fmt_words{ii+1}))) + --icol; + endif + endif + endif + ## Next fmt_word, next column + ++ii; ++icol; + endwhile + + ## Done. Reshape words back into 1 long vector and strip padded empty words + words = reshape (words, 1, numel (words))(1 : end-num_words_padded); + + #catch + # warning ("strread: unable to parse text or file with given format string"); + # return; + + #end_try_catch + endif + + ## For each specifier, process corresponding column k = 1; for m = 1:num_words_per_line - data = words (m:num_words_per_line:end); - ## Map to format - ## FIXME - add support for formats like "%4s" or "<%s>", "%[a-zA-Z]" - ## Someone with regexp experience is needed. - switch fmt_words{m} - case "%s" - data (end+1:num_lines) = {""}; - varargout {k} = data'; - k++; - case {"%d", "%f"} - n = cellfun (@isempty, data); - data = str2double (data); - data(n) = numeric_fill_value; - data (end+1:num_lines) = numeric_fill_value; - varargout {k} = data.'; - k++; - case {"%*", "%*s"} - ## skip the word - otherwise - ## Ensure descriptive content is consistent - if (numel (unique (data)) > 1 - || ! strcmpi (unique (data), fmt_words{m})) - error ("strread: FORMAT does not match data"); - endif - endswitch + try + if (format_repeat_count < 0) + data = words(m:num_words_per_line:end); + elseif (format_repeat_count == 0) + data = {}; + else + lastline = ... + min (num_words_per_line * format_repeat_count + m - 1, numel (words)); + data = words(m:num_words_per_line:lastline); + endif + + ## Map to format + ## FIXME - add support for formats like "<%s>", "%[a-zA-Z]" + ## Someone with regexp experience is needed. + switch fmt_words{m}(1:min (2, length (fmt_words{m}))) + case "%s" + if (pad_out) + data(end+1:num_lines) = {""}; + endif + varargout{k} = data'; + k++; + case {"%d", "%u", "%f", "%n"} + n = cellfun ("isempty", data); + ### FIXME - erroneously formatted data lead to NaN, not an error + data = str2double (data); + if (! isempty (regexp (fmt_words{m}, "%[du]"))) + ## Cast to integer + ## FIXME: NaNs will be transformed into zeros + data = int32 (data); + end + data(n) = numeric_fill_value; + if (pad_out) + data(end+1:num_lines) = numeric_fill_value; + endif + varargout{k} = data.'; + k++; + case {"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%8", "%9"} + nfmt = strsplit (fmt_words{m}(2:end-1), '.'); + swidth = str2double (nfmt{1}); + switch fmt_words{m}(end) + case {"d", "u", "f", "n%"} + n = cellfun ("isempty", data); + ### FIXME - erroneously formatted data lead to NaN, not an error + ### => ReturnOnError can't be implemented for numeric data + data = str2double (strtrunc (data, swidth)); + data(n) = numeric_fill_value; + if (pad_out) + data(end+1:num_lines) = numeric_fill_value; + endif + if (numel (nfmt) > 1) + sprec = str2double (nfmt{2}); + data = 10^-sprec * round (10^sprec * data); + elseif (! isempty (regexp (fmt_words{m}, "[du]"))) + ## Cast to integer + ## FIXME: NaNs will be transformed into zeros + data = int32 (data); + end + varargout{k} = data.'; + k++; + case "s" + if (pad_out) + data(end+1:num_lines) = {""} + endif + varargout{k} = strtrunc (data, swidth)'; + k++; + otherwise + endswitch + case {"%*", "%*s"} + ## skip the word + otherwise + ## Ensure descriptive content is consistent. + ## Test made a bit lax to accomodate for incomplete last lines + n = find (! cellfun ("isempty", data)); + if (numel (unique (data(n))) > 1 + || ! strcmpi (unique (data), fmt_words{m})) + error ("strread: FORMAT does not match data"); + endif + endswitch + catch + ## As strread processes columnwise, ML-compatible error processing + ## (row after row) is not feasible. In addition Octave sets unrecognizable + ## numbers to NaN w/o error. But maybe Octave is better in this respect. + if (err_action) + ## Just try the next column where ML bails out + else + rethrow (lasterror); + endif + end_try_catch endfor + endfunction -function out = split_by (text, sep) - sep = union (sep, "\n"); - pat = sprintf ('[^%s]+', sep); - [~, ~, ~, out] = regexp (text, pat); - out(cellfun (@isempty, out)) = {""}; - out = strtrim (out); +function out = split_by (text, sep, mult_dlms_s1, eol_char) + + ## Check & if needed, process MultipleDelimsAsOne parameter + if (mult_dlms_s1) + mult_dlms_s1 = true; + ## FIXME: Should re-implement strsplit() function here in order + ## to avoid strrep on megabytes of data. + ## If \n is in sep collection we need to enclose it in spaces in text + ## to avoid it being included in consecutive delim series + text = strrep (text, eol_char, [" " eol_char " "]); + else + mult_dlms_s1 = false; + endif + + ## Split text string along delimiters + out = strsplit (text, sep, mult_dlms_s1); + ## In case of trailing delimiter, strip stray last empty word + if (!isempty (out) && any (sep == text(end))) + out(end) = []; + endif + + ## Empty cells converted to empty cellstrings. + out(cellfun ("isempty", out)) = {""}; + endfunction + %!test %! [a, b] = strread ("1 2", "%f%f"); -%! assert (a == 1 && b == 2); - -%!test -%! str = "# comment\n# comment\n1 2 3"; -%! [a, b] = strread (str, '%d %s', 'commentstyle', 'shell'); -%! assert (a, [1; 3]); -%! assert (b, {"2"; ""}); +%! assert (a, 1); +%! assert (b, 2); %!test %! str = ''; %! a = rand (10, 1); -%! b = char (round (65 + 20 * rand (10, 1))); +%! b = char (randi ([65, 85], 10, 1)); %! for k = 1:10 -%! str = sprintf ('%s %.6f %s\n', str, a (k), b (k)); +%! str = sprintf ('%s %.6f %s\n', str, a(k), b(k)); %! endfor %! [aa, bb] = strread (str, '%f %s'); -%! assert (a, aa, 1e-5); +%! assert (a, aa, 1e-6); %! assert (cellstr (b), bb); %!test %! str = ''; %! a = rand (10, 1); -%! b = char (round (65 + 20 * rand (10, 1))); +%! b = char (randi ([65, 85], 10, 1)); %! for k = 1:10 -%! str = sprintf ('%s %.6f %s\n', str, a (k), b (k)); +%! str = sprintf ('%s %.6f %s\n', str, a(k), b(k)); %! endfor %! aa = strread (str, '%f %*s'); -%! assert (a, aa, 1e-5); +%! assert (a, aa, 1e-6); %!test %! str = sprintf ('/* this is\nacomment*/ 1 2 3'); @@ -283,6 +721,12 @@ %! assert (a, [1; 2; 3]); %!test +%! str = "# comment\n# comment\n1 2 3"; +%! [a, b] = strread (str, '%n %s', 'commentstyle', 'shell', 'endofline', "\n"); +%! assert (a, [1; 3]); +%! assert (b, {"2"}); + +%!test %! str = sprintf ("Tom 100 miles/hr\nDick 90 miles/hr\nHarry 80 miles/hr"); %! fmt = "%s %f miles/hr"; %! c = cell (1, 2); @@ -294,3 +738,65 @@ %! a = strread ("a b c, d e, , f", "%s", "delimiter", ","); %! assert (a, {"a b c"; "d e"; ""; "f"}); +%!test +%! # Bug #33536 +%! [a, b, c] = strread ("1,,2", "%s%s%s", "delimiter", ","); +%! assert (a{1}, '1'); +%! assert (b{1}, ''); +%! assert (c{1}, '2'); + +%!test +%! # Bug #33536 +%! a = strread ("[SomeText]", "[%s", "delimiter", "]"); +%! assert (a{1}, "SomeText"); + +%!test +%! dat = "Data file.\r\n= = = = =\r\nCOMPANY : <Company name>\r\n"; +%! a = strread (dat, "%s", 'delimiter', "\n", 'whitespace', '', 'endofline', "\r\n"); +%! assert (a{2}, "= = = = ="); +%! assert (double (a{3}(end-5:end)), [32 110 97 109 101 62]); + +%!test +%! [a, b, c, d] = strread ("1,2,3,,5,6", "%d%f%d%f", 'delimiter', ','); +%! assert (c, int32 (3)); +%! assert (d, NaN); + +%!test +%! [a, b, c, d] = strread ("1,2,3,,5,6\n", "%d%d%f%d", 'delimiter', ','); +%! assert (c, [3; NaN]); +%! assert (d, int32 ([0; 0])); + +%!test +%! # Default format (= %f) +%1 [a, b, c] = strread ("0.12 0.234 0.3567"); +%1 assert (a, 0.12); +%1 assert (b, 0.234); +%1 assert (c, 0.3567); + +%!test +%! [a, b] = strread('0.41 8.24 3.57 6.24 9.27', "%f%f", 2, 'delimiter', ' '); +%1 assert (a, [0.41; 3.57]); + +%!test +%! # TreatAsEmpty +%! [a, b, c, d] = strread ("1,2,3,NN,5,6\n", "%d%d%d%f", 'delimiter', ',', 'TreatAsEmpty', 'NN'); +%! assert (c, int32 ([3; 0])); +%! assert (d, [NaN; NaN]); + +%!test +%! # No delimiters at all besides EOL. Plain reading numbers & strings +%! str = "Text1Text2Text\nText398Text4Text\nText57Text"; +%! c = textscan (str, "Text%dText%1sText"); +%! assert (c{1}, int32 ([1; 398; 57])); +%! assert (c{2}(1:2), {'2'; '4'}); +%! assert (isempty (c{2}{3}), true); + +%% MultipleDelimsAsOne +%!test +%! str = "11, 12, 13,, 15\n21,, 23, 24, 25\n,, 33, 34, 35"; +%! [a b c d] = strread (str, "%f %f %f %f", 'delimiter', ',', 'multipledelimsasone', 1, 'endofline', "\n"); +%! assert (a', [11, 21, NaN]); +%! assert (b', [12, 23, 33]); +%! assert (c', [13, 24, 34]); +%! assert (d', [15, 25, 35]); +
--- a/scripts/io/textread.m +++ b/scripts/io/textread.m @@ -19,30 +19,43 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @dots{}] =} textread (@var{filename}) ## @deftypefnx {Function File} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}) +## @deftypefnx {Function File} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n}) ## @deftypefnx {Function File} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{prop1}, @var{value1}, @dots{}) +## @deftypefnx {Function File} {[@var{a}, @dots{}] =} textread (@var{filename}, @var{format}, @var{n}, @var{prop1}, @var{value1}, @dots{}) ## Read data from a text file. ## ## The file @var{filename} is read and parsed according to @var{format}. The ## function behaves like @code{strread} except it works by parsing a file -## instead -## of a string. See the documentation of @code{strread} for details. +## instead of a string. See the documentation of @code{strread} for details. +## ## In addition to the options supported by @code{strread}, this function -## supports one more: +## supports two more: +## ## @itemize ## @item "headerlines": +## The first @var{value} number of lines of @var{filename} are skipped. +## +## @item "endofline": +## Specify a single character or "\r\n". If no value is given, it will be +## inferred from the file. If set to "" (empty string) EOLs are ignored as +## delimiters. ## @end itemize -## The first @var{value} number of lines of @var{str} are skipped. -## @seealso{strread, load, dlmread, fscanf} +## +## The optional input @var{n} specifes the number of times to use +## @var{format} when parsing, i.e., the format repeat count. +## +## @seealso{strread, load, dlmread, fscanf, textscan} ## @end deftypefn function varargout = textread (filename, format = "%f", varargin) + ## Check input if (nargin < 1) print_usage (); endif - if (!ischar (filename) || !ischar (format)) - error ("textread: first and second input arguments must be strings"); + if (! ischar (filename) || ! ischar (format)) + error ("textread: FILENAME and FORMAT arguments must be strings"); endif ## Read file @@ -51,21 +64,85 @@ error ("textread: could not open '%s' for reading", filename); endif - ## Maybe skip header lines + ## Skip header lines if requested headerlines = find (strcmpi (varargin, "headerlines"), 1); - if (! isempty (headerlines)) - hdr_lines = floor (varargin{headerlines + 1}); - ## Beware of zero valued headerline, fskipl will count lines to EOF then - if (hdr_lines > 0) - fskipl (fid, hdr_lines); - endif + ## Beware of zero valued headerline, fskipl would skip to EOF + if (! isempty (headerlines) && (varargin{headerlines + 1} > 0)) + fskipl (fid, varargin{headerlines + 1}); varargin(headerlines:headerlines+1) = []; endif - str = fread (fid, "char=>char").'; + if (nargin > 2 && isnumeric (varargin{1})) + nlines = varargin{1}; + else + nlines = Inf; + endif + + if (isfinite (nlines) && (nlines >= 0)) + str = tmp_str = ""; + n = 0; + ## FIXME: Can this be done without slow loop? + while (ischar (tmp_str) && n++ <= nlines) + str = strcat (str, tmp_str); + tmp_str = fgets (fid); + endwhile + else + str = fread (fid, "char=>char").'; + endif fclose (fid); + if (isempty (str)) + warning ("textread: empty file"); + return; + endif + + endofline = find (strcmpi (varargin, "endofline"), 1); + if (! isempty (endofline)) + ## 'endofline' option set by user. + if (! ischar (varargin{endofline + 1})); + error ("textread: character value required for EndOfLine"); + endif + else + ## Determine EOL from file. Search for EOL candidates in first 3000 chars + eol_srch_len = min (length (str), 3000); + ## First try DOS (CRLF) + if (! isempty (findstr ("\r\n", str(1 : eol_srch_len)))) + eol_char = "\r\n"; + ## Perhaps old Macintosh? (CR) + elseif (! isempty (findstr ("\r", str(1 : eol_srch_len)))) + eol_char = "\r"; + ## Otherwise, use plain UNIX (LF) + else + eol_char = "\n"; + endif + ## Set up default endofline param value + varargin(end+1:end+2) = {'endofline', eol_char}; + endif + + ## Set up default whitespace param value if needed + if (isempty (find (strcmpi ('whitespace', varargin)))) + varargin(end+1:end+2) = {'whitespace', " \b\t"}; + endif + ## Call strread to make it do the real work [varargout{1:max (nargout, 1)}] = strread (str, format, varargin {:}); endfunction + + +%!test +%! f = tmpnam(); +%! d = rand (5, 3); +%! dlmwrite (f, d, 'precision', '%5.2f'); +%! [a, b, c] = textread (f, "%f %f %f", "delimiter", ",", "headerlines", 3); +%! unlink(f); +%! assert (a, d(4:5, 1), 1e-2); +%! assert (b, d(4:5, 2), 1e-2); +%! assert (c, d(4:5, 3), 1e-2); + +%% Test input validation +%!error textread () +%!error textread (1) +%!error <arguments must be strings> textread (1, '%f') +%!error <arguments must be strings> textread ("fname", 1) +
--- a/scripts/io/textscan.m +++ b/scripts/io/textscan.m @@ -22,23 +22,40 @@ ## @deftypefnx {Function File} {@var{C} =} textscan (@var{fid}, @var{format}, @var{param}, @var{value}, @dots{}) ## @deftypefnx {Function File} {@var{C} =} textscan (@var{fid}, @var{format}, @var{n}, @var{param}, @var{value}, @dots{}) ## @deftypefnx {Function File} {@var{C} =} textscan (@var{str}, @dots{}) -## @deftypefnx {Function File} {[@var{C}, @var{position}] =} textscan (@dots{}) -## Read data from a text file. +## @deftypefnx {Function File} {[@var{C}, @var{position}] =} textscan (@var{fid}, @dots{}) +## Read data from a text file or string. ## ## The file associated with @var{fid} is read and parsed according to ## @var{format}. The function behaves like @code{strread} except it works by ## parsing a file instead of a string. See the documentation of -## @code{strread} for details. In addition to the options supported by -## @code{strread}, this function supports one more: +## @code{strread} for details. +## +## In addition to the options supported by +## @code{strread}, this function supports a few more: +## ## @itemize +## @item "collectoutput": +## A value of 1 or true instructs textscan to concatenate consecutive columns +## of the same class in the output cell array. A value of 0 or false (default) +## leaves output in distinct columns. +## +## @item "endofline": +## Specify "\r", "\n" or "\r\n" (for CR, LF, or CRLF). If no value is given, +## it will be inferred from the file. If set to "" (empty string) EOLs are +## ignored as delimiters and added to whitespace. +## ## @item "headerlines": +## The first @var{value} number of lines of @var{fid} are skipped. +## +## @item "returnonerror": +## If set to numerical 1 or true (default), return normally when read errors +## have been encountered. If set to 0 or false, return an error and no data. ## @end itemize -## The first @var{value} number of lines of @var{str} are skipped. ## -## The optional input, @var{n}, specifes the number of lines to be read from -## the file, associated with @var{fid}. +## The optional input @var{n} specifes the number of times to use +## @var{format} when parsing, i.e., the format repeat count. ## -## The output, @var{C}, is a cell array whose length is given by the number +## The output @var{C} is a cell array whose length is given by the number ## of format specifiers. ## ## The second output, @var{position}, provides the position, in characters, @@ -47,89 +64,208 @@ ## @seealso{dlmread, fscanf, load, strread, textread} ## @end deftypefn -function [C, p] = textscan (fid, format, varargin) +function [C, position] = textscan (fid, format = "%f", varargin) ## Check input if (nargin < 1) print_usage (); - elseif (nargin == 1 || isempty (format)) + endif + + if (isempty (format)) format = "%f"; endif - if (nargin > 2 && isnumeric (varargin{1})) - nlines = varargin{1}; - args = varargin(2:end); + if (! (isa (fid, "double") && fid > 0) && ! ischar (fid)) + error ("textscan: first argument must be a file id or character string"); + endif + + if (! ischar (format)) + error ("textscan: FORMAT must be a string"); + endif + + args = varargin; + if (nargin > 2 && isnumeric (args{1})) + nlines = args{1}; else nlines = Inf; - args = varargin; endif if (! any (strcmpi (args, "emptyvalue"))) ## Matlab returns NaNs for missing values - args{end+1} = "emptyvalue"; - args{end+1} = NaN; + args(end+1:end+2) = {'emptyvalue', NaN}; + endif + + ## Check default parameter values that differ for strread & textread + + ipos = find (strcmpi (args, "whitespace")); + if (isempty (ipos)) + ## Matlab default whitespace = " \b\t" + args(end+1:end+2) = {'whitespace', " \b\t"}; + whitespace = " \b\t"; + else + ## Check if there's at least one string format specifier + fmt = strrep (format, "%", " %"); + fmt = regexp (fmt, '[^ ]+', 'match'); + fmt = strtrim (fmt(strmatch ("%", fmt))) + has_str_fmt = all (cellfun ("isempty", strfind (strtrim (fmt(strmatch ("%", fmt))), 's'))); + ## If there is a format, AND whitespace value = empty, + ## don't add a space (char(32)) to whitespace + if (! (isempty (args{ipos+1}) && has_str_fmt)) + args{ipos+1} = unique ([" ", whitespace]); + endif + endif + + if (! any (strcmpi (args, "delimiter"))) + ## Matlab says default delimiter = whitespace. + ## strread() will pick this up further + args(end+1:end+2) = {'delimiter', ""}; + endif + + collop = false; + ipos = find (strcmpi (args, "collectoutput")); + if (! isempty (ipos)) + ## Search & concatenate consecutive columns of same class requested + if (isscalar (args{ipos+1}) + && (islogical (args{ipos+1}) || isnumeric (args{ipos+1}))) + collop = args{ipos+1}; + else + warning ("textscan: illegal value for CollectOutput parameter - ignored"); + endif + ## Remove argument before call to strread() below + args(ipos:ipos+1) = []; + endif + + if (any (strcmpi (args, "returnonerror"))) + ## Because of the way strread() reads data (columnwise) this parameter + ## can't be neatly implemented. strread() will pick it up anyway + warning ('textscan: ReturnOnError is not fully implemented'); + else + ## Set default value (=true) + args(end+1:end+2) = {"returnonerror", 1}; + endif + + if (ischar (fid)) + ## Read from a text string + if (nargout == 2) + error ("textscan: cannot provide position information for character input"); + endif + str = fid; + else + ## Skip header lines if requested + headerlines = find (strcmpi (args, "headerlines"), 1); + ## Beware of zero valued headerline, fskipl would skip to EOF + if (! isempty (headerlines) && (args{headerlines + 1} > 0)) + fskipl (fid, varargin{headerlines + 1}); + args(headerlines:headerlines+1) = []; + endif + if (isfinite (nlines) && (nlines >= 0)) + str = tmp_str = ""; + n = 0; + ## FIXME: Can this be done without slow loop? + while (ischar (tmp_str) && n++ < nlines) + tmp_str = fgets (fid); + if (ischar (tmp_str)) + str = strcat (str, tmp_str); + endif + endwhile + else + str = fread (fid, "char=>char").'; + endif endif - if (isa (fid, "double") && fid > 0 || ischar (fid)) - if (ischar (format)) - if (ischar (fid)) - if (nargout == 2) - error ("textscan: cannot provide position information for character input"); - endif - str = fid; - else - ## Maybe skip header lines - headerlines = find (strcmpi (args, "headerlines"), 1); - if (! isempty (headerlines)) - hdr_lines = floor (varargin{headerlines + 1}); - ## Beware of zero valued headerline, fskipl will count lines to EOF - if (hdr_lines > 0) - fskipl (fid, hdr_lines); - endif - endif - if (isfinite (nlines)) - str = ""; - for n = 1:nlines - str = strcat (str, fgets (fid)); - endfor - else - str = fread (fid, "char=>char").'; - endif + ## Check for empty result + if (isempty (str)) + warning ("textscan: no data read"); + C = []; + return; + endif + + ## Check value of 'endofline'. String or file doesn't seem to matter + endofline = find (strcmpi (args, "endofline"), 1); + if (! isempty (endofline)) + if (ischar (args{endofline + 1})) + eol_char = args{endofline + 1}; + if (isempty (strmatch (eol_char, {"", "\n", "\r", "\r\n"}, 'exact'))) + error ("textscan: illegal EndOfLine character value specified"); endif - - ## Determine the number of data fields - num_fields = numel (strfind (format, "%")) - ... - numel (idx_star = strfind (format, "%*")); - - ## Call strread to make it do the real work - C = cell (1, num_fields); - [C{:}] = strread (str, format, args{:}); - - if (ischar (fid) && isfinite (nlines)) - C = cellfun (@(x) x(1:nlines), C, "uniformoutput", false); - endif - - if (nargout == 2) - p = ftell (fid); - endif - else - error ("textscan: FORMAT must be a valid specification"); + error ("textscan: character value required for EndOfLine"); endif else - error ("textscan: first argument must be a file id or character string"); + ## Determine EOL from file. Search for EOL candidates in first 3000 chars + eol_srch_len = min (length (str), 3000); + ## First try DOS (CRLF) + if (! isempty (findstr ("\r\n", str(1 : eol_srch_len)))) + eol_char = "\r\n"; + ## Perhaps old Macintosh? (CR) + elseif (! isempty (findstr ("\r", str(1 : eol_srch_len)))) + eol_char = "\r"; + ## Otherwise, use plain UNIX (LF) + else + eol_char = "\n"; + endif + ## Set up the default endofline param value + args(end+1:end+2) = {'endofline', eol_char}; + endif + + ## Determine the number of data fields + num_fields = numel (strfind (format, "%")) - numel (strfind (format, "%*")); + + ## Strip trailing EOL to avoid returning stray missing values (f. strread) + if (strcmp (str(end-length (eol_char) + 1 : end), eol_char)); + str(end-length (eol_char) + 1 : end) = ""; + endif + + ## Call strread to make it do the real work + C = cell (1, num_fields); + [C{:}] = strread (str, format, args{:}); + + ## If requested, collect output columns of same class + if (collop) + C = colloutp (C); endif + if (nargout == 2) + position = ftell (fid); + endif + +endfunction + + +## Collect consecutive columns of same class into one cell column +function C = colloutp (C) + + ## Start at rightmost column and work backwards to avoid ptr mixup + ii = numel (C); + while ii > 1 + clss1 = class (C{ii}); + jj = ii; + while (jj > 1 && strcmp (clss1, class (C{jj - 1}))) + ## Column to the left is still same class; check next column to the left + --jj; + endwhile + if (jj < ii) + ## Concatenate columns into current column + C{jj} = [C{jj : ii}]; + ## Wipe concatenated columns to the right, resume search to the left + C(jj+1 : ii) = []; + ii = jj - 1; + else + ## No similar class in column to the left, search from there + --ii; + endif + endwhile + endfunction %!test %! str = "1, 2, 3, 4\n 5, , , 8\n 9, 10, 11, 12"; %! fmtstr = "%f %d %f %s"; %! c = textscan (str, fmtstr, 2, "delimiter", ",", "emptyvalue", -Inf); -%! assert (isequal (c{1}, [1;5])) +%! assert (isequal (c{1}, [1;5])); %! assert (length (c{1}), 2); -%! assert (iscellstr (c{4})) -%! assert (isequal (c{3}, [3; -Inf])) +%! assert (iscellstr (c{4})); +%! assert (isequal (c{3}, [3; -Inf])); %!test %! b = [10:10:100]; @@ -137,7 +273,60 @@ %! str = sprintf ("%g miles/hr = %g kilometers/hr\n", b); %! fmt = "%f miles/hr = %f kilometers/hr"; %! c = textscan (str, fmt); -%! assert (b(1,:)', c{1}) -%! assert (b(2,:)', c{2}) +%! assert (b(1,:)', c{1}, 1e-5); +%! assert (b(2,:)', c{2}, 1e-5); + +#%!test +#%! str = "13, 72, NA, str1, 25\r\n// Middle line\r\n36, na, 05, str3, 6"; +#%! a = textscan(str, '%d %n %f %s %n', 'delimiter', ',','treatAsEmpty', {'NA', 'na'},'commentStyle', '//'); +#%! assert (a{1}, int32([13; 36])); +#%! assert (a{2}, [72; NaN]); +#%! assert (a{3}, [NaN; 5]); +#%! assert (a{4}, {"str1"; "str3"}); +#%! assert (a{5}, [25; 6]); + +%!test +%! str = "Km:10 = hhhBjjj miles16hour\r\n"; +%! str = [str "Km:15 = hhhJjjj miles241hour\r\n"]; +%! str = [str "Km:2 = hhhRjjj miles3hour\r\n"]; +%! str = [str "Km:25 = hhhZ\r\n"]; +%! fmt = "Km:%d = hhh%1sjjj miles%dhour"; +%! a = textscan (str, fmt, 'delimiter', ' '); +%! assert (a{1}', int32([10 15 2 25])); +%! assert (a{2}', {'B' 'J' 'R' 'Z'}); +%! assert (a{3}', int32([16 241 3 0])); + +%% Test with default endofline parameter +%!test +%! c = textscan ("L1\nL2", "%s"); +%! assert (c{:}, {"L1"; "L2"}); +%% Test with endofline parameter set to '' (empty) - newline should be in word +%!test +%! c = textscan ("L1\nL2", "%s", 'endofline', ''); +%! assert (int8(c{:}{:}), int8([ 76, 49, 10, 76, 50 ])); +%!test +%! # No delimiters at all besides EOL. Skip fields, even empty fields +%! str = "Text1Text2Text\nTextText4Text\nText57Text"; +%! c = textscan (str, "Text%*dText%dText"); +%! assert (c{1}, int32 ([2; 4; 0])); + +%!test +%% CollectOutput test +%! b = [10:10:100]; +%! b = [b; 8*b/5; 8*b*1000/5]; +%! str = sprintf ("%g miles/hr = %g (%g) kilometers (meters)/hr\n", b); +%! fmt = "%f miles%s %s %f (%f) kilometers %*s"; +%! c = textscan (str, fmt, 'collectoutput', 1); +%! assert (size(c{3}), [10, 2]); +%! assert (size(c{2}), [10, 2]); + +%% Test input validation +%!error textscan () +%!error textscan (single (4)) +%!error textscan ({4}) +%!error <must be a string> textscan ("Hello World", 2) +%!error <cannot provide position information> [C, pos] = textscan ("Hello World") +%!error <character value required> textscan ("Hello World", '%s', 'EndOfLine', 3) +
new file mode 100644 --- /dev/null +++ b/scripts/linear-algebra/bicg.m @@ -0,0 +1,249 @@ +## Copyright (C) 2006 Sylvain Pelissier <sylvain.pelissier@gmail.com> +## Copyright (C) 2011 Carlo de Falco +## +## 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 this program; If not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## +## @deftypefn {Function File} {@var{x} =} bicg (@var{A}, @var{b}, @var{rtol}, @var{maxit}, @var{M1}, @var{M2}, @var{x0}) +## @deftypefnx {Function File} {@var{x} =} bicg (@var{A}, @var{b}, @var{rtol}, @var{maxit}, @var{P}) +## @deftypefnx {Function File} {[@var{x}, @var{flag}, @var{relres}, @var{iter}, @var{resvec}] =} bicg (@var{A}, @var{b}, ...) +## +## Solve @code{A x = b} using the Bi-conjugate gradient iterative method. +## +## @itemize @minus +## @item @var{rtol} is the relative tolerance, if not given or set to [] the default value 1e-6 is used. +## @item @var{maxit} the maximum number of outer iterations, if not given or set to [] the default value @code{min (20, numel (b))} is used. +## @item @var{x0} the initial guess, if not given or set to [] the default value @code{zeros (size (b))} is used. +## @end itemize +## +## @var{A} can be passed as a matrix or as a function handle or +## inline function @code{f} such that @code{f(x, "notransp") = A*x} and @code{f(x, "transp") = A'*x}. +## +## The preconditioner @var{P} is given as @code{P = M1 * M2}. +## Both @var{M1} and @var{M2} can be passed as a matrix or as a function handle or +## inline function @code{g} such that @code{g(x, 'notransp') = M1 \ x} or @code{g(x, 'notransp') = M2 \ x} and +## @code{g(x, 'transp') = M1' \ x} or @code{g(x, 'transp') = M2' \ x}. +## +## If colled with more than one output parameter +## +## @itemize @minus +## @item @var{flag} indicates the exit status: +## @itemize @minus +## @item 0: iteration converged to the within the chosen tolerance +## @item 1: the maximum number of iterations was reached before convergence +## @item 3: the algorithm reached stagnation +## @end itemize +## (the value 2 is unused but skipped for compatibility). +## @item @var{relres} is the final value of the relative residual. +## @item @var{iter} is the number of iterations performed. +## @item @var{resvec} is a vector containing the relative residual at each iteration. +## @end itemize +## +## @seealso{pcg,cgs,bigcstab,gmres} +## +## @end deftypefn + + +function [x, flag, res1, k, resvec] = bicg (A, b, tol, maxit, M1, M2, x0) + + if ((nargin >= 2) && isvector (full (b))) + + if (ischar (A)) + fun = str2func (A); + Ax = @(x) feval (fun, x, "notransp"); + Atx = @(x) feval (fun, x, "transp"); + elseif (ismatrix (A)) + Ax = @(x) A * x; + Atx = @(x) A' * x; + elseif (isa (A, "function_handle")) + Ax = @(x) feval (A, x, "notransp"); + Atx = @(x) feval (A, x, "transp"); + else + error (["bicg: first argument is expected to " ... + "be a function or a square matrix"]); + endif + + if ((nargin < 3) || (isempty (tol))) + tol = 1e-6; + endif + + if ((nargin < 4) || (isempty (maxit))) + maxit = min (rows (b), 20); + endif + + if ((nargin < 5) || isempty (M1)) + M1m1x = @(x, ignore) x; + M1tm1x = M1m1x; + elseif (ischar (M1)) + fun = str2func (M1); + M1m1x = @(x) feval (fun, x, "notransp"); + M1tm1x = @(x) feval (fun, x, "transp"); + elseif (ismatrix (M1)) + M1m1x = @(x) M1 \ x; + M1tm1x = @(x) M1' \ x; + elseif (isa (M1, "function_handle")) + M1m1x = @(x) feval (M1, x, "notransp"); + M1tm1x = @(x) feval (M1, x, "transp"); + else + error (["bicg: preconditioner is expected to " ... + "be a function or matrix"]); + endif + + if ((nargin < 6) || isempty (M2)) + M2m1x = @(x, ignore) x; + M2tm1x = M2m1x; + elseif (ischar (M2)) + fun = str2func (M2); + M2m1x = @(x) feval (fun, x, "notransp"); + M2tm1x = @(x) feval (fun, x, "transp"); + elseif (ismatrix (M2)) + M2m1x = @(x) M2 \ x; + M2tm1x = @(x) M2' \ x; + elseif (isa (M2, "function_handle")) + M2m1x = @(x) feval (M2, x, "notransp"); + M2tm1x = @(x) feval (M2, x, "transp"); + else + error (["bicg: preconditioner is expected to " ... + "be a function or matrix"]); + endif + + Pm1x = @(x) M2m1x (M1m1x (x)); + Ptm1x = @(x) M1tm1x (M2tm1x (x)); + + if ((nargin < 7) || (isempty (x0))) + x0 = zeros (size (b)); + endif + + y = x = x0; + c = b; + + r0 = b - Ax (x); + s0 = c - Atx (y); + + d = Pm1x (r0); + f = Ptm1x (s0); + + bnorm = norm (b); + res0 = Inf; + + if (any (r0 != 0)) + + for k = 1:maxit + + a = (s0' * Pm1x (r0)) ./ (f' * Ax (d)); + + x += a * d; + y += conj (a) * f; + + r1 = r0 - a * Ax (d); + s1 = s0 - conj (a) * Atx (f); + + beta = (s1' * Pm1x (r1)) ./ (s0' * Pm1x (r0)); + + d = Pm1x (r1) + beta * d; + f = Ptm1x (s1) + conj (beta) * f; + + r0 = r1; + s0 = s1; + + res1 = norm (b - Ax (x)) / bnorm; + if (res1 < tol) + flag = 0; + if (nargout < 2) + printf ("bicg converged at iteration %i ", k); + printf ("to a solution with relative residual %e\n", res1); + endif + break; + endif + + if (res0 <= res1) + flag = 3; + printf ("bicg stopped at iteration %i ", k); + printf ("without converging to the desired tolerance %e\n", tol); + printf ("because the method stagnated.\n"); + printf ("The iterate returned (number %i) ", k-1); + printf ("has relative residual %e\n", res0); + break + endif + res0 = res1; + if (nargout > 4) + resvec(k) = res0; + endif + endfor + + if (k == maxit) + flag = 1; + printf ("bicg stopped at iteration %i ", maxit); + printf ("without converging to the desired tolerance %e\n", tol); + printf ("because the maximum number of iterations was reached. "); + printf ("The iterate returned (number %i) has ", maxit); + printf ("relative residual %e\n", res1); + endif + + else + flag = 0; + if (nargout < 2) + printf ("bicg converged after 0 interations\n"); + endif + endif + + else + print_usage (); + endif + +endfunction; + + +%!test +%! n = 100; +%! A = spdiags ([-2*ones(n,1) 4*ones(n,1) -ones(n,1)], -1:1, n, n); +%! b = sum (A, 2); +%! tol = 1e-8; +%! maxit = 15; +%! M1 = spdiags ([ones(n,1)/(-2) ones(n,1)],-1:0, n, n); +%! M2 = spdiags ([4*ones(n,1) -ones(n,1)], 0:1, n, n); +%! [x, flag, relres, iter, resvec] = bicg (A, b, tol, maxit, M1, M2); +%! assert (x, ones (size (b)), 1e-7); +%! +%!test +%! n = 100; +%! A = spdiags ([-2*ones(n,1) 4*ones(n,1) -ones(n,1)], -1:1, n, n); +%! b = sum (A, 2); +%! tol = 1e-8; +%! maxit = 15; +%! M1 = spdiags ([ones(n,1)/(-2) ones(n,1)],-1:0, n, n); +%! M2 = spdiags ([4*ones(n,1) -ones(n,1)], 0:1, n, n); +%! +%! function y = afun (x, t, a) +%! switch t +%! case "notransp" +%! y = a * x; +%! case "transp" +%! y = a' * x; +%! endswitch +%! endfunction +%! +%! [x, flag, relres, iter, resvec] = bicg (@(x, t) afun (x, t, A), +%! b, tol, maxit, M1, M2); +%! assert (x, ones (size (b)), 1e-7); + +%!test +%! n = 100; +%! tol = 1e-8; +%! a = sprand (n, n, .1); +%! A = a' * a + 100 * eye (n); +%! b = sum (A, 2); +%! [x, flag, relres, iter, resvec] = bicg (A, b, tol, [], diag (diag (A))); +%! assert (x, ones (size (b)), 1e-7);
--- a/scripts/linear-algebra/commutation_matrix.m +++ b/scripts/linear-algebra/commutation_matrix.m @@ -95,3 +95,25 @@ endfor endfunction + +%!test +%! c = commutation_matrix(1,1); +%! assert(c,1); + +%!test +%! A = rand(3,5); +%! vc = vec(A); +%! vr = vec(A'); +%! c = commutation_matrix(3,5); +%! assert(c*vc,vr); + +%!test +%! A = rand(4,6); +%! vc = vec(A); +%! vr = vec(A'); +%! c = commutation_matrix(4,6); +%! assert(c*vc,vr); + +%!error commutation_matrix(0,0); +%!error commutation_matrix(1,0); +%!error commutation_matrix(0,1);
--- a/scripts/linear-algebra/isdefinite.m +++ b/scripts/linear-algebra/isdefinite.m @@ -63,3 +63,22 @@ endif endfunction + +%!test +%! A = [-1 0; 0 -1]; +%! assert (isdefinite (A), -1) + +%!test +%! A = [1 0; 0 1]; +%! assert (isdefinite (A), 1) + +%!test +%! A = [2 -1 0; -1 2 -1; 0 -1 2]; +%! assert (isdefinite (A), 1) + +%!test +%! A = [1 0; 0 0]; +%! assert (isdefinite (A), 0) + +%!error isdefinite () +%!error isdefinite ([1 2; 3 4]) \ No newline at end of file
--- a/scripts/linear-algebra/module.mk +++ b/scripts/linear-algebra/module.mk @@ -7,7 +7,6 @@ linear-algebra/cross.m \ linear-algebra/duplication_matrix.m \ linear-algebra/expm.m \ - linear-algebra/gmres.m \ linear-algebra/housh.m \ linear-algebra/isdefinite.m \ linear-algebra/ishermitian.m \
--- a/scripts/linear-algebra/null.m +++ b/scripts/linear-algebra/null.m @@ -77,3 +77,35 @@ endif endfunction + +%!test +%! A = 0; +%! assert(null(A), 1); + +%!test +%! A = 1; +%! assert(null(A), zeros(1,0)) + +%!test +%! A = [1 0; 0 1]; +%! assert(null(A), zeros(2,0)); + +%!test +%! A = [1 0; 1 0]; +%! assert(null(A), [0 1]') + +%!test +%! A = [1 1; 0 0]; +%! assert(null(A), [-1/sqrt(2) 1/sqrt(2)]', eps) + +%!test +%! tol = 1e-4; +%! A = [1 0; 0 tol-eps]; +%! assert(null(A,tol), [0 1]') + +%!test +%! tol = 1e-4; +%! A = [1 0; 0 tol+eps]; +%! assert(null(A,tol), zeros(2,0)); + +%!error null()
--- a/scripts/linear-algebra/orth.m +++ b/scripts/linear-algebra/orth.m @@ -39,6 +39,11 @@ if (nargin == 1 || nargin == 2) + if (isempty (A)) + retval = []; + return; + endif + [U, S, V] = svd (A); [rows, cols] = size (A);
--- a/scripts/linear-algebra/rank.m +++ b/scripts/linear-algebra/rank.m @@ -58,3 +58,54 @@ retval = sum (sigma > tolerance); endfunction + +%!test +%! A = [1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12; +%! 1 2 3.1 4 5 6 7; +%! 2 3 4 5 6 7 8; +%! 3 4 5 6 7 8 9; +%! 4 5 6 7 8 9 10; +%! 5 6 7 8 9 10 11]; +%! assert(rank(A),4); + +%!test +%! A = [1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12; +%! 1 2 3.0000001 4 5 6 7; +%! 4 5 6 7 8 9 12.00001; +%! 3 4 5 6 7 8 9; +%! 4 5 6 7 8 9 10; +%! 5 6 7 8 9 10 11]; +%! assert(rank(A),4); + +%!test +%! A = [1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12; +%! 1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12.00001; +%! 3 4 5 6 7 8 9; +%! 4 5 6 7 8 9 10; +%! 5 6 7 8 9 10 11]; +%! assert(rank(A),3); + +%!test +%! A = [1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12; +%! 1 2 3 4 5 6 7; +%! 4 5 6 7 8 9 12; +%! 3 4 5 6 7 8 9; +%! 4 5 6 7 8 9 10; +%! 5 6 7 8 9 10 11]; +%! assert(rank(A),3); + +%!test +%! A = eye(100); +%! assert(rank(A),100); + +%!test +%! A = [1, 2, 3; 1, 2.001, 3; 1, 2, 3.0000001]; +%! assert(rank(A),3) +%! assert(rank(A,0.0009),1) +%! assert(rank(A,0.0006),2) +%! assert(rank(A,0.00000002),3) \ No newline at end of file
--- a/scripts/miscellaneous/ans.m +++ b/scripts/miscellaneous/ans.m @@ -28,3 +28,7 @@ ## @noindent ## is evaluated, the value returned by @code{ans} is 25. ## @end defvr + +## Mark file as being tested. No real test needed for a documentation .m file +%!assert (1) +
--- a/scripts/miscellaneous/bug_report.m +++ b/scripts/miscellaneous/bug_report.m @@ -43,3 +43,6 @@ puts ("\n"); endfunction + +## Mark file as being tested. No real test needed for this function. +%!assert (1)
--- a/scripts/miscellaneous/comma.m +++ b/scripts/miscellaneous/comma.m @@ -21,3 +21,7 @@ ## Array index, function argument, or command separator. ## @seealso{semicolon} ## @end deftypefn + +## Mark file as being tested. No real test needed for a documentation .m file +%!assert (1) +
--- a/scripts/miscellaneous/edit.m +++ b/scripts/miscellaneous/edit.m @@ -54,7 +54,7 @@ ## filename. If @file{name.ext} is not modifiable, it will be copied to ## @env{HOME} before editing. ## -## @strong{WARNING!} You may need to clear name before the new definition +## @strong{Warning:} You may need to clear name before the new definition ## is available. If you are editing a .cc file, you will need ## to mkoctfile @file{name.cc} before the definition will be available. ## @end itemize
--- a/scripts/miscellaneous/fullfile.m +++ b/scripts/miscellaneous/fullfile.m @@ -26,7 +26,7 @@ if (nargin > 0) ## Discard all empty arguments - varargin(cellfun (@isempty, varargin)) = []; + varargin(cellfun ("isempty", varargin)) = []; nargs = numel (varargin); if (nargs > 1) filename = varargin{1};
--- a/scripts/miscellaneous/getfield.m +++ b/scripts/miscellaneous/getfield.m @@ -50,8 +50,8 @@ print_usage (); endif subs = varargin; - flds = cellfun (@ischar, subs); - idxs = cellfun (@iscell, subs); + flds = cellfun ("isclass", subs, "char"); + idxs = cellfun ("isclass", subs, "cell"); if (all (flds | idxs)) typs = merge (flds, {"."}, {"()"}); obj = subsref (s, struct ("type", typs, "subs", subs));
--- a/scripts/miscellaneous/info.m +++ b/scripts/miscellaneous/info.m @@ -43,3 +43,6 @@ http://www.octave.org/bugs.html\n"); endfunction + +## Mark file as being tested. No real test needed for this function. +%! assert (1)
--- a/scripts/miscellaneous/ismac.m +++ b/scripts/miscellaneous/ismac.m @@ -32,3 +32,5 @@ endfunction +%!error ismac (1); +%!assert (islogical (ismac ()));
--- a/scripts/miscellaneous/ispc.m +++ b/scripts/miscellaneous/ispc.m @@ -31,3 +31,6 @@ endif endfunction + +%!error ispc (1); +%!assert (islogical (ispc ()));
--- a/scripts/miscellaneous/isunix.m +++ b/scripts/miscellaneous/isunix.m @@ -31,3 +31,6 @@ endif endfunction + +%!error isunix (1); +%!assert (islogical (isunix ()));
--- a/scripts/miscellaneous/list_primes.m +++ b/scripts/miscellaneous/list_primes.m @@ -83,3 +83,9 @@ endwhile endfunction + +%!test +%! assert (list_primes(), [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,\ +%! 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]); +%! assert (list_primes(5), [2, 3, 5, 7, 11]); +
--- a/scripts/miscellaneous/ls.m +++ b/scripts/miscellaneous/ls.m @@ -63,7 +63,7 @@ retval = strvcat (regexp (output, '\S+', 'match'){:}); endif else - error ("ls: command exited abnormally with status %d", status); + error ("ls: command exited abnormally with status %d\n", status); endif else
--- a/scripts/miscellaneous/mkoctfile.m +++ b/scripts/miscellaneous/mkoctfile.m @@ -75,26 +75,30 @@ ## Print the configuration variable VAR@. Recognized variables are: ## ## @example -## ALL_CFLAGS FFTW_LIBS +## ALL_CFLAGS FFTW3F_LIBS ## ALL_CXXFLAGS FLIBS ## ALL_FFLAGS FPICFLAG ## ALL_LDFLAGS INCFLAGS -## BLAS_LIBS LDFLAGS -## CC LD_CXX -## CFLAGS LD_STATIC_FLAG -## CPICFLAG LFLAGS -## CPPFLAGS LIBCRUFT -## CXX LIBOCTAVE -## CXXFLAGS LIBOCTINTERP -## CXXPICFLAG LIBREADLINE +## BLAS_LIBS LAPACK_LIBS +## CC LDFLAGS +## CFLAGS LD_CXX +## CPICFLAG LD_STATIC_FLAG +## CPPFLAGS LFLAGS +## CXX LIBCRUFT +## CXXFLAGS LIBOCTAVE +## CXXPICFLAG LIBOCTINTERP ## DEPEND_EXTRA_SED_PATTERN LIBS ## DEPEND_FLAGS OCTAVE_LIBS -## DL_LD RDYNAMIC_FLAG -## DL_LDFLAGS RLD_FLAG -## F2C SED -## F2CFLAGS XTRA_CFLAGS -## F77 XTRA_CXXFLAGS -## FFLAGS +## DL_LD OCTAVE_LINK_DEPS +## DL_LDFLAGS OCT_LINK_DEPS +## EXEEXT RDYNAMIC_FLAG +## F77 READLINE_LIBS +## F77_INTEGER_8_FLAG SED +## FFLAGS XTRA_CFLAGS +## FFTW3_LDFLAGS XTRA_CXXFLAGS +## FFTW3_LIBS +## FFTW3F_LDFLAGS +## ## @end example ## ## @item --link-stand-alone
--- a/scripts/miscellaneous/module.mk +++ b/scripts/miscellaneous/module.mk @@ -61,7 +61,6 @@ miscellaneous/tar.m \ miscellaneous/tempdir.m \ miscellaneous/tempname.m \ - miscellaneous/unimplemented.m \ miscellaneous/unix.m \ miscellaneous/unpack.m \ miscellaneous/untar.m \
--- a/scripts/miscellaneous/news.m +++ b/scripts/miscellaneous/news.m @@ -36,3 +36,7 @@ endif endfunction + + +## Remove from test statistics. No real tests possible +%!assert (1)
--- a/scripts/miscellaneous/paren.m +++ b/scripts/miscellaneous/paren.m @@ -21,3 +21,7 @@ ## @deftypefnx {Operator} {} ) ## Array index or function argument delimeter. ## @end deftypefn + +## Mark file as being tested. No real test needed for a documentation .m file +%!assert (1) +
--- a/scripts/miscellaneous/private/__xzip__.m +++ b/scripts/miscellaneous/private/__xzip__.m @@ -112,10 +112,10 @@ endfunction function [d, f] = myfileparts (files) - [d, f, ext] = cellfun (@(x) fileparts (x), files, "uniformoutput", false); + [d, f, ext] = cellfun ("fileparts", files, "uniformoutput", false); f = cellfun (@(x, y) sprintf ("%s%s", x, y), f, ext, "uniformoutput", false); - idx = cellfun (@isdir, files); + idx = cellfun ("isdir", files); d(idx) = ""; f(idx) = files(idx); endfunction
--- a/scripts/miscellaneous/semicolon.m +++ b/scripts/miscellaneous/semicolon.m @@ -21,3 +21,7 @@ ## Array row or command separator. ## @seealso{comma} ## @end deftypefn + +## Mark file as being tested. No real test needed for a documentation .m file +%!assert (1) +
--- a/scripts/miscellaneous/setfield.m +++ b/scripts/miscellaneous/setfield.m @@ -50,8 +50,8 @@ endif subs = varargin(1:end-1); rhs = varargin{end}; - flds = cellfun (@ischar, subs); - idxs = cellfun (@iscell, subs); + flds = cellfun ("isclass", subs, "char"); + idxs = cellfun ("isclass", subs, "cell"); if (all (flds | idxs)) typs = merge (flds, {"."}, {"()"}); obj = subsasgn (obj, struct ("type", typs, "subs", subs), rhs);
--- a/scripts/miscellaneous/swapbytes.m +++ b/scripts/miscellaneous/swapbytes.m @@ -32,6 +32,7 @@ ## @end deftypefn function y = swapbytes (x) + if (nargin != 1) print_usage (); endif @@ -53,4 +54,11 @@ y = reshape (typecast (reshape (typecast (x(:), "uint8"), nb, numel (x)) ([nb : -1 : 1], :) (:), clx), size(x)); endif + endfunction + + +%!assert (double (swapbytes (uint16 (1:4))), [256 512 768 1024]) +%!error (swapbytes ()) +%!error (swapbytes (1, 2)) +
--- a/scripts/miscellaneous/symvar.m +++ b/scripts/miscellaneous/symvar.m @@ -28,3 +28,6 @@ function args = symvar (s) args = argnames (inline (s)); endfunction + +## This function is tested by the tests for argnames(). +%!assert (1)
--- a/scripts/miscellaneous/warning_ids.m +++ b/scripts/miscellaneous/warning_ids.m @@ -284,3 +284,6 @@ function warning_ids () help ("warning_ids"); endfunction + +## Remove from test statistics. No real tests possible +%!assert (1)
--- a/scripts/miscellaneous/what.m +++ b/scripts/miscellaneous/what.m @@ -90,7 +90,7 @@ if (length (f) > 0) printf ("%s %s:\n\n", msg, p); - maxlen = max (cellfun (@length, f)); + maxlen = max (cellfun ("length", f)); ncols = max (1, floor (terminal_size()(2) / (maxlen + 3))); fmt = ""; for i = 1: ncols
--- a/scripts/miscellaneous/xor.m +++ b/scripts/miscellaneous/xor.m @@ -48,7 +48,11 @@ ## Typecast to logicals is necessary for other numeric types. z = logical (x) != logical (y); else - error ("xor: X and Y must be of common size or scalars"); + try + z = bsxfun (@xor, x, y); + catch + error ("xor: X and Y must be of compatible size or scalars"); + end_try_catch endif else print_usage ();
--- a/scripts/optimization/fminbnd.m +++ b/scripts/optimization/fminbnd.m @@ -49,7 +49,8 @@ ## This is patterned after opt/fmin.f from Netlib, which in turn is taken from ## Richard Brent: Algorithms For Minimization Without Derivatives, Prentice-Hall (1973) -## PKG_ADD: __all_opts__ ("fminbnd"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("fminbnd"); function [x, fval, info, output] = fminbnd (fun, xmin, xmax, options = struct ())
--- a/scripts/optimization/fminunc.m +++ b/scripts/optimization/fminunc.m @@ -77,7 +77,8 @@ ## @seealso{fminbnd, optimset} ## @end deftypefn -## PKG_ADD: __all_opts__ ("fminunc"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("fminunc"); function [x, fval, info, output, grad, hess] = fminunc (fcn, x0, options = struct ())
--- a/scripts/optimization/fsolve.m +++ b/scripts/optimization/fsolve.m @@ -127,7 +127,8 @@ ## @end example ## @end deftypefn -## PKG_ADD: __all_opts__ ("fsolve"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("fsolve"); function [x, fvec, info, output, fjac] = fsolve (fcn, x0, options = struct ())
--- a/scripts/optimization/fzero.m +++ b/scripts/optimization/fzero.m @@ -93,7 +93,8 @@ ## the need for external functions and error handling. The algorithm has ## also been slightly modified. -## PKG_ADD: __all_opts__ ("fzero"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("fzero"); function [x, fval, info, output] = fzero (fun, x0, options = struct ())
--- a/scripts/optimization/lsqnonneg.m +++ b/scripts/optimization/lsqnonneg.m @@ -63,7 +63,8 @@ ## @seealso{optimset, pqpnonneg} ## @end deftypefn -## PKG_ADD: __all_opts__ ("lsqnonneg"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("lsqnonneg"); ## This is implemented from Lawson and Hanson's 1973 algorithm on page ## 161 of Solving Least Squares Problems.
--- a/scripts/optimization/pqpnonneg.m +++ b/scripts/optimization/pqpnonneg.m @@ -58,7 +58,8 @@ ## @seealso{optimset, lsqnonneg, qp} ## @end deftypefn -## PKG_ADD: __all_opts__ ("pqpnonneg"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("pqpnonneg"); ## This is analogical to the lsqnonneg implementation, which is ## implemented from Lawson and Hanson's 1973 algorithm on page
--- a/scripts/optimization/qp.m +++ b/scripts/optimization/qp.m @@ -108,7 +108,8 @@ ## @end table ## @end deftypefn -## PKG_ADD: __all_opts__ ("qp"); +## PKG_ADD: ## Discard result to avoid polluting workspace with ans at startup. +## PKG_ADD: [~] = __all_opts__ ("qp"); function [x, obj, INFO, lambda] = qp (x0, H, varargin)
--- a/scripts/path/matlabroot.m +++ b/scripts/path/matlabroot.m @@ -31,5 +31,5 @@ endfunction +%!assert (matlabroot(), OCTAVE_HOME()) -
--- a/scripts/pkg/pkg.m +++ b/scripts/pkg/pkg.m @@ -20,8 +20,10 @@ ## -*- texinfo -*- ## @deftypefn {Command} {} pkg @var{command} @var{pkg_name} ## @deftypefnx {Command} {} pkg @var{command} @var{option} @var{pkg_name} -## This command interacts with the package manager. Different actions will -## be taken depending on the value of @var{command}. +## Manage packages (groups of add-on functions) for Octave. Different actions +## are available depending on the value of @var{command}. +## +## Available commands: ## ## @table @samp ## @@ -40,34 +42,44 @@ ## ## @table @code ## @item -nodeps -## The package manager will disable the dependency checking. That way it -## is possible to install a package even if it depends on another package -## that's not installed on the system. @strong{Use this option with care.} +## The package manager will disable dependency checking. With this option it +## is possible to install a package even when it depends on another package +## which is not installed on the system. @strong{Use this option with care.} ## ## @item -noauto ## The package manager will not automatically load the installed package -## when starting Octave, even if the package requests that it is. +## when starting Octave. This overrides any setting within the package. ## ## @item -auto ## The package manager will automatically load the installed package when -## starting Octave, even if the package requests that it isn't. +## starting Octave. This overrides any setting within the package. ## ## @item -local -## A local installation is forced, even if the user has system privileges. +## A local installation (package available only to current user) is forced, +## even if the user has system privileges. ## ## @item -global -## A global installation is forced, even if the user doesn't normally have -## system privileges +## A global installation (package available to all users) is forced, even if +## the user doesn't normally have system privileges. ## ## @item -forge ## Install a package directly from the Octave-Forge repository. This ## requires an internet connection and the cURL library. ## ## @item -verbose -## The package manager will print the output of all of the commands that are -## performed. +## The package manager will print the output of all commands as +## they are performed. ## @end table ## +## @item update +## Check installed Octave-Forge pacakages against repository and update any +## outdated items. This requires an internet connection and the cURL library. +## Usage: +## +## @example +## pkg update +## @end example +## ## @item uninstall ## Uninstall named packages. For example, ## @@ -90,47 +102,53 @@ ## ## @noindent ## adds the @code{image} package to the path. It is possible to load all -## installed packages at once with the command +## installed packages at once with the keyword @samp{all}. Usage: ## ## @example ## pkg load all ## @end example ## ## @item unload -## Removes named packages from the path. After unloading a package it is -## no longer possible to use the functions provided by the package. -## This command behaves like the @code{load} command. +## Remove named packages from the path. After unloading a package it is +## no longer possible to use the functions provided by the package. It is +## possible to unload all installed packages at once with the keyword +## @samp{all}. Usage: +## +## @example +## pkg unload all +## @end example ## ## @item list -## Show a list of the currently installed packages. By requesting one or two -## output argument it is possible to get a list of the currently installed -## packages. For example, +## Show the list of currently installed packages. For example, ## ## @example -## installed_packages = pkg list; +## installed_packages = pkg ("list") ## @end example ## ## @noindent ## returns a cell array containing a structure for each installed package. -## The command ## +## If two output arguments are requested @code{pkg} splits the list of +## installed packages into those which were installed by the current user, +## and those which were installed by the system administrator. +## ## @example -## [@var{user_packages}, @var{system_packages}] = pkg list +## [user_packages, system_packages] = pkg ("list") ## @end example ## -## @noindent -## splits the list of installed packages into those who are installed by -## the current user, and those installed by the system administrator. +## The option '-forge' lists packages available at the Octave-Forge repository. +## This requires an internet connection and the cURL library. For example: ## -## The option '-forge' lists packages available at the Octave-Forge repository. -## This requires an internet connection and the cURL library. +## @example +## oct_forge_pkgs = pkg ("list", "-forge") +## @end example ## ## @item describe ## Show a short description of the named installed packages, with the option -## '-verbose' also list functions provided by the package, e.g.: +## '-verbose' also list functions provided by the package. For example, ## ## @example -## pkg describe -verbose all +## pkg describe -verbose all ## @end example ## ## @noindent @@ -140,7 +158,7 @@ ## output rather than printed on screen: ## ## @example -## desc = pkg ("describe", "secs1d", "image") +## desc = pkg ("describe", "secs1d", "image") ## @end example ## ## @noindent @@ -148,7 +166,7 @@ ## error, unless a second output is requested: ## ## @example -## [ desc, flag] = pkg ("describe", "secs1d", "image") +## [desc, flag] = pkg ("describe", "secs1d", "image") ## @end example ## ## @noindent @@ -170,20 +188,20 @@ ## output argument. For example: ## ## @example -## p = pkg prefix +## pfx = pkg ("prefix") ## @end example ## ## The location in which to install the architecture dependent files can be -## independent specified with an addition argument. For example: +## independently specified with an addition argument. For example: ## ## @example ## pkg prefix ~/my_octave_packages ~/my_arch_dep_pkgs ## @end example ## ## @item local_list -## Set the file in which to look for information on the locally +## Set the file in which to look for information on locally ## installed packages. Locally installed packages are those that are -## typically available only to the current user. For example: +## available only to the current user. For example: ## ## @example ## pkg local_list ~/.octave_packages @@ -196,9 +214,9 @@ ## @end example ## ## @item global_list -## Set the file in which to look for, for information on the globally +## Set the file in which to look for information on globally ## installed packages. Globally installed packages are those that are -## typically available to all users. For example: +## available to all users. For example: ## ## @example ## pkg global_list /usr/share/octave/octave_packages @@ -210,21 +228,8 @@ ## pkg global_list ## @end example ## -## @item rebuild -## Rebuilds the package database from the installed directories. This can -## be used in cases where for some reason the package database is corrupted. -## It can also take the @option{-auto} and @option{-noauto} options to allow the -## autoloading state of a package to be changed. For example, -## -## @example -## pkg rebuild -noauto image -## @end example -## -## @noindent -## will remove the autoloading status of the image package. -## ## @item build -## Builds a binary form of a package or packages. The binary file produced +## Build a binary form of a package or packages. The binary file produced ## will itself be an Octave package that can be installed normally with ## @code{pkg}. The form of the command to build a binary package is ## @@ -236,7 +241,21 @@ ## where @code{builddir} is the name of a directory where the temporary ## installation will be produced and the binary packages will be found. ## The options @option{-verbose} and @option{-nodeps} are respected, while -## the other options are ignored. +## all other options are ignored. +## +## @item rebuild +## Rebuild the package database from the installed directories. This can +## be used in cases where the package database has been corrupted. +## It can also take the @option{-auto} and @option{-noauto} options to allow the +## autoloading state of a package to be changed. For example, +## +## @example +## pkg rebuild -noauto image +## @end example +## +## @noindent +## will remove the autoloading status of the image package. +## ## @end table ## @end deftypefn @@ -267,7 +286,8 @@ available_actions = {"list", "install", "uninstall", "load", ... "unload", "prefix", "local_list", ... - "global_list", "rebuild", "build","describe"}; + "global_list", "rebuild", "build", ... + "describe", "update"}; ## Handle input if (length (varargin) == 0 || ! iscellstr (varargin)) print_usage (); @@ -349,8 +369,8 @@ unwind_protect if (octave_forge) - [urls, local_files] = cellfun (@get_forge_download, files, "uniformoutput", false); - [files, succ] = cellfun (@urlwrite, urls, local_files, "uniformoutput", false); + [urls, local_files] = cellfun ("get_forge_download", files, "uniformoutput", false); + [files, succ] = cellfun ("urlwrite", urls, local_files, "uniformoutput", false); succ = [succ{:}]; if (! all (succ)) i = find (! succ, 1); @@ -362,7 +382,7 @@ global_list, global_install); unwind_protect_cleanup - cellfun (@unlink, local_files); + cellfun ("unlink", local_files); end_unwind_protect case "uninstall" @@ -492,6 +512,21 @@ error ("you can request at most two outputs when calling 'pkg describe'"); endswitch + case "update" + if (nargout == 0) + installed_pkgs_lst = installed_packages (local_list, global_list); + for i = 1:length (installed_pkgs_lst) + installed_pkg_name = installed_pkgs_lst{i}.name; + installed_pkg_version = installed_pkgs_lst{i}.version; + forge_pkg_version = get_forge_pkg (installed_pkg_name); + if (compare_versions (forge_pkg_version, installed_pkg_version, ">")) + feval (@pkg, "install", "-forge", installed_pkg_name); + endif + endfor + else + error ("no output arguments available"); + endif + otherwise error ("you must specify a valid action for 'pkg'. See 'help pkg' for details"); endswitch @@ -1383,7 +1418,7 @@ if (isempty (filenames)) idx = []; else - idx = cellfun (@is_architecture_dependent, filenames); + idx = cellfun ("is_architecture_dependent", filenames); endif archdependent = filenames (idx); archindependent = filenames (!idx);
--- a/scripts/plot/axis.m +++ b/scripts/plot/axis.m @@ -323,10 +323,10 @@ data(data<=0) = NaN; end if (iscell (data)) - data = data (find (! cellfun (@isempty, data))); + data = data (find (! cellfun ("isempty", data))); if (! isempty (data)) - lims_min = min (cellfun (@min, cellfun (@min, data, 'uniformoutput', false)(:))); - lims_max = max (cellfun (@max, cellfun (@max, data, 'uniformoutput', false)(:))); + lims_min = min (cellfun ("min", cellfun ("min", data, 'uniformoutput', false)(:))); + lims_max = max (cellfun ("max", cellfun ("max", data, 'uniformoutput', false)(:))); lims = [lims_min, lims_max]; else lims = [0, 1];
--- a/scripts/plot/isonormals.m +++ b/scripts/plot/isonormals.m @@ -46,47 +46,49 @@ ## ## For example: ## -## @example +## @c Set example in small font to prevent overfull line +## @smallexample ## function [] = isofinish (p) -## set (gca, "PlotBoxAspectRatioMode","manual","PlotBoxAspectRatio",[1 1 1]); -## set (p, "VertexNormals", -get(p,"VertexNormals")); ## Revert normals +## set (gca, "PlotBoxAspectRatioMode", "manual", ... +## "PlotBoxAspectRatio",[1 1 1]); +## set (p, "VertexNormals", -get(p,"VertexNormals")); # Revert normals ## set (p, "FaceColor", "interp"); ## ## set (p, "FaceLighting", "phong"); -## ## light ("Position", [1 1 5]); ## Available with JHandles +## ## light ("Position", [1 1 5]); # Available with JHandles ## endfunction ## -## N = 15; ## Increase number of vertices in each direction -## iso = .4; ## Change isovalue to .1 to display a sphere +## N = 15; # Increase number of vertices in each direction +## iso = .4; # Change isovalue to .1 to display a sphere ## lin = linspace (0, 2, N); ## [x, y, z] = meshgrid (lin, lin, lin); ## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); -## figure (); ## Open another figure window +## figure (); # Open another figure window ## ## subplot (2, 2, 1); view (-38, 20); ## [f, v, cdat] = isosurface (x, y, z, c, iso, y); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); +## "FaceColor", "interp", "EdgeColor", "none"); ## isofinish (p); ## Call user function isofinish ## ## subplot (2, 2, 2); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## isonormals (x, y, z, c, p); ## Directly modify patch +## "FaceColor", "interp", "EdgeColor", "none"); +## isonormals (x, y, z, c, p); # Directly modify patch ## isofinish (p); ## ## subplot (2, 2, 3); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## n = isonormals (x, y, z, c, v); ## Compute normals of isosurface -## set (p, "VertexNormals", n); ## Manually set vertex normals +## "FaceColor", "interp", "EdgeColor", "none"); +## n = isonormals (x, y, z, c, v); # Compute normals of isosurface +## set (p, "VertexNormals", n); # Manually set vertex normals ## isofinish (p); ## ## subplot (2, 2, 4); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## isonormals (x, y, z, c, v, "negate"); ## Use reverse directly +## "FaceColor", "interp", "EdgeColor", "none"); +## isonormals (x, y, z, c, v, "negate"); # Use reverse directly ## isofinish (p); -## @end example +## @end smallexample ## ## @seealso{isosurface, isocolors} ## @end deftypefn
--- a/scripts/plot/isosurface.m +++ b/scripts/plot/isosurface.m @@ -71,24 +71,27 @@ ## Another example for an isosurface geometry with different additional ## coloring ## -## @example -## N = 15; ## Increase number of vertices in each direction -## iso = .4; ## Change isovalue to .1 to display a sphere +## @c Set example in small font to prevent overfull line +## @smallexample +## N = 15; # Increase number of vertices in each direction +## iso = .4; # Change isovalue to .1 to display a sphere ## lin = linspace (0, 2, N); ## [x, y, z] = meshgrid (lin, lin, lin); ## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); -## figure (); ## Open another figure window +## figure (); # Open another figure window ## ## subplot (2, 2, 1); view (-38, 20); ## [f, v] = isosurface (x, y, z, c, iso); ## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceColor", "green", "FaceLighting", "phong"); -## # light ("Position", [1 1 5]); ## Available with the JHandles package +## # light ("Position", [1 1 5]); # Available with the JHandles package ## ## subplot (2, 2, 2); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "blue"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceColor", "none", "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); ## @@ -96,17 +99,19 @@ ## [f, v, c] = isosurface (x, y, z, c, iso, y); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ ## "FaceColor", "interp", "EdgeColor", "none"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); ## ## subplot (2, 2, 4); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ ## "FaceColor", "interp", "EdgeColor", "blue"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); -## @end example +## @end smallexample ## ## @seealso{isonormals, isocolors} ## @end deftypefn
--- a/scripts/plot/module.mk +++ b/scripts/plot/module.mk @@ -20,38 +20,38 @@ plot/private/__errplot__.m \ plot/private/__ezplot__.m \ plot/private/__fltk_file_filter__.m \ - plot/private/__ghostscript__.m \ + plot/private/__fltk_ginput__.m \ + plot/private/__fltk_print__.m \ plot/private/__getlegenddata__.m \ + plot/private/__ghostscript__.m \ + plot/private/__gnuplot_get_var__.m \ + plot/private/__gnuplot_ginput__.m \ + plot/private/__gnuplot_has_feature__.m \ plot/private/__gnuplot_has_terminal__.m\ + plot/private/__gnuplot_open_stream__.m \ + plot/private/__gnuplot_print__.m \ + plot/private/__gnuplot_version__.m \ + plot/private/__go_draw_axes__.m \ + plot/private/__go_draw_figure__.m \ plot/private/__interp_cube__.m \ plot/private/__line__.m \ + plot/private/__marching_cube__.m \ + plot/private/__next_line_color__.m \ + plot/private/__next_line_style__.m \ plot/private/__patch__.m \ plot/private/__pie__.m \ plot/private/__plt__.m \ plot/private/__pltopt__.m \ + plot/private/__print_parse_opts__.m \ plot/private/__quiver__.m \ plot/private/__scatter__.m \ plot/private/__stem__.m \ plot/private/__tight_eps_bbox__.m plot_FCN_FILES = \ - plot/__fltk_ginput__.m \ - plot/__fltk_print__.m \ plot/__gnuplot_drawnow__.m \ - plot/__gnuplot_get_var__.m \ - plot/__gnuplot_ginput__.m \ - plot/__gnuplot_has_feature__.m \ - plot/__gnuplot_open_stream__.m \ - plot/__gnuplot_print__.m \ - plot/__gnuplot_version__.m \ plot/__go_close_all__.m \ - plot/__go_draw_axes__.m \ - plot/__go_draw_figure__.m \ - plot/__marching_cube__.m \ - plot/__next_line_color__.m \ - plot/__next_line_style__.m \ plot/__plt_get_axis_arg__.m \ - plot/__print_parse_opts__.m \ plot/allchild.m \ plot/ancestor.m \ plot/area.m \ @@ -171,6 +171,9 @@ plot/surfnorm.m \ plot/text.m \ plot/title.m \ + plot/trimesh.m \ + plot/triplot.m \ + plot/trisurf.m \ plot/uigetdir.m \ plot/uigetfile.m \ plot/uimenu.m \
--- a/scripts/plot/pareto.m +++ b/scripts/plot/pareto.m @@ -66,11 +66,11 @@ if (ischar (y)) y = cellstr (y); else - y = cellfun (@num2str, num2cell (y), "uniformoutput", false); + y = cellfun ("num2str", num2cell (y), "uniformoutput", false); endif endif else - y = cellfun (@int2str, num2cell (1 : numel(x)), + y = cellfun ("int2str", num2cell (1 : numel(x)), "uniformoutput", false); endif
--- a/scripts/plot/pcolor.m +++ b/scripts/plot/pcolor.m @@ -80,3 +80,14 @@ endif endfunction + +%!demo +%! clf +%! [~,~,Z]=peaks; +%! pcolor(Z); + +%!demo +%! [X,Y,Z]=sombrero; +%! [Fx,Fy] = gradient(Z); +%! pcolor(X,Y,Fx+Fy); +%! shading interp;
--- a/scripts/plot/plotyy.m +++ b/scripts/plot/plotyy.m @@ -78,7 +78,7 @@ ca = get (f, "currentaxes"); if (isempty (ca)) ax = []; - elseif (strcmp (get (ca, "tag"), "plotyy")); + elseif (strcmp (get (ca, "tag"), "plotyy")) ax = get (ca, "__plotyy_axes__"); else ax = ca; @@ -113,8 +113,6 @@ endif end_unwind_protect - set (ax, "activepositionproperty", "position"); - if (nargout > 0) Ax = ax; H1 = h1; @@ -162,10 +160,24 @@ colors = get (ax(1), "colororder"); set (ax(2), "colororder", [colors(2:end,:); colors(1,:)]); + if (strcmp (get (ax(1), "autopos_tag"), "subplot")) + set (ax(2), "autopos_tag", "subplot"); + else + set (ax, "activepositionproperty", "position"); + endif + h2 = feval (fun2, x2, y2); set (ax(2), "yaxislocation", "right"); set (ax(2), "ycolor", getcolor (h2(1))); - set (ax(2), "position", get (ax(1), "position")); + + + if (strcmp (get(ax(1), "activepositionproperty"), "position")) + set (ax(2), "position", get (ax(1), "position")); + else + set (ax(2), "outerposition", get (ax(1), "outerposition")); + set (ax(2), "looseinset", get (ax(1), "looseinset")); + endif + set (ax(2), "xlim", xlim); set (ax(2), "color", "none"); set (ax(2), "box", "off"); @@ -184,6 +196,10 @@ addlistener (ax(1), "position", {@update_position, ax(2)}); addlistener (ax(2), "position", {@update_position, ax(1)}); + addlistener (ax(1), "outerposition", {@update_position, ax(2)}); + addlistener (ax(2), "outerposition", {@update_position, ax(1)}); + addlistener (ax(1), "looseinset", {@update_position, ax(2)}); + addlistener (ax(2), "looseinset", {@update_position, ax(1)}); addlistener (ax(1), "view", {@update_position, ax(2)}); addlistener (ax(2), "view", {@update_position, ax(1)}); addlistener (ax(1), "plotboxaspectratio", {@update_position, ax(2)}); @@ -257,17 +273,27 @@ if (! recursion) unwind_protect recursion = true; - position = get (h, "position"); view = get (h, "view"); - plotboxaspectratio = get (h, "plotboxaspectratio"); - plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); - oldposition = get (ax2, "position"); oldview = get (ax2, "view"); + plotboxaspectratio = get (h, "plotboxaspectratio"); oldplotboxaspectratio = get (ax2, "plotboxaspectratio"); + plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); oldplotboxaspectratiomode = get (ax2, "plotboxaspectratiomode"); - if (! (isequal (position, oldposition) && isequal (view, oldview))) - set (ax2, "position", position, "view", view); + + if (strcmp (get(h, "activepositionproperty"), "position")) + position = get (h, "position"); + oldposition = get (ax2, "position"); + if (! (isequal (position, oldposition) && isequal (view, oldview))) + set (ax2, "position", position, "view", view); + endif + else + outerposition = get (h, "outerposition"); + oldouterposition = get (ax2, "outerposition"); + if (! (isequal (outerposition, oldouterposition) && isequal (view, oldview))) + set (ax2, "outerposition", outerposition, "view", view); + endif endif + if (! (isequal (plotboxaspectratio, oldplotboxaspectratio) && isequal (plotboxaspectratiomode, oldplotboxaspectratiomode))) set (ax2, "plotboxaspectratio", plotboxaspectratio);
--- a/scripts/plot/polar.m +++ b/scripts/plot/polar.m @@ -211,3 +211,15 @@ endif endfunction + + +%!demo +%! theta = linspace (0, 2*pi, 1000); +%! rho = sin (7*theta); +%! polar (theta, rho); + +%!demo +%! theta = linspace (0, 10*pi, 1000); +%! rho = sin (5/4*theta); +%! polar (theta, rho); +
--- a/scripts/plot/private/__axis_label__.m +++ b/scripts/plot/private/__axis_label__.m @@ -25,24 +25,20 @@ function retval = __axis_label__ (caller, txt, varargin) - if (ischar (txt)) - ca = gca (); + ca = gca (); - h = get (gca (), caller); + h = get (gca (), caller); - set (h, "fontangle", get (ca, "fontangle"), - "fontname", get (ca, "fontname"), - "fontsize", get (ca, "fontsize"), - "fontunits", get (ca, "fontunits"), - "fontweight", get (ca, "fontweight"), - "string", txt, - varargin{:}); + set (h, "fontangle", get (ca, "fontangle"), + "fontname", get (ca, "fontname"), + "fontsize", get (ca, "fontsize"), + "fontunits", get (ca, "fontunits"), + "fontweight", get (ca, "fontweight"), + "string", txt, + varargin{:}); - if (nargout > 0) - retval = h; - endif - else - error ("%s: expecting first argument to be character string", caller); + if (nargout > 0) + retval = h; endif endfunction
--- a/scripts/plot/private/__ghostscript__.m +++ b/scripts/plot/private/__ghostscript__.m @@ -44,7 +44,7 @@ cleanup_cmd = ""; args = varargin; - n = find (cellfun (@isstruct, args)); + n = find (cellfun ("isclass", args, "struct")); if (! isempty (n)) f = fieldnames (args{n}); for m = 1:numel(f)
rename from scripts/plot/__gnuplot_has_feature__.m rename to scripts/plot/private/__gnuplot_has_feature__.m
rename from scripts/plot/__gnuplot_open_stream__.m rename to scripts/plot/private/__gnuplot_open_stream__.m
rename from scripts/plot/__go_draw_axes__.m rename to scripts/plot/private/__go_draw_axes__.m --- a/scripts/plot/__go_draw_axes__.m +++ b/scripts/plot/private/__go_draw_axes__.m @@ -1250,6 +1250,11 @@ colorspec = get_text_colorspec (color, mono); endif + if (ischar (obj.string)) + num_lines = size (obj.string, 1); + else + num_lines = numel (obj.string); + endif switch valign ## Text offset in characters. This relies on gnuplot for font metrics. case "top" @@ -1257,17 +1262,18 @@ case "cap" dy = -0.5; case "middle" - dy = 0; + dy = 0.5 * (num_lines - 1); case "baseline" - dy = 0.5; + dy = 0.5 + (num_lines - 1); case "bottom" - dy = 0.5; + dy = 0.5 + (num_lines - 1); endswitch ## Gnuplot's Character units are different for x/y and vary with fontsize. The aspect ratio ## of 1:1.7 was determined by experiment to work for eps/ps/etc. For the MacOS aqua terminal ## a value of 2.5 is needed. However, the difference is barely noticable. dx_and_dy = [(-dy * sind (angle)), (dy * cosd(angle))] .* [1.7 1]; + ## FIXME - Multiline text produced the gnuplot "warning: ft_render: skipping glyph" if (nd == 3) ## This produces the desired vertical alignment in 3D. fprintf (plot_stream, @@ -1312,7 +1318,7 @@ fputs (plot_stream, "unset hidden3d;\n"); endif - have_data = (! (isempty (data) || all (cellfun (@isempty, data)))); + have_data = (! (isempty (data) || all (cellfun ("isempty", data)))); ## Note we don't use the [xy]2range of gnuplot as we don't use the ## dual axis plotting features of gnuplot. @@ -2129,10 +2135,31 @@ bld = false; endif + ## The text object maybe multiline, and may be of any class str = getfield (obj, fld); + if (ischar (str) && size (str, 1) > 1) + str = cellstr (str); + elseif (isnumeric (str)) + str = cellstr (num2str (str(:))); + endif + if (iscellstr (str)) + for n = 1:numel(str) + if (isnumeric (str{n})) + str{n} = num2str (str{n}); + endif + endfor + str = sprintf ("%s\n", str{:})(1:end-1); + endif + if (enhanced) if (strcmpi (obj.interpreter, "tex")) - str = __tex2enhanced__ (str, fnt, it, bld); + if (iscellstr (str)) + for n = 1:numel(str) + str{n} = __tex2enhanced__ (str{n}, fnt, it, bld); + endfor + else + str = __tex2enhanced__ (str, fnt, it, bld); + endif elseif (strcmpi (obj.interpreter, "latex")) if (! warned_latex) warning ("latex markup not supported for text objects"); @@ -2328,7 +2355,7 @@ l = length (s) - length (strfind(s,'{')) - length (strfind(s,'}')); m = regexp (s, '/([\w-]+|[\w-]+=\d+)', 'matches'); if (!isempty (m)) - l = l - sum (cellfun (@length, m)); + l = l - sum (cellfun ("length", m)); endif endfunction
--- a/scripts/plot/private/__patch__.m +++ b/scripts/plot/private/__patch__.m @@ -134,7 +134,7 @@ endif else args = varargin; - if (any(cellfun (@(x) strcmpi(x,"faces") || strcmpi(x, "vertices"), args))) + if (any (strcmpi (args, "faces") | strcmpi (args, "vertices"))) args = setdata (args); else args = setvertexdata (args);
rename from scripts/plot/__print_parse_opts__.m rename to scripts/plot/private/__print_parse_opts__.m --- a/scripts/plot/__print_parse_opts__.m +++ b/scripts/plot/private/__print_parse_opts__.m @@ -361,7 +361,8 @@ endfunction -%!test +## Test blocks are not allowed (and not needed) for private functions +#%!test %! opts = __print_parse_opts__ (); %! assert (opts.devopt, "pswrite"); %! assert (opts.use_color, 1); @@ -369,11 +370,11 @@ %! assert (opts.canvas_size, [576, 432]); %! assert (opts.ghostscript.device, "pswrite") -%!test +#%!test %! opts = __print_parse_opts__ ("test.pdf", "-S640,480"); %! assert (opts.canvas_size, [307.2, 230.4], 0.1); -%!test +#%!test %! opts = __print_parse_opts__ ("-dpsc", "-append", "-loose"); %! assert (opts.devopt, "pswrite"); %! assert (opts.send_to_printer, true); @@ -382,14 +383,14 @@ %! assert (opts.ghostscript.device, "pswrite") %! assert (opts.ghostscript.epscrop, false); -%!test +#%!test %! opts = __print_parse_opts__ ("-deps", "-tight"); %! assert (opts.tight_flag, true); %! assert (opts.send_to_printer, true); %! assert (opts.use_color, -1); %! assert (opts.ghostscript.device, "") -%!test +#%!test %! opts = __print_parse_opts__ ("-djpg", "foobar", "-mono", "-loose"); %! assert (opts.devopt, "jpeg") %! assert (opts.name, "foobar.jpg") @@ -401,7 +402,7 @@ %! assert (opts.printer, ""); %! assert (opts.use_color, -1); -%!test +#%!test %! opts = __print_parse_opts__ ("-ddeskjet", "foobar", "-mono", "-Pmyprinter"); %! assert (opts.ghostscript.output, "foobar.deskjet") %! assert (opts.ghostscript.device, "deskjet") @@ -410,7 +411,7 @@ %! assert (opts.printer, "-Pmyprinter"); %! assert (opts.use_color, -1); -%!test +#%!test %! opts = __print_parse_opts__ ("-f5", "-dljet3"); %! assert (opts.ghostscript.device, "ljet3") %! assert (strfind (opts.ghostscript.output, ".ljet3"))
--- a/scripts/plot/rectangle.m +++ b/scripts/plot/rectangle.m @@ -25,8 +25,8 @@ ## @deftypefnx {Function File} {@var{h} =} rectangle (@dots{}) ## ## Draw rectangular patch defined by @var{pos} and @var{curv}. The variable -## @code{@var{pos}(1 : 2)} defines the lower left-hand corner of the patch -## and @code{@var{pos}(3 : 4)} defines its width and height. By default, the +## @code{@var{pos}(1:2)} defines the lower left-hand corner of the patch +## and @code{@var{pos}(3:4)} defines its width and height. By default, the ## value of @var{pos} is @code{[0, 0, 1, 1]}. ## ## The variable @var{curv} defines the curvature of the sides of the rectangle @@ -41,7 +41,7 @@ ## by ## ## @example -## min (pos (1: 2)) / max (pos (1:2)) * curv +## min (pos (1:2)) / max (pos (1:2)) * curv ## @end example ## ## Other properties are passed to the underlying patch command. If called
--- a/scripts/plot/refreshdata.m +++ b/scripts/plot/refreshdata.m @@ -83,7 +83,7 @@ obj = get (h (i)); fldnames = fieldnames (obj); m = regexpi (fieldnames(obj), '^.+datasource$', "match"); - idx = cellfun (@(x) !isempty(x), m); + idx = ! cellfun ("isempty", m); if (any (idx)) tmp = m(idx); props = [props; {vertcat(tmp{:})}];
--- a/scripts/plot/subplot.m +++ b/scripts/plot/subplot.m @@ -124,7 +124,22 @@ units = "normalized"; set (0, "defaultaxesunits", units); set (cf, "units", "pixels"); - pos = subplot_position (rows, cols, index, "position"); + + ## FIXME: At the moment we force gnuplot to use the aligned mode + ## which will set "activepositionproperty" to "position". + ## Τhis can yield to text overlap between labels and titles + ## see bug #31610 + if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")) + align_axes = true; + endif + + if (align_axes) + pos = subplot_position (rows, cols, index, "position"); + elseif (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")) + pos = subplot_position (rows, cols, index, "outerpositiontight"); + else + pos = subplot_position (rows, cols, index, "outerposition"); + endif set (cf, "nextplot", "add"); @@ -144,7 +159,11 @@ || strcmp (get (child, "tag"), "colorbar")) continue; endif - objpos = get (child, "position"); + if (align_axes) + objpos = get (child, "position"); + else + objpos = get (child, "outerposition"); + endif if (all (objpos == pos) && ! replace_axes) ## If the new axes are in exactly the same position as an ## existing axes object, use the existing axes. @@ -170,14 +189,13 @@ if (found) set (cf, "currentaxes", tmp); + elseif (align_axes) + tmp = axes ("box", "off", "position", pos); + elseif (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")) + tmp = axes ("box", "off", "outerposition", pos); else - outpos = subplot_position (rows, cols, index, "outerposition"); - tmp = axes ("looseinset", [0 0 0 0], "box", "off", - "outerposition", outpos, "position", pos); - endif - - if (align_axes || strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")) - set (tmp, "activepositionproperty", "position"); + tmp = axes ("looseinset", [0 0 0 0], "box", "off", "outerposition", pos, + "autopos_tag", "subplot"); endif unwind_protect_cleanup @@ -193,67 +211,55 @@ function pos = subplot_position (rows, cols, index, position_property) - defaultaxesposition = get (0, "defaultaxesposition"); - defaultaxesouterposition = get (0, "defaultaxesouterposition"); - if (rows == 1 && cols == 1) ## Trivial result for subplot (1,1,1) if (strcmpi (position_property, "position")) - pos = defaultaxesposition; + pos = get (0, "defaultaxesposition"); else - pos = defaultaxesouterposition; + pos = get (0, "defaultaxesouterposition"); endif return endif - ## The outer margins surrounding all subplot "positions" are independent of - ## the number of rows and/or columns - margins.left = defaultaxesposition(1); - margins.bottom = defaultaxesposition(2); - margins.right = 1.0 - margins.left - defaultaxesposition(3); - margins.top = 1.0 - margins.bottom - defaultaxesposition(4); - - ## Fit from Matlab experiments - pc = 1 ./ [0.1860, (margins.left + margins.right - 1)]; - margins.column = 1 ./ polyval (pc , cols); - pr = 1 ./ [0.2282, (margins.top + margins.bottom - 1)]; - margins.row = 1 ./ polyval (pr , rows); - - ## Calculate the width/height of the subplot axes "position". - ## This is also consistent with Matlab - width = 1 - margins.left - margins.right - (cols-1)*margins.column; - width = width / cols; - height = 1 - margins.top - margins.bottom - (rows-1)*margins.row; - height = height / rows; + if (strcmp (position_property, "outerposition") + || strcmp (position_property, "outerpositiontight")) + margins.left = 0.05; + margins.bottom = 0.05; + margins.right = 0.05; + margins.top = 0.05; + if (strcmp (position_property, "outerpositiontight")) + margins.column = 0.; + margins.row = 0.; + else + margins.column = 0.04 / cols; + margins.row = 0.04 / rows; + endif + width = 1 - margins.left - margins.right - (cols-1)*margins.column; + width = width / cols; + height = 1 - margins.top - margins.bottom - (rows-1)*margins.row; + height = height / rows; + else + defaultaxesposition = get (0, "defaultaxesposition"); - if (strcmp (position_property, "outerposition") ) - ## Calculate the inset of the position relative to the outerposition - ## The outerpositions are assumed to be tiled. Matlab's implementation - ## has outerposition overlap. - if (rows > 1) - ## Title on top and xlabel & xticks on bottom - inset.top = margins.row * (1/3); - inset.bottom = margins.row * (2/3); - ## Matlab behavior is approximately ... - % inset.bottom = margins.row; - else - inset.bottom = margins.bottom; - inset.top = margins.top; - endif - if (cols > 1) - ## ylabel & yticks on left and some overhang for xticks on right - x = 0.1; - inset.right = x * margins.column; - inset.left = (1 - x) * margins.column; - else - inset.left = margins.left; - inset.right = margins.right; - endif - ## Apply the inset to the geometries for the "position" property. - margins.column = margins.column - inset.right - inset.left; - margins.row = margins.row - inset.top - inset.bottom; - width = width + inset.right + inset.left; - height = height + inset.top + inset.bottom; + ## The outer margins surrounding all subplot "positions" are independent + ## of the number of rows and/or columns + margins.left = defaultaxesposition(1); + margins.bottom = defaultaxesposition(2); + margins.right = 1.0 - margins.left - defaultaxesposition(3); + margins.top = 1.0 - margins.bottom - defaultaxesposition(4); + + ## Fit from Matlab experiments + pc = 1 ./ [0.1860, (margins.left + margins.right - 1)]; + margins.column = 1 ./ polyval (pc , cols); + pr = 1 ./ [0.2282, (margins.top + margins.bottom - 1)]; + margins.row = 1 ./ polyval (pr , rows); + + ## Calculate the width/height of the subplot axes "position". + ## This is also consistent with Matlab + width = 1 - margins.left - margins.right - (cols-1)*margins.column; + width = width / cols; + height = 1 - margins.top - margins.bottom - (rows-1)*margins.row; + height = height / rows; endif ## Index offsets from the lower left subplot @@ -265,12 +271,6 @@ x0 = xi .* (width + margins.column) + margins.left; y0 = yi .* (height + margins.row) + margins.bottom; - if (strcmp (position_property, "outerposition") ) - ## Shift from position(1:2) to outerposition(1:2) - x0 = x0 - inset.left; - y0 = y0 - inset.bottom; - endif - if (numel(x0) > 1) ## subplot (row, col, m:n) x1 = max (x0(:)) + width;
--- a/scripts/plot/surface.m +++ b/scripts/plot/surface.m @@ -155,3 +155,7 @@ endif endfunction + +## Mark file as being tested. Tests for surface are in +## surf.m, surfc.m, surfl.m, and pcolor.m +%!assert(1)
--- a/scripts/plot/surfc.m +++ b/scripts/plot/surfc.m @@ -45,7 +45,26 @@ drawnow (); zmin = get (ax, "zlim")(1); - [c, tmp2] = __contour__ (ax, zmin, varargin{:}); + # don't pass axis handle and/or string arguments to __contour__() + stop_idx = nargin; + for i = 2 : nargin + if (ischar (varargin{i})) + stop_idx = i - 1; + break; + endif + endfor + + start_idx = 1; + if (ishandle (varargin{1})) + start_idx = 2; + endif + + if (stop_idx - start_idx == 1 || stop_idx - start_idx == 3) + #don't pass a color matrix c to __contour__ + stop_idx -= 1; + endif + + [c, tmp2] = __contour__ (ax, zmin, varargin{start_idx:stop_idx}); tmp = [tmp; tmp2];
--- a/scripts/plot/text.m +++ b/scripts/plot/text.m @@ -47,15 +47,33 @@ endif label = varargin{offset}; - if (ischar (label) || iscellstr (label)) - varargin(1:offset) = []; - if (ischar (label)) + varargin(1:offset) = []; + + nx = numel (x); + ny = numel (y); + nz = numel (z); + if (ischar (label) || isnumeric (label)) + nt = size (label, 1); + if (nx > 1 && nt == 1) + ## Mutiple text objects with same string + label = repmat ({label}, [nx, 1]); + nt = nx; + elseif (nx > 1 && nt == nx) + ## Mutiple text objects with different strings label = cellstr (label); + elseif (ischar (label)) + ## Single text object with one or more lines + label = {label}; endif - n = numel (label); - nx = numel (x); - ny = numel (y); - nz = numel (z); + elseif (iscell (label)) + nt = numel (label); + if (nx > 1 && nt == 1) + label = repmat ({label}, [nx, 1]); + nt = nx; + elseif (! (nx > 1 && nt == nx)) + label = {label}; + nt = 1; + endif else error ("text: expecting LABEL to be a character string or cell array of character strings"); endif @@ -63,35 +81,35 @@ x = y = z = 0; nx = ny = nz = 1; label = {""}; - n = 1; + nt = 1; endif if (rem (numel (varargin), 2) == 0) - if (nx == ny && nx == nz) + if (nx == ny && nx == nz && (nt == nx || nt == 1 || nx == 1)) pos = [x(:), y(:), z(:)]; ca = gca (); - tmp = zeros (n, 1); - if (n == 1) - label = label{1}; - for i = 1:nx - tmp(i) = __go_text__ (ca, "string", label, + tmp = zeros (nt, 1); + if (nx == 1) + ## TODO - Modify __go_text__() to accept cell-strings + tmp = __go_text__ (ca, "string", "foobar", + varargin{:}, + "position", pos); + set (tmp, "string", label{1}); + elseif (nt == nx) + for n = 1:nt + tmp(n) = __go_text__ (ca, "string", label{n}, varargin{:}, - "position", pos(i,:)); - endfor - __request_drawnow__ (); - elseif (n == nx) - for i = 1:nx - tmp(i) = __go_text__ (ca, "string", label{i}, - varargin{:}, - "position", pos(i,:)); + "position", pos(n,:)); endfor __request_drawnow__ (); else error ("text: dimension mismatch for coordinates and LABEL"); endif + elseif (nt == nx || nt == 1 || nx == 1) + error ("text: dimension mismatch for coordinates"); else - error ("text: dimension mismatch for coordinates"); + error ("text: mismatch betwween coordinates and strings"); endif if (nargout > 0) @@ -142,3 +160,61 @@ %! endfor %! caxis ([-100 100]) %! title ("Vertically Aligned at Bottom") + +%!demo +%! clf +%! axis ([0 8 0 8]) +%! title (["First title";"Second title"]) +%! xlabel (["First xlabel";"Second xlabel"]) +%! ylabel (["First ylabel";"Second ylabel"]) +%! text (4, 4, {"Hello", "World"}, ... +%! "horizontalalignment", "center", ... +%! "verticalalignment", "middle") +%! grid on + +%!demo +%! clf +%! h = mesh (peaks, "edgecolor", 0.7 * [1 1 1], ... +%! "facecolor", "none", ... +%! "facealpha", 0); +%! title (["First title";"Second title"]) +%! xlabel (["First xlabel";"Second xlabel"]) +%! ylabel (["First ylabel";"Second ylabel"]) +%! zlabel (["First zlabel";"Second zlabel"]) +%! text (0, 0, 5, {"Hello", "World"}, ... +%! "horizontalalignment", "center", ... +%! "verticalalignment", "middle") +%! hold on +%! plot3 (0, 0, 5, "+k") +%! + +%!demo +%! clf +%! h = text (0.5, 0.3, "char"); +%! assert ("char", class (get (h, "string"))) +%! h = text (0.5, 0.4, ["char row 1"; "char row 2"]); +%! assert ("char", class (get (h, "string"))) +%! h = text (0.5, 0.6, {"cell2str (1,1)", "cell2str (1,2)"; "cell2str (2,1)", "cell2str (2,2)"}); +%! assert ("cell", class (get (h, "string"))) +%! h = text (0.5, 0.8, "foobar"); +%! set (h, "string", 1:3) +%! h = text ([0.1, 0.1], [0.3, 0.4], "one string & two objects"); +%! assert ("char", class (get (h(1), "string"))) +%! assert ("char", class (get (h(2), "string"))) +%! h = text ([0.1, 0.1], [0.5, 0.6], {"one cellstr & two objects"}); +%! assert ("cell", class (get (h(1), "string"))) +%! assert ("cell", class (get (h(2), "string"))) +%! h = text ([0.1, 0.1], [0.7, 0.8], {"cellstr 1 object 1", "cellstr 2 object 2"}); +%! assert ("char", class (get (h(1), "string"))) +%! assert ("char", class (get (h(2), "string"))) +%! h = text ([0.1, 0.1], [0.1, 0.2], ["1st string & 1st object"; "2nd string & 2nd object"]); +%! assert ("char", class (get (h(1), "string"))) +%! assert ("char", class (get (h(2), "string"))) +%! h = text (0.7, 0.6, "single string"); +%! assert ("char", class (get (h, "string"))) +%! h = text (0.7, 0.5, {"single cell-string"}); +%! assert ("cell", class (get (h, "string"))) +%! xlabel (1:2) +%! ylabel (1:2) +%! title (1:2) +
--- a/scripts/plot/uimenu.m +++ b/scripts/plot/uimenu.m @@ -66,8 +66,10 @@ ## @group ## f = uimenu("label", "&File", "accelerator", "f"); ## e = uimenu("label", "&Edit", "accelerator", "e"); -## uimenu(f, "label", "Close", "accelerator", "q", "callback", "close (gcf)"); -## uimenu(e, "label", "Toggle &Grid", "accelerator", "g", "callback", "grid (gca)"); +## uimenu(f, "label", "Close", "accelerator", "q", ... +## "callback", "close (gcf)"); +## uimenu(e, "label", "Toggle &Grid", "accelerator", "g", ... +## "callback", "grid (gca)"); ## @end group ## @end example ## @seealso{figure}
--- a/scripts/plot/whitebg.m +++ b/scripts/plot/whitebg.m @@ -74,7 +74,7 @@ if (isroot) fac = get (0, "factory"); fields = fieldnames (fac); - fieldindex = intersect (find (!cellfun (@isempty, regexp(fields, 'color'))), union (find (!cellfun (@isempty, regexp(fields, 'factoryaxes.*'))), find (!cellfun (@isempty, regexp(fields, 'factoryfigure.*'))))); + fieldindex = intersect (find (!cellfun ("isempty", regexp(fields, 'color'))), union (find (!cellfun ("isempty", regexp(fields, 'factoryaxes.*'))), find (!cellfun ("isempty", regexp(fields, 'factoryfigure.*'))))); ## Check whether the factory value has been replaced for nf = 1 : numel (fieldindex); @@ -104,7 +104,7 @@ for nh = 1 : numel(h) p = get (h (nh)); fields = fieldnames (p); - fieldindex = find (!cellfun (@isempty, regexp(fields, 'color'))); + fieldindex = find (!cellfun ("isempty", regexp(fields, 'color'))); if (numel (fieldindex)) for nf = 1 : numel (fieldindex); field = fields {fieldindex (nf)}; @@ -121,7 +121,7 @@ def = get (h (nh), "default"); fields = fieldnames (def); if (! isempty (fields)) - fieldindex = find (!cellfun (@isempty, regexp(fields, 'color'))); + fieldindex = find (!cellfun ("isempty", regexp(fields, 'color'))); for nf = 1 : numel (fieldindex) defaultfield = fields {fieldindex (nf)}; defaultvalue = 1 - subsref (def, struct ("type", ".", "subs", defaultfield));
--- a/scripts/polynomial/mkpp.m +++ b/scripts/polynomial/mkpp.m @@ -17,50 +17,66 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{pp} =} mkpp (@var{x}, @var{p}) -## @deftypefnx {Function File} {@var{pp} =} mkpp (@var{x}, @var{p}, @var{d}) +## @deftypefn {Function File} {@var{pp} =} mkpp (@var{breaks}, @var{coefs}) +## @deftypefnx {Function File} {@var{pp} =} mkpp (@var{breaks}, @var{coefs}, @var{d}) +## +## Construct a piece-wise polynomial (pp) structure from sample points +## @var{breaks} and coefficients @var{coefs}. @var{breaks} must be a vector of +## strictly increasing values. The number of intervals is given by +## @code{@var{ni} = length (@var{breaks}) - 1}. +## When @var{m} is the polynomial order @var{coefs} must be of +## size: @var{ni} x @var{m} + 1. ## -## Construct a piecewise polynomial structure from sample points -## @var{x} and coefficients @var{p}. The i-th row of @var{p}, -## @code{@var{p} (@var{i},:)}, contains the coefficients for the polynomial -## over the @var{i}-th interval, ordered from highest to -## lowest. There must be one row for each interval in @var{x}, so -## @code{rows (@var{p}) == length (@var{x}) - 1}. +## The i-th row of @var{coefs}, +## @code{@var{coefs} (@var{i},:)}, contains the coefficients for the polynomial +## over the @var{i}-th interval, ordered from highest (@var{m}) to +## lowest (@var{0}). ## -## @var{p} may also be a multi-dimensional array, specifying a vector-valued -## or array-valued polynomial. The shape is determined by @var{d}. If @var{d} -## is -## not given, the default is @code{size (p)(1:end-2)}. If @var{d} is given, the -## leading dimensions of @var{p} are reshaped to conform to @var{d}. +## @var{coefs} may also be a multi-dimensional array, specifying a vector-valued +## or array-valued polynomial. In that case the polynomial order is defined +## by the length of the last dimension of @var{coefs}. +## The size of first dimension(s) are given by the scalar or +## vector @var{d}. If @var{d} is not given it is set to @code{1}. +## In any case @var{coefs} is reshaped to a 2d matrix of +## size @code{[@var{ni}*prod(@var{d} @var{m})] } ## ## @seealso{unmkpp, ppval, spline} ## @end deftypefn function pp = mkpp (x, P, d) + + # check number of arguments if (nargin < 2 || nargin > 3) print_usage (); endif - pp.x = x(:); - n = length (x) - 1; - if (n < 1) + + # check x + if (length (x) < 2) error ("mkpp: at least one interval is needed"); endif - nd = ndims (P); - k = size (P, nd); - if (nargin < 3) - if (nd == 2) - d = 1; - else - d = prod (size (P)(1:nd-1)); - endif + + if (!isvector (x)) + error ("mkpp: x must be a vector"); endif - pp.d = d; - pp.P = P = reshape (P, prod (d), [], k); - pp.orient = 0; + + len = length (x) - 1; + dP = length (size (P)); - if (size (P, 2) != n) - error ("mkpp: num intervals in X doesn't match num polynomials in P"); - endif + pp = struct ("form", "pp", + "breaks", x(:).', + "coefs", [], + "pieces", len, + "order", prod (size (P)) / len, + "dim", 1); + + if (nargin == 3) + pp.dim = d; + pp.order /= prod (d); + endif + + dim_vec = [pp.pieces * prod(pp.dim), pp.order]; + pp.coefs = reshape (P, dim_vec); + endfunction %!demo # linear interpolation @@ -72,3 +88,25 @@ %! xi=linspace(0,pi,50); %! plot(x,t,"x",xi,ppval(pp,xi)); %! legend("control","interp"); + +%!shared b,c,pp +%! b = 1:3; c = 1:24; pp=mkpp(b,c); +%!assert (pp.pieces,2); +%!assert (pp.order,12); +%!assert (pp.dim,1); +%!assert (size(pp.coefs),[2,12]); +%! pp=mkpp(b,c,2); +%!assert (pp.pieces,2); +%!assert (pp.order,6); +%!assert (pp.dim,2); +%!assert (size(pp.coefs),[4,6]); +%! pp=mkpp(b,c,3); +%!assert (pp.pieces,2); +%!assert (pp.order,4); +%!assert (pp.dim,3); +%!assert (size(pp.coefs),[6,4]); +%! pp=mkpp(b,c,[2,3]); +%!assert (pp.pieces,2); +%!assert (pp.order,2); +%!assert (pp.dim,[2,3]); +%!assert (size(pp.coefs),[12,2]);
--- a/scripts/polynomial/module.mk +++ b/scripts/polynomial/module.mk @@ -10,7 +10,6 @@ polynomial/poly.m \ polynomial/polyaffine.m \ polynomial/polyder.m \ - polynomial/polyderiv.m \ polynomial/polyfit.m \ polynomial/polygcd.m \ polynomial/polyint.m \
--- a/scripts/polynomial/pchip.m +++ b/scripts/polynomial/pchip.m @@ -27,8 +27,8 @@ ## ## The variable @var{x} must be a strictly monotonic vector (either ## increasing or decreasing). While @var{y} can be either a vector or -## array. In the case where @var{y} is a vector, it must have a length -## of @var{n}. If @var{y} is an array, then the size of @var{y} must +## an array. In the case where @var{y} is a vector, it must have the +## length @var{n}. If @var{y} is an array, then the size of @var{y} must ## have the form ## @tex ## $$[s_1, s_2, \cdots, s_k, n]$$ @@ -73,15 +73,22 @@ print_usage (); endif + ## make row vector x = x(:).'; n = length (x); ## Check the size and shape of y if (isvector (y)) - y = y(:).'; + y = y(:).'; ##row vector szy = size (y); + if !(size_equal (x, y)) + error ("pchip: length of X and Y must match") + endif else szy = size (y); + if (n != szy(end)) + error ("pchip: length of X and last dimension of Y must match") + endif y = reshape (y, [prod(szy(1:end-1)), szy(end)]); endif @@ -94,16 +101,12 @@ error("pchip: X must be strictly monotonic"); endif - if (columns (y) != n) - error("pchip: size of X and Y must match"); - endif - - f1 = y(:,1:n-1); + f1 = y(:, 1:n-1); ## Compute derivatives. d = __pchip_deriv__ (x, y, 2); - d1 = d(:,1:n-1); - d2 = d(:,2:n); + d1 = d(:, 1:n-1); + d2 = d(:, 2:n); ## This is taken from SLATEC. h = diag (h); @@ -114,14 +117,12 @@ c3 = del1 + del2; c2 = -c3 - del1; c3 = c3 / h; - coeffs = cat (3, c3, c2, d1, f1); - pp = mkpp (x, coeffs, szy(1:end-1)); - if (nargin == 2) - ret = pp; - else - ret = ppval (pp, xi); + ret = mkpp (x, coeffs, szy(1:end-1)); + + if (nargin == 3) + ret = ppval (ret, xi); endif endfunction @@ -138,7 +139,7 @@ %! %------------------------------------------------------------------- %! % confirm that pchip agreed better to discontinuous data than spline -%!shared x,y +%!shared x,y,y2,pp,yi1,yi2,yi3 %! x = 0:8; %! y = [1, 1, 1, 1, 0.5, 0, 0, 0, 0]; %!assert (pchip(x,y,x), y); @@ -148,3 +149,23 @@ %!assert (isempty(pchip(x',y',[]))); %!assert (isempty(pchip(x,y,[]))); %!assert (pchip(x,[y;y],x), [pchip(x,y,x);pchip(x,y,x)]) +%!assert (pchip(x,[y;y],x'), [pchip(x,y,x);pchip(x,y,x)]) +%!assert (pchip(x',[y;y],x), [pchip(x,y,x);pchip(x,y,x)]) +%!assert (pchip(x',[y;y],x'), [pchip(x,y,x);pchip(x,y,x)]) +%!test +%! x=(0:8)*pi/4;y=[sin(x);cos(x)]; +%! y2(:,:,1)=y;y2(:,:,2)=y+1;y2(:,:,3)=y-1; +%! pp=pchip(x,shiftdim(y2,2)); +%! yi1=ppval(pp,(1:4)*pi/4); +%! yi2=ppval(pp,repmat((1:4)*pi/4,[5,1])); +%! yi3=ppval(pp,[pi/2,pi]); +%!assert(size(pp.coefs),[48,4]); +%!assert(pp.pieces,8); +%!assert(pp.order,4); +%!assert(pp.dim,[3,2]); +%!assert(ppval(pp,pi),[0,-1;1,0;-1,-2],1e-14); +%!assert(yi3(:,:,2),ppval(pp,pi),1e-14); +%!assert(yi3(:,:,1),[1,0;2,1;0,-1],1e-14); +%!assert(squeeze(yi1(1,2,:)),[1/sqrt(2); 0; -1/sqrt(2);-1],1e-14); +%!assert(size(yi2),[3,2,5,4]); +%!assert(squeeze(yi2(1,2,3,:)),[1/sqrt(2); 0; -1/sqrt(2);-1],1e-14); \ No newline at end of file
--- a/scripts/polynomial/polyder.m +++ b/scripts/polynomial/polyder.m @@ -1,4 +1,4 @@ -## Copyright (C) 1995-2011 John W. Eaton +## Copyright (C) 1994-2011 John W. Eaton ## ## This file is part of Octave. ## @@ -17,27 +17,84 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} polyderiv (@var{p}) -## @deftypefnx {Function File} {[@var{k}] =} polyderiv (@var{a}, @var{b}) -## @deftypefnx {Function File} {[@var{q}, @var{d}] =} polyderiv (@var{b}, @var{a}) -## An alias for @code{polyderiv}. -## @seealso{polyderiv} +## @deftypefn {Function File} {} polyder (@var{p}) +## @deftypefnx {Function File} {[@var{k}] =} polyder (@var{a}, @var{b}) +## @deftypefnx {Function File} {[@var{q}, @var{d}] =} polyder (@var{b}, @var{a}) +## Return the coefficients of the derivative of the polynomial whose +## coefficients are given by the vector @var{p}. If a pair of polynomials +## is given, return the derivative of the product @math{@var{a}*@var{b}}. +## If two inputs and two outputs are given, return the derivative of the +## polynomial quotient @math{@var{b}/@var{a}}. The quotient numerator is +## in @var{q} and the denominator in @var{d}. +## @seealso{poly, polyint, polyreduce, roots, conv, deconv, residue, +## filter, polygcd, polyval, polyvalm} ## @end deftypefn -## Author: John W. Eaton +## Author: Tony Richardson <arichard@stark.cc.oh.us> +## Created: June 1994 +## Adapted-By: jwe function [q, d] = polyder (p, a) - if (nargin == 1) - q = polyderiv (p); - elseif (nargin == 2) - if (nargout == 2) - [q, d] = polyderiv (p, a); + if (nargin == 1 || nargin == 2) + if (! isvector (p)) + error ("polyder: argument must be a vector"); + endif + if (nargin == 2) + if (! isvector (a)) + error ("polyder: argument must be a vector"); + endif + if (nargout == 1) + ## derivative of p*a returns a single polynomial + q = polyder (conv (p, a)); + else + ## derivative of p/a returns numerator and denominator + d = conv (a, a); + if (numel (p) == 1) + q = -p * polyder (a); + elseif (numel (a) == 1) + q = a * polyder (p); + else + q = conv (polyder (p), a) - conv (p, polyder (a)); + q = polyreduce (q); + endif + + ## remove common factors from numerator and denominator + x = polygcd (q, d); + if (length(x) != 1) + q = deconv (q, x); + d = deconv (d, x); + endif + + ## move all the gain into the numerator + q = q/d(1); + d = d/d(1); + endif else - q = polyderiv (p, a); + lp = numel (p); + if (lp == 1) + q = 0; + return; + elseif (lp == 0) + q = []; + return; + endif + + ## Force P to be a row vector. + p = p(:).'; + + q = p(1:(lp-1)) .* [(lp-1):-1:1]; endif else print_usage (); endif endfunction + + +%!assert(all (all (polyder ([1, 2, 3]) == [2, 2]))); +%!assert(polyder (13) == 0); + +%!error polyder ([]); +%!error polyder ([1, 2; 3, 4]); +
--- a/scripts/polynomial/polyint.m +++ b/scripts/polynomial/polyint.m @@ -61,3 +61,18 @@ retval = [(p ./ [lp:-1:1]), k]; endfunction + +%!test +%! A = [3, 2, 1]; +%! assert (polyint(A),polyint(A,0)); +%! assert (polyint(A),polyint(A')); +%! assert (polyint(A),[1, 1, 1, 0]); +%! assert (polyint(A,1),ones(1,4)); + +%!test +%! A = ones(1,8); +%! B = [length(A):-1:1]; +%! assert (polyint(A),[1./B, 0]); + +%!error polyint() +%!error polyint(ones(2,2))
--- a/scripts/polynomial/polyout.m +++ b/scripts/polynomial/polyout.m @@ -97,3 +97,9 @@ str = num2str (c, 5); endif endfunction + +%!assert (polyout ([3 2 1]), '3*s^2 + 2*s^1 + 1') +%!assert (polyout ([3 2 1], 'x'), '3*x^2 + 2*x^1 + 1') +%!assert (polyout ([3 2 1], 'wxyz'), '3*wxyz^2 + 2*wxyz^1 + 1') +%!assert (polyout ([5 4 3 2 1], '1'),'5*1^4 + 4*1^3 + 3*1^2 + 2*1^1 + 1') +%!error polyout ([])
--- a/scripts/polynomial/polyval.m +++ b/scripts/polynomial/polyval.m @@ -20,7 +20,7 @@ ## @deftypefn {Function File} {@var{y} =} polyval (@var{p}, @var{x}) ## @deftypefnx {Function File} {@var{y} =} polyval (@var{p}, @var{x}, [], @var{mu}) ## Evaluate the polynomial @var{p} at the specified values of @var{x}. When -## @var{mu} is present evaluate the polynomial for +## @var{mu} is present, evaluate the polynomial for ## (@var{x}-@var{mu}(1))/@var{mu}(2). ## If @var{x} is a vector or matrix, the polynomial is evaluated for each of ## the elements of @var{x}. @@ -39,17 +39,19 @@ ## Created: June 1994 ## Adapted-By: jwe -function [y, dy] = polyval (p, x, s, mu) +function [y, dy] = polyval (p, x, s = [], mu) if (nargin < 2 || nargin > 4 || (nargout == 2 && nargin < 3)) print_usage (); endif - if (nargin < 3) - s = []; - endif - - if (! (isvector (p) || isempty (p))) + if (isempty (x)) + y = []; + return; + elseif (isempty (p)) + y = zeros (size (x)); + return; + elseif (! isvector (p)) error ("polyval: first argument must be a vector"); endif @@ -57,16 +59,6 @@ x = (x - mu(1)) / mu(2); endif - if (isempty (x)) - y = []; - return; - endif - - if (length (p) == 0) - y = p; - return; - endif - n = length (p) - 1; y = p(1) * ones (size (x)); for i = 2:n+1 @@ -80,10 +72,23 @@ ## dy = t * sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df) ## If my inference is correct, then t must equal 1 for polyval. ## This is because finv (0.5, n, n) = 1.0 for any n. - k = numel (x); - A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); - dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); - dy = reshape (dy, size (x)); + try + k = numel (x); + A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); + dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); + dy = reshape (dy, size (x)); + catch + if (isempty (s)) + error ("polyval: third input is required.") + elseif (isstruct (s) + && all (ismember ({"R", "normr", "df"}, fieldnames (s)))) + error (lasterr ()) + elseif (isstruct (s)) + error ("polyval: third input is missing the required fields."); + else + error ("polyval: third input is not a structure."); + endif + end_try_catch endif endfunction @@ -142,3 +147,6 @@ %! assert (y, polyval(p,x), eps) %! x = reshape(x, [1, 1, 5, 2]); +%!assert (zeros (1, 10), polyval ([], 1:10)) +%!assert ([], polyval (1, [])) +%!assert ([], polyval ([], []))
--- a/scripts/polynomial/ppder.m +++ b/scripts/polynomial/ppder.m @@ -17,28 +17,54 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{ppd} =} ppder (@var{pp}) -## Compute the piecewise derivative of the piecewise polynomial struct @var{pp}. +## @deftypefn {Function File} {ppd =} ppder (pp, m) +## Computes the piecewise @var{m}-th derivative of a piecewise polynomial +## struct @var{pp}. If @var{m} is omitted the first derivate is +## calculated. ## @seealso{mkpp, ppval, ppint} ## @end deftypefn -function ppd = ppder (pp) - if (nargin != 1) +function ppd = ppder (pp, m) + + if ((nargin < 1) || (nargin > 2)) print_usage (); + elseif (nargin == 1) + m = 1; endif - if (! isstruct (pp)) + + if !(isstruct (pp) && strcmp (pp.form, "pp")) error ("ppder: PP must be a structure"); endif [x, p, n, k, d] = unmkpp (pp); - p = reshape (p, [], k); - if (k <= 1) - pd = zeros (rows (p), 1); - k = 1; + + if (k - m <= 0) + x = [x(1) x(end)]; + pd = zeros (prod (d), 1); else - k -= 1; - pd = p(:,1:k) * diag (k:-1:1); + f = k : -1 : 1; + ff = bincoeff (f, m + 1) .* factorial (m + 1) ./ f; + k -= m; + pd = p(:,1:k) * diag (ff(1:k)); endif + ppd = mkpp (x, pd, d); endfunction +%!shared x,y,pp,ppd +%! x=0:8;y=[x.^2;x.^3+1];pp=spline(x,y); +%! ppd=ppder(pp); +%!assert(ppval(ppd,x),[2*x;3*x.^2],1e-14) +%!assert(ppd.order,3) +%! ppd=ppder(pp,2); +%!assert(ppval(ppd,x),[2*ones(size(x));6*x],1e-14) +%!assert(ppd.order,2) +%! ppd=ppder(pp,3); +%!assert(ppd.order,1) +%!assert(ppd.pieces,8) +%!assert(size(ppd.coefs),[16,1]) +%! ppd=ppder(pp,4); +%!assert(ppd.order,1) +%!assert(ppd.pieces,1) +%!assert(size(ppd.coefs),[2,1]) +%!assert(ppval(ppd,x),zeros(size(y)),1e-14)
--- a/scripts/polynomial/ppint.m +++ b/scripts/polynomial/ppint.m @@ -28,7 +28,7 @@ if (nargin < 1 || nargin > 2) print_usage (); endif - if (! isstruct (pp)) + if (! isstruct (pp) && strcmp (pp.form, "pp")) error ("ppint: PP must be a structure"); endif @@ -39,17 +39,20 @@ pi = p / diag (k:-1:1); k += 1; if (nargin == 1) - pi(:,k) = 0; + pi(:, k) = 0; else - pi(:,k) = repmat (c(:), n, 1); + pi(:, k) = repmat (c(:), n, 1); endif ppi = mkpp (x, pi, d); - ## Adjust constants so the the result is continuous. - - jumps = reshape (ppjumps (ppi), prod (d), n-1); - ppi.P(:,2:n,k) -= cumsum (jumps, 2); - + tmp = -cumsum (ppjumps (ppi), length (d) + 1); + ppi.coefs(prod(d)+1:end, k) = tmp(:); + endfunction +%!shared x,y,pp,ppi +%! x=0:8;y=[ones(size(x));x+1];pp=spline(x,y); +%! ppi=ppint(pp); +%!assert(ppval(ppi,x),[x;0.5*x.^2+x],1e-14) +%!assert(ppi.order,5)
--- a/scripts/polynomial/ppjumps.m +++ b/scripts/polynomial/ppjumps.m @@ -28,29 +28,31 @@ if (nargin != 1) print_usage (); endif - if (! isstruct (pp)) + + if (! isstruct (pp) && strcmp (pp.form, "pp")) error ("ppjumps: PP must be a structure"); endif ## Extract info. - x = pp.x; - P = pp.P; - d = pp.d; - [nd, n, k] = size (P); + [x, P, n, k, d] = unmkpp(pp); + nd = length (d) + 1; ## Offsets. - dx = diff (x(1:n)).'; - dx = dx(ones (1, nd), :); # spread (do nothing in 1D) + dx = diff(x(1:n)); + dx = repmat (dx, [prod(d), 1]); + dx = reshape (dx, [d, n-1]); + dx = shiftdim (dx, nd - 1); - ## Use Horner scheme to get limits from the left. - llim = P(:,1:n-1,1); - for i = 2:k; + ## Use Horner scheme. + if (k>1) + llim = shiftdim (reshape (P(1:(n-1) * prod(d), 1), [d, n-1]), nd - 1); + endif + + for i = 2 : k; llim .*= dx; - llim += P(:,1:n-1,i); + llim += shiftdim (reshape (P(1:(n-1) * prod (d), i), [d, n-1]), nd - 1); endfor - - rlim = P(:,2:n,k); # limits from the right - jumps = reshape (rlim - llim, [d, n-1]); - + + rlim = shiftdim (ppval (pp, x(2:end-1)), nd - 1); + jumps = shiftdim (rlim - llim, 1); endfunction -
--- a/scripts/polynomial/ppval.m +++ b/scripts/polynomial/ppval.m @@ -18,16 +18,18 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {@var{yi} =} ppval (@var{pp}, @var{xi}) -## Evaluate piecewise polynomial @var{pp} at the points @var{xi}. -## If @var{pp} is scalar-valued, the result is an array of the same shape as -## @var{xi}. -## Otherwise, the size of the result is @code{[pp.d, length(@var{xi})]} if -## @var{xi} is a vector, or @code{[pp.d, size(@var{xi})]} if it is a -## multi-dimensional array. If pp.orient is 1, the dimensions are permuted as +## Evaluate piece-wise polynomial structure @var{pp} at the points @var{xi}. +## If @var{pp} describes a scalar polynomial function, the result is an +## array of the same shape as @var{xi}. +## Otherwise, the size of the result is @code{[pp.dim, length(@var{xi})]} if +## @var{xi} is a vector, or @code{[pp.dim, size(@var{xi})]} if it is a +## multi-dimensional array. +## +##, the dimensions are permuted as ## in interp1, to ## @code{[pp.d, length(@var{xi})]} and @code{[pp.d, size(@var{xi})]} ## respectively. -## @seealso{mkpp, unmkpp, spline} +## @seealso{mkpp, unmkpp, spline, pchip, interp1} ## @end deftypefn function yi = ppval (pp, xi) @@ -35,48 +37,85 @@ if (nargin != 2) print_usage (); endif - if (! isstruct (pp)) - error ("ppval: PP must be a structure"); + if (! isstruct (pp) && strcmp (pp.form, "pp")) + error ("ppval: expects a pp-form structure"); endif ## Extract info. - x = pp.x; - P = pp.P; - d = pp.d; - k = size (P, 3); - nd = size (P, 1); - - ## Determine resulting shape. - if (d == 1) # scalar case - yisz = size (xi); - elseif (isvector (xi)) # this is special - yisz = [d, length(xi)]; - else # general - yisz = [d, size(xi)]; + [x, P, n, k, d] = unmkpp (pp); + + ## dimension checks + sxi = size (xi); + if (isvector (xi)) + xi = xi(:).'; endif + + nd = length (d); ## Determine intervals. - xi = xi(:); xn = numel (xi); - idx = lookup (x, xi, "lr"); + P = reshape (P, [d, n * k]); + P = shiftdim (P, nd); + P = reshape (P, [n, k, d]); + Pidx = P(idx(:), :);#2d matrix size x: coefs*prod(d) y: prod(sxi) + + if (isvector(xi)) + Pidx = reshape (Pidx, [xn, k, d]); + Pidx = shiftdim (Pidx, 1); + dimvec = [d, xn]; + else + Pidx = reshape (Pidx, [sxi, k, d]); + Pidx = shiftdim (Pidx, length (sxi)); + dimvec = [d, sxi]; + end + ndv = length (dimvec); + ## Offsets. - dx = (xi - x(idx)).'; - dx = dx(ones (1, nd), :); # spread (do nothing in 1D) + dx = (xi - x(idx)); + dx = repmat (dx, [prod(d), 1]); + dx = reshape (dx, dimvec); + dx = shiftdim (dx, ndv - 1); ## Use Horner scheme. - yi = P(:,idx,1); - for i = 2:k; + yi = Pidx; + if (k > 1) + yi = shiftdim (reshape (Pidx(1,:), dimvec), ndv - 1); + endif + + for i = 2 : k; yi .*= dx; - yi += P(:,idx,i); + yi += shiftdim (reshape (Pidx(i,:), dimvec), ndv - 1); endfor - + ## Adjust shape. - yi = reshape (yi, yisz); - if (d != 1 && pp.orient == 1) - ## Switch dimensions to match interp1 order. - yi = shiftdim (yi, length (d)); + if ((numel (xi) > 1) || (length (d) == 1)) + yi = reshape (shiftdim (yi, 1), dimvec); endif + if (isvector (xi) && (d == 1)) + yi = reshape (yi, sxi); + elseif (isfield (pp, "orient") && strcmp (pp.orient, "first")) + yi = shiftdim(yi, nd); + endif + + ## + #if (d == 1) + # yi = reshape (yi, sxi); + #endif + endfunction + +%!shared b,c,pp,pp2,xi,abserr +%! b = 1:3; c = ones(2); pp=mkpp(b,c);abserr = 1e-14;pp2=mkpp(b,[c;c],2); +%! xi = [1.1 1.3 1.9 2.1]; +%!assert (ppval(pp,1.1), 1.1, abserr); +%!assert (ppval(pp,2.1), 1.1, abserr); +%!assert (ppval(pp,xi), [1.1 1.3 1.9 1.1], abserr); +%!assert (ppval(pp,xi.'), [1.1 1.3 1.9 1.1].', abserr); +%!assert (ppval(pp2,1.1), [1.1;1.1], abserr); +%!assert (ppval(pp2,2.1), [1.1;1.1], abserr); +%!assert (ppval(pp2,xi), [1.1 1.3 1.9 1.1;1.1 1.3 1.9 1.1], abserr); +%!assert (ppval(pp2,xi'), [1.1 1.3 1.9 1.1;1.1 1.3 1.9 1.1], abserr); +%!assert (size(ppval(pp2,[xi;xi])), [2 2 4]);
--- a/scripts/polynomial/spline.m +++ b/scripts/polynomial/spline.m @@ -83,15 +83,15 @@ ## Check the size and shape of y ndy = ndims (y); szy = size (y); - if (ndy == 2 && (szy(1) == 1 || szy(2) == 1)) - if (szy(1) == 1) + if (ndy == 2 && (szy(1) == n || szy(2) == n)) + if (szy(2) == n) a = y.'; else a = y; szy = fliplr (szy); endif else - a = reshape (y, [prod(szy(1:end-1)), szy(end)]).'; + a = shiftdim (reshape (y, [prod(szy(1:end-1)), szy(end)]), 1); endif for k = (1:columns (a))(any (isnan (a))) @@ -120,9 +120,9 @@ if (n == 2) d = (dfs + dfe) / (x(2) - x(1)) ^ 2 + ... - 2 * (a(1,:) - a(2,:)) / (x(2) - x(1)) ^ 3; + 2 * (a(1,:) - a(2,:)) / (x(2) - x(1)) ^ 3; c = (-2 * dfs - dfe) / (x(2) - x(1)) - ... - 3 * (a(1,:) - a(2,:)) / (x(2) - x(1)) ^ 2; + 3 * (a(1,:) - a(2,:)) / (x(2) - x(1)) ^ 2; b = dfs; a = a(1,:); @@ -132,7 +132,7 @@ a = a(1:n-1,:); else if (n == 3) - dg = 1.5 * h(1) - 0.5 * h(2); + dg = 1.5 * h(1) - 0.5 * h(2); c(2:n-1,:) = 1/dg(1); else dg = 2 * (h(1:n-2) .+ h(2:n-1)); @@ -153,9 +153,9 @@ endif c(1,:) = (3 / h(1) * (a(2,:) - a(1,:)) - 3 * dfs - - c(2,:) * h(1)) / (2 * h(1)); + - c(2,:) * h(1)) / (2 * h(1)); c(n,:) = - (3 / h(n-1) * (a(n,:) - a(n-1,:)) - 3 * dfe - + c(n-1,:) * h(n-1)) / (2 * h(n-1)); + + c(n-1,:) * h(n-1)) / (2 * h(n-1)); b(1:n-1,:) = diff (a) ./ h(1:n-1, idx) ... - h(1:n-1,idx) / 3 .* (c(2:n,:) + 2 * c(1:n-1,:)); d = diff (c) ./ (3 * h(1:n-1, idx)); @@ -229,15 +229,14 @@ - h(1:n-1, idx) / 3 .* (c(2:n,:) + 2 * c(1:n-1,:)); d = diff (c) ./ (3 * h(1:n-1, idx)); - d = d(1:n-1,:); - c = c(1:n-1,:); - b = b(1:n-1,:); - a = a(1:n-1,:); + d = d(1:n-1,:);d = d.'(:); + c = c(1:n-1,:);c = c.'(:); + b = b(1:n-1,:);b = b.'(:); + a = a(1:n-1,:);a = a.'(:); endif endif - coeffs = cat (3, d.', c.', b.', a.'); - ret = mkpp (x, coeffs, szy(1:end-1)); + ret = mkpp (x, cat (2, d, c, b, a), szy(1:end-1)); if (nargin == 3) ret = ppval (ret, xi); @@ -263,6 +262,9 @@ %!assert (isempty(spline(x',y',[]))); %!assert (isempty(spline(x,y,[]))); %!assert (spline(x,[y;y],x), [spline(x,y,x);spline(x,y,x)],abserr) +%!assert (spline(x,[y;y],x'), [spline(x,y,x);spline(x,y,x)],abserr) +%!assert (spline(x',[y;y],x), [spline(x,y,x);spline(x,y,x)],abserr) +%!assert (spline(x',[y;y],x'), [spline(x,y,x);spline(x,y,x)],abserr) %! y = cos(x) + i*sin(x); %!assert (spline(x,y,x), y, abserr) %!assert (real(spline(x,y,x)), real(y), abserr);
--- a/scripts/polynomial/unmkpp.m +++ b/scripts/polynomial/unmkpp.m @@ -50,15 +50,13 @@ if (nargin == 0) print_usage (); endif - if (! isstruct (pp)) + if (! (isstruct (pp) && strcmp (pp.form, "pp"))) error ("unmkpp: expecting piecewise polynomial structure"); endif - x = pp.x; - P = pp.P; - n = size (P, 2); - k = size (P, 3); - d = pp.d; - if (d == 1) - P = reshape (P, n, k); - endif + x = pp.breaks; + P = pp.coefs; + n = pp.pieces; + k = pp.order; + d = pp.dim; + endfunction
--- a/scripts/set/powerset.m +++ b/scripts/set/powerset.m @@ -75,3 +75,9 @@ endif endfunction + + +%!test +%! c = sort (cellstr ({ [], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]})); +%! p = sort (cellstr (powerset ([1, 2, 3]))); +%! assert (p, c);
--- a/scripts/set/setxor.m +++ b/scripts/set/setxor.m @@ -1,17 +1,17 @@ -## Copyright (C) 2008-2011 Jaroslav Hajek +## Copyright (C) 2008-2011 Jaroslav Hajek ## Copyright (C) 2000, 2006-2007 Paul Kienzle ## ## 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 +## 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. +## 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 @@ -20,17 +20,16 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} setxor (@var{a}, @var{b}) ## @deftypefnx {Function File} {} setxor (@var{a}, @var{b}, 'rows') +## @deftypefnx {Function File} {[@var{c}, @var{ia}, @var{ib}] =} setxor (@var{a}, @var{b}) ## ## Return the elements exclusive to @var{a} or @var{b}, sorted in ascending ## order. If @var{a} and @var{b} are both column vectors return a column ## vector, otherwise return a row vector. ## @var{a}, @var{b} may be cell arrays of string(s). ## -## @deftypefnx {Function File} {[@var{c}, @var{ia}, @var{ib}] =} setxor (@var{a}, @var{b}) -## -## Return index vectors @var{ia} and @var{ib} such that @code{a(ia)} and -## @code{b(ib)} are -## disjoint sets whose union is @var{c}. +## With three output arguments, return index vectors @var{ia} and @var{ib} +## such that @code{a(ia)} and @code{b(ib)} are disjoint sets whose union +## is @var{c}. ## ## @seealso{unique, union, intersect, setdiff, ismember} ## @end deftypefn
--- a/scripts/signal/autoreg_matrix.m +++ b/scripts/signal/autoreg_matrix.m @@ -47,3 +47,16 @@ endfor endfunction + + +%!test +%! K=4; +%! A = zeros(1,K+1); +%! A(1) = 1; +%! B = eye(K+1); +%! B(:,1) = 1; +%! assert (autoreg_matrix(A,K),B); + +%!error autoreg_matrix() +%!error autoreg_matrix(1) +%!error autoreg_matrix(ones(4,1),5)
--- a/scripts/signal/fftshift.m +++ b/scripts/signal/fftshift.m @@ -58,9 +58,7 @@ sz = size (x); sz2 = ceil (sz(dim) / 2); idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{dim} = [sz2+1:sz(dim), 1:sz2]; retval = x(idx{:}); else
--- a/scripts/signal/ifftshift.m +++ b/scripts/signal/ifftshift.m @@ -45,10 +45,7 @@ nd = ndims (x); sz = size (x); sz2 = floor (sz(dim) / 2); - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{dim} = [sz2+1:sz(dim), 1:sz2]; retval = x(idx{:}); else
--- a/scripts/signal/sinc.m +++ b/scripts/signal/sinc.m @@ -45,3 +45,10 @@ endif endfunction + + +%!assert (sinc (0), 1); +%!assert (sinc (1), 0,1e-6); +%!assert (sinc (1/2), 2/pi, 1e-6) + +%!error sinc()
--- a/scripts/signal/sinewave.m +++ b/scripts/signal/sinewave.m @@ -43,3 +43,13 @@ endif endfunction + +%!assert (sinewave (1), 0); +%!assert (sinewave (1, 4, 1), 1); +%!assert (sinewave (1, 12, 1), 1/2, 1e-6); +%!assert (sinewave (1, 12, 2), sqrt (3)/2, 1e-6); +%!assert (sinewave (1, 20, 1), (sqrt (5)-1)/4, 1e-6); +%!assert (sinewave (1), sinewave (1, 1,0)); +%!assert (sinewave (3, 4), sinewave(3, 4, 0)); + +%!error sinewave ();
--- a/scripts/signal/unwrap.m +++ b/scripts/signal/unwrap.m @@ -55,11 +55,8 @@ error ("unwrap: DIM must be an integer and a valid dimension"); endif else - ## Find the first non-singleton dimension - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + ## Find the first non-singleton dimension. + (dim = find (sz > 1, 1)) || (dim = 1); endif rng = 2*pi; @@ -74,17 +71,14 @@ ## Take first order difference to see so that wraps will show up ## as large values, and the sign will show direction. - idx = cell (); - for i = 1:nd - idx{i} = 1:sz(i); - endfor + idx = repmat ({':'}, nd, 1); idx{dim} = [1,1:m-1]; d = x(idx{:}) - x; - ## Find only the peaks, and multiply them by the range so that there - ## are kronecker deltas at each wrap point multiplied by the range - ## value. - p = rng * (((d > tol) > 0) - ((d < -tol) > 0)); + ## Find only the peaks, and multiply them by the appropriate amount + ## of ranges so that there are kronecker deltas at each wrap point + ## multiplied by the appropriate amount of range values. + p = ceil(abs(d)./rng) .* rng .* (((d > tol) > 0) - ((d < -tol) > 0)); ## Now need to "integrate" this so that the deltas become steps. r = cumsum (p, dim); @@ -134,4 +128,28 @@ %! t(++i) = xassert(any(abs(r - unwrap(w,0.8)) > 100)); %! %! assert(all(t)); - +%! +%!test +%! A = [pi*(-4), pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64]; +%! assert (unwrap(A), unwrap(A, pi)); +%! assert (unwrap(A, pi), unwrap(A, pi, 2)); +%! assert (unwrap(A', pi), unwrap(A', pi, 1)); +%! +%!test +%! A = [pi*(-4); pi*(2+1/3); pi*(16+1)]; +%! B = [pi*(-2+1/6); pi*(4+1/2); pi*(32+3/2)]; +%! C = [pi/4; pi*(8+2/3); pi*64]; +%! D = [pi*(-2+1/6); pi*(2+1/3); pi*(8+2/3)]; +%! E(:, :, 1) = [A, B, C, D]; +%! E(:, :, 2) = [A+B, B+C, C+D, D+A]; +%! F(:, :, 1) = [unwrap(A), unwrap(B), unwrap(C), unwrap(D)]; +%! F(:, :, 2) = [unwrap(A+B), unwrap(B+C), unwrap(C+D), unwrap(D+A)]; +%! assert (unwrap(E), F); +%! +%!test +%! A = [0, 2*pi, 4*pi, 8*pi, 16*pi, 65536*pi]; +%! B = [pi*(-2+1/6), pi/4, pi*(2+1/3), pi*(4+1/2), pi*(8+2/3), pi*(16+1), pi*(32+3/2), pi*64]; +%! assert (unwrap(A), zeros(1, length(A))); +%! assert (diff(unwrap(B), 1)<2*pi, true(1, length(B)-1)); +%! +%!error unwrap()
--- a/scripts/sparse/module.mk +++ b/scripts/sparse/module.mk @@ -5,6 +5,7 @@ sparse/cgs.m \ sparse/colperm.m \ sparse/etreeplot.m \ + sparse/gmres.m \ sparse/gplot.m \ sparse/nonzeros.m \ sparse/pcg.m \
--- a/scripts/sparse/nonzeros.m +++ b/scripts/sparse/nonzeros.m @@ -27,12 +27,13 @@ print_usage (); endif - [i, j, t] = find (s); + [~, ~, t] = find (s); t = t(:); endfunction + %!assert(nonzeros([1,2;3,0]),[1;3;2]) %!assert(nonzeros([1,2,3,0]),[1;2;3]) %!assert(nonzeros(sparse([1,2;3,0])),[1;3;2])
--- a/scripts/sparse/svds.m +++ b/scripts/sparse/svds.m @@ -150,6 +150,8 @@ ## Scale everything by the 1-norm to make things more stable. b = A / max_a; b_opts = opts; + ## Call to eigs is always a symmetric matrix by construction + b_opts.issym = true; b_opts.tol = opts.tol / max_a; b_sigma = sigma; if (!ischar (b_sigma))
--- a/scripts/specfun/bessel.m +++ b/scripts/specfun/bessel.m @@ -91,3 +91,4 @@ error ("bessel: you must use besselj, bessely, besseli, or besselk"); endfunction +%!error bessel ()
rename from scripts/elfun/lcm.m rename to scripts/specfun/lcm.m --- a/scripts/elfun/lcm.m +++ b/scripts/specfun/lcm.m @@ -34,7 +34,7 @@ if (nargin > 1) if (common_size (varargin{:}) != 0) error ("lcm: all args must be of the same size or scalar"); - elseif (! all (cellfun (@isnumeric, varargin))) + elseif (! all (cellfun ("isnumeric", varargin))) error ("lcm: all arguments must be numeric"); endif
--- a/scripts/specfun/module.mk +++ b/scripts/specfun/module.mk @@ -7,6 +7,7 @@ specfun/factor.m \ specfun/factorial.m \ specfun/isprime.m \ + specfun/lcm.m \ specfun/legendre.m \ specfun/nchoosek.m \ specfun/nthroot.m \
--- a/scripts/specfun/nthroot.m +++ b/scripts/specfun/nthroot.m @@ -35,8 +35,9 @@ ## @end group ## @end example ## -## @var{n} must be a scalar. If @var{n} is not an even integer and @var{X} has -## negative entries, an error is produced. +## @var{x} must have all real entries. @var{n} must be a scalar. +## If @var{n} is an even integer and @var{X} has negative entries, an +## error is produced. ## @seealso{realsqrt, sqrt, cbrt} ## @end deftypefn @@ -46,7 +47,11 @@ print_usage (); endif - if (! isscalar (n)) + if (any (iscomplex (x(:)))) + error ("nthroot: X must not contain complex values"); + endif + + if (! isscalar (n) || n == 0) error ("nthroot: N must be a nonzero scalar"); endif @@ -58,7 +63,7 @@ y = 1 ./ nthroot (x, -n); else ## Compute using power. - if (n == round (n) && mod (n, 2) == 1) + if (n == fix (n) && mod (n, 2) == 1) y = abs (x) .^ (1/n) .* sign (x); elseif (any (x(:) < 0)) error ("nthroot: if X contains negative values, N must be an odd integer"); @@ -66,7 +71,7 @@ y = x .^ (1/n); endif - if (finite (n) && n > 0 && n == round (n)) + if (finite (n) && n > 0 && n == fix (n)) ## Correction. y = ((n-1)*y + x ./ (y.^(n-1))) / n; y = merge (finite (y), y, x); @@ -76,8 +81,18 @@ endfunction -%!assert(nthroot(-32,5), -2); -%!assert(nthroot(81,4), 3); -%!assert(nthroot(Inf,4), Inf); -%!assert(nthroot(-Inf,7), -Inf); -%!assert(nthroot(-Inf,-7), 0); +%!assert (nthroot(-32,5), -2); +%!assert (nthroot(81,4), 3); +%!assert (nthroot(Inf,4), Inf); +%!assert (nthroot(-Inf,7), -Inf); +%!assert (nthroot(-Inf,-7), 0); + +%% Test input validation +%!error (nthroot ()) +%!error (nthroot (1)) +%!error (nthroot (1,2,3)) +%!error (nthroot (1+j,2)) +%!error (nthroot (1,[1 2])) +%!error (nthroot (1,0)) +%!error (nthroot (-1,2)) +
--- a/scripts/specfun/perms.m +++ b/scripts/specfun/perms.m @@ -63,3 +63,11 @@ endfor endif endfunction + +%!error perms (); +%!error perms (1, 2); + +%!assert (perms ([1,2,3]), [1,2,3;2,1,3;1,3,2;2,3,1;3,1,2;3,2,1]); +%!assert (perms (1:3), perms ([1,2,3])); + +%!assert (perms (int8([1,2,3])), int8([1,2,3;2,1,3;1,3,2;2,3,1;3,1,2;3,2,1]));
--- a/scripts/specfun/primes.m +++ b/scripts/specfun/primes.m @@ -92,3 +92,11 @@ endif endfunction + +%!error primes (); +%!error primes (1, 2); + +%!assert (size (primes (350)), [1, 70]); +%!assert (size (primes (350)), [1, 70]); + +%!assert (primes (357)(end), 353);
--- a/scripts/special-matrix/module.mk +++ b/scripts/special-matrix/module.mk @@ -8,7 +8,6 @@ special-matrix/magic.m \ special-matrix/pascal.m \ special-matrix/rosser.m \ - special-matrix/sylvester_matrix.m \ special-matrix/toeplitz.m \ special-matrix/vander.m \ special-matrix/wilkinson.m
--- a/scripts/startup/__finish__.m +++ b/scripts/startup/__finish__.m @@ -36,3 +36,5 @@ endfunction +## No test needed for internal helper function. +%!assert (1)
--- a/scripts/statistics/base/center.m +++ b/scripts/statistics/base/center.m @@ -23,7 +23,7 @@ ## If @var{x} is a vector, subtract its mean. ## If @var{x} is a matrix, do the above for each column. ## If the optional argument @var{dim} is given, operate along this dimension. -## @seealso{studentize} +## @seealso{zscore} ## @end deftypefn ## Author: KH <Kurt.Hornik@wu-wien.ac.at> @@ -35,7 +35,7 @@ print_usage (); endif - if (!isnumeric (x)) + if (! (isnumeric (x) || islogical (x))) error ("center: X must be a numeric vector or matrix"); endif @@ -47,10 +47,7 @@ sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -58,25 +55,28 @@ endif endif - n = size (x, dim); + n = sz(dim); if (n == 0) retval = x; else - retval = bsxfun (@minus, x, sum (x, dim) / n); + retval = bsxfun (@minus, x, mean (x, dim)); endif endfunction %!assert(center ([1,2,3]), [-1,0,1]) +%!assert(center (single([1,2,3])), single([-1,0,1])) %!assert(center (int8 ([1,2,3])), [-1,0,1]) +%!assert(center (logical ([1, 0, 0, 1])), [0.5, -0.5, -0.5, 0.5]) %!assert(center (ones (3,2,0,2)), zeros (3,2,0,2)) +%!assert(center (ones (3,2,0,2, 'single')), zeros (3,2,0,2, 'single')) %!assert(center (magic (3)), [3,-4,1;-2,0,2;-1,4,-3]) +%!assert(center ([1 2 3; 6 5 4], 2), [-1 0 1; 1 0 -1]) %% Test input validation %!error center () %!error center (1, 2, 3) -%!error center ([true true]) %!error center (1, ones(2,2)) %!error center (1, 1.5) %!error center (1, 0)
new file mode 100644 --- /dev/null +++ b/scripts/statistics/base/corr.m @@ -0,0 +1,112 @@ +## Copyright (C) 1996-2011 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/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} corr (@var{x}) +## @deftypefnx {Function File} {} corr (@var{x}, @var{y}) +## Compute matrix of correlation coefficients. +## +## If each row of @var{x} and @var{y} is an observation and each column is +## a variable, then the @w{(@var{i}, @var{j})-th} entry of +## @code{corr (@var{x}, @var{y})} is the correlation between the +## @var{i}-th variable in @var{x} and the @var{j}-th variable in @var{y}. +## @tex +## $$ +## {\rm corr}(x,y) = {{\rm cov}(x,y) \over {\rm std}(x) {\rm std}(y)} +## $$ +## @end tex +## @ifnottex +## +## @example +## corr(x,y) = cov(x,y)/(std(x)*std(y)) +## @end example +## +## @end ifnottex +## If called with one argument, compute @code{corr (@var{x}, @var{x})}, +## the correlation between the columns of @var{x}. +## @seealso{cov} +## @end deftypefn + +## Author: Kurt Hornik <hornik@wu-wien.ac.at> +## Created: March 1993 +## Adapted-By: jwe + +function retval = corr (x, y = []) + + if (nargin < 1 || nargin > 2) + print_usage (); + endif + + ## Input validation is done by cov.m. Don't repeat tests here + + ## Special case, scalar is always 100% correlated with itself + if (isscalar (x)) + if (isa (x, 'single')) + retval = single (1); + else + retval = 1; + endif + return; + endif + + ## No check for division by zero error, which happens only when + ## there is a constant vector and should be rare. + if (nargin == 2) + c = cov (x, y); + s = std (x)' * std (y); + retval = c ./ s; + else + c = cov (x); + s = sqrt (diag (c)); + retval = c ./ (s * s'); + endif + +endfunction + + +%!test +%! x = rand (10); +%! cc1 = corr (x); +%! cc2 = corr (x, x); +%! assert (size (cc1) == [10, 10] && size (cc2) == [10, 10]); +%! assert (cc1, cc2, sqrt (eps)); + +%!test +%! x = [1:3]'; +%! y = [3:-1:1]'; +%! assert (corr (x,y), -1, 5*eps) +%! assert (corr (x,flipud (y)), 1, 5*eps) +%! assert (corr ([x, y]), [1 -1; -1 1], 5*eps) + +%!test +%! x = single ([1:3]'); +%! y = single ([3:-1:1]'); +%! assert (corr (x,y), single (-1), 5*eps) +%! assert (corr (x,flipud (y)), single (1), 5*eps) +%! assert (corr ([x, y]), single ([1 -1; -1 1]), 5*eps) + +%!assert (corr (5), 1); +%!assert (corr (single(5)), single(1)); + +%% Test input validation +%!error corr (); +%!error corr (1, 2, 3); +%!error corr ([1; 2], ["A", "B"]); +%!error corr (ones (2,2,2)); +%!error corr (ones (2,2), ones (2,2,2)); +
--- a/scripts/statistics/base/cov.m +++ b/scripts/statistics/base/cov.m @@ -55,7 +55,7 @@ ## @item 1: ## normalize with @math{N}, this provides the second moment around the mean ## @end table -## @seealso{corrcoef, cor} +## @seealso{corr} ## @end deftypefn ## Author: KH <Kurt.Hornik@wu-wien.ac.at> @@ -67,7 +67,8 @@ print_usage (); endif - if (! (isnumeric (x) && isnumeric (y))) + if ( ! (isnumeric (x) || islogical (x)) + || ! (isnumeric (y) || islogical (y))) error ("cov: X and Y must be numeric matrices or vectors"); endif @@ -75,7 +76,7 @@ error ("cov: X and Y must be 2-D matrices or vectors"); endif - if (nargin == 2 && isscalar(y)) + if (nargin == 2 && isscalar (y)) opt = y; endif @@ -83,22 +84,27 @@ error ("cov: normalization OPT must be 0 or 1"); endif + ## Special case, scalar has zero covariance if (isscalar (x)) - c = 0; + if (isa (x, 'single')) + c = single (0); + else + c = 0; + endif return; endif - if (rows (x) == 1) - x = x'; + if (isrow (x)) + x = x.'; endif n = rows (x); - if (nargin == 1 || isscalar(y)) + if (nargin == 1 || isscalar (y)) x = center (x, 1); c = conj (x' * x / (n - 1 + opt)); else - if (rows (y) == 1) - y = y'; + if (isrow (y)) + y = y.'; endif if (rows (y) != n) error ("cov: X and Y must have the same number of observations"); @@ -110,17 +116,36 @@ endfunction + %!test %! x = rand (10); %! cx1 = cov (x); %! cx2 = cov (x, x); -%! assert(size (cx1) == [10, 10] && size (cx2) == [10, 10] && norm(cx1-cx2) < 1e1*eps); +%! assert(size (cx1) == [10, 10] && size (cx2) == [10, 10]); +%! assert(cx1, cx2, 1e1*eps); + +%!test +%! x = [1:3]'; +%! y = [3:-1:1]'; +%! assert (cov (x,y), -1, 5*eps) +%! assert (cov (x,flipud (y)), 1, 5*eps) +%! assert (cov ([x, y]), [1 -1; -1 1], 5*eps) + +%!test +%! x = single ([1:3]'); +%! y = single ([3:-1:1]'); +%! assert (cov (x,y), single (-1), 5*eps) +%! assert (cov (x,flipud (y)), single (1), 5*eps) +%! assert (cov ([x, y]), single ([1 -1; -1 1]), 5*eps) %!test %! x = [1:5]; %! c = cov (x); -%! assert(isscalar (c)); -%! assert(c, 2.5); +%! assert (isscalar (c)); +%! assert (c, 2.5); + +%!assert(cov (5), 0); +%!assert(cov (single(5)), single(0)); %!test %! x = [1:5]; @@ -129,13 +154,10 @@ %! c = cov (x, 1); %! assert(c, 2); -%!assert(cov (5), 0); - %% Test input validation %!error cov (); %!error cov (1, 2, 3, 4); -%!error cov ([true, true]); -%!error cov ([1, 2], [true, true]); +%!error cov ([1; 2], ["A", "B"]); %!error cov (ones (2,2,2)); %!error cov (ones (2,2), ones (2,2,2)); %!error cov (1, 3);
--- a/scripts/statistics/base/gls.m +++ b/scripts/statistics/base/gls.m @@ -82,10 +82,21 @@ if (rx != ry) error ("gls: number of rows of X and Y must be equal"); endif - if (!issquare(o) || ro != ry*cy) + if (!issquare (o) || ro != ry*cy) error ("gls: matrix O must be square matrix with rows = rows (Y) * cols (Y)"); endif + if (isinteger (x)) + x = double (x); + endif + if (isinteger (y)) + y = double (y); + endif + if (isinteger (o)) + o = double (o); + endif + + ## Start of algorithm o = o^(-1/2); z = kron (eye (cy), x); z = o * z; @@ -116,7 +127,7 @@ %! y = 3*x + 2; %! x = [x, ones(5,1)]; %! o = diag (ones (5,1)); -%! assert (gls (y,x,o), [3; 2], 50*eps) +%! assert (gls (y,x,o), [3; 2], 50*eps); %% Test input validation %!error gls ()
--- a/scripts/statistics/base/histc.m +++ b/scripts/statistics/base/histc.m @@ -61,7 +61,7 @@ error ("histc: EDGES must be real-valued, not complex"); else ## Make sure 'edges' is sorted - edges = edges (:); + edges = edges(:); if (!issorted (edges) || edges(1) > edges(end)) warning ("histc: edge values not sorted on input"); edges = sort (edges); @@ -72,10 +72,7 @@ sz = size (x); if (nargin < 3) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -103,25 +100,25 @@ ## Prepare indices idx1 = cell (1, dim-1); for k = 1:length (idx1) - idx1 {k} = 1:sz(k); + idx1{k} = 1:sz(k); endfor idx2 = cell (length (sz) - dim); for k = 1:length (idx2) - idx2 {k} = 1:sz(k+dim); + idx2{k} = 1:sz(k+dim); endfor ## Compute the histograms for k = 1:num_edges-1 b = (edges (k) <= x & x < edges (k+1)); - n (idx1 {:}, k, idx2 {:}) = sum (b, dim); + n(idx1{:}, k, idx2{:}) = sum (b, dim); if (nargout > 1) - idx (b) = k; + idx(b) = k; endif endfor b = (x == edges (end)); - n (idx1 {:}, num_edges, idx2 {:}) = sum (b, dim); + n(idx1{:}, num_edges, idx2{:}) = sum (b, dim); if (nargout > 1) - idx (b) = num_edges; + idx(b) = num_edges; endif else @@ -160,6 +157,7 @@ endfunction + %!test %! x = linspace (0, 10, 1001); %! n = histc (x, 0:10);
--- a/scripts/statistics/base/iqr.m +++ b/scripts/statistics/base/iqr.m @@ -39,7 +39,7 @@ print_usage (); endif - if (!(ismatrix (x) && isnumeric (x)) || isscalar(x)) + if (! (isnumeric (x) || islogical (x))) error ("iqr: X must be a numeric vector or matrix"); endif @@ -48,10 +48,7 @@ nel = numel (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -60,27 +57,33 @@ endif ## This code is a bit heavy, but is needed until empirical_inv - ## takes other than vector arguments. - c = sz(dim); + ## can take a matrix, rather than just a vector argument. + n = sz(dim); sz(dim) = 1; - y = zeros (sz); + if (isa (x, 'single')) + y = zeros (sz, 'single'); + else + y = zeros (sz); + endif stride = prod (sz(1:dim-1)); - for i = 1 : nel / c; + for i = 1 : nel / n; offset = i; offset2 = 0; while (offset > stride) offset -= stride; offset2++; endwhile - offset += offset2 * stride * c; - rng = [0 : c-1] * stride + offset; + offset += offset2 * stride * n; + rng = [0 : n-1] * stride + offset; - y (i) = empirical_inv (3/4, x(rng)) - empirical_inv (1/4, x(rng)); + y(i) = diff (empirical_inv ([1/4, 3/4], x(rng))); endfor endfunction + %!assert (iqr (1:101), 50); +%!assert (iqr (single(1:101)), single(50)); %%!test %%! x = [1:100]; @@ -90,5 +93,6 @@ %!error iqr (); %!error iqr (1, 2, 3); %!error iqr (1); -%!error iqr ([true, true]); +%!error iqr (['A'; 'B']); %!error iqr (1:10, 3); +
--- a/scripts/statistics/base/kendall.m +++ b/scripts/statistics/base/kendall.m @@ -74,7 +74,8 @@ print_usage (); endif - if (! (isnumeric (x) && isnumeric (y))) + if ( ! (isnumeric (x) || islogical (x)) + || ! (isnumeric (y) || islogical (y))) error ("kendall: X and Y must be numeric matrices or vectors"); endif @@ -82,14 +83,14 @@ error ("kendall: X and Y must be 2-D matrices or vectors"); endif - if (rows (x) == 1) - x = x'; + if (isrow (x)) + x = x.'; endif [n, c] = size (x); if (nargin == 2) - if (rows (y) == 1) - y = y'; + if (isrow (y)) + y = y.'; endif if (rows (y) != n) error ("kendall: X and Y must have the same number of observations"); @@ -98,22 +99,36 @@ endif endif + if (isa (x, 'single') || isa (y, 'single')) + cls = 'single'; + else + cls = 'double'; + endif r = ranks (x); - m = sign (kron (r, ones (n, 1)) - kron (ones (n, 1), r)); - tau = corrcoef (m); + m = sign (kron (r, ones (n, 1, cls)) - kron (ones (n, 1, cls), r)); + tau = corr (m); if (nargin == 2) - tau = tau (1 : c, (c + 1) : columns (x)); + tau = tau(1 : c, (c + 1) : columns (x)); endif endfunction +%!test +%! x = [1:2:10]; +%! y = [100:10:149]; +%! assert (kendall (x,y), 1, 5*eps); +%! assert (kendall (x,fliplr (y)), -1, 5*eps); + +%!assert (kendall (logical(1)), 1); +%!assert (kendall (single(1)), single(1)); + %% Test input validation %!error kendall (); %!error kendall (1, 2, 3); -%!error kendall ([true, true]); -%!error kendall (ones(1,2), [true, true]); +%!error kendall (['A'; 'B']); +%!error kendall (ones(2,1), ['A'; 'B']); %!error kendall (ones (2,2,2)); %!error kendall (ones (2,2), ones (2,2,2)); %!error kendall (ones (2,2), ones (3,2));
--- a/scripts/statistics/base/kurtosis.m +++ b/scripts/statistics/base/kurtosis.m @@ -54,7 +54,7 @@ print_usage (); endif - if (!isnumeric (x)) + if (! (isnumeric (x) || islogical (x))) error ("kurtosis: X must be a numeric vector or matrix"); endif @@ -62,10 +62,7 @@ sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -73,16 +70,14 @@ endif endif - c = sz(dim); + n = sz(dim); sz(dim) = 1; - idx = ones (1, nd); - idx(dim) = c; - x = x - repmat (mean (x, dim), idx); + x = center (x, dim); # center also promotes integer to double for next line retval = zeros (sz, class (x)); s = std (x, [], dim); + idx = find (s > 0); x = sum (x.^4, dim); - ind = find (s > 0); - retval(ind) = x(ind) ./ (c * s(ind) .^ 4) - 3; + retval(idx) = x(idx) ./ (n * s(idx) .^ 4) - 3; endfunction @@ -90,12 +85,14 @@ %!test %! x = [-1; 0; 0; 0; 1]; %! y = [x, 2*x]; -%! assert(all (abs (kurtosis (y) - [-1.4, -1.4]) < sqrt (eps))); +%! assert (kurtosis (y), [-1.4, -1.4], sqrt (eps)); + +%!assert (kurtosis (single(1)), single(0)); %% Test input validation %!error kurtosis () %!error kurtosis (1, 2, 3) -%!error kurtosis (true(1,2)) +%!error kurtosis (['A'; 'B']) %!error kurtosis (1, ones(2,2)) %!error kurtosis (1, 1.5) %!error kurtosis (1, 0)
--- a/scripts/statistics/base/logit.m +++ b/scripts/statistics/base/logit.m @@ -47,6 +47,7 @@ endfunction + %!test %! p = [0.01:0.01:0.99]; %! assert(logit (p), log (p ./ (1-p)), 25*eps)
--- a/scripts/statistics/base/mahalanobis.m +++ b/scripts/statistics/base/mahalanobis.m @@ -34,7 +34,8 @@ print_usage (); endif - if (! (isnumeric (x) && isnumeric (y))) + if ( ! (isnumeric (x) || islogical (x)) + || ! (isnumeric (y) || islogical (y))) error ("mahalanobis: X and Y must be numeric matrices or vectors"); endif @@ -49,11 +50,16 @@ error ("mahalanobis: X and Y must have the same number of columns"); endif + if (isinteger (x)) + x = double (x); + endif + xm = mean (x); ym = mean (y); - x = x - ones (xr, 1) * xm; - y = y - ones (yr, 1) * ym; + ## Center data by subtracting means + x = bsxfun (@minus, x, xm); + y = bsxfun (@minus, y, ym); w = (x' * x + y' * y) / (xr + yr - 2); @@ -63,11 +69,12 @@ endfunction + %% Test input validation %!error mahalanobis (); %!error mahalanobis (1, 2, 3); -%!error mahalanobis ([true], [true]); -%!error mahalanobis ([1, 2], [true, true]); +%!error mahalanobis ('A', 'B'); +%!error mahalanobis ([1, 2], ['A', 'B']); %!error mahalanobis (ones (2,2,2)); %!error mahalanobis (ones (2,2), ones (2,2,2)); %!error mahalanobis (ones (2,2), ones (2,3));
--- a/scripts/statistics/base/mean.m +++ b/scripts/statistics/base/mean.m @@ -69,15 +69,15 @@ error ("mean: X must be a numeric vector or matrix"); endif - need_dim = 0; + need_dim = false; if (nargin == 1) opt = "a"; - need_dim = 1; + need_dim = true; elseif (nargin == 2) if (ischar (opt1)) opt = opt1; - need_dim = 1; + need_dim = true; else dim = opt1; opt = "a"; @@ -100,22 +100,15 @@ sz = size (x); if (need_dim) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; + (dim = find (sz > 1, 1)) || (dim = 1); + else + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= nd)) + error ("mean: DIM must be an integer and a valid dimension"); endif endif - if (!(isscalar (dim) && dim == fix (dim)) - || !(1 <= dim && dim <= nd)) - error ("mean: DIM must be an integer and a valid dimension"); - endif - - if (dim > nd) - n = 1; - else - n = sz(dim); - endif + n = sz(dim); if (strcmp (opt, "a")) y = sum (x, dim) / n; @@ -129,6 +122,7 @@ endfunction + %!test %! x = -10:10; %! y = x'; @@ -137,9 +131,12 @@ %! assert(mean (y) == 0); %! assert(mean (z) == [0, 10]); +%!assert(mean (magic(3), 1), [5, 5, 5]); +%!assert(mean (magic(3), 2), [5; 5; 5]); %!assert(mean ([2 8], 'g'), 4); %!assert(mean ([4 4 2], 'h'), 3); %!assert(mean (logical ([1 0 1 1])), 0.75); +%!assert(mean (single ([1 0 1 1])), single (0.75)); %% Test input validation %!error mean ();
--- a/scripts/statistics/base/meansq.m +++ b/scripts/statistics/base/meansq.m @@ -52,7 +52,7 @@ print_usage (); endif - if (!isnumeric (x)) + if (! (isnumeric (x) || islogical (x))) error ("mean: X must be a numeric vector or matrix"); endif @@ -60,29 +60,28 @@ sz = size (x); if (nargin < 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; + (dim = find (sz > 1, 1)) || (dim = 1); + else + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= nd)) + error ("mean: DIM must be an integer and a valid dimension"); endif endif - if (!(isscalar (dim) && dim == fix (dim)) - || !(1 <= dim && dim <= nd)) - error ("mean: DIM must be an integer and a valid dimension"); - endif - - y = sumsq (x, dim) / size (x, dim); + y = sumsq (x, dim) / sz(dim); endfunction -%!assert(meansq (1:5), 11) -%!assert(meansq (magic (4)), [94.5, 92.5, 92.5, 94.5]) +%!assert(meansq (1:5), 11); +%!assert(meansq (single(1:5)), single(11)); +%!assert(meansq (magic (4)), [94.5, 92.5, 92.5, 94.5]); +%!assert(meansq (magic (4), 2), [109.5; 77.5; 77.5; 109.5]); %% Test input validation %!error meansq () %!error meansq (1, 2, 3) -%!error kurtosis ([true true]) +%!error meansq (['A'; 'B']); %!error meansq (1, ones(2,2)) %!error meansq (1, 1.5) %!error meansq (1, 0)
--- a/scripts/statistics/base/median.m +++ b/scripts/statistics/base/median.m @@ -55,18 +55,19 @@ print_usage (); endif - if (!isnumeric (x)) + if (! (isnumeric (x) || islogical (x))) error ("median: X must be a numeric vector or matrix"); endif + if (isempty (x)) + error ("median: X cannot be an empty matrix"); + endif + nd = ndims (x); sz = size (x); - if (nargin != 2) + if (nargin < 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -74,22 +75,19 @@ endif endif - if (numel (x) > 0) - n = size (x, dim); - k = floor ((n+1) / 2); - if (mod (n, 2) == 1) - retval = nth_element (x, k, dim); - else - retval = mean (nth_element (x, k:k+1, dim), dim); - endif - ## Inject NaNs where needed, to be consistent with Matlab. - retval(any (isnan (x), dim)) = NaN; + n = sz(dim); + k = floor ((n+1) / 2); + if (mod (n, 2) == 1) + retval = nth_element (x, k, dim); else - error ("median: invalid matrix argument"); + retval = mean (nth_element (x, k:k+1, dim), dim); endif + ## Inject NaNs where needed, to be consistent with Matlab. + retval(any (isnan (x), dim)) = NaN; endfunction + %!test %! x = [1, 2, 3, 4, 5, 6]; %! x2 = x'; @@ -101,13 +99,14 @@ %! assert(median ([x2, 2*x2]) == [3.5, 7]); %! assert(median ([y2, 3*y2]) == [4, 12]); +%!assert(median (single([1,2,3])), single(2)); %!assert(median ([1,2,NaN;4,5,6;NaN,8,9]), [NaN, 5, NaN]); %% Test input validation %!error median (); %!error median (1, 2, 3); %!error median ({1:5}); -%!error median (true(1,5)); +%!error median (['A'; 'B']); %!error median (1, ones(2,2)); %!error median (1, 1.5); %!error median (1, 0);
--- a/scripts/statistics/base/mode.m +++ b/scripts/statistics/base/mode.m @@ -39,18 +39,15 @@ print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("mode: X must be a numeric vector or matrix"); endif nd = ndims (x); sz = size (x); - if (nargin != 2) + if (nargin < 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == round (dim)) || !(1 <= dim && dim <= nd)) @@ -78,11 +75,11 @@ t = cat (dim, true (sz2), diff (xs, 1, dim) != 0); if (dim != 1) - t2 (permute (t != 0, perm)) = diff ([find(permute (t, perm))(:); prod(sz)+1]); + t2(permute (t != 0, perm)) = diff ([find(permute (t, perm))(:); prod(sz)+1]); f = max (ipermute (t2, perm), [], dim); xs = permute (xs, perm); else - t2 (t) = diff ([find(t)(:); prod(sz)+1]); + t2(t) = diff ([find(t)(:); prod(sz)+1]); f = max (t2, [], dim); endif @@ -90,14 +87,15 @@ if (issparse (x)) m = sparse (sz2(1), sz2(2)); else - m = zeros (sz2); + m = zeros (sz2, class (x)); endif for i = 1 : prod (sz2) - c{i} = xs (t2 (:, i) == f(i), i); - m (i) = c{i}(1); + c{i} = xs(t2(:, i) == f(i), i); + m(i) = c{i}(1); endfor endfunction + %!test %! [m, f, c] = mode (toeplitz (1:5)); %! assert (m, [1,2,2,2,1]); @@ -114,15 +112,19 @@ %! [m2, f2, c2] = mode (full (a)); %! assert (m, sparse (m2)); %! assert (f, sparse (f2)); -%! assert (c, cellfun (@(x) sparse (0), c2, 'uniformoutput', false)); +%! c_exp(1:length(a)) = { sparse (0) }; +%! assert (c ,c_exp); +%! assert (c2,c_exp ); -%!assert(mode([2,3,1,2,3,4],1),[2,3,1,2,3,4]) -%!assert(mode([2,3,1,2,3,4],2),2) -%!assert(mode([2,3,1,2,3,4]),2) +%!assert(mode ([2,3,1,2,3,4],1),[2,3,1,2,3,4]); +%!assert(mode ([2,3,1,2,3,4],2),2); +%!assert(mode ([2,3,1,2,3,4]),2); +%!assert(mode (single([2,3,1,2,3,4])), single(2)); +%!assert(mode (int8([2,3,1,2,3,4])), int8(2)); -%!assert(mode([2;3;1;2;3;4],1),2) -%!assert(mode([2;3;1;2;3;4],2),[2;3;1;2;3;4]) -%!assert(mode([2;3;1;2;3;4]),2) +%!assert(mode ([2;3;1;2;3;4],1),2); +%!assert(mode ([2;3;1;2;3;4],2),[2;3;1;2;3;4]); +%!assert(mode ([2;3;1;2;3;4]),2); %!shared x %! x(:,:,1) = toeplitz (1:3); @@ -157,7 +159,7 @@ %!error mode () %!error mode (1, 2, 3) %!error mode ({1 2 3}) -%!error mode (true(1,3)) +%!error mode (['A'; 'B']) %!error mode (1, ones(2,2)) %!error mode (1, 1.5) %!error mode (1, 0)
--- a/scripts/statistics/base/module.mk +++ b/scripts/statistics/base/module.mk @@ -3,10 +3,8 @@ statistics_base_FCN_FILES = \ statistics/base/center.m \ statistics/base/cloglog.m \ - statistics/base/cor.m \ - statistics/base/corrcoef.m \ + statistics/base/corr.m \ statistics/base/cov.m \ - statistics/base/cut.m \ statistics/base/gls.m \ statistics/base/histc.m \ statistics/base/iqr.m \ @@ -33,9 +31,9 @@ statistics/base/spearman.m \ statistics/base/statistics.m \ statistics/base/std.m \ - statistics/base/studentize.m \ statistics/base/table.m \ - statistics/base/var.m + statistics/base/var.m \ + statistics/base/zscore.m FCN_FILES += $(statistics_base_FCN_FILES)
--- a/scripts/statistics/base/moment.m +++ b/scripts/statistics/base/moment.m @@ -110,27 +110,27 @@ function m = moment (x, p, opt1, opt2) - if ((nargin < 2) || (nargin > 4)) + if (nargin < 2 || nargin > 4) print_usage (); endif - if (!isnumeric(x) || isempty(x) ) + if (!(isnumeric (x) || islogical (x)) || isempty (x)) error ("moment: X must be a non-empty numeric matrix or vector"); endif - if (!(isnumeric(p) && isscalar(p))) + if (! (isnumeric (p) && isscalar (p))) error ("moment: P must be a numeric scalar"); endif - need_dim = 0; + need_dim = false; if (nargin == 2) type = ""; - need_dim = 1; + need_dim = true; elseif (nargin == 3) if (ischar (opt1)) type = opt1; - need_dim = 1; + need_dim = true; else dim = opt1; type = ""; @@ -151,10 +151,7 @@ sz = size (x); if (need_dim) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -164,10 +161,8 @@ n = sz(dim); - if any (type == "c") - rng = ones (1, length (sz)); - rng(dim) = sz(dim); - x = x - repmat (sum (x, dim), rng) / n; + if (any (type == "c")) + x = center (x, dim); endif if any (type == "a") x = abs (x); @@ -178,11 +173,21 @@ endfunction +%!test +%! x = rand (10); +%! assert (moment (x,1), mean (x), 1e1*eps); +%! assert (moment (x,2), meansq (x), 1e1*eps); +%! assert (moment (x,1,2), mean (x,2), 1e1*eps); +%! assert (moment (x,1,'c'), mean (center (x)), 1e1*eps); +%! assert (moment (x,1,'a'), mean (abs (x)), 1e1*eps); + +%!assert (moment (single([1 2 3]),1), single(2)); + %% Test input validation %!error moment () %!error moment (1) %!error moment (1, 2, 3, 4, 5) -%!error moment ([true true], 2) +%!error moment (['A'; 'B'], 2) %!error moment (ones(2,0,3), 2) %!error moment (1, true) %!error moment (1, ones(2,2))
--- a/scripts/statistics/base/ols.m +++ b/scripts/statistics/base/ols.m @@ -100,6 +100,14 @@ error ("ols: number of rows of X and Y must be equal"); endif + if (isinteger (x)) + x = double (x); + endif + if (isinteger (y)) + y = double (y); + endif + + ## Start of algorithm z = x' * x; rnk = rank (z); @@ -118,6 +126,7 @@ endfunction + %!test %! x = [1:5]'; %! y = 3*x + 2;
--- a/scripts/statistics/base/ppplot.m +++ b/scripts/statistics/base/ppplot.m @@ -77,6 +77,7 @@ endfunction + %% Test input validation %!error ppplot (); %!error ppplot (ones(2,2));
--- a/scripts/statistics/base/prctile.m +++ b/scripts/statistics/base/prctile.m @@ -40,52 +40,48 @@ ## Author: Ben Abbott <bpabbott@mac.com> ## Description: Matlab style prctile function. -function q = prctile (x, p, dim) +function q = prctile (x, p = [], dim) if (nargin < 1 || nargin > 3) print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("prctile: X must be a numeric vector or matrix"); endif - if (!isnumeric(p)) - error ("prctile: P must be a numeric vector"); + + if (isempty (p)) + p = [0, 25, 50, 75, 100]; endif - if (nargin == 1) - p = [0, 25, 50, 75, 100]; + if (! (isnumeric (p) && isvector (p))) + error ("prctile: P must be a numeric vector"); endif nd = ndims (x); if (nargin == 2) if (nd == 2) - ## If a matrix or vector, use the 1st dimension. + ## If a matrix or vector, always use 1st dimension. dim = 1; else ## If an N-d array, find the first non-singleton dimension. - dim = find (size(v) > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); endif else - if (!(isscalar (dim) && dim == fix (dim)) || - !(1 <= dim && dim <= nd)) + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= nd)) error ("prctile: DIM must be an integer and a valid dimension"); endif endif ## Convert from percent to decimal. - p = p / 100; + p /= 100; - ## The 5th method is compatible with Matlab. - method = 5; - - q = quantile (x, p, dim, method); + q = quantile (x, p, dim); endfunction + %!test %! pct = 50; %! q = prctile (1:4, pct, 1); @@ -171,8 +167,9 @@ %% Test input validation %!error prctile () %!error prctile (1, 2, 3, 4) -%!error prctile ([true, false], 10) +%!error prctile (['A'; 'B'], 10) %!error prctile (1:10, [true, false]) +%!error prctile (1:10, ones (2,2)) %!error prctile (1, 1, 1.5) %!error prctile (1, 1, 0) %!error prctile (1, 1, 3)
--- a/scripts/statistics/base/probit.m +++ b/scripts/statistics/base/probit.m @@ -27,10 +27,18 @@ function y = probit (p) - if (nargin == 1) - y = stdnormal_inv (p); - else + + if (nargin != 1) print_usage (); endif + y = stdnormal_inv (p); + endfunction + +%!assert(probit([-1, 0, 0.5, 1, 2]), [NaN, -Inf, 0, Inf, NaN]); + +%% Test input validation +%!error probit () +%!error probit (1, 2) +
--- a/scripts/statistics/base/quantile.m +++ b/scripts/statistics/base/quantile.m @@ -90,31 +90,40 @@ ## ## Examples: ## -## @example +## @c Set example in small font to prevent overfull line +## @smallexample ## @group -## x = randi (1000, [10, 1]); # Create random empirical data in range 1-1000 -## q = quantile (x, [0, 1]); # Return minimum, maximum of empirical distribution -## q = quantile (x, [0.25 0.5 0.75]); # Return quartiles of empirical distribution +## x = randi (1000, [10, 1]); # Create empirical data in range 1-1000 +## q = quantile (x, [0, 1]); # Return minimum, maximum of distribution +## q = quantile (x, [0.25 0.5 0.75]); # Return quartiles of distribution ## @end group -## @end example +## @end smallexample ## @seealso{prctile} ## @end deftypefn ## Author: Ben Abbott <bpabbott@mac.com> ## Description: Matlab style quantile function of a discrete/continuous distribution -function q = quantile (x, p, dim = 1, method = 5) +function q = quantile (x, p = [], dim = 1, method = 5) if (nargin < 1 || nargin > 4) print_usage (); endif - if (nargin < 2) + if (! (isnumeric (x) || islogical (x))) + error ("quantile: X must be a numeric vector or matrix"); + endif + + if (isempty (p)) p = [0.00 0.25, 0.50, 0.75, 1.00]; endif - if (!(isscalar (dim) && dim == fix (dim)) || - !(1 <= dim && dim <= ndims (x))) + if (! (isnumeric (p) && isvector (p))) + error ("quantile: P must be a numeric vector"); + endif + + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= ndims (x))) error ("quantile: DIM must be an integer and a valid dimension"); endif @@ -143,6 +152,7 @@ endfunction + %!test %! p = 0.5; %! x = sort (rand (11)); @@ -282,9 +292,14 @@ %% Test input validation %!error quantile () %!error quantile (1, 2, 3, 4, 5) +%!error quantile (['A'; 'B'], 10) +%!error quantile (1:10, [true, false]) +%!error quantile (1:10, ones (2,2)) %!error quantile (1, 1, 1.5) %!error quantile (1, 1, 0) %!error quantile (1, 1, 3) +%!error quantile ((1:5)', 0.5, 1, 0) +%!error quantile ((1:5)', 0.5, 1, 10) ## For the cumulative probability values in @var{p}, compute the ## quantiles, @var{q} (the inverse of the cdf), for the sample, @var{x}. @@ -304,37 +319,35 @@ print_usage (); endif - if (!isnumeric (x)) - error ("quantile: X must be a numeric vector or matrix"); + if (isinteger (x) || islogical (x)) + x = double (x); endif - ## Save length and set shape of quantiles. - n = numel (p); + ## set shape of quantiles to column vector. p = p(:); ## Save length and set shape of samples. ## FIXME: does sort guarantee that NaN's come at the end? x = sort (x); m = sum (! isnan (x)); - mx = size (x, 1); - nx = size (x, 2); + [xr, xc] = size (x); ## Initialize output values. - inv = Inf*(-(p < 0) + (p > 1)); - inv = repmat (inv, 1, nx); + inv = Inf (class (x)) * (-(p < 0) + (p > 1)); + inv = repmat (inv, 1, xc); ## Do the work. - if (any(k = find((p >= 0) & (p <= 1)))) + if (any (k = find ((p >= 0) & (p <= 1)))) n = length (k); - p = p (k); - ## Special case. - if (mx == 1) + p = p(k); + ## Special case of 1 row. + if (xr == 1) inv(k,:) = repmat (x, n, 1); - return + return; endif ## The column-distribution indices. - pcd = kron (ones (n, 1), mx*(0:nx-1)); + pcd = kron (ones (n, 1), xr*(0:xc-1)); mm = kron (ones (n, 1), m); switch (method) case {1, 2, 3} @@ -375,7 +388,7 @@ p = kron (p, m-1) + 1; case 8 - ## Median unbiased . + ## Median unbiased. p = kron (p, m+1/3) + 1/3; case 9 @@ -387,7 +400,7 @@ endswitch ## Duplicate single values. - imm1 = mm == 1; + imm1 = (mm == 1); x(2,imm1) = x(1,imm1); ## Interval indices.
--- a/scripts/statistics/base/range.m +++ b/scripts/statistics/base/range.m @@ -37,20 +37,24 @@ function y = range (x, dim) + if (nargin < 1 || nargin > 2) + print_usage (); + endif + if (nargin == 1) y = max (x) - min (x); - elseif (nargin == 2) + else y = max (x, [], dim) - min (x, [], dim); - else - print_usage (); endif endfunction -%!assert(range (1:10), 9) -%!assert(range (magic (3)), [5, 8, 5]) -%!assert(range (magic (3), 2), [7; 4; 7]) -%!assert(range (2), 0) + +%!assert(range (1:10), 9); +%!assert(range (single(1:10)), single(9)); +%!assert(range (magic (3)), [5, 8, 5]); +%!assert(range (magic (3), 2), [7; 4; 7]); +%!assert(range (2), 0); %% Test input validation %!error range ()
--- a/scripts/statistics/base/ranks.m +++ b/scripts/statistics/base/ranks.m @@ -37,7 +37,7 @@ print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("ranks: X must be a numeric vector or matrix"); endif @@ -45,10 +45,7 @@ sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -89,18 +86,18 @@ endfunction -%!assert(ranks (1:2:10), 1:5) -%!assert(ranks (10:-2:1), 5:-1:1) -%!assert(ranks ([2, 1, 2, 4]), [2.5, 1, 2.5, 4]) -%!assert(ranks (ones(1, 5)), 3*ones(1, 5)) -%!assert(ranks (1e6*ones(1, 5)), 3*ones(1, 5)) -%!assert(ranks (rand (1, 5), 1), ones(1, 5)) +%!assert(ranks (1:2:10), 1:5); +%!assert(ranks (10:-2:1), 5:-1:1); +%!assert(ranks ([2, 1, 2, 4]), [2.5, 1, 2.5, 4]); +%!assert(ranks (ones(1, 5)), 3*ones(1, 5)); +%!assert(ranks (1e6*ones(1, 5)), 3*ones(1, 5)); +%!assert(ranks (rand (1, 5), 1), ones(1, 5)); %% Test input validation %!error ranks () %!error ranks (1, 2, 3) %!error ranks ({1, 2}) -%!error ranks (true(2,1)) +%!error ranks (['A'; 'B']) %!error ranks (1, 1.5) %!error ranks (1, 0) %!error ranks (1, 3)
--- a/scripts/statistics/base/run_count.m +++ b/scripts/statistics/base/run_count.m @@ -36,7 +36,7 @@ print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("run_count: X must be a numeric vector or matrix"); endif @@ -48,10 +48,7 @@ sz = size (x); if (nargin != 3) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) @@ -59,6 +56,7 @@ endif endif + ## Algorithm works on rows. Permute array if necessary, ipermute back at end if (dim != 1) perm = [1 : nd]; perm(1) = dim; @@ -76,7 +74,7 @@ infvec = Inf ([1, sz(2 : end)]); ind = find (diff ([infvec; x; -infvec]) < 0); - tmp(ind(2:end) - 1) = diff(ind); + tmp(ind(2:end) - 1) = diff (ind); tmp = tmp(idx{:}); sz(1) = n; @@ -86,7 +84,7 @@ retval(idx{:}) = sum (tmp == k); endfor idx{1} = n; - retval (idx{:}) = sum (tmp >= n); + retval(idx{:}) = sum (tmp >= n); if (dim != 1) retval = ipermute (retval, perm); @@ -105,7 +103,7 @@ %!error run_count (1) %!error run_count (1, 2, 3, 4) %!error run_count ({1, 2}, 3) -%!error run_count (true(3), 3) +%!error run_count (['A'; 'A'; 'B'], 3) %!error run_count (1:5, ones(2,2)) %!error run_count (1:5, 1.5) %!error run_count (1:5, -2)
--- a/scripts/statistics/base/runlength.m +++ b/scripts/statistics/base/runlength.m @@ -30,11 +30,12 @@ ## @end deftypefn function [count, value] = runlength (x) + if (nargin != 1) print_usage (); endif - if (!isnumeric (x) || !isvector (x)) + if (!(isnumeric (x) || islogical (x)) || !isvector (x)) error ("runlength: X must be a numeric vector"); endif @@ -47,8 +48,10 @@ if (nargout == 2) value = x(idx); endif + endfunction + %!assert (runlength([2 2 0 4 4 4 0 1 1 1 1]), [2 1 3 1 4]); %!assert (runlength([2 2 0 4 4 4 0 1 1 1 1]'), [2 1 3 1 4]); %!test @@ -59,5 +62,5 @@ %% Test input validation %!error runlength () %!error runlength (1, 2) -%!error runlength (true(1,2)) +%!error runlength (['A'; 'B']) %!error runlength (ones(2,2))
--- a/scripts/statistics/base/skewness.m +++ b/scripts/statistics/base/skewness.m @@ -51,7 +51,7 @@ print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("skewness: X must be a numeric vector or matrix"); endif @@ -59,10 +59,7 @@ sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == round (dim)) || !(1 <= dim && dim <= nd)) @@ -70,19 +67,18 @@ endif endif - c = sz(dim); - idx = ones (1, nd); - idx(dim) = c; - x = x - repmat (mean (x, dim), idx); + n = sz(dim); sz(dim) = 1; + x = center (x, dim); # center also promotes integer to double for next line retval = zeros (sz, class (x)); s = std (x, [], dim); - ind = find (s > 0); + idx = find (s > 0); x = sum (x .^ 3, dim); - retval(ind) = x(ind) ./ (c * s(ind) .^ 3); + retval(idx) = x(idx) ./ (n * s(idx) .^ 3); endfunction + %!assert(skewness ([-1,0,1]), 0); %!assert(skewness ([-2,0,1]) < 0); %!assert(skewness ([-1,0,2]) > 0); @@ -92,10 +88,12 @@ %! y = [x, 2*x]; %! assert(all (abs (skewness (y) - [0.75, 0.75]) < sqrt (eps))); +%!assert (skewness (single(1)), single(0)); + %% Test input validation %!error skewness () %!error skewness (1, 2, 3) -%!error skewness ([true true]) +%!error skewness (['A'; 'B']) %!error skewness (1, ones(2,2)) %!error skewness (1, 1.5) %!error skewness (1, 0)
--- a/scripts/statistics/base/spearman.m +++ b/scripts/statistics/base/spearman.m @@ -39,11 +39,12 @@ function rho = spearman (x, y = []) - if ((nargin < 1) || (nargin > 2)) + if (nargin < 1 || nargin > 2) print_usage (); endif - if (! (isnumeric (x) && isnumeric (y))) + if ( ! (isnumeric (x) || islogical (x)) + || ! (isnumeric (y) || islogical (y))) error ("spearman: X and Y must be numeric matrices or vectors"); endif @@ -51,30 +52,43 @@ error ("spearman: X and Y must be 2-D matrices or vectors"); endif - if (rows (x) == 1) - x = x'; + if (isrow (x)) + x = x.'; endif - n = rows (x); if (nargin == 1) - rho = corrcoef (ranks (x)); + rho = corr (ranks (x)); else - if (rows (y) == 1) - y = y'; + if (isrow (y)) + y = y.'; endif - if (rows (y) != n) + if (rows (x) != rows (y)) error ("spearman: X and Y must have the same number of observations"); endif - rho = corrcoef (ranks (x), ranks (y)); + rho = corr (ranks (x), ranks (y)); + endif + + ## Restore class cleared by ranks + if (isa (x, 'single') || isa (y, 'single')) + rho = single (rho); endif endfunction + +%!test +%! x = 1:10; +%! y = exp (x); +%! assert (spearman (x,y), 1, 5*eps); +%! assert (spearman (x,-y), -1, 5*eps); + +%!assert(spearman ([1 2 3], [-1 1 -2]), -0.5, 5*eps) + %% Test input validation %!error spearman (); %!error spearman (1, 2, 3); -%!error spearman ([true, true]); -%!error spearman (ones(1,2), [true, true]); +%!error spearman (['A'; 'B']); +%!error spearman (ones(1,2), {1, 2}); %!error spearman (ones (2,2,2)); %!error spearman (ones (2,2), ones (2,2,2)); %!error spearman (ones (2,2), ones (3,2));
--- a/scripts/statistics/base/statistics.m +++ b/scripts/statistics/base/statistics.m @@ -38,7 +38,7 @@ print_usage (); endif - if (!isnumeric(x)) + if (! (isnumeric (x) || islogical (x))) error ("statistics: X must be a numeric vector or matrix"); endif @@ -46,10 +46,7 @@ sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == round (dim)) || !(1 <= dim && dim <= nd)) @@ -68,16 +65,22 @@ endfunction + %!test -%! x = rand(7,5); +%! x = rand (7,5); %! s = statistics (x); -%! m = median (x); -%! assert (m, s(3,:), eps); +%! assert (min (x), s(1,:), eps); +%! assert (median (x), s(3,:), eps); +%! assert (max (x), s(5,:), eps); +%! assert (mean (x), s(6,:), eps); +%! assert (std (x), s(7,:), eps); +%! assert (skewness (x), s(8,:), eps); +%! assert (kurtosis (x), s(9,:), eps); %% Test input validation %!error statistics () %!error statistics (1, 2, 3) -%!error statistics ([true true]) +%!error statistics (['A'; 'B']) %!error statistics (1, ones(2,2)) %!error statistics (1, 1.5) %!error statistics (1, 0)
--- a/scripts/statistics/base/std.m +++ b/scripts/statistics/base/std.m @@ -67,7 +67,7 @@ print_usage (); endif - if (! (isnumeric (x))) + if (! (isnumeric (x) || islogical (x))) error ("std: X must be a numeric vector or matrix"); endif @@ -78,22 +78,27 @@ error ("std: normalization OPT must be 0 or 1"); endif + nd = ndims (x); sz = size (x); if (nargin < 3) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; + (dim = find (sz > 1, 1)) || (dim = 1); + else + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= nd)) + error ("std: DIM must be an integer and a valid dimension"); endif endif - n = size (x, dim); - if (n == 1) - retval = zeros (sz); - elseif (numel (x) > 0) + n = sz(dim); + if (n == 1 || isempty (x)) + if (isa (x, 'single')) + retval = zeros (sz, 'single'); + else + retval = zeros (sz); + endif + else retval = sqrt (sumsq (center (x, dim), dim) / (n - 1 + opt)); - else - error ("std: X must not be empty"); endif endfunction @@ -102,14 +107,21 @@ %!test %! x = ones (10, 2); %! y = [1, 3]; -%! assert(std (x) == [0, 0] && abs (std (y) - sqrt (2)) < sqrt (eps)); -%! assert (std (x, 0, 3), zeros (10, 2)) -%! assert (std (ones (3, 1, 2), 0, 2), zeros (3, 1, 2)) +%! assert(std (x) == [0, 0]); +%! assert(std (y), sqrt (2), sqrt (eps)); +%! assert(std (x, 0, 2), zeros (10, 1)); + +%!assert(std (ones (3, 1, 2), 0, 2), zeros (3, 1, 2)); +%!assert(std ([1 2], 0), sqrt(2)/2, 5*eps); +%!assert(std ([1 2], 1), 0.5, 5*eps); +%!assert(std(1), 0); +%!assert(std(single(1)), single(0)); +%!assert(std([]), []); +%!assert(std(ones (1,3,0,2)), ones (1,3,0,2)); %% Test input validation %!error std (); %!error std (1, 2, 3, 4); -%!error std (true(1,2)) +%!error std (['A'; 'B']) %!error std (1, -1); -%!error std ([], 1);
--- a/scripts/statistics/base/table.m +++ b/scripts/statistics/base/table.m @@ -60,6 +60,7 @@ endfunction + %% Test input validation %!error table () %!error table (1, 2, 3)
--- a/scripts/statistics/base/var.m +++ b/scripts/statistics/base/var.m @@ -64,7 +64,7 @@ print_usage (); endif - if (!isnumeric (x)) + if (! (isnumeric (x) || islogical (x))) error ("var: X must be a numeric vector or matrix"); endif @@ -75,16 +75,25 @@ error ("var: normalization OPT must be 0 or 1"); endif + nd = ndims (x); + sz = size (x); if (nargin < 3) - dim = find (size (x) > 1, 1); - if (isempty (dim)) - dim = 1; + ## Find the first non-singleton dimension. + (dim = find (sz > 1, 1)) || (dim = 1); + else + if (!(isscalar (dim) && dim == fix (dim)) + || !(1 <= dim && dim <= nd)) + error ("var: DIM must be an integer and a valid dimension"); endif endif - n = size (x, dim); + n = sz(dim); if (n == 1) - retval = zeros (size (x), class (x)); + if (isa (x, 'single')) + retval = zeros (sz, 'single'); + else + retval = zeros (sz); + endif elseif (numel (x) > 0) retval = sumsq (center (x, dim), dim) / (n - 1 + opt); else @@ -93,15 +102,17 @@ endfunction -%!assert (var (13), 0) -%!assert (var ([1,2,3]), 1) -%!assert (var ([1,2,3], 1), 2/3, eps) -%!assert (var ([1,2,3], [], 1), [0,0,0]) + +%!assert(var (13), 0); +%!assert(var (single(13)), single(0)); +%!assert(var ([1,2,3]), 1); +%!assert(var ([1,2,3], 1), 2/3, eps); +%!assert(var ([1,2,3], [], 1), [0,0,0]); %% Test input validation %!error var () %!error var (1,2,3,4) -%!error var (true(1,2)) +%!error var (['A'; 'B']) %!error var (1, -1); %!error var ([],1)
copy from scripts/statistics/base/studentize.m copy to scripts/statistics/base/zscore.m --- a/scripts/statistics/base/studentize.m +++ b/scripts/statistics/base/zscore.m @@ -17,8 +17,8 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} studentize (@var{x}) -## @deftypefnx {Function File} {} studentize (@var{x}, @var{dim}) +## @deftypefn {Function File} {} zscore (@var{x}) +## @deftypefnx {Function File} {} zscore (@var{x}, @var{dim}) ## If @var{x} is a vector, subtract its mean and divide by its standard ## deviation. ## @@ -31,58 +31,54 @@ ## Author: KH <Kurt.Hornik@wu-wien.ac.at> ## Description: Subtract mean and divide by standard deviation -function t = studentize (x, dim) +function z = zscore (x, dim) if (nargin != 1 && nargin != 2) print_usage (); endif - if (! isnumeric(x)) - error ("studentize: X must be a numeric vector or matrix"); - endif - - if (isinteger (x)) - x = double (x); + if (! (isnumeric (x) || islogical (x))) + error ("zscore: X must be a numeric vector or matrix"); endif nd = ndims (x); sz = size (x); if (nargin != 2) ## Find the first non-singleton dimension. - dim = find (sz > 1, 1); - if (isempty (dim)) - dim = 1; - endif + (dim = find (sz > 1, 1)) || (dim = 1); else if (!(isscalar (dim) && dim == fix (dim)) || !(1 <= dim && dim <= nd)) - error ("studentize: DIM must be an integer and a valid dimension"); + error ("zscore: DIM must be an integer and a valid dimension"); endif endif - c = sz(dim); - if (c == 0) - t = x; + n = sz(dim); + if (n == 0) + z = x; else - idx = ones (1, nd); - idx(dim) = c; - t = x - repmat (mean (x, dim), idx); - t = t ./ repmat (max (cat (dim, std(t, [], dim), ! any (t, dim)), [], dim), idx); + x = center (x, dim); # center also promotes integer to double for next line + z = zeros (sz, class (x)); + s = std (x, [], dim); + s(s==0) = 1; + z = bsxfun (@rdivide, x, s); endif endfunction -%!assert(studentize ([1,2,3]), [-1,0,1]) -%!assert(studentize (int8 ([1,2,3])), [-1,0,1]) -#%!assert(studentize (ones (3,2,0,2)), zeros (3,2,0,2)) -%!assert(studentize ([2,0,-2;0,2,0;-2,-2,2]), [1,0,-1;0,1,0;-1,-1,1]) + +%!assert(zscore ([1,2,3]), [-1,0,1]) +%!assert(zscore (single([1,2,3])), single([-1,0,1])) +%!assert(zscore (int8([1,2,3])), [-1,0,1]) +%!assert(zscore (ones (3,2,2,2)), zeros (3,2,2,2)) +%!assert(zscore ([2,0,-2;0,2,0;-2,-2,2]), [1,0,-1;0,1,0;-1,-1,1]) %% Test input validation -%!error studentize () -%!error studentize (1, 2, 3) -%!error studentize ([true true]) -%!error studentize (1, ones(2,2)) -%!error studentize (1, 1.5) -%!error studentize (1, 0) -%!error studentize (1, 3) +%!error zscore () +%!error zscore (1, 2, 3) +%!error zscore (['A'; 'B']) +%!error zscore (1, ones(2,2)) +%!error zscore (1, 1.5) +%!error zscore (1, 0) +%!error zscore (1, 3)
--- a/scripts/statistics/distributions/logistic_inv.m +++ b/scripts/statistics/distributions/logistic_inv.m @@ -31,7 +31,11 @@ print_usage (); endif - inv = zeros (size (x)); + if (isa (x, 'single')) + inv = zeros (size (x), 'single'); + else + inv = zeros (size (x)); + endif k = find ((x < 0) | (x > 1) | isnan (x)); if (any (k))
--- a/scripts/statistics/tests/cor_test.m +++ b/scripts/statistics/tests/cor_test.m @@ -91,7 +91,7 @@ m = method (1); if (m == "p") - r = cor (x, y); + r = corr (x, y); df = n - 2; t.method = "Pearson's product moment correlation"; t.params = df;
--- a/scripts/statistics/tests/wilcoxon_test.m +++ b/scripts/statistics/tests/wilcoxon_test.m @@ -23,7 +23,7 @@ ## @var{y}) == 1/2. Under the null, the test statistic @var{z} ## approximately follows a standard normal distribution when @var{n} > 25. ## -## @strong{Warning}: This function assumes a normal distribution for @var{z} +## @strong{Caution:} This function assumes a normal distribution for @var{z} ## and thus is invalid for @var{n} @leq{} 25. ## ## With the optional argument string @var{alt}, the alternative of
--- a/scripts/strings/deblank.m +++ b/scripts/strings/deblank.m @@ -18,10 +18,22 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} deblank (@var{s}) -## Remove trailing blanks and nulls from @var{s}. If @var{s} +## Remove trailing whitespace and nulls from @var{s}. If @var{s} ## is a matrix, @var{deblank} trims each row to the length of longest -## string. If @var{s} is a cell array, operate recursively on each -## element of the cell array. +## string. If @var{s} is a cell array of strings, operate recursively on each +## string element. +## +## Examples: +## @example +## @group +## deblank (" abc ") +## @result{} " abc" +## +## deblank ([" abc "; " def "]) +## @result{} [" abc " ; " def"] +## @end group +## @end example +## @seealso{strtrim} ## @end deftypefn ## Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at> @@ -33,53 +45,34 @@ print_usage (); endif - char_arg = ischar (s); - - if (char_arg || isnumeric (s)) + if (ischar (s)) - if (! isempty (s)) - if (char_arg) - k = find (! isspace (s) & s != "\0"); - else - warning ("deblank: expecting character string argument"); - k = find (s != 0); - endif - - if (isempty (k)) - s = resize (s, 0, 0); - else - s = s(:,1:ceil (max (k) / rows (s))); - endif + k = find (! isspace (s) & s != "\0"); + if (isempty (s) || isempty (k)) + s = ""; + else + s = s(:,1:ceil (max (k) / rows (s))); endif - elseif (iscell(s)) + elseif (iscellstr (s)) - s = cellfun (@deblank, s, "uniformoutput", false); + s = regexprep (s, "[\\s\v\\0]+$", ''); else - error ("deblank: expecting character string argument"); + error ("deblank: S argument must be a string or cellstring"); endif endfunction -%!assert (strcmp (deblank (" f o o "), " f o o")); -%!assert (deblank ([]), []) -%!assert (deblank ({}), {}) -%!assert (deblank (""), "") - -%!assert (deblank ([0,0,0]), []) +%!assert (strcmp (deblank (" f o o \0"), " f o o")); %!assert (deblank (' '), '') %!assert (deblank (" "), "") - -%!assert (typeinfo (deblank (" ")), "string") -%!assert (typeinfo (deblank (' ')), "sq_string") +%!assert (deblank (""), "") +%!assert (deblank ({}), {}) -%!assert (deblank ([1,2,0]), [1,2]) -%!assert (deblank ([1,2,0,32]), [1,2,0,32]) +%!error <Invalid call to deblank> deblank (); +%!error <Invalid call to deblank> deblank ("foo", "bar"); +%!error <argument must be a string> deblank (1); +%!error <argument must be a string> deblank ({[]}); -%!assert (deblank (int8 ([1,2,0])), int8 ([1,2])) - -%!error deblank (); - -%!error deblank ("foo", "bar");
--- a/scripts/strings/index.m +++ b/scripts/strings/index.m @@ -62,13 +62,13 @@ if (strcmp (direction, "last")) if (iscell (f)) - n = cellfun (@min, f); + n = cellfun ("min", f); else n = f(end); endif elseif (strcmp (direction, "first")) if (iscell (f)) - n = cellfun (@max, f); + n = cellfun ("max", f); else n = f(1); endif
--- a/scripts/strings/mat2str.m +++ b/scripts/strings/mat2str.m @@ -28,7 +28,7 @@ ## scalar then both real and imaginary parts of the matrix are printed ## to the same precision. Otherwise @code{@var{n} (1)} defines the ## precision of the real part and @code{@var{n} (2)} defines the -## precision of the imaginary part. The default for @var{n} is 17. +## precision of the imaginary part. The default for @var{n} is 15. ## ## If the argument 'class' is given, then the class of @var{x} is ## included in the string in such a way that the eval will result in the @@ -56,13 +56,13 @@ if (nargin < 2 || isempty (n)) ## Default precision - n = 17; + n = 15; endif if (nargin < 3) if (ischar (n)) cls = n; - n = 17; + n = 15; else cls = ""; endif @@ -137,3 +137,4 @@ %!assert (mat2str (true), "true"); %!assert (mat2str (false), "false"); %!assert (mat2str (logical (eye (2))), "[true,false;false,true]"); +%!assert (mat2str (0.7), "0.7")
--- a/scripts/strings/strcat.m +++ b/scripts/strings/strcat.m @@ -61,14 +61,14 @@ elseif (nargin > 1) ## Convert to cells of strings uo = "uniformoutput"; - reals = cellfun (@isreal, varargin); + reals = cellfun ("isreal", varargin); if (any (reals)) - varargin(reals) = cellfun (@char, varargin(reals), uo, false); + varargin(reals) = cellfun ("char", varargin(reals), uo, false); endif - chars = cellfun (@ischar, varargin); + chars = cellfun ("isclass", varargin, "char"); allchar = all (chars); - varargin(chars) = cellfun (@cellstr, varargin(chars), uo, false); - if (! all (cellfun (@iscell, varargin))) + varargin(chars) = cellfun ("cellstr", varargin(chars), uo, false); + if (! all (cellfun ("isclass", varargin, "cell"))) error ("strcat: inputs must be strings or cells of strings"); endif @@ -81,7 +81,7 @@ endif ## Cellfun handles everything for us. - st = cellfun (@horzcat, varargin{:}, uo, false); + st = cellfun ("horzcat", varargin{:}, uo, false); if (allchar) ## If all inputs were strings, return strings.
--- a/scripts/strings/strmatch.m +++ b/scripts/strings/strmatch.m @@ -19,13 +19,15 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} strmatch (@var{s}, @var{A}, "exact") -## Return indices of entries of @var{A} that match the string @var{s}. -## The second argument @var{A} may be a string matrix or a cell array of -## strings. If the third argument @code{"exact"} is not given, then +## @deftypefn {Function File} {} strmatch (@var{s}, @var{A}) +## @deftypefnx {Function File} {} strmatch (@var{s}, @var{A}, "exact") +## Return indices of entries of @var{A} which begin with the string @var{s}. +## The second argument @var{A} must be a string, character matrix, or a cell +## array of strings. If the third argument @code{"exact"} is not given, then ## @var{s} only needs to match @var{A} up to the length of @var{s}. -## Trailing whitespace is ignored. -## Results are returned as a column vector. +## Trailing spaces and nulls in @var{s} and @var{A} are ignored when matching. +## option. +## ## For example: ## ## @example @@ -33,13 +35,16 @@ ## strmatch ("apple", "apple juice") ## @result{} 1 ## -## strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]) +## strmatch ("apple", ["apple "; "apple juice"; "an apple"]) ## @result{} [1; 2] ## -## strmatch ("apple", @{"apple pie"; "apple juice"; "tomato"@}) -## @result{} [1; 2] +## strmatch ("apple", ["apple "; "apple juice"; "an apple"], "exact") +## @result{} [1] ## @end group ## @end example +## +## @strong{Caution:} @code{strmatch} is scheduled for deprecation. Use +## @code{strcmpi} or @code{strncmpi} in all new code. ## @seealso{strfind, findstr, strcmp, strncmp, strcmpi, strncmpi, find} ## @end deftypefn @@ -52,29 +57,19 @@ print_usage (); endif - if (! ischar (s)) + if (! ischar (s) || (! isempty (s) && ! isvector (s))) error ("strmatch: S must be a string"); + elseif (! (ischar (A) || iscellstr (A))) + error ("strmatch: A must be a string or cell array of strings"); endif - ## Truncate trailing whitespace. - s = strtrimr (s); - + ## Trim blanks and nulls from search string + s = regexprep (s, "[ \\0]+$", ''); len = length (s); exact = nargin == 3 && ischar (exact) && strcmp (exact, "exact"); - if (iscell (A)) - if (len > 0) - idx = find (strncmp (s, A, len)); - else - idx = find (strcmp (s, A)); - endif - if (exact) - ## We can't just use strcmp, because we need to ignore whitespace. - B = cellfun (@strtrimr, A(idx), "uniformoutput", false); - idx = idx (strcmp (s, B)); - endif - elseif (ischar (A)) + if (ischar (A)) [nr, nc] = size (A); if (len > nc) idx = []; @@ -82,34 +77,43 @@ match = all (bsxfun (@eq, A(:,1:len), s), 2); if (exact) AA = A(:,len+1:nc); - match &= all (AA == "\0" | AA == " ", 2); + match &= all (AA == " " | AA == "\0", 2); endif idx = find (match); endif else - error ("strmatch: A must be a string or cell array of strings"); + if (len > 0) + idx = find (strncmp (s, A, len)); + else + idx = find (strcmp (s, A)); + endif + if (exact) + ## We can't just use strcmp, because we need to ignore spaces at end. + B = regexprep (A(idx), "[ \\0]+$", ''); + idx = idx(strcmp (s, B)); + endif endif endfunction -## Removes nuls and blanks from the end of the array -function s = strtrimr (s) - blnks = s == "\0" | s == " "; - i = find (blnks, 1, "last"); - if (i && all (blnks(i:end))) - s = s(1:i-1); - endif -endfunction -%!error <Invalid call to strmatch> strmatch(); -%!error <Invalid call to strmatch> strmatch("a", "aaa", "exact", 1); %!assert (strmatch("a", {"aaa", "bab", "bbb"}), 1); %!assert (strmatch ("apple", "apple juice"), 1); -%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), -%! [1; 2]); -%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), -%! [1; 2]); +%!assert (strmatch ("apple", ["apple pie"; "apple juice"; "an apple"]), [1; 2]); +%!assert (strmatch ("apple", {"apple pie"; "apple juice"; "tomato"}), [1; 2]); %!assert (strmatch ("apple pie", "apple"), []); -%!assert (strmatch ("a b", {"a b", "a c", "c d"})); -%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4]) -%!assert (strmatch ('', { '', '% comment line', 'var a = 5', ''}, 'exact'), [1,4]) +%!assert (strmatch ("a ", "a"), 1); +%!assert (strmatch ("a", "a \0", "exact"), 1); +%!assert (strmatch ("a b", {"a b", "a c", "c d"}), 1); +%!assert (strmatch ("", {"", "foo", "bar", ""}), [1, 4]); +%!assert (strmatch ('', { '', '% comment', 'var a = 5', ''}, 'exact'), [1,4]); + +%% Test input validation +%!error <Invalid call to strmatch> strmatch(); +%!error <Invalid call to strmatch> strmatch("a"); +%!error <Invalid call to strmatch> strmatch("a", "aaa", "exact", 1); +%!error <S must be a string> strmatch(1, "aaa"); +%!error <S must be a string> strmatch(char ("a", "bb"), "aaa"); +%!error <A must be a string> strmatch("a", 1); +%!error <A must be a string> strmatch("a", {"hello", [1]}); +
--- a/scripts/strings/strsplit.m +++ b/scripts/strings/strsplit.m @@ -28,7 +28,7 @@ function s = strsplit (p, sep, strip_empty = false) if (nargin < 2 || nargin > 3 || ! ischar (p) || rows (p) > 1 - || ! ischar (sep) || ! islogical (strip_empty)) + || ! ischar (sep) || ! isscalar (strip_empty)) print_usage (); endif
--- a/scripts/strings/strtrim.m +++ b/scripts/strings/strtrim.m @@ -18,20 +18,21 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} strtrim (@var{s}) -## Remove leading and trailing whitespace and nulls from @var{s}. If +## Remove leading and trailing whitespace from @var{s}. If ## @var{s} is a matrix, @var{strtrim} trims each row to the length of -## longest string. If @var{s} is a cell array, operate recursively on -## each element of the cell array. For example: +## longest string. If @var{s} is a cell array of strings, operate recursively +## on each string element. For example: ## ## @example ## @group ## strtrim (" abc ") -## @result{} "abc" +## @result{} "abc" ## ## strtrim ([" abc "; " def "]) -## @result{} ["abc "; " def"] +## @result{} ["abc " ; " def"] ## @end group ## @end example +## @seealso{deblank} ## @end deftypefn ## Author: John Swensen <jpswensen@jhu.edu> @@ -46,19 +47,19 @@ if (ischar (s)) - k = find (! isspace (s) & s != "\0"); + k = find (! isspace (s)); if (isempty (s) || isempty (k)) s = ""; else s = s(:, ceil (min (k) / rows (s)):ceil (max (k) / rows (s))); endif - elseif (iscell(s)) + elseif (iscellstr (s)) - s = regexprep (s, "^[\\s\v\\0]+|[\\s\v\\0]+$", ''); + s = regexprep (s, "^[\\s\v]+|[\\s\v]+$", ''); else - error ("strtrim: S argument must be a string"); + error ("strtrim: S argument must be a string or cellstring"); endif endfunction @@ -73,4 +74,5 @@ %!error <Invalid call to strtrim> strtrim (); %!error <Invalid call to strtrim> strtrim ("abc", "def"); %!error <argument must be a string> strtrim (1); +%!error <argument must be a string> strtrim ({[]});
--- a/scripts/strings/untabify.m +++ b/scripts/strings/untabify.m @@ -52,64 +52,72 @@ function s = untabify (t, tw = 8, dblank = false) - if (nargin > 0 && nargin < 4 && (ischar (t) || iscellstr (t))) - if (ischar (t)) - s = replace_tabs (t, tw); - else - s = cellfun (@(str) replace_tabs (str, tw), t, "uniformoutput", false); - endif - if (dblank) - s = deblank (s); - endif - else - print_usage (); - endif + if (nargin < 1 || nargin > 3) + print_usage (); + elseif (! (ischar (t) || iscellstr (t))) + error ("untabify: T must be a string or cellstring"); + endif + + if (ischar (t)) + s = replace_tabs (t, tw); + else + s = cellfun (@(str) replace_tabs (str, tw), t, "uniformoutput", false); + endif + + if (dblank) + s = deblank (s); + endif endfunction function s = replace_tabs (t, tw) - if (ndims (t) == 2) - if (isempty (t)) - s = t; - else - nr = rows (t); - sc = cell (nr, 1); - for j = 1:nr - n = 1:numel(t(j,:)); - m = find (t(j,:) == "\t"); - t(j,m) = " "; - for i = 1:numel(m) - k = tw * ceil (n(m(i)) / tw); - dn = k - n(m(i)); - n(m(i):end) += dn; - endfor - sc{j} = blanks (n(end)); - sc{j}(n) = t(j,:); - endfor - s = char (sc); - endif - else - error ("untabify: character strings to untabify must have 2 dimensions"); - endif + + if (ndims (t) != 2) + error ("untabify: character strings to untabify must have 2 dimensions"); + endif + + if (isempty (t)) + s = t; + else + nr = rows (t); + sc = cell (nr, 1); + for j = 1:nr + n = 1:numel(t(j,:)); + m = find (t(j,:) == "\t"); + t(j,m) = " "; + for i = 1:numel(m) + k = tw * ceil (n(m(i)) / tw); + dn = k - n(m(i)); + n(m(i):end) += dn; + endfor + sc{j} = blanks (n(end)); + sc{j}(n) = t(j,:); + endfor + s = char (sc); + endif + endfunction + %!test %! s = untabify ("\thello\t"); -%! assert (isequal (s, horzcat (blanks(8), "hello "))) +%! assert (s, [blanks(8) "hello" blanks(3)]); + +%!test +%! s = untabify ("\thello\t", 2); +%! assert (s, [blanks(2) "hello" blanks(1)]); %!test %! s = untabify ("\thello\t", 4, true); -%! assert (isequal (s, horzcat (blanks(4), "hello"))) +%! assert (s, [blanks(4) "hello"]); -%!test -%! s = untabify ("\thello\t", 2, true); -%! assert (isequal (s, horzcat (blanks(2), "hello"))) +%!assert (isempty (untabify (""))) %!test -%! s = untabify (""); -%! assert (isempty (s)) +%! s = char (randi ([97 97+25], 3, 3)); +%! assert (untabify (s), char (untabify (cellstr (s)))); -%!test -%! s = char (fix (100 + 10*rand (3,3))); -%! assert (isequal (untabify (s), untabify ({s}){1})) +%!error untabify () +%!error untabify (1,2,3,4) +%!error <must be a string> untabify (1)
--- a/scripts/strings/validatestring.m +++ b/scripts/strings/validatestring.m @@ -118,7 +118,7 @@ ## are the matches a substring of each other, if so, choose the ## shortest. If not, raise an error. match_idx = find (matches); - match_l = cellfun (@length, strarray(match_idx)); + match_l = cellfun ("length", strarray(match_idx)); longest_idx = find (match_l == max (match_l), 1); shortest_idx = find (match_l == min (match_l), 1); longest = strarray(match_idx)(longest_idx);
--- a/scripts/testfun/demo.m +++ b/scripts/testfun/demo.m @@ -17,35 +17,39 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Command} {} demo @var{name} @var{n} +## @deftypefn {Command} {} demo @var{name} +## @deftypefnx {Command} {} demo @var{name} @var{n} +## @deftypefnx {Function File} {} demo ('@var{name}') ## @deftypefnx {Function File} {} demo ('@var{name}', @var{n}) ## -## Runs any examples associated with the function '@var{name}'. +## Run example code block @var{n} associated with the function @var{name}. +## If @var{n} is not specified, all examples are run. +## ## Examples are stored in the script file, or in a file with the same -## name but no extension somewhere on your path. To keep them separate -## from the usual script code, all lines are prefixed by @code{%!}. Each -## example is introduced by the keyword 'demo' flush left to the prefix, -## with no intervening spaces. The remainder of the example can contain -## arbitrary Octave code. For example: +## name but no extension located on Octave's load path. To keep examples +## separate from regular script code, all lines are prefixed by @code{%!}. Each +## example must also be introduced by the keyword 'demo' flush left to the +## prefix with no intervening spaces. The remainder of the example can +## contain arbitrary Octave code. For example: ## ## @example ## @group -## %!demo -## %! t=0:0.01:2*pi; x = sin(t); -## %! plot(t,x) -## %! %------------------------------------------------- -## %! % the figure window shows one cycle of a sine wave +## %!demo +## %! t=0:0.01:2*pi; x = sin(t); +## %! plot (t,x) +## %! %------------------------------------------------- +## %! % the figure window shows one cycle of a sine wave ## @end group ## @end example ## ## Note that the code is displayed before it is executed, so a simple -## comment at the end suffices. It is generally not necessary to use -## disp or printf within the demo. +## comment at the end suffices for labeling what is being shown. It is +## generally not necessary to use @code{disp} or @code{printf} within the demo. ## ## Demos are run in a function environment with no access to external -## variables. This means that all demos in your function must use -## separate initialization code. Alternatively, you can combine your -## demos into one huge demo, with the code: +## variables. This means that every demo must have separate initialization +## code. Alternatively, all demos can be combined into a single large demo +## with the code ## ## @example ## %! input("Press <enter> to continue: ","s"); @@ -53,11 +57,13 @@ ## ## @noindent ## between the sections, but this is discouraged. Other techniques -## include using multiple plots by saying figure between each, or -## using subplot to put multiple plots in the same window. +## to avoid multiple initialization blocks include using multiple plots +## with a new @code{figure} command between each plot, or using @code{subplot} +## to put multiple plots in the same window. ## -## Also, since demo evaluates inside a function context, you cannot -## define new functions inside a demo. Instead you will have to +## Also, because demo evaluates within a function context, you cannot +## define new functions inside a demo. If you must have function blocks, +## rather than just anonymous functions or inline functions, you will have to ## use @code{eval(example('function',n))} to see them. Because eval only ## evaluates one line, or one statement if the statement crosses ## multiple lines, you must wrap your demo in "if 1 <demo stuff> endif" @@ -73,6 +79,7 @@ ## %! endif ## @end group ## @end example +## ## @seealso{test, example} ## @end deftypefn @@ -88,20 +95,19 @@ if (nargin < 2) n = 0; - elseif (strcmp ("char", class (n))) + elseif (ischar (n)) n = str2double (n); endif [code, idx] = test (name, "grabdemo"); - if (length (idx) == 0) - warning ("demo not available for %s", name); + if (isempty (idx)) + warning ("no demo available for %s", name); return; elseif (n >= length (idx)) warning ("only %d demos available for %s", length (idx) - 1, name); return; endif - if (n > 0) doidx = n; else @@ -123,7 +129,7 @@ __demo__; catch ## Let the programmer know which demo failed. - printf ("%s example %d: failed\n%s\n", name, doidx(i), __error_text__); + printf ("%s example %d: failed\n%s\n", name, doidx(i), lasterr ()); end_try_catch clear __demo__; endfor @@ -132,6 +138,6 @@ %!demo %! t=0:0.01:2*pi; x = sin(t); -%! plot(t,x) +%! plot (t,x) %! %------------------------------------------------- %! % the figure window shows one cycle of a sine wave
--- a/scripts/testfun/example.m +++ b/scripts/testfun/example.m @@ -17,16 +17,18 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Command} {} example @var{name} @var{n} +## @deftypefn {Command} {} example @var{name} +## @deftypefnx {Command} {} example @var{name} @var{n} +## @deftypefnx {Function File} {} example ('@var{name}') ## @deftypefnx {Function File} {} example ('@var{name}', @var{n}) -## @deftypefnx {Function File} {[@var{x}, @var{idx}] =} example ('@var{name}', @var{n}) +## @deftypefnx {Function File} {[@var{s}, @var{idx}] =} example (@dots{}) ## -## Display the code for example @var{n} associated with the function -## '@var{name}', but do not run it. If @var{n} is not given, all examples +## Display the code for example @var{n} associated with the function +## '@var{name}', but do not run it. If @var{n} is not specified, all examples ## are displayed. ## -## Called with output arguments, the examples are returned in the form of -## a string @var{x}, with @var{idx} indicating the ending position of the +## When called with output arguments, the examples are returned in the form of +## a string @var{s}, with @var{idx} indicating the ending position of the ## various examples. ## ## See @code{demo} for a complete explanation. @@ -41,7 +43,7 @@ if (nargin < 2) n = 0; - elseif (strcmp ("char", class (n))) + elseif (ischar (n)) n = str2double (n); endif @@ -65,15 +67,16 @@ else doidx = 1:length(idx)-1; endif - if (length (idx) == 0) - warning ("example not available for %s", name); + if (isempty (idx)) + warning ("no example available for %s", name); + return; elseif (n >= length(idx)) warning ("only %d examples available for %s", length(idx)-1, name); - doidx = []; + return; endif for i = 1:length (doidx) - block = code (idx(doidx(i)):idx(doidx(i)+1)-1); + block = code(idx(doidx(i)):idx(doidx(i)+1)-1); printf ("%s example %d:%s\n\n", name, doidx(i), block); endfor endif @@ -82,17 +85,18 @@ %!## warning: don't modify the demos without modifying the tests! %!demo -%! example('example'); +%! example ('example'); %!demo -%! t=0:0.01:2*pi; x=sin(t); -%! plot(t,x) +%! t=0:0.01:2*pi; x = sin(t); +%! plot (t,x) -%!assert (example('example',1), "\n example('example');"); +%!assert (example('example',1), "\n example ('example');"); %!test -%! [code, idx] = example('example'); +%! [code, idx] = example ('example'); %! assert (code, ... -%! "\n example('example');\n t=0:0.01:2*pi; x=sin(t);\n plot(t,x)") -%! assert (idx, [1, 22, 59]); +%! "\n example ('example');\n t=0:0.01:2*pi; x = sin(t);\n plot (t,x)") +%! assert (idx, [1, 23, 63]); +%% Test input validation %!error example; -%!error example('example',3,5) +%!error example('example', 3, 5)
--- a/scripts/testfun/rundemos.m +++ b/scripts/testfun/rundemos.m @@ -35,6 +35,7 @@ if (is_absolute_filename (directory)) dirs = {directory}; else + directory = regexprep (directory, ['\',filesep(),'$'], ""); fullname = find_dir_in_path (directory); if (! isempty (fullname)) dirs = {fullname};
--- a/scripts/testfun/runtests.m +++ b/scripts/testfun/runtests.m @@ -35,6 +35,7 @@ if (is_absolute_filename (directory)) dirs = {directory}; else + directory = regexprep (directory, ['\',filesep(),'$'], ""); fullname = find_dir_in_path (directory); if (! isempty (fullname)) dirs = {fullname};
--- a/scripts/testfun/test.m +++ b/scripts/testfun/test.m @@ -132,7 +132,7 @@ __rundemo = 0; __verbose = 0; __demo_code = ""; - __demo_idx = 1; + __demo_idx = []; elseif (strcmp (__flag, "explain")) fprintf (__fid, "# %s new test file\n", __signal_file); fprintf (__fid, "# %s no tests in file\n", __signal_empty); @@ -286,7 +286,7 @@ input ("Press <enter> to continue: ", "s"); catch __success = 0; - __msg = sprintf ("%sdemo failed\n%s", __signal_fail, __error_text__); + __msg = sprintf ("%sdemo failed\n%s", __signal_fail, lasterr ()); end_try_catch clear __test__; @@ -359,7 +359,7 @@ catch __success = 0; __msg = sprintf ("%stest failed: syntax error\n%s", - __signal_fail, __error_text__); + __signal_fail, lasterr ()); end_try_catch endif __code = ""; @@ -389,7 +389,7 @@ catch __success = 0; __msg = sprintf ("%stest failed: syntax error\n%s", - __signal_fail, __error_text__); + __signal_fail, lasterr ()); end_try_catch if (__success) @@ -488,13 +488,13 @@ eval (sprintf ("%s__test__(%s);", __shared_r, __shared)); catch if (strcmp (__type, "xtest")) - __msg = sprintf ("%sknown failure\n%s", __signal_fail, __error_text__); + __msg = sprintf ("%sknown failure\n%s", __signal_fail, lasterr ()); __xfail++; else - __msg = sprintf ("%stest failed\n%s", __signal_fail, __error_text__); + __msg = sprintf ("%stest failed\n%s", __signal_fail, lasterr ()); __success = 0; endif - if (isempty (__error_text__)) + if (isempty (lasterr ())) error ("empty error text, probably Ctrl-C --- aborting"); endif end_try_catch
--- a/scripts/time/datenum.m +++ b/scripts/time/datenum.m @@ -50,7 +50,7 @@ ## Days can be fractional. ## @end itemize ## -## @strong{Warning:} this function does not attempt to handle Julian +## @strong{Caution:} this function does not attempt to handle Julian ## calendars so dates before Octave 15, 1582 are wrong by as much ## as eleven days. Also be aware that only Roman Catholic countries ## adopted the calendar in 1582. It took until 1924 for it to be
--- a/scripts/time/now.m +++ b/scripts/time/now.m @@ -37,7 +37,11 @@ function t = now () - t = datenum (clock ()); + if (nargin == 0) + t = datenum (clock ()); + else + print_usage (); + endif ## The following doesn't work (e.g., one hour off on 2005-10-04): ## @@ -50,3 +54,8 @@ ## changing by an hour the offset from CUT for part of the year. endfunction + +%!error now (1); +%!assert (isnumeric (now ())); +%!assert (now () > 0); +%!assert (now () <= now ());
--- a/src/DLD-FUNCTIONS/__contourc__.cc +++ b/src/DLD-FUNCTIONS/__contourc__.cc @@ -333,3 +333,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__delaunayn__.cc +++ b/src/DLD-FUNCTIONS/__delaunayn__.cc @@ -226,3 +226,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__dispatch__.cc +++ b/src/DLD-FUNCTIONS/__dispatch__.cc @@ -129,3 +129,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__dsearchn__.cc +++ b/src/DLD-FUNCTIONS/__dsearchn__.cc @@ -108,3 +108,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__fltk_uigetfile__.cc +++ b/src/DLD-FUNCTIONS/__fltk_uigetfile__.cc @@ -130,4 +130,11 @@ return retval; } +/* + +## No test needed for internal helper function. +%!assert (1) + +*/ + #endif
--- a/src/DLD-FUNCTIONS/__glpk__.cc +++ b/src/DLD-FUNCTIONS/__glpk__.cc @@ -854,3 +854,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__init_fltk__.cc +++ b/src/DLD-FUNCTIONS/__init_fltk__.cc @@ -648,13 +648,13 @@ begin (); { + canvas = new + OpenGL_fltk (0, 0, ww , hh - status_h, number ()); + uimenu = new fltk_uimenu(0, 0, ww, menu_h); uimenu->hide (); - canvas = new - OpenGL_fltk (0, 0, ww , hh - status_h, number ()); - bottom = new Fl_Box (0, hh - status_h, @@ -861,8 +861,11 @@ void show_canvas (void) { - canvas->show (); - canvas->make_current (); + if (fp.is_visible ()) + { + canvas->show (); + canvas->make_current (); + } } void hide_canvas (void) @@ -1837,10 +1840,10 @@ case figure::properties::ID_MENUBAR: figure_manager::toggle_menubar_visibility (ov.string_value (), fp.menubar_is("figure")); break; - case figure::properties::ID_NAME: 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;
--- a/src/DLD-FUNCTIONS/__lin_interpn__.cc +++ b/src/DLD-FUNCTIONS/__lin_interpn__.cc @@ -355,3 +355,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__magick_read__.cc +++ b/src/DLD-FUNCTIONS/__magick_read__.cc @@ -531,6 +531,13 @@ return output; } +/* + +## No test needed for internal helper function. +%!assert (1) + +*/ + #ifdef HAVE_MAGICK static void @@ -916,6 +923,13 @@ return retval; } +/* + +## No test needed for internal helper function. +%!assert (1) + +*/ + #ifdef HAVE_MAGICK template<class T> @@ -1134,6 +1148,13 @@ return retval; } +/* + +## No test needed for internal helper function. +%!assert (1) + +*/ + #undef GET_PARAM // Determine the file formats supported by GraphicsMagick. This is @@ -1193,3 +1214,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__pchip_deriv__.cc +++ b/src/DLD-FUNCTIONS/__pchip_deriv__.cc @@ -147,3 +147,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__qp__.cc +++ b/src/DLD-FUNCTIONS/__qp__.cc @@ -528,3 +528,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/__voronoi__.cc +++ b/src/DLD-FUNCTIONS/__voronoi__.cc @@ -248,3 +248,10 @@ return retval; } + +/* + +## No test needed for internal helper function. +%!assert (1) + +*/
--- a/src/DLD-FUNCTIONS/bsxfun.cc +++ b/src/DLD-FUNCTIONS/bsxfun.cc @@ -312,15 +312,18 @@ DEFUN_DLD (bsxfun, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} bsxfun (@var{f}, @var{A}, @var{B})\n\ -Apply a binary function @var{f} element-by-element to two matrix arguments\n\ -@var{A} and @var{B}. @var{f} is a function handle, inline function, or\n\ -string containing the name of the function to evaluate.\n\ -The function @var{f} must be capable of accepting two column-vector\n\ -arguments of equal length, or one column vector argument and a scalar.\n\ +The binary singleton expansion function applier does what its name\n\ +suggests: applies a binary function @var{f} element-by-element to two\n\ +array arguments @var{A} and @var{B}, and expands as necessary\n\ +singleton dimensions in either input argument. @var{f} is a function\n\ +handle, inline function, or string containing the name of the function\n\ +to evaluate. The function @var{f} must be capable of accepting two\n\ +column-vector arguments of equal length, or one column vector argument\n\ +and a scalar.\n\ \n\ -The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\ -singleton dimensions of the matrices will be expanded to the same\n\ -dimensionality as the other matrix.\n\ +The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\ +singleton dimensions of the arrays will be expanded to the same\n\ +dimensionality as the other array.\n\ @seealso{arrayfun, cellfun}\n\ @end deftypefn") { @@ -766,4 +769,45 @@ %!assert (bsxfun (@max, a, b), max (aa, bb)); %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0)); %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0)); + +%% Test automatic bsxfun +% +%!test +%! funs = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, \ +%! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, \ +%! @and, @or, @xor }; +%! +%! float_types = {@single, @double}; +%! int_types = {@int8, @int16, @int32, @int64, \ +%! @uint8, @uint16, @uint32, @uint64}; +%! +%! x = rand (3)*10-5; +%! y = rand (3,1)*10-5; +%! +%! for i=1:length (funs) +%! for j = 1:length(float_types) +%! for k = 1:length(int_types) +%! +%! fun = funs{i}; +%! f_type = float_types{j}; +%! i_type = int_types{k}; +%! +%! assert (bsxfun (fun, f_type (x), i_type (y)), \ +%! fun (f_type(x), i_type (y))); +%! assert (bsxfun (fun, f_type (y), i_type (x)), \ +%! fun (f_type(y), i_type (x))); +%! +%! assert (bsxfun (fun, i_type (x), i_type (y)), \ +%! fun (i_type (x), i_type (y))); +%! assert (bsxfun (fun, i_type (y), i_type (x)), \ +%! fun (i_type (y), i_type (x))); +%! +%! assert (bsxfun (fun, f_type (x), f_type (y)), \ +%! fun (f_type (x), f_type (y))); +%! assert (bsxfun (fun, f_type(y), f_type(x)), \ +%! fun (f_type (y), f_type (x))); +%! endfor +%! endfor +%! endfor +%! */
--- a/src/DLD-FUNCTIONS/cellfun.cc +++ b/src/DLD-FUNCTIONS/cellfun.cc @@ -58,6 +58,8 @@ #include "ov-uint32.h" #include "ov-uint64.h" +#include "ov-fcn-handle.h" + static octave_value_list get_output_list (octave_idx_type count, octave_idx_type nargout, const octave_value_list& inputlist, @@ -122,8 +124,10 @@ @item ndims\n\ Return the number of dimensions of each element.\n\ \n\ -@item prodofsize\n\ -Return the product of dimensions of each element.\n\ +@item numel\n\ +@itemx prodofsize\n\ +Return the number of elements contained within each cell element. The\n\ +number is the product of the dimensions of the object at each cell element.\n\ \n\ @item size\n\ Return the size along the @var{k}-th dimension.\n\ @@ -142,7 +146,7 @@ \n\ @example\n\ @group\n\ -cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\ +cellfun (\"atan2\", @{1, 0@}, @{0, 1@})\n\ @result{}ans = [1.57080 0.00000]\n\ @end group\n\ @end example\n\ @@ -177,7 +181,7 @@ \n\ @example\n\ @group\n\ -cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\ +cellfun (\"tolower\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\ \"UniformOutput\",false)\n\ @result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\ @end group\n\ @@ -200,7 +204,7 @@ @example\n\ @group\n\ function y = foo (s, x), y = NaN; endfunction\n\ -cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\ +cellfun (\"factorial\", @{-1,2@}, 'ErrorHandler', @@foo)\n\ @result{} ans = [NaN 2]\n\ @end group\n\ @end example\n\ @@ -220,6 +224,7 @@ } octave_value func = args(0); + bool symbol_table_lookup = false; if (! args(1).is_cell ()) { @@ -337,6 +342,8 @@ func = symbol_table::find_function (name); if (func.is_undefined ()) error ("cellfun: invalid function NAME: %s", name.c_str ()); + + symbol_table_lookup = true; } } } @@ -347,6 +354,30 @@ if (func.is_function_handle () || func.is_inline_function () || func.is_function ()) { + + // The following is an optimisation because the symbol table can + // give a more specific function class, so this can result in + // fewer polymorphic function calls as the function gets called + // for each value of the array. + if (! symbol_table_lookup ) + { + if (func.is_function_handle ()) + { + octave_fcn_handle* f = func.fcn_handle_value (); + + // Overloaded function handles need to check the type of + // the arguments for each element of the array, so they + // cannot be optimised this way. + if (f -> is_overloaded ()) + goto nevermind; + } + octave_value f = symbol_table::find_function (func.function_value () + -> name ()); + if (f.is_defined ()) + func = f; + } + nevermind: + unwind_protect frame; frame.protect_var (buffer_error_messages);
--- a/src/DLD-FUNCTIONS/chol.cc +++ b/src/DLD-FUNCTIONS/chol.cc @@ -493,9 +493,6 @@ %!testif HAVE_CHOLMOD %! Ainv3 = cholinv(sparse(A)); %! assert (norm(Ainv-Ainv3),0,1e-10) -%!testif HAVE_CHOLMOD -%! Ainv4 = spcholinv(sparse(A)); -%! assert (norm(Ainv-Ainv4),0,1e-10) */
--- a/src/DLD-FUNCTIONS/config-module.awk +++ b/src/DLD-FUNCTIONS/config-module.awk @@ -1,4 +1,7 @@ BEGIN { + FS = "|"; + nfiles = 0; + print "## DO NOT EDIT -- generated from module-files by config-module.awk"; print "" print "EXTRA_DIST += \\" @@ -6,9 +9,14 @@ print " DLD-FUNCTIONS/config-module.awk \\" print " DLD-FUNCTIONS/module-files" print "" - nfiles = 0; -} { - files[++nfiles] = $1; +} +/^#.*/ { next; } +{ + nfiles++; + files[nfiles] = $1; + cppflags[nfiles] = $2; + ldflags[nfiles] = $3; + libraries[nfiles] = $4; } END { sep = " \\\n"; print "DLD_FUNCTIONS_SRC = \\"; @@ -22,9 +30,9 @@ sep = " \\\n"; print "DLD_FUNCTIONS_LIBS = $(DLD_FUNCTIONS_SRC:.cc=.la)"; print ""; - print "octlib_LTLIBRARIES += $(DLD_FUNCTIONS_LIBS)"; + print "if AMCOND_ENABLE_DYNAMIC_LINKING"; print ""; - print "if AMCOND_ENABLE_DYNAMIC_LINKING"; + print "octlib_LTLIBRARIES += $(DLD_FUNCTIONS_LIBS)"; print ""; print "## Use stamp files to avoid problems with checking timestamps"; print "## of symbolic links"; @@ -41,18 +49,28 @@ print "\t touch $(@F)"; print ""; } + print "else"; + print ""; + print "noinst_LTLIBRARIES = $(DLD_FUNCTIONS_LIBS)"; + print ""; print "endif"; - print ""; 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]); - printf ("DLD_FUNCTIONS_%s_la_LDFLAGS = @NO_UNDEFINED_LDFLAG@ -module\n", - basename); - printf ("DLD_FUNCTIONS_%s_la_LIBADD = $(OCT_LINK_DEPS)\n", basename); + 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 = liboctinterp.la ../liboctave/liboctave.la ../libcruft/libcruft.la %s $(OCT_LINK_DEPS)\n", + basename, libraries[i]); } - print ""; - }
--- a/src/DLD-FUNCTIONS/dot.cc +++ b/src/DLD-FUNCTIONS/dot.cc @@ -238,6 +238,17 @@ /* +%! assert(dot ([1, 2], [2, 3]), 11); + +%!test +%! x = [2, 1; 2, 1]; +%! y = [-0.5, 2; 0.5, -2]; +%! assert(dot (x, y), [0 0]); + +%!test +%! x = [ 1+i, 3-i; 1-i, 3-i]; +%! assert(dot (x, x), [4, 20]); + */ DEFUN_DLD (blkmm, args, , @@ -344,3 +355,14 @@ return retval; } + +/* + +%!test +%! x(:,:,1) = [1 2; 3 4]; +%! x(:,:,2) = [1 1; 1 1]; +%! z(:,:,1) = [7 10; 15 22]; +%! z(:,:,2) = [2 2; 2 2]; +%! assert(blkmm (x,x),z); + +*/
--- a/src/DLD-FUNCTIONS/eigs.cc +++ b/src/DLD-FUNCTIONS/eigs.cc @@ -323,6 +323,7 @@ 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; @@ -399,7 +400,8 @@ else acm = (args(0).complex_matrix_value()); a_is_complex = true; - symmetric = false; // ARAPACK doesn't special case complex symmetric + symmetric = false; // ARPACK doesn't special case complex symmetric + sym_tested = true; } else { @@ -407,19 +409,17 @@ { asmm = (args(0).sparse_matrix_value()); a_is_sparse = true; - symmetric = asmm.is_symmetric(); } else { amm = (args(0).matrix_value()); - symmetric = amm.is_symmetric(); } } } // 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.. + // 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 ())) { @@ -481,10 +481,13 @@ { octave_value tmp; - // issym is ignored if A is not a function + // issym is ignored for complex matrix inputs tmp = map.getfield ("issym"); - if (tmp.is_defined () && have_a_fun) - symmetric = tmp.double_value () != 0.; + 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"); @@ -543,6 +546,15 @@ 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)
--- a/src/DLD-FUNCTIONS/filter.cc +++ b/src/DLD-FUNCTIONS/filter.cc @@ -104,16 +104,17 @@ return y; } - octave_idx_type si_dim = 0; - for (octave_idx_type i = 0; i < x_dims.length (); i++) + for (octave_idx_type i = 1; i < dim; i++) { - if (i == dim) - continue; - - if (x_dims(i) == 1) - continue; - - if (si_dims(++si_dim) != x_dims(i)) + if (si_dims(i) != x_dims(i-1)) + { + error ("filter: dimensionality of SI and X must agree"); + return y; + } + } + for (octave_idx_type i = dim+1; i < x_dims.length (); i++) + { + if (si_dims(i) != x_dims(i)) { error ("filter: dimensionality of SI and X must agree"); return y; @@ -456,19 +457,10 @@ } else { - dim_vector si_dims = args (3).dims (); - bool si_is_vector = true; - for (int i = 0; i < si_dims.length (); i++) - if (si_dims(i) != 1 && si_dims(i) < si_dims.numel ()) - { - si_is_vector = false; - break; - } - si = args(3).float_complex_array_value (); - if (si_is_vector) - si = si.reshape (dim_vector (1, si.numel ())); + if (si.is_vector () && x.is_vector ()) + si = si.reshape (dim_vector (si.numel (), 1)); } if (! error_state) @@ -513,19 +505,10 @@ } else { - dim_vector si_dims = args (3).dims (); - bool si_is_vector = true; - for (int i = 0; i < si_dims.length (); i++) - if (si_dims(i) != 1 && si_dims(i) < si_dims.numel ()) - { - si_is_vector = false; - break; - } - si = args(3).complex_array_value (); - if (si_is_vector) - si = si.reshape (dim_vector (1, si.numel ())); + if (si.is_vector () && x.is_vector ()) + si = si.reshape (dim_vector (si.numel (), 1)); } if (! error_state) @@ -573,19 +556,10 @@ } else { - dim_vector si_dims = args (3).dims (); - bool si_is_vector = true; - for (int i = 0; i < si_dims.length (); i++) - if (si_dims(i) != 1 && si_dims(i) < si_dims.numel ()) - { - si_is_vector = false; - break; - } - si = args(3).float_array_value (); - if (si_is_vector) - si = si.reshape (dim_vector (1, si.numel ())); + if (si.is_vector () && x.is_vector ()) + si = si.reshape (dim_vector (si.numel (), 1)); } if (! error_state) @@ -630,19 +604,10 @@ } else { - dim_vector si_dims = args (3).dims (); - bool si_is_vector = true; - for (int i = 0; i < si_dims.length (); i++) - if (si_dims(i) != 1 && si_dims(i) < si_dims.numel ()) - { - si_is_vector = false; - break; - } - si = args(3).array_value (); - if (si_is_vector) - si = si.reshape (dim_vector (1, si.numel ())); + if (si.is_vector () && x.is_vector ()) + si = si.reshape (dim_vector (si.numel (), 1)); } if (! error_state) @@ -749,8 +714,20 @@ %! %!assert(filter (1, ones(10,1)/10, []), []); %!assert(filter (1, ones(10,1)/10, zeros(0,10)), zeros(0,10)); +%!assert(filter (1, ones(10,1)/10, single (1:5)), repmat (single (10), 1, 5)); +%% Test using initial conditions +%!assert(filter([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2]); +%!assert(filter([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2]); %!assert(filter([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18]); -%!assert(filter (1, ones(10,1)/10, single (1:5)), repmat (single (10), 1, 5)); -%% Should put some tests of the "DIM" parameter in here. +%!error (filter([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]')); +%!assert(filter([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2), [2 6; 3 13; 5 21]); +%% Test of DIM parameter +%!test +%! x = ones (2, 1, 3, 4); +%! x(1,1,:,:) = [1 2 3 4; 5 6 7 8; 9 10 11 12]; +%! y0 = [1 1 6 2 15 3 2 1 8 2 18 3 3 1 10 2 21 3 4 1 12 2 24 3]; +%! y0 = reshape (y0, size (x)); +%! y = filter([1 1 1], 1, x, [], 3); +%! assert (y, y0); */
--- a/src/DLD-FUNCTIONS/givens.cc +++ b/src/DLD-FUNCTIONS/givens.cc @@ -203,3 +203,13 @@ return retval; } + +/* + +%!assert (givens (1,1), [1, 1; -1, 1]/sqrt(2), 2*eps); +%!assert (givens (1,0), eye(2)); +%!assert (givens (0,1), [0, 1; -1 0]); +%!error givens(1); +%!error givens() + +*/
--- a/src/DLD-FUNCTIONS/kron.cc +++ b/src/DLD-FUNCTIONS/kron.cc @@ -264,3 +264,15 @@ return retval; } + +/* + +%!test +%! x = ones(2); +%! assert( kron (x, x), ones (4)); + +%!test +%! z = [1, 2, 3, 4; 1, 2, 3, 4; 1, 2, 3, 4]; +%! assert( kron (1:4, ones (3, 1)), z) + +*/
--- a/src/DLD-FUNCTIONS/module-files +++ b/src/DLD-FUNCTIONS/module-files @@ -1,40 +1,41 @@ +# FILE|CPPFLAGS|LDFLAGS|LIBRARIES __contourc__.cc -__delaunayn__.cc +__delaunayn__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) __dispatch__.cc __dsearchn__.cc -__fltk_uigetfile__.cc -__glpk__.cc -__init_fltk__.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) __lin_interpn__.cc -__magick_read__.cc +__magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) __pchip_deriv__.cc __qp__.cc -__voronoi__.cc -amd.cc +__voronoi__.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) +amd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) balance.cc besselj.cc betainc.cc bsxfun.cc -ccolamd.cc +ccolamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) cellfun.cc -chol.cc -colamd.cc +chol.cc|$(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(QRUPDATE_LDFLAGS) $(SPARSE_XLDFLAGS)|$(QRUPDATE_LIBS) $(SPARSE_XLIBS) +colamd.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) colloc.cc conv2.cc -convhulln.cc +convhulln.cc|$(QHULL_CPPFLAGS)|$(QHULL_LDFLAGS)|$(QHULL_LIBS) daspk.cc dasrt.cc dassl.cc det.cc dlmread.cc -dmperm.cc +dmperm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) dot.cc eig.cc -eigs.cc -fft.cc -fft2.cc -fftn.cc -fftw.cc +eigs.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) $(LAPACK_LIBS) $(BLAS_LIBS) +fft.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) +fft2.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) +fftn.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) +fftw.cc|$(FFTW_XCPPFLAGS)|$(FFTW_XLDFLAGS)|$(FFTW_XLIBS) filter.cc find.cc gammainc.cc @@ -58,13 +59,13 @@ nproc.cc onCleanup.cc pinv.cc -qr.cc +qr.cc|$(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(QRUPDATE_LDFLAGS) $(SPARSE_XLDFLAGS)|$(QRUPDATE_LIBS) $(SPARSE_XLIBS) quad.cc quadcc.cc -qz.cc +qz.cc|||$(LAPACK_LIBS) $(BLAS_LIBS) rand.cc rcond.cc -regexp.cc +regexp.cc|$(REGEX_CPPFLAGS)|$(REGEX_LDFLAGS)|$(REGEX_LIBS) schur.cc spparms.cc sqrtm.cc @@ -73,10 +74,10 @@ sub2ind.cc svd.cc syl.cc -symbfact.cc -symrcm.cc +symbfact.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) +symrcm.cc|$(SPARSE_XCPPFLAGS)|$(SPARSE_XLDFLAGS)|$(SPARSE_XLIBS) time.cc tril.cc tsearch.cc typecast.cc -urlwrite.cc +urlwrite.cc|$(CURL_CPPFLAGS)|$(CURL_LDFLAGS)|$(CURL_LIBS)
--- a/src/DLD-FUNCTIONS/qr.cc +++ b/src/DLD-FUNCTIONS/qr.cc @@ -76,6 +76,8 @@ "-*- 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\ @@ -188,7 +190,7 @@ \n\ @example\n\ @group\n\ -[@var{C},@var{R}] = spqr (@var{A},@var{B})\n\ +[@var{C}, @var{R}] = qr (@var{A}, @var{B})\n\ x = @var{R} \\ @var{C}\n\ @end group\n\ @end example\n\
--- a/src/DLD-FUNCTIONS/quadcc.cc +++ b/src/DLD-FUNCTIONS/quadcc.cc @@ -50,8 +50,7 @@ int depth, rdepth, ndiv; } cquad_ival; -/* Some constants and matrices that we'll need. - */ +/* Some constants and matrices that we'll need. */ static const double xi[33] = { -1., -0.99518472667219688624, -0.98078528040323044912, @@ -1473,9 +1472,7 @@ } - -/* The actual integration routine. - */ +/* The actual integration routine. */ DEFUN_DLD (quadcc, args, nargout, "-*- texinfo -*-\n\ @@ -1545,6 +1542,7 @@ @seealso{quad, quadv, quadl, quadgk, trapz, dblquad, triplequad}\n\ @end deftypefn") { + octave_value_list retval; /* Some constants that we will need. */ static const int n[4] = { 4, 8, 16, 32 }; @@ -1563,11 +1561,11 @@ double a, b, tol, iivals[cquad_heapsize], *sing; /* Variables needed for transforming the integrand. */ - int wrap = 0; + bool wrap = false; double xw; /* Stuff we will need to call the integrand. */ - octave_value_list fargs, retval; + octave_value_list fargs, fvals; /* Actual variables (as opposed to constants above). */ double m, h, ml, hl, mr, hr, temp; @@ -1580,48 +1578,49 @@ /* Parse the input arguments. */ - if (nargin < 1) + if (nargin < 3) { - error - ("quadcc: first argument (integrand) of type function handle required"); - return octave_value_list (); + print_usage (); + return retval; } + + if (args(0).is_function_handle () || args(0).is_inline_function ()) + fcn = args(0).function_value (); else { - if (args (0).is_function_handle () || args (0).is_inline_function ()) - fcn = args (0).function_value (); - else - { - error ("quadcc: first argument (integrand) must be a function handle or an inline function"); - return octave_value_list(); - } + std::string fcn_name = unique_symbol_name ("__quadcc_fcn_"); + std::string fname = "function y = "; + fname.append (fcn_name); + fname.append ("(x) y = "); + fcn = extract_function (args(0), "quadcc", fcn_name, fname, + "; endfunction"); } - if (nargin < 2 || !args (1).is_real_scalar ()) + if (!args(1).is_real_scalar ()) { - error ("quadcc: second argument (left interval edge) must be a single real scalar"); - return octave_value_list (); + error ("quadcc: lower limit of integration (A) must be a single real scalar"); + return retval; } else - a = args (1).double_value (); + a = args(1).double_value (); - if (nargin < 3 || !args (2).is_real_scalar ()) + if (!args(2).is_real_scalar ()) { - error ("quadcc: third argument (right interval edge) must be a single real scalar"); - return octave_value_list (); + error ("quadcc: upper limit of integration (B) must be a single real scalar"); + return retval; } else - b = args (2).double_value (); + b = args(2).double_value (); - if (nargin < 4) + if (nargin < 4 || args(3).is_empty ()) tol = 1.0e-6; - else if (!args (3).is_real_scalar ()) + else if (!args(3).is_real_scalar () || args(3).double_value () <= 0) { - error ("quadcc: fourth argument (tolerance) must be a single real scalar"); - return octave_value_list (); + error ("quadcc: tolerance (TOL) must be a single real scalar > 0"); + return retval; } else - tol = args (3).double_value (); + tol = args(3).double_value (); if (nargin < 5) { @@ -1629,20 +1628,21 @@ iivals[0] = a; iivals[1] = b; } - else if (!(args (4).is_real_scalar () || args (4).is_real_matrix ())) + else if (!(args(4).is_real_scalar () || args(4).is_real_matrix ())) { - error ("quadcc: fifth argument (singularities) must be a vector of real values"); - return octave_value_list (); + error ("quadcc: list of singularities (SING) must be a vector of real values"); + return retval; } else { - nivals = 1 + args (4).length (); - if ( nivals > cquad_heapsize ) { - error ("quadcc: maximum number of singular points is limited to %i", - cquad_heapsize-1); - return octave_value_list(); + nivals = 1 + args(4).length (); + if (nivals > cquad_heapsize) + { + error ("quadcc: maximum number of singular points is limited to %i", + cquad_heapsize-1); + return retval; } - sing = args (4).array_value ().fortran_vec (); + sing = args(4).array_value ().fortran_vec (); iivals[0] = a; for (i = 0; i < nivals - 2; i++) iivals[i + 1] = sing[i]; @@ -1652,7 +1652,7 @@ /* If a or b are +/-Inf, transform the integral. */ if (xisinf (a) || xisinf (b)) { - wrap = 1; + wrap = true; for (i = 0; i <= nivals; i++) if (xisinf (iivals[i])) iivals[i] = copysign (1.0, iivals[i]); @@ -1688,19 +1688,18 @@ for (i = 0; i <= n[3]; i++) ex (i) = m + xi[i] * h; } - fargs (0) = ex; - retval = feval (fcn, fargs, 1); - if (retval.length () != 1 || !retval (0).is_real_matrix ()) + fargs(0) = ex; + fvals = feval (fcn, fargs, 1); + if (fvals.length () != 1 || !fvals(0).is_real_matrix ()) { - error - ("quadcc: integrand must return a single, real-valued vector"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector"); + return retval; } - Matrix effex = retval (0).matrix_value (); + Matrix effex = fvals(0).matrix_value (); if (effex.length () != ex.length ()) { - error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input"); + return retval; } for (i = 0; i <= n[3]; i++) { @@ -1809,18 +1808,18 @@ for (i = 0; i < n[d] / 2; i++) ex (i) = m + xi[(2 * i + 1) * skip[d]] * h; } - fargs (0) = ex; - retval = feval (fcn, fargs, 1); - if (retval.length () != 1 || !retval (0).is_real_matrix ()) + fargs(0) = ex; + fvals = feval (fcn, fargs, 1); + if (fvals.length () != 1 || !fvals(0).is_real_matrix ()) { - error ("quadcc: integrand must return a single, real-valued vector"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector"); + return retval; } - Matrix effex = retval (0).matrix_value (); + Matrix effex = fvals(0).matrix_value (); if (effex.length () != ex.length ()) { - error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input"); + return retval; } neval += effex.length (); for (i = 0; i < n[d] / 2; i++) @@ -1957,18 +1956,18 @@ for (i = 0; i < n[0] - 1; i++) ex (i) = ml + xi[(i + 1) * skip[0]] * hl; } - fargs (0) = ex; - retval = feval (fcn, fargs, 1); - if (retval.length () != 1 || !retval (0).is_real_matrix ()) + fargs(0) = ex; + fvals = feval (fcn, fargs, 1); + if (fvals.length () != 1 || !fvals(0).is_real_matrix ()) { - error ("quadcc: integrand must return a single, real-valued vector"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector"); + return retval; } - Matrix effex = retval (0).matrix_value (); + Matrix effex = fvals(0).matrix_value (); if (effex.length () != ex.length ()) { - error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input"); + return retval; } neval += effex.length (); for (i = 0; i < n[0] - 1; i++) @@ -2053,18 +2052,18 @@ for (i = 0; i < n[0] - 1; i++) ex (i) = mr + xi[(i + 1) * skip[0]] * hr; } - fargs (0) = ex; - retval = feval (fcn, fargs, 1); - if (retval.length () != 1 || !retval (0).is_real_matrix ()) + fargs(0) = ex; + fvals = feval (fcn, fargs, 1); + if (fvals.length () != 1 || !fvals(0).is_real_matrix ()) { - error ("quadcc: integrand must return a single, real-valued vector"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector"); + return retval; } - Matrix effex = retval (0).matrix_value (); + Matrix effex = fvals(0).matrix_value (); if (effex.length () != ex.length ()) { - error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); - return octave_value_list (); + error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input"); + return retval; } neval += effex.length (); for (i = 0; i < n[0] - 1; i++) @@ -2234,11 +2233,39 @@ } */ /* Clean up and present the results. */ - retval (0) = igral; + if (nargout > 2) + retval(2) = neval; if (nargout > 1) - retval (1) = err; - if (nargout > 2) - retval (2) = neval; + retval(1) = err; + retval(0) = igral; /* All is well that ends well. */ return retval; } + + +/* + +%!assert (quadcc(@sin,-pi,pi), 0, 1e-6) +%!assert (quadcc(inline('sin'),-pi,pi), 0, 1e-6) +%!assert (quadcc('sin',-pi,pi), 0, 1e-6) + +%!assert (quadcc(@sin,-pi,0), -2, 1e-6) +%!assert (quadcc(@sin,0,pi), 2, 1e-6) +%!assert (quadcc(@(x) 1./sqrt(x), 0, 1), 2, 1e-6) +%!assert (quadcc(@(x) 1./(sqrt(x).*(x+1)), 0, Inf), pi, 1e-6) + +%!assert (quadcc (@(x) exp(-x .^ 2), -Inf, Inf), sqrt(pi), 1e-6) +%!assert (quadcc (@(x) exp(-x .^ 2), -Inf, 0), sqrt(pi)/2, 1e-6) + +%% Test input validation +%!error (quadcc ()) +%!error (quadcc (@sin)) +%!error (quadcc (@sin, 0)) +%!error (quadcc (@sin, ones(2), pi)) +%!error (quadcc (@sin, -i, pi)) +%!error (quadcc (@sin, 0, ones(2))) +%!error (quadcc (@sin, 0, i)) +%!error (quadcc (@sin, 0, pi, 0)) +%!error (quadcc (@sin, 0, pi, 1e-6, [ i ])) + +*/
--- a/src/DLD-FUNCTIONS/rand.cc +++ b/src/DLD-FUNCTIONS/rand.cc @@ -177,20 +177,17 @@ octave_idx_type base = NINTbig (r.base ()); octave_idx_type incr = NINTbig (r.inc ()); - octave_idx_type lim = NINTbig (r.limit ()); - if (base < 0 || lim < 0) - error ("%s: all dimensions must be positive", fcn); - else + for (octave_idx_type i = 0; i < n; i++) { - for (octave_idx_type i = 0; i < n; i++) - { - dims(i) = base; - base += incr; - } + //Negative dimensions are treated as zero for Matlab + //compatibility + dims(i) = base >= 0 ? base : 0; + base += incr; + } - goto gen_matrix; - } + goto gen_matrix; + } else error ("%s: all elements of range must be integers", @@ -208,15 +205,10 @@ for (octave_idx_type i = 0; i < len; i++) { + //Negative dimensions are treated as zero for Matlab + //compatibility octave_idx_type elt = iv(i); - - if (elt < 0) - { - error ("%s: all dimensions must be positive", fcn); - goto done; - } - - dims(i) = iv(i); + dims(i) = elt >=0 ? elt : 0; } goto gen_matrix; @@ -278,13 +270,14 @@ for (int i = 0; i < nargin; i++) { - dims(i) = args(idx+i).int_value (); - + octave_idx_type elt = args(idx+i).int_value (); if (error_state) { error ("%s: expecting integer arguments", fcn); goto done; } + //Negative is zero for Matlab compatibility + dims(i) = elt >= 0 ? elt : 0; } goto gen_matrix;
--- a/src/DLD-FUNCTIONS/rcond.cc +++ b/src/DLD-FUNCTIONS/rcond.cc @@ -85,3 +85,12 @@ return retval; } + +/* + +%!assert( rcond (eye (2)), 1) +%!assert( rcond (ones (2)), 0) +%!assert( rcond ([1 1; 2 1]), 1/9) +%!assert( rcond (magic (4)), 0, eps) + +*/
--- a/src/DLD-FUNCTIONS/sqrtm.cc +++ b/src/DLD-FUNCTIONS/sqrtm.cc @@ -49,22 +49,20 @@ bool singular = false; - /* - * the following code is equivalent to this triple loop: - * - * n = rows (T); - * for j = 1:n - * T(j,j) = sqrt (T(j,j)); - * for i = j-1:-1:1 - * T(i,j) /= (T(i,i) + T(j,j)); - * k = 1:i-1; - * T(k,j) -= T(k,i) * T(i,j); - * endfor - * endfor - * - * this is an in-place, cache-aligned variant of the code - * given in Higham's paper. - */ + // The following code is equivalent to this triple loop: + // + // n = rows (T); + // for j = 1:n + // T(j,j) = sqrt (T(j,j)); + // for i = j-1:-1:1 + // T(i,j) /= (T(i,i) + T(j,j)); + // k = 1:i-1; + // T(k,j) -= T(k,i) * T(i,j); + // endfor + // endfor + // + // this is an in-place, cache-aligned variant of the code + // given in Higham's paper. const octave_idx_type n = T.rows (); element_type *Tp = T.fortran_vec (); @@ -117,38 +115,32 @@ { case MatrixType::Upper: case MatrixType::Diagonal: - { - if (! x.diag ().any_element_is_negative ()) - { - // Do it in real arithmetic. - sqrtm_utri_inplace (x); - retval = x; - retval.matrix_type (mt); - } - else - iscomplex = true; - - break; - } - case MatrixType::Lower: + if (! x.diag ().any_element_is_negative ()) { - if (! x.diag ().any_element_is_negative ()) - { - x = x.transpose (); - sqrtm_utri_inplace (x); - retval = x.transpose (); - retval.matrix_type (mt); - } - else - iscomplex = true; + // Do it in real arithmetic. + sqrtm_utri_inplace (x); + retval = x; + retval.matrix_type (mt); + } + else + iscomplex = true; + break; - break; + case MatrixType::Lower: + if (! x.diag ().any_element_is_negative ()) + { + x = x.transpose (); + sqrtm_utri_inplace (x); + retval = x.transpose (); + retval.matrix_type (mt); } + else + iscomplex = true; + break; + default: - { - iscomplex = true; - break; - } + iscomplex = true; + break; } if (iscomplex) @@ -166,46 +158,41 @@ { case MatrixType::Upper: case MatrixType::Diagonal: - { - sqrtm_utri_inplace (x); - retval = x; - retval.matrix_type (mt); + sqrtm_utri_inplace (x); + retval = x; + retval.matrix_type (mt); + break; - break; - } case MatrixType::Lower: - { - x = x.transpose (); - sqrtm_utri_inplace (x); - retval = x.transpose (); - retval.matrix_type (mt); + x = x.transpose (); + sqrtm_utri_inplace (x); + retval = x.transpose (); + retval.matrix_type (mt); + break; - break; - } default: - { - ComplexMatrix u; + { + ComplexMatrix u; - do - { - ComplexSCHUR schur (x, std::string (), true); - x = schur.schur_matrix (); - u = schur.unitary_matrix (); - } - while (0); // schur no longer needed. + do + { + ComplexSCHUR schur (x, std::string (), true); + x = schur.schur_matrix (); + u = schur.unitary_matrix (); + } + while (0); // schur no longer needed. - sqrtm_utri_inplace (x); + sqrtm_utri_inplace (x); - x = u * x; // original x no longer needed. - ComplexMatrix res = xgemm (x, u, blas_no_trans, blas_conj_trans); + x = u * x; // original x no longer needed. + ComplexMatrix res = xgemm (x, u, blas_no_trans, blas_conj_trans); - if (cutoff > 0 && xnorm (imag (res), one) <= cutoff) - retval = real (res); - else - retval = res; - - break; - } + if (cutoff > 0 && xnorm (imag (res), one) <= cutoff) + retval = real (res); + else + retval = res; + } + break; } } @@ -246,22 +233,17 @@ } if (arg.is_diag_matrix ()) - { - // sqrtm of a diagonal matrix is just sqrt. - retval(0) = arg.sqrt (); - } + // sqrtm of a diagonal matrix is just sqrt. + retval(0) = arg.sqrt (); else if (arg.is_single_type ()) - { - retval(0) = do_sqrtm<FloatMatrix, FloatComplexMatrix, FloatComplexSCHUR> (arg); - } + retval(0) = do_sqrtm<FloatMatrix, FloatComplexMatrix, FloatComplexSCHUR> (arg); else if (arg.is_numeric_type ()) - { - retval(0) = do_sqrtm<Matrix, ComplexMatrix, ComplexSCHUR> (arg); - } + retval(0) = do_sqrtm<Matrix, ComplexMatrix, ComplexSCHUR> (arg); if (nargout > 1 && ! error_state) { // This corresponds to generic code + // // norm (s*s - x, "fro") / norm (x, "fro"); octave_value s = retval(0); @@ -270,3 +252,22 @@ return retval; } + +/* + +%!assert (sqrtm (2*ones (2)), ones (2), 3*eps) + +## The following two tests are from the reference in the docstring above. + +%!test +%! x = [0 1; 0 0]; +%! assert (any (isnan (sqrtm (x))(:) )) + +%!test +%! x = eye (4); x(2,2) = x(3,3) = 2^-26; x(1,4) = 1; +%! z = eye (4); z(2,2) = z(3,3) = 2^-13; z(1,4) = 0.5; +%! [y, err] = sqrtm(x); +%! assert (y, z) +%! assert (err, 0) ## Yes, this one has to hold exactly + +*/
--- a/src/DLD-FUNCTIONS/urlwrite.cc +++ b/src/DLD-FUNCTIONS/urlwrite.cc @@ -112,11 +112,11 @@ { BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; - CURLcode res = curl_easy_perform (curl); - if (res != CURLE_OK) + errnum = curl_easy_perform (curl); + if (errnum != CURLE_OK) { if (curlerror) - error ("%s", curl_easy_strerror (res)); + error ("%s", curl_easy_strerror (errnum)); } else retval = true; @@ -145,6 +145,7 @@ std::string host; bool valid; bool ascii; + mutable CURLcode errnum; private: CURL *curl; @@ -250,11 +251,7 @@ std::string lasterror (void) const { - CURLcode errnum; - - curl_easy_getinfo (rep->handle(), CURLINFO_OS_ERRNO, &errnum); - - return std::string (curl_easy_strerror (errnum)); + return std::string (curl_easy_strerror (rep->errnum)); } void set_ostream (std::ostream& os) const
--- a/src/Makefile.am +++ b/src/Makefile.am @@ -310,6 +310,7 @@ defaults.h \ graphics.h \ oct-conf.h \ + profiler.h \ mxarray.h \ version.h @@ -446,6 +447,7 @@ pager.cc \ pr-output.cc \ procstream.cc \ + profiler.cc \ sighandlers.cc \ siglist.c \ sparse.cc \ @@ -478,20 +480,15 @@ include TEMPLATE-INST/module.mk if AMCOND_ENABLE_DYNAMIC_LINKING - DLD_DYNAMIC_SRC = $(DLD_FUNCTIONS_SRC) - DLD_STATIC_SRC = OCT_FILES = $(DLD_FUNCTIONS_LIBS:.la=.oct) OCT_STAMP_FILES = $(subst DLD-FUNCTIONS/,DLD-FUNCTIONS/$(am__leading_dot),$(DLD_FUNCTIONS_LIBS:.la=.oct-stamp)) else - DLD_DYNAMIC_SRC = - DLD_STATIC_SRC = $(DLD_FUNCTIONS_SRC) OCT_FILES = OCT_STAMP_FILES = endif liboctinterp_la_SOURCES = \ $(DIST_SRC) \ - $(DLD_STATIC_SRC) \ $(OPERATORS_SRC) \ $(TEMPLATE_INST_SRC) @@ -506,87 +503,14 @@ version.h \ $(OPT_INC) +liboctinterp_la_CPPFLAGS = @OCTINTERP_DLL_DEFS@ $(AM_CPPFLAGS) -if AMCOND_ENABLE_DYNAMIC_LINKING - OCTAVE_LIBS = \ - ./liboctinterp.la \ - ../liboctave/liboctave.la \ - ../libcruft/libcruft.la \ - ../libcruft/libranlib.la \ - ../libgnu/libgnu.la \ - $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) \ - $(QRUPDATE_LDFLAGS) $(QRUPDATE_LIBS) \ - $(FFTW_XLDFLAGS) $(FFTW_XLIBS) \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(GRAPHICS_LDFLAGS) $(GRAPHICS_LIBS) \ - $(FT2_LDFLAGS) $(FT2_LIBS) \ - $(HDF5_LDFLAGS) $(HDF5_LIBS) $(Z_LDFLAGS) $(Z_LIBS) \ - $(OPENGL_LIBS) $(X11_LIBS) $(CARBON_LIBS) \ - $(READLINE_LIBS) $(TERM_LIBS) \ - $(LIBGLOB) \ - $(REGEX_LDFLAGS) $(REGEX_LIBS) \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(DL_LIBS) $(PTHREAD_LIBS) \ - $(LIBS) \ - $(FLIBS) -else - ## FIXME -- this list is probably not complete now. It may not even - ## be possible to build a statically linked copy of Octave that is - ## fully functional. - OCTAVE_LIBS = \ - ./liboctinterp.la \ - ../liboctave/liboctave.la \ - ../libcruft/libcruft.la \ - ../libcruft/libranlib.la \ - ../libgnu/libgnu.la \ - $(FFTW_XLDFLAGS) $(FFTW_XLIBS) \ - $(QHULL_LDFLAGS) $(QHULL_LIBS) \ - $(QRUPDATE_LDFLAGS) $(QRUPDATE_LIBS) \ - $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) \ - $(REGEX_LDFLAGS) $(REGEX_LIBS) \ - $(CURL_LDFLAGS) $(CURL_LIBS) \ - $(GLPK_LDFLAGS) $(GLPK_LIBS) \ - $(MAGICK_LDFLAGS) $(MAGICK_LIBS) \ - $(GRAPHICS_LDFLAGS) $(GRAPHICS_LIBS) \ - $(FT2_LDFLAGS) $(FT2_LIBS) \ - $(HDF5_LDFLAGS) $(HDF5_LIBS) $(Z_LDFLAGS) $(Z_LIBS) \ - $(OPENGL_LIBS) $(X11_LIBS) $(CARBON_LIBS) \ - $(READLINE_LIBS) $(TERM_LIBS) \ - $(LIBGLOB) \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(DL_LIBS) $(PTHREAD_LIBS) \ - $(LIBS) \ - $(FLIBS) -endif +include link-deps.mk -OCTINTERP_LINK_DEPS = \ - $(RLD_FLAG) \ +liboctinterp_la_LIBADD = \ ../liboctave/liboctave.la \ ../libcruft/libcruft.la \ - ../libcruft/libranlib.la \ - ../libgnu/libgnu.la \ - $(FFTW_XLDFLAGS) $(FFTW_XLIBS) \ - $(FT2_LDFLAGS) $(FT2_LIBS) \ - $(HDF5_LDFLAGS) $(HDF5_LIBS) $(Z_LDFLAGS) $(Z_LIBS) \ - $(OPENGL_LIBS) $(X11_LIBS) $(CARBON_LIBS) \ - $(READLINE_LIBS) $(TERM_LIBS) \ - $(LIBGLOB) \ - $(LAPACK_LIBS) $(BLAS_LIBS) \ - $(LIBS) \ - $(FLIBS) - -liboctinterp_la_LIBADD = $(OCTINTERP_LINK_DEPS) - -## Additional library dependencies used by module.mk files -OCT_LINK_DEPS = \ - $(RLD_FLAG) $(LDFLAGS) \ - ./liboctinterp.la \ - ../liboctave/liboctave.la \ - ../libcruft/libcruft.la \ - ../libcruft/libranlib.la \ - ../libgnu/libgnu.la - -liboctinterp_la_CPPFLAGS = @OCTINTERP_DLL_DEFS@ $(AM_CPPFLAGS) + $(LIBOCTINTERP_LINK_DEPS) # Increment these as needed and according to the rules in the libtool manual: liboctinterp_current = 0 @@ -598,120 +522,39 @@ liboctinterp_la_LDFLAGS = \ -version-info $(liboctinterp_version_info) \ $(NO_UNDEFINED_LDFLAG) \ - -bindir $(bindir) + -bindir $(bindir) \ + $(LIBOCTINTERP_LINK_OPTS) display.df display.lo: CPPFLAGS += $(X11_FLAGS) -DLD-FUNCTIONS/__magick_read__.df: CPPFLAGS += $(MAGICK_CPPFLAGS) -DLD_FUNCTIONS___magick_read___la_CPPFLAGS = $(AM_CPPFLAGS) $(MAGICK_CPPFLAGS) -DLD_FUNCTIONS___magick_read___la_LIBADD += $(MAGICK_LDFLAGS) $(MAGICK_LIBS) - -DLD-FUNCTIONS/convhulln.df: CPPFLAGS += $(QHULL_CPPFLAGS) -DLD_FUNCTIONS_convhulln_la_CPPFLAGS = $(AM_CPPFLAGS) $(QHULL_CPPFLAGS) -DLD_FUNCTIONS_convhulln_la_LIBADD += $(QHULL_LDFLAGS) $(QHULL_LIBS) - -DLD-FUNCTIONS/__delaunayn__.df: CPPFLAGS += $(QHULL_CPPFLAGS) -DLD_FUNCTIONS___delaunayn___la_CPPFLAGS = $(AM_CPPFLAGS) $(QHULL_CPPFLAGS) -DLD_FUNCTIONS___delaunayn___la_LIBADD += $(QHULL_LDFLAGS) $(QHULL_LIBS) - -DLD-FUNCTIONS/__voronoi__.df: CPPFLAGS += $(QHULL_CPPFLAGS) -DLD_FUNCTIONS___voronoi___la_CPPFLAGS = $(AM_CPPFLAGS) $(QHULL_CPPFLAGS) -DLD_FUNCTIONS___voronoi___la_LIBADD += $(QHULL_LDFLAGS) $(QHULL_LIBS) - -DLD-FUNCTIONS/eigs.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_eigs_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_eigs_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) $(LAPACK_LIBS) $(BLAS_LIBS) - -#DLD-FUNCTIONS/qz.df DLD-FUNCTIONS/qz.lo: -DLD_FUNCTIONS_qz_la_LIBADD += $(LAPACK_LIBS) $(BLAS_LIBS) - -DLD-FUNCTIONS/qr.df: CPPFLAGS += $(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_qr_la_CPPFLAGS = $(AM_CPPFLAGS) $(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_qr_la_LIBADD += $(QRUPDATE_LDFLAGS) $(QRUPDATE_LIBS) $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/chol.df: CPPFLAGS += $(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_chol_la_CPPFLAGS = $(AM_CPPFLAGS) $(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_chol_la_LIBADD += $(QRUPDATE_LDFLAGS) $(QRUPDATE_LIBS) $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/regexp.df: CPPFLAGS += $(REGEX_CPPFLAGS) -DLD_FUNCTIONS_regexp_la_CPPFLAGS = $(AM_CPPFLAGS) $(REGEX_CPPFLAGS) -DLD_FUNCTIONS_regexp_la_LIBADD += $(REGEX_LDFLAGS) $(REGEX_LIBS) - -DLD-FUNCTIONS/urlwrite.df: CPPFLAGS += $(CURL_CPPFLAGS) -DLD_FUNCTIONS_urlwrite_la_CPPFLAGS = $(AM_CPPFLAGS) $(CURL_CPPFLAGS) -DLD_FUNCTIONS_urlwrite_la_LIBADD += $(CURL_LDFLAGS) $(CURL_LIBS) - -DLD-FUNCTIONS/__fltk_uigetfile__.df: CPPFLAGS += $(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS) -DLD_FUNCTIONS___fltk_uigetfile___la_CPPFLAGS = $(AM_CPPFLAGS) $(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS) -DLD_FUNCTIONS___fltk_uigetfile___la_LIBADD += $(GRAPHICS_LDFLAGS) $(GRAPHICS_LIBS) $(FT2_LDFLAGS) $(FT2_LIBS) - -DLD-FUNCTIONS/__glpk__.df: CPPFLAGS += $(GLPK_CPPFLAGS) -DLD_FUNCTIONS___glpk___la_CPPFLAGS = $(AM_CPPFLAGS) $(GLPK_CPPFLAGS) -DLD_FUNCTIONS___glpk___la_LIBADD += $(GLPK_LDFLAGS) $(GLPK_LIBS) - -DLD-FUNCTIONS/__init_fltk__.df: CPPFLAGS += $(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS) -DLD_FUNCTIONS___init_fltk___la_CPPFLAGS = $(AM_CPPFLAGS) $(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS) -DLD_FUNCTIONS___init_fltk___la_LIBADD += $(GRAPHICS_LDFLAGS) $(GRAPHICS_LIBS) $(FT2_LDFLAGS) $(FT2_LIBS) - -DLD-FUNCTIONS/amd.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_amd_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_amd_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/colamd.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_colamd_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_colamd_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/ccolamd.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_ccolamd_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_ccolamd_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/symbfact.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_symbfact_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_symbfact_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/dmperm.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_dmperm_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_dmperm_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/symrcm.df: CPPFLAGS += $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_symrcm_la_CPPFLAGS = $(AM_CPPFLAGS) $(SPARSE_XCPPFLAGS) -DLD_FUNCTIONS_symrcm_la_LIBADD += $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) - -DLD-FUNCTIONS/fft.df: CPPFLAGS += $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fft_la_CPPFLAGS = $(AM_CPPFLAGS) $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fft_la_LIBADD += $(FFTW_XLDFLAGS) $(FFTW_XLIBS) - -DLD-FUNCTIONS/fft2.df: CPPFLAGS += $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fft2_la_CPPFLAGS = $(AM_CPPFLAGS) $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fft2_la_LIBADD += $(FFTW_XLDFLAGS) $(FFTW_XLIBS) - -DLD-FUNCTIONS/fftn.df: CPPFLAGS += $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fftn_la_CPPFLAGS = $(AM_CPPFLAGS) $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fftn_la_LIBADD += $(FFTW_XLDFLAGS) $(FFTW_XLIBS) - -DLD-FUNCTIONS/fftw.df: CPPFLAGS += $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fftw_la_CPPFLAGS = $(AM_CPPFLAGS) $(FFTW_XCPPFLAGS) -DLD_FUNCTIONS_fftw_la_LIBADD += $(FFTW_XLDFLAGS) $(FFTW_XLIBS) - - octave_SOURCES = main.c -octave_LDADD = $(OCTAVE_LIBS) +octave_LDADD = \ + liboctinterp.la \ + ../liboctave/liboctave.la \ + ../libcruft/libcruft.la \ + $(OCTAVE_LINK_DEPS) +octave_LDFLAGS = \ + $(NO_UNDEFINED_LDFLAG) \ + $(OCTAVE_LINK_OPTS) ## Section for defining and creating DEF_FILES SRC_DEF_FILES := $(shell $(srcdir)/find-defun-files.sh "$(srcdir)" $(DIST_SRC)) -DLD_STATIC_DEF_FILES = $(DLD_STATIC_SRC:.cc=.df) -DLD_DYNAMIC_DEF_FILES = $(DLD_DYNAMIC_SRC:.cc=.df) +DLD_FUNCTIONS_DEF_FILES = $(DLD_FUNCTIONS_SRC:.cc=.df) ## builtins.cc depends on $(DEF_FILES), so DEF_FILES should only include ## .df files that correspond to sources included in liboctave. -DEF_FILES = $(SRC_DEF_FILES) $(DLD_STATIC_DEF_FILES) +if AMCOND_ENABLE_DYNAMIC_LINKING + DEF_FILES = $(SRC_DEF_FILES) +else + DEF_FILES = $(SRC_DEF_FILES) $(DLD_FUNCTIONS_DEF_FILES) +endif -ALL_DEF_FILES = $(DEF_FILES) $(DLD_DYNAMIC_DEF_FILES) +ALL_DEF_FILES = $(SRC_DEF_FILES) $(DLD_FUNCTIONS_DEF_FILES) -$(DEF_FILES) $(DYNAMIC_DLD_DEF_FILES): mkdefs Makefile +$(SRC_DEF_FILES): mkdefs Makefile $(DEF_FILES): $(OPT_HANDLERS) $(OPT_INC) @@ -794,9 +637,13 @@ $(OPT_INC) : %.h : %.in $(MAKE) -C $(@D) $(@F) -DLD-FUNCTIONS/PKG_ADD: $(DLD_DYNAMIC_DEF_FILES) mk-pkg-add - $(srcdir)/mk-pkg-add $(DLD_DYNAMIC_DEF_FILES) > $@-t +if AMCOND_ENABLE_DYNAMIC_LINKING +DLD_FUNCTIONS_PKG_ADD_FILE = DLD-FUNCTIONS/PKG_ADD + +DLD-FUNCTIONS/PKG_ADD: $(DLD_FUNCTIONS_DEF_FILES) mk-pkg-add + $(srcdir)/mk-pkg-add $(DLD_FUNCTIONS_DEF_FILES) > $@-t mv $@-t $@ +endif lex.lo lex.o oct-parse.lo oct-parse.o: \ AM_CXXFLAGS := $(filter-out -Wold-style-cast, $(AM_CXXFLAGS)) @@ -828,8 +675,7 @@ gendoc$(BUILD_EXEEXT): gendoc.cc $(BUILD_CXX) $(BUILD_CXXFLAGS) -o $@ $^ $(BUILD_LDFLAGS) - -all-local: $(OCT_STAMP_FILES) DLD-FUNCTIONS/PKG_ADD .DOCSTRINGS +all-local: $(OCT_STAMP_FILES) $(DLD_FUNCTIONS_PKG_ADD_FILE) .DOCSTRINGS if AMCOND_BUILD_COMPILED_AUX_PROGRAMS octave-config.cc: octave-config.cc.in Makefile @@ -882,8 +728,8 @@ if AMCOND_ENABLE_DYNAMIC_LINKING install-oct: $(top_srcdir)/build-aux/mkinstalldirs $(DESTDIR)$(octfiledir) - if [ -n "`cat DLD-FUNCTIONS/PKG_ADD`" ]; then \ - $(INSTALL_DATA) DLD-FUNCTIONS/PKG_ADD $(DESTDIR)$(octfiledir)/PKG_ADD; \ + if [ -n "`cat $(DLD_FUNCTIONS_PKG_ADD_FILE)`" ]; then \ + $(INSTALL_DATA) $(DLD_FUNCTIONS_PKG_ADD_FILE) $(DESTDIR)$(octfiledir)/PKG_ADD; \ fi cd $(DESTDIR)$(octlibdir) && \ for ltlib in $(DLD_FUNCTIONS_LIBS); do \ @@ -911,7 +757,7 @@ CLEANFILES = \ $(bin_SCRIPTS) \ - DLD-FUNCTIONS/PKG_ADD \ + $(DLD_FUNCTIONS_PKG_ADD_FILE) \ doc-files \ gendoc.cc \ gendoc$(BUILD_EXEEXT) \
--- a/src/OPERATORS/op-int.h +++ b/src/OPERATORS/op-int.h @@ -21,6 +21,7 @@ */ #include "quit.h" +#include "bsxfun.h" #define DEFINTBINOP_OP(name, t1, t2, op, t3) \ BINOPDECL (name, a1, a2) \ @@ -703,8 +704,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -722,8 +730,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -741,8 +756,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T2 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -760,8 +782,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -779,8 +808,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T2 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \
--- a/src/data.cc +++ b/src/data.cc @@ -1943,6 +1943,9 @@ %!error <dimension mismatch> cat (3, cat (3, [], []), [1,2;3,4]); %!error <dimension mismatch> cat (3, zeros (0, 0, 2), [1,2;3,4]); +%!assert ([zeros(3,2,2); ones(1,2,2)], repmat([0;0;0;1],[1,2,2]) ); +%!assert ([zeros(3,2,2); ones(1,2,2)], vertcat(zeros(3,2,2), ones(1,2,2)) ); + */ static octave_value @@ -4194,8 +4197,8 @@ @end example\n\ \n\ Calling @code{eye} with no arguments is equivalent to calling it\n\ -with an argument of 1. This odd definition is for compatibility\n\ -with @sc{matlab}.\n\ +with an argument of 1. Any negative dimensions are treated as zero. \n\ +These odd definitions are for compatibility with @sc{matlab}.\n\ @seealso{speye}\n\ @end deftypefn") {
--- a/src/defaults.cc +++ b/src/defaults.cc @@ -419,6 +419,17 @@ return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (EDITOR); } +/* +%!error (EDITOR (1, 2)); +%!test +%! orig_val = EDITOR (); +%! old_val = EDITOR ("X"); +%! assert (orig_val, old_val); +%! assert (EDITOR (), "X"); +%! EDITOR (orig_val); +%! assert (EDITOR (), orig_val); +*/ + DEFUN (EXEC_PATH, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} EXEC_PATH ()\n\ @@ -438,6 +449,17 @@ return retval; } +/* +%!error (EXEC_PATH (1, 2)); +%!test +%! orig_val = EXEC_PATH (); +%! old_val = EXEC_PATH ("X"); +%! assert (orig_val, old_val); +%! assert (EXEC_PATH (), "X"); +%! EXEC_PATH (orig_val); +%! assert (EXEC_PATH (), orig_val); +*/ + DEFUN (IMAGE_PATH, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} IMAGE_PATH ()\n\ @@ -449,6 +471,17 @@ return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (IMAGE_PATH); } +/* +%!error (IMAGE_PATH (1, 2)); +%!test +%! orig_val = IMAGE_PATH (); +%! old_val = IMAGE_PATH ("X"); +%! assert (orig_val, old_val); +%! assert (IMAGE_PATH (), "X"); +%! IMAGE_PATH (orig_val); +%! assert (IMAGE_PATH (), orig_val); +*/ + DEFUN (OCTAVE_HOME, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} OCTAVE_HOME ()\n\ @@ -465,6 +498,11 @@ return retval; } +/* +%!error OCTAVE_HOME (1); +%!assert (ischar (OCTAVE_HOME ())); +*/ + DEFUNX ("OCTAVE_VERSION", FOCTAVE_VERSION, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} OCTAVE_VERSION ()\n\ @@ -482,3 +520,8 @@ return retval; } + +/* +%!error OCTAVE_VERSION (1); +%!assert (ischar (OCTAVE_VERSION ())); +*/
--- a/src/error.cc +++ b/src/error.cc @@ -1066,6 +1066,10 @@ octave_scalar_map m = args(0).scalar_map_value (); + // empty struct is not an error. return and resume calling function. + if (m.nfields () == 0) + return retval; + if (m.contains ("message")) { octave_value c = m.getfield ("message"); @@ -1684,10 +1688,6 @@ return retval; } -// For backward compatibility. -DEFALIAS (error_text, lasterr); -DEFALIAS (__error_text__, lasterr); - DEFUN (lastwarn, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{msg}, @var{msgid}] =} lastwarn (@var{msg}, @var{msgid})\n\
--- a/src/genprops.awk +++ b/src/genprops.awk @@ -300,8 +300,9 @@ emit_get_accessor(i, "graphics_handle", "handle_value"); else if (type[i] == "string_property") emit_get_accessor(i, "std::string", "string_value"); - else if (type[i] == "string_array_property") - emit_get_accessor(i, "octave_value", "get"); + else if (type[i] == "string_array_property" \ + || type[i] == "text_label_property") + emit_get_accessor(i, "octave_value", "get"); else if (type[i] == "double_property") emit_get_accessor(i, "double", "double_value"); else if (type[i] == "double_radio_property")
--- a/src/gl-render.cc +++ b/src/gl-render.cc @@ -665,7 +665,7 @@ double p1, double p1N, double p2, double p2N, double dx, double dy, double dz, - int xyz, bool doubleside) + int xyz, bool mirror) { glBegin (GL_LINES); @@ -679,7 +679,7 @@ { glVertex3d (val, p1, p2); glVertex3d (val, p1+dy, p2+dz); - if (doubleside) + if (mirror) { glVertex3d (val, p1N, p2N); glVertex3d (val, p1N-dy, p2N-dz); @@ -689,7 +689,7 @@ { glVertex3d (p1, val, p2); glVertex3d (p1+dx, val, p2+dz); - if (doubleside) + if (mirror) { glVertex3d (p1N, val, p2N); glVertex3d (p1N-dx, val, p2N-dz); @@ -699,7 +699,7 @@ { glVertex3d (p1, p2, val); glVertex3d (p1+dx, p2+dy, val); - if (doubleside) + if (mirror) { glVertex3d (p1N, p2N, val); glVertex3d (p1N-dx, p2N-dy, val); @@ -966,7 +966,7 @@ string_vector xticklabels = props.get_xticklabel ().all_strings (); int wmax = 0, hmax = 0; bool tick_along_z = nearhoriz || xisinf (fy); - bool box = props.is_box (); + bool mirror = props.is_box () && xstate != AXE_ANY_DIR; set_color (props.get_xcolor_rgb ()); @@ -982,14 +982,14 @@ render_tickmarks (xticks, x_min, x_max, ypTick, ypTick, zpTick, zpTickN, 0., 0., signum(zpTick-zpTickN)*fz*xticklen, - 0, (box && xstate != AXE_ANY_DIR)); + 0, mirror); } else { render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN, zpTick, zpTick, 0., signum(ypTick-ypTickN)*fy*xticklen, - 0., 0, (box && xstate != AXE_ANY_DIR)); + 0., 0, mirror); } // tick texts @@ -1021,12 +1021,12 @@ render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick, zpTick, zpTickN, 0., 0., signum(zpTick-zpTickN)*fz*xticklen/2, - 0, (box && xstate != AXE_ANY_DIR)); + 0, mirror); else render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN, zpTick, zpTick, 0., signum(ypTick-ypTickN)*fy*xticklen/2, - 0., 0, (box && xstate != AXE_ANY_DIR)); + 0., 0, mirror); } gh_manager::get_object (props.get_xlabel ()).set ("visible", "on"); @@ -1073,7 +1073,8 @@ string_vector yticklabels = props.get_yticklabel ().all_strings (); int wmax = 0, hmax = 0; bool tick_along_z = nearhoriz || xisinf (fx); - bool box = props.is_box (); + bool mirror = props.is_box () && ystate != AXE_ANY_DIR + && (props.get_tag () != "plotyy"); set_color (props.get_ycolor_rgb ()); @@ -1088,12 +1089,12 @@ render_tickmarks (yticks, y_min, y_max, xpTick, xpTick, zpTick, zpTickN, 0., 0., signum(zpTick-zpTickN)*fz*yticklen, - 1, (box && ystate != AXE_ANY_DIR)); + 1, mirror); else render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN, zpTick, zpTick, signum(xPlaneN-xPlane)*fx*yticklen, - 0., 0., 1, (box && ystate != AXE_ANY_DIR)); + 0., 0., 1, mirror); // tick texts if (yticklabels.numel () > 0) @@ -1125,12 +1126,12 @@ render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick, zpTick, zpTickN, 0., 0., signum(zpTick-zpTickN)*fz*yticklen/2, - 1, (box && ystate != AXE_ANY_DIR)); + 1, mirror); else render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN, zpTick, zpTick, signum(xpTick-xpTickN)*fx*yticklen/2, - 0., 0., 1, (box && ystate != AXE_ANY_DIR)); + 0., 0., 1, mirror); } gh_manager::get_object (props.get_ylabel ()).set ("visible", "on"); @@ -1169,7 +1170,7 @@ Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ()); string_vector zticklabels = props.get_zticklabel ().all_strings (); int wmax = 0, hmax = 0; - bool box = props.is_box (); + bool mirror = props.is_box () && zstate != AXE_ANY_DIR; set_color (props.get_zcolor_rgb ()); @@ -1185,7 +1186,7 @@ render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, yPlane, yPlane, signum(xPlaneN-xPlane)*fx*zticklen, - 0., 0., 2, (box && zstate != AXE_ANY_DIR)); + 0., 0., 2, mirror); else render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN, yPlane, yPlane, 0., @@ -1198,7 +1199,7 @@ render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, yPlaneN, yPlane, 0., signum(yPlaneN-yPlane)*fy*zticklen, - 0., 2, (box && zstate != AXE_ANY_DIR)); + 0., 2, mirror); else render_tickmarks (zticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlane, @@ -1250,7 +1251,7 @@ render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane, yPlane, yPlane, signum(xPlaneN-xPlane)*fx*zticklen/2, - 0., 0., 2, (box && zstate != AXE_ANY_DIR)); + 0., 0., 2, mirror); else render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN, yPlane, yPlane, 0., @@ -1263,7 +1264,7 @@ render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlane, 0., signum(yPlaneN-yPlane)*fy*zticklen/2, - 0., 2, (box && zstate != AXE_ANY_DIR)); + 0., 2, mirror); else render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, yPlaneN, yPlaneN, @@ -2421,7 +2422,7 @@ void opengl_renderer::draw_text (const text::properties& props) { - if (props.get_string ().empty ()) + if (props.get_string ().is_empty ()) return; const Matrix pos = xform.scale (props.get_data_position ());
--- a/src/gl2ps-renderer.cc +++ b/src/gl2ps-renderer.cc @@ -199,7 +199,7 @@ void glps_renderer::draw_text (const text::properties& props) { - if (props.get_string ().empty ()) + if (props.get_string ().is_empty ()) return; set_font (props); @@ -223,9 +223,15 @@ // FIXME: handle margin and surrounding box glRasterPos3d (pos(0), pos(1), pos(2)); - gl2psTextOpt (props.get_string ().c_str (), fontname.c_str (), fontsize, + + octave_value string_prop = props.get_string (); + + string_vector sv = string_prop.all_strings (); + + std::string s = sv.join ("\n"); + + gl2psTextOpt (s.c_str (), fontname.c_str (), fontsize, alignment_to_mode (halign, valign), props.get_rotation ()); - } #endif
--- a/src/gl2ps.c +++ b/src/gl2ps.c @@ -50,7 +50,7 @@ #include <png.h> #endif -/********************************************************************* +/********************************************************************* * * Private definitions, data structures and prototypes * @@ -167,7 +167,6 @@ written to the file or not, and 'format' indicates if it is visible or not */ GLenum format, type; - GLfloat zoom_x, zoom_y; GLfloat *pixels; } GL2PSimage; @@ -228,7 +227,7 @@ GLboolean zerosurfacearea; GL2PSbsptree2d *imagetree; GL2PSprimitive *primitivetoadd; - + /* PDF-specific */ int streamlength; GL2PSlist *pdfprimlist, *pdfgrouplist; @@ -266,7 +265,7 @@ static GLint gl2psPrintPrimitives(void); -/********************************************************************* +/********************************************************************* * * Utility routines * @@ -283,7 +282,7 @@ case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; } va_start(args, fmt); - vfprintf(stderr, fmt, args); + vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } @@ -360,16 +359,16 @@ static int gl2psAllocCompress(unsigned int srcsize) { gl2psFreeCompress(); - + if(!gl2ps->compress || !srcsize) return GL2PS_ERROR; - + gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen); - + return GL2PS_SUCCESS; } @@ -377,18 +376,18 @@ { if(!gl2ps->compress || !srcsize) return NULL; - + if(srcsize < gl2ps->compress->srcLen) return gl2ps->compress->start; - + gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); - gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, + gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; - gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, + gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, gl2ps->compress->destLen); - + return gl2ps->compress->start; } @@ -407,8 +406,8 @@ { /* For compatibility with older zlib versions, we use compress(...) instead of compress2(..., Z_BEST_COMPRESSION) */ - return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, - gl2ps->compress->start, gl2ps->compress->srcLen); + return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, + gl2ps->compress->start, gl2ps->compress->srcLen); } #endif @@ -456,7 +455,7 @@ /* add the gzip file header */ fwrite(tmp, 10, 1, gl2ps->stream); } -#endif +#endif } static void gl2psPrintGzipFooter() @@ -477,7 +476,7 @@ n += 4; /* DICTID */ } /* write the data, without the zlib header and footer */ - fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), + fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 1, gl2ps->stream); /* add the gzip file footer */ crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); @@ -496,7 +495,7 @@ gl2psFree(gl2ps->compress); gl2ps->compress = NULL; } -#endif +#endif } /* The list handling routines */ @@ -545,7 +544,7 @@ static void gl2psListDelete(GL2PSlist *list) { - if(!list) return; + if(!list) return; gl2psFree(list->array); gl2psFree(list); } @@ -618,7 +617,7 @@ static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) { - static const char cb64[] = + static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; out[0] = cb64[ in[0] >> 2 ]; @@ -671,7 +670,7 @@ return GL_FALSE; return GL_TRUE; } - + static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) { int i; @@ -690,20 +689,20 @@ int i; if(n < 2) return GL_TRUE; - + for(i = 1; i < n; i++){ if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] || fabs(rgba[0][1] - rgba[i][1]) > threshold[1] || fabs(rgba[0][2] - rgba[i][2]) > threshold[2]) return GL_FALSE; } - + return GL_TRUE; } static void gl2psSetLastColor(GL2PSrgba rgba) { - int i; + int i; for(i = 0; i < 3; ++i){ gl2ps->lastrgba[i] = rgba[i]; } @@ -712,13 +711,13 @@ static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y, GLfloat *red, GLfloat *green, GLfloat *blue) { - + GLsizei width = im->width; GLsizei height = im->height; GLfloat *pixels = im->pixels; GLfloat *pimag; - /* OpenGL image is from down to up, PS image is up to down */ + /* OpenGL image is from down to up, PS image is up to down */ switch(im->format){ case GL_RGBA: pimag = pixels + 4 * (width * (height - 1 - y) + x); @@ -741,13 +740,11 @@ { int size; GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); - + image->width = im->width; image->height = im->height; image->format = im->format; image->type = im->type; - image->zoom_x = im->zoom_x; - image->zoom_y = im->zoom_y; switch(image->format){ case GL_RGBA: @@ -761,7 +758,7 @@ image->pixels = (GLfloat*)gl2psMalloc(size); memcpy(image->pixels, im->pixels, size); - + return image; } @@ -783,7 +780,7 @@ { unsigned int i; GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); - for(i = 0; i < length; i++) + for(i = 0; i < length; i++) gl2psListAdd(png, &data[i]); } @@ -801,21 +798,21 @@ if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) return; - + if(!(info_ptr = png_create_info_struct(png_ptr))){ png_destroy_write_struct(&png_ptr, NULL); return; } - + if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } - + png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG); png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); - png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); @@ -839,7 +836,7 @@ /* Helper routines for text strings */ -static GLint gl2psAddText(GLint type, const char *str, const char *fontname, +static GLint gl2psAddText(GLint type, const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { GLfloat pos[4]; @@ -871,7 +868,7 @@ glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); - strcpy(prim->data.text->str, str); + strcpy(prim->data.text->str, str); prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); strcpy(prim->data.text->fontname, fontname); prim->data.text->fontsize = fontsize; @@ -880,7 +877,7 @@ gl2psListAdd(gl2ps->auxprimitives, &prim); glPassThrough(GL2PS_TEXT_TOKEN); - + return GL2PS_SUCCESS; } @@ -888,13 +885,13 @@ { GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); - strcpy(text->str, t->str); + strcpy(text->str, t->str); text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char)); strcpy(text->fontname, t->fontname); text->fontsize = t->fontsize; text->alignment = t->alignment; text->angle = t->angle; - + return text; } @@ -914,7 +911,7 @@ /* returns TRUE if gl2ps supports the argument combination: only two blending modes have been implemented so far */ - if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || + if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || (sfactor == GL_ONE && dfactor == GL_ZERO) ) return GL_TRUE; return GL_FALSE; @@ -934,7 +931,7 @@ v->rgba[3] = 1.0F; return; } - + switch(gl2ps->blendfunc[0]){ case GL_ONE: v->rgba[3] = 1.0F; @@ -955,9 +952,9 @@ a remarkable amount of PDF handling code inside this file depends on it if activated */ /* - t->prop = T_CONST_COLOR; + t->prop = T_CONST_COLOR; for(i = 0; i < 3; ++i){ - if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || + if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){ t->prop = T_VAR_COLOR; break; @@ -965,7 +962,7 @@ } */ - if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || + if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){ t->prop |= T_VAR_ALPHA; } @@ -1008,7 +1005,7 @@ } prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - + prim->type = p->type; prim->numverts = p->numverts; prim->boundary = p->boundary; @@ -1044,17 +1041,17 @@ return GL_TRUE; } -/********************************************************************* +/********************************************************************* * - * 3D sorting routines + * 3D sorting routines * *********************************************************************/ static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) { - return (plane[0] * point[0] + - plane[1] * point[1] + - plane[2] * point[2] + + return (plane[0] * point[0] + + plane[1] * point[1] + + plane[2] * point[2] + plane[3]); } @@ -1101,13 +1098,13 @@ switch(prim->type){ case GL2PS_TRIANGLE : case GL2PS_QUADRANGLE : - v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; - v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; - v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; - w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; - w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; - w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; - if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || + v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; + v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; + v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; + w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; + w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; + w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; + if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; @@ -1115,16 +1112,16 @@ } else{ gl2psGetNormal(v, w, plane); - plane[3] = - - plane[0] * prim->verts[0].xyz[0] - - plane[1] * prim->verts[0].xyz[1] + plane[3] = + - plane[0] * prim->verts[0].xyz[0] + - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; case GL2PS_LINE : - v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; - v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; - v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; + v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; + v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; + v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; @@ -1135,9 +1132,9 @@ else if(GL2PS_ZERO(v[1])) w[1] = 1.0F; else w[2] = 1.0F; gl2psGetNormal(v, w, plane); - plane[3] = - - plane[0] * prim->verts[0].xyz[0] - - plane[1] * prim->verts[0].xyz[1] + plane[3] = + - plane[0] * prim->verts[0].xyz[0] + - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; @@ -1172,11 +1169,11 @@ sect = -gl2psComparePointPlane(a->xyz, plane) / psca; else sect = 0.0F; - + c->xyz[0] = a->xyz[0] + v[0] * sect; c->xyz[1] = a->xyz[1] + v[1] * sect; c->xyz[2] = a->xyz[2] + v[2] * sect; - + c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0]; c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1]; c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2]; @@ -1199,10 +1196,10 @@ numverts = 4; } switch(numverts){ - case 1 : child->type = GL2PS_POINT; break; - case 2 : child->type = GL2PS_LINE; break; - case 3 : child->type = GL2PS_TRIANGLE; break; - case 4 : child->type = GL2PS_QUADRANGLE; break; + case 1 : child->type = GL2PS_POINT; break; + case 2 : child->type = GL2PS_LINE; break; + case 3 : child->type = GL2PS_TRIANGLE; break; + case 4 : child->type = GL2PS_QUADRANGLE; break; default: child->type = GL2PS_NO_TYPE; break; } } @@ -1221,13 +1218,13 @@ child->verts[i] = parent->verts[index0[i]]; } else{ - gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], + gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], plane, &child->verts[i]); } } } -static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, +static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, GLshort i, GLshort j) { GLint k; @@ -1250,9 +1247,9 @@ { GLint type = GL2PS_COINCIDENT; GLshort i, j; - GLfloat d[5]; - - for(i = 0; i < prim->numverts; i++){ + GLfloat d[5]; + + for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } @@ -1264,11 +1261,11 @@ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; - else if(type != GL2PS_IN_BACK_OF) return 1; + else if(type != GL2PS_IN_BACK_OF) return 1; if(d[i] < -GL2PS_EPSILON) return 1; } else if(d[j] < -GL2PS_EPSILON){ - if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; + if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) return 1; if(d[i] > GL2PS_EPSILON) return 1; } @@ -1277,16 +1274,16 @@ return 0; } -static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, +static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, GL2PSprimitive **front, GL2PSprimitive **back) { GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5]; GLint type; - GLfloat d[5]; + GLfloat d[5]; type = GL2PS_COINCIDENT; - for(i = 0; i < prim->numverts; i++){ + for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } @@ -1301,7 +1298,7 @@ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; - else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; + else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; if(d[i] < -GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); gl2psAddIndex(out0, out1, &out, i, j); @@ -1310,7 +1307,7 @@ gl2psAddIndex(out0, out1, &out, j, -1); } else if(d[j] < -GL2PS_EPSILON){ - if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; + if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING; if(d[i] > GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); @@ -1337,7 +1334,7 @@ return type; } -static void gl2psDivideQuad(GL2PSprimitive *quad, +static void gl2psDivideQuad(GL2PSprimitive *quad, GL2PSprimitive **t1, GL2PSprimitive **t2) { *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); @@ -1366,17 +1363,17 @@ GL2PSprimitive *q, *w; GLfloat dq = 0.0F, dw = 0.0F, diff; int i; - + q = *(GL2PSprimitive**)a; w = *(GL2PSprimitive**)b; for(i = 0; i < q->numverts; i++){ - dq += q->verts[i].xyz[2]; + dq += q->verts[i].xyz[2]; } dq /= (GLfloat)q->numverts; for(i = 0; i < w->numverts; i++){ - dw += w->verts[i].xyz[2]; + dw += w->verts[i].xyz[2]; } dw /= (GLfloat)w->numverts; @@ -1427,7 +1424,7 @@ for(j = 0; j < gl2psListNbr(primitives); j++){ if(j != i){ prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); - count += gl2psTestSplitPrimitive(prim2, plane); + count += gl2psTestSplitPrimitive(prim2, plane); } if(count > best) break; } @@ -1461,7 +1458,7 @@ static void gl2psFreePrimitive(void *data) { GL2PSprimitive *q; - + q = *(GL2PSprimitive**)data; gl2psFree(q->verts); if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ @@ -1486,7 +1483,7 @@ gl2psListAdd(list, &t2); gl2psFreePrimitive(&prim); } - + } static void gl2psFreeBspTree(GL2PSbsptree **tree) @@ -1598,7 +1595,7 @@ } gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); } - else if(GL_TRUE == compare(-epsilon, result)){ + else if(GL_TRUE == compare(-epsilon, result)){ gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); @@ -1666,18 +1663,18 @@ else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){ factor = gl2ps->offset[0]; units = gl2ps->offset[1]; - area = - (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * - (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * + area = + (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * + (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - + (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); if(!GL2PS_ZERO(area)){ - dZdX = + dZdX = ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) * (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) - (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area; - dZdY = + dZdY = ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * @@ -1695,15 +1692,15 @@ } } -/********************************************************************* +/********************************************************************* * - * 2D sorting routines (for occlusion culling) + * 2D sorting routines (for occlusion culling) * *********************************************************************/ static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) { - GLfloat n; + GLfloat n; plane[0] = b[1] - a[1]; plane[1] = a[0] - b[0]; @@ -1712,7 +1709,7 @@ if(!GL2PS_ZERO(n)){ plane[0] /= n; plane[1] /= n; - plane[3] = -plane[0]*a[0]-plane[1]*a[1]; + plane[3] = -plane[0]*a[0]-plane[1]*a[1]; return 1; } else{ @@ -1897,8 +1894,8 @@ } static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, - GL2PSplane plane, - GL2PSprimitive **front, + GL2PSplane plane, + GL2PSprimitive **front, GL2PSprimitive **back) { /* cur will hold the position of the current vertex @@ -1907,10 +1904,10 @@ v1 and v2 represent the current and previous vertices, respectively flag is set if the current vertex should be checked against the plane */ GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1; - + /* list of vertices that will go in front and back primitive */ GL2PSvertex *front_list = NULL, *back_list = NULL; - + /* number of vertices in front and back list */ GLshort front_count = 0, back_count = 0; @@ -1927,7 +1924,7 @@ if(i == 0){ prev0 = cur; } - } + } if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && (i < prim->numverts)){ if(cur == GL2PS_POINT_INFRONT){ @@ -1982,12 +1979,12 @@ { GLint ret = 0; GL2PSprimitive *frontprim = NULL, *backprim = NULL; - + /* FIXME: until we consider the actual extent of text strings and pixmaps, never cull them. Otherwise the whole string/pixmap gets culled as soon as the reference point is hidden */ - if(prim->type == GL2PS_PIXMAP || - prim->type == GL2PS_TEXT || + if(prim->type == GL2PS_PIXMAP || + prim->type == GL2PS_TEXT || prim->type == GL2PS_SPECIAL){ return 1; } @@ -2001,7 +1998,7 @@ else{ switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); - case GL2PS_IN_FRONT_OF: + case GL2PS_IN_FRONT_OF: if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); else return 0; case GL2PS_SPANNING: @@ -2136,14 +2133,14 @@ gl2psBuildPolygonBoundary(tree->front); } -/********************************************************************* +/********************************************************************* * * Feedback buffer parser * *********************************************************************/ -static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, - GL2PSvertex *verts, GLint offset, +static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, + GL2PSvertex *verts, GLint offset, GLushort pattern, GLint factor, GLfloat width, char boundary) { @@ -2210,7 +2207,7 @@ while(used > 0){ if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; - + switch((GLint)*current){ case GL_POINT_TOKEN : current ++; @@ -2218,7 +2215,7 @@ i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; - gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, + gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, pattern, factor, psize, 0); break; case GL_LINE_TOKEN : @@ -2231,7 +2228,7 @@ i = gl2psGetVertex(&vertices[1], current); current += i; used -= i; - gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, + gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, pattern, factor, lwidth, 0); break; case GL_POLYGON_TOKEN : @@ -2262,7 +2259,7 @@ else v ++; } - break; + break; case GL_BITMAP_TOKEN : case GL_DRAW_PIXEL_TOKEN : case GL_COPY_PIXEL_TOKEN : @@ -2271,7 +2268,7 @@ i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; - break; + break; case GL_PASS_THROUGH_TOKEN : switch((GLint)current[1]){ case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; @@ -2281,32 +2278,32 @@ case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break; case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break; case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break; - case GL2PS_BEGIN_STIPPLE_TOKEN : + case GL2PS_BEGIN_STIPPLE_TOKEN : current += 2; - used -= 2; - pattern = (GLushort)current[1]; + used -= 2; + pattern = (GLushort)current[1]; current += 2; - used -= 2; - factor = (GLint)current[1]; + used -= 2; + factor = (GLint)current[1]; break; - case GL2PS_SRC_BLEND_TOKEN : - current += 2; - used -= 2; + case GL2PS_SRC_BLEND_TOKEN : + current += 2; + used -= 2; gl2ps->blendfunc[0] = (GLint)current[1]; break; - case GL2PS_DST_BLEND_TOKEN : - current += 2; - used -= 2; + case GL2PS_DST_BLEND_TOKEN : + current += 2; + used -= 2; gl2ps->blendfunc[1] = (GLint)current[1]; break; - case GL2PS_POINT_SIZE_TOKEN : - current += 2; - used -= 2; + case GL2PS_POINT_SIZE_TOKEN : + current += 2; + used -= 2; psize = current[1]; break; - case GL2PS_LINE_WIDTH_TOKEN : - current += 2; - used -= 2; + case GL2PS_LINE_WIDTH_TOKEN : + current += 2; + used -= 2; lwidth = current[1]; break; case GL2PS_IMAGEMAP_TOKEN : @@ -2320,26 +2317,24 @@ prim->pattern = 0; prim->factor = 0; prim->width = 1; - + node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap)); node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); node->image->type = 0; node->image->format = 0; - node->image->zoom_x = 1.0F; - node->image->zoom_y = 1.0F; node->next = NULL; - + if(gl2ps->imagemap_head == NULL) gl2ps->imagemap_head = node; else gl2ps->imagemap_tail->next = node; gl2ps->imagemap_tail = node; prim->data.image = node->image; - + current += 2; used -= 2; i = gl2psGetVertex(&prim->verts[0], ¤t[1]); current += i; used -= i; - + node->image->width = (GLint)current[2]; current += 2; used -= 2; node->image->height = (GLint)current[2]; @@ -2359,12 +2354,12 @@ sizeoffloat = sizeof(GLfloat); v = 2 * sizeoffloat; - vtot = node->image->height + node->image->height * + vtot = node->image->height + node->image->height * ((node->image->width - 1) / 8); node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot); node->image->pixels[0] = prim->verts[0].xyz[0]; node->image->pixels[1] = prim->verts[0].xyz[1]; - + for(i = 0; i < vtot; i += sizeoffloat){ current += 2; used -= 2; if((vtot - i) >= 4) @@ -2378,15 +2373,15 @@ case GL2PS_DRAW_PIXELS_TOKEN : case GL2PS_TEXT_TOKEN : if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) - gl2psListAdd(gl2ps->primitives, + gl2psListAdd(gl2ps->primitives, gl2psListPointer(gl2ps->auxprimitives, auxindex++)); else gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); break; } - current += 2; - used -= 2; - break; + current += 2; + used -= 2; + break; default : gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); current ++; @@ -2398,7 +2393,7 @@ gl2psListReset(gl2ps->auxprimitives); } -/********************************************************************* +/********************************************************************* * * PostScript routines * @@ -2428,17 +2423,17 @@ if((width <= 0) || (height <= 0)) return; gl2psPrintf("gsave\n"); - gl2psPrintf("%.2f %.2f translate\n", x, y); - gl2psPrintf("%.2f %.2f scale\n", width * im->zoom_x, height * im->zoom_y); + gl2psPrintf("%.2f %.2f translate\n", x, y); + gl2psPrintf("%d %d scale\n", width, height); if(greyscale){ /* greyscale */ - gl2psPrintf("/picstr %d string def\n", width); - gl2psPrintf("%d %d %d\n", width, height, 8); - gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); + gl2psPrintf("/picstr %d string def\n", width); + gl2psPrintf("%d %d %d\n", width, height, 8); + gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile picstr readhexstring pop }\n"); gl2psPrintf("image\n"); for(row = 0; row < height; row++){ - for(col = 0; col < width; col++){ + for(col = 0; col < width; col++){ gl2psGetRGB(im, col, row, &dr, &dg, &db); fgrey = (0.30F * dr + 0.59F * dg + 0.11F * db); grey = (unsigned char)(255. * fgrey); @@ -2446,8 +2441,8 @@ } gl2psPrintf("\n"); } - nbhex = width * height * 2; - gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); + nbhex = width * height * 2; + gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); } else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */ nrgb = width * 3; @@ -2468,7 +2463,7 @@ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2481,7 +2476,7 @@ b = (b<<2) + blue; if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2493,7 +2488,7 @@ gl2psWriteByte(b); b = 0; icase++; - } + } else if(icase == 2) { b = green; b = (b<<2) + blue; @@ -2512,7 +2507,7 @@ gl2psWriteByte(b); b = 0; icase++; - } + } else if(icase == 3) { b = blue; if(col < width) { @@ -2540,7 +2535,7 @@ nrgb = width * 3; nbits = nrgb * nbit; nbyte = nbits / 8; - if((nbyte * 8) != nbits) nbyte++; + if((nbyte * 8) != nbits) nbyte++; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, nbit); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); @@ -2554,7 +2549,7 @@ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2563,12 +2558,12 @@ green = (unsigned char)(15. * dg); gl2psPrintf("%x%x", red, green); icase++; - } + } else if(icase == 2) { blue = (unsigned char)(15. * db); if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2591,7 +2586,7 @@ nbyte = width * 3; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, 8); - gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); + gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); gl2psPrintf("false 3\n"); gl2psPrintf("colorimage\n"); @@ -2608,7 +2603,7 @@ gl2psPrintf("\n"); } } - + gl2psPrintf("grestore\n"); } @@ -2616,14 +2611,14 @@ GLsizei width, GLsizei height, const unsigned char *imagemap){ int i, size; - + if((width <= 0) || (height <= 0)) return; - + size = height + height * (width - 1) / 8; - + gl2psPrintf("gsave\n"); gl2psPrintf("%.2f %.2f translate\n", x, y); - gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); + gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height); for(i = 0; i < size; i++){ gl2psWriteByte(*imagemap); @@ -2657,7 +2652,7 @@ "%%%%LanguageLevel: 3\n" "%%%%DocumentData: Clean7Bit\n" "%%%%Pages: 1\n", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); @@ -2666,18 +2661,18 @@ "%%%%DocumentMedia: Default %d %d 0 () ()\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait", (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : - (int)gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : + (int)gl2ps->viewport[2], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); } gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" "%%%%EndComments\n", - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : (int)gl2ps->viewport[0], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : (int)gl2ps->viewport[1], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : (int)gl2ps->viewport[2], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); @@ -2725,7 +2720,7 @@ /* rotated text routines: same nameanem with R appended */ gl2psPrintf("/FCT { FC translate 0 0 } BD\n" - "/SR { gsave FCT moveto rotate show grestore } BD\n" + "/SR { gsave FCT moveto rotate show grestore } BD\n" "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n" "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n" "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n"); @@ -2740,7 +2735,7 @@ "/L { lineto } BD\n" "/LE { lineto stroke } BD\n" "/T { newpath moveto lineto lineto closepath fill } BD\n"); - + /* Smooth-shaded triangle with PostScript level 3 shfill operator: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */ @@ -2794,11 +2789,11 @@ " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */ " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */ " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"); - + /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); - + /* Gouraud shaded triangle using recursive subdivision until the difference between corner colors does not exceed the thresholds: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill */ @@ -2832,7 +2827,7 @@ " ifelse }\n" " ifelse }\n" " ifelse } BD\n"); - + gl2psPrintf("tryPS3shading\n" "{ /shfill where\n" " { /ST { STshfill } BD }\n" @@ -2849,7 +2844,7 @@ "%%%%EndSetup\n" "%%%%Page: 1 1\n" "%%%%BeginPageSetup\n"); - + if(gl2ps->options & GL2PS_LANDSCAPE){ gl2psPrintf("%d 0 translate 90 rotate\n", (int)gl2ps->viewport[3]); @@ -2859,14 +2854,14 @@ "mark\n" "gsave\n" "1.0 1.0 scale\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", - gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], - (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], + gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], + (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } } @@ -2896,7 +2891,7 @@ } } -static void gl2psParseStipplePattern(GLushort pattern, GLint factor, +static void gl2psParseStipplePattern(GLushort pattern, GLint factor, int *nb, int array[10]) { int i, n; @@ -2936,10 +2931,10 @@ if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return 0; - + gl2ps->lastpattern = pattern; gl2ps->lastfactor = factor; - + if(!pattern || !factor){ /* solid line */ len += gl2psPrintf("[] 0 %s\n", str); @@ -2953,7 +2948,7 @@ } len += gl2psPrintf("] 0 %s\n", str); } - + return len; } @@ -2976,7 +2971,7 @@ switch(prim->type){ case GL2PS_POINT : gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("%g %g %g P\n", + gl2psPrintf("%g %g %g P\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); break; case GL2PS_LINE : @@ -3139,14 +3134,14 @@ gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", - rgba[0], rgba[1], rgba[2], + rgba[0], rgba[1], rgba[2], x, y, x+w, y, x+w, y+h, x, y+h); } - + gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath clip\n", x, y, x+w, y, x+w, y+h, x, y+h); - + } static GLint gl2psPrintPostScriptEndViewport(void) @@ -3188,7 +3183,7 @@ "Encapsulated Postscript" }; -/********************************************************************* +/********************************************************************* * * LaTeX routines * @@ -3216,7 +3211,7 @@ time(&now); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" @@ -3225,7 +3220,7 @@ GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\setlength{\\unitlength}{1pt}\n" "\\begin{picture}(0,0)\n" "\\includegraphics{%s}\n" @@ -3243,13 +3238,10 @@ switch(prim->type){ case GL2PS_TEXT : - fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", + fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", prim->data.text->fontsize); - fprintf(gl2ps->stream, "\\put(%g,%g)", + fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - if(prim->data.text->angle) - fprintf(gl2ps->stream, "{\\rotatebox{%g}", prim->data.text->angle); - fprintf(gl2ps->stream, "{\\makebox(0,0)"); switch(prim->data.text->alignment){ case GL2PS_TEXT_C: fprintf(gl2ps->stream, "{"); @@ -3280,6 +3272,8 @@ fprintf(gl2ps->stream, "[bl]{"); break; } + if(prim->data.text->angle) + fprintf(gl2ps->stream, "\\rotatebox{%g}{", prim->data.text->angle); fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2], prim->data.text->str); @@ -3307,7 +3301,7 @@ static void gl2psPrintTeXBeginViewport(GLint viewport[4]) { glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintTeXHeader(); gl2ps->header = GL_FALSE; @@ -3336,7 +3330,7 @@ "LaTeX text" }; -/********************************************************************* +/********************************************************************* * * PDF routines * @@ -3372,7 +3366,7 @@ static int gl2psPrintPDFFillColor(GL2PSrgba rgba) { int i, offs = 0; - + for(i = 0; i < 3; ++i){ if(GL2PS_ZERO(rgba[i])) offs += gl2psPrintf("%.0f ", 0.); @@ -3398,18 +3392,18 @@ static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y) { GLfloat rad, crad, srad; - + if(text->angle == 0.0F){ gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f Td\n" "(%s) Tj\n" - "ET\n", + "ET\n", cnt, text->fontsize, x, y, text->str); } else{ - rad = (GLfloat)M_PI * text->angle / 180.0F; + rad = M_PI * text->angle / 180.0F; srad = (GLfloat)sin(rad); crad = (GLfloat)cos(rad); gl2ps->streamlength += gl2psPrintf @@ -3434,23 +3428,23 @@ static void gl2psPDFstacksInit(void) { - gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; - gl2ps->extgs_stack = 0; - gl2ps->font_stack = 0; - gl2ps->im_stack = 0; - gl2ps->trgroupobjects_stack = 0; - gl2ps->shader_stack = 0; - gl2ps->mshader_stack = 0; + gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; + gl2ps->extgs_stack = 0; + gl2ps->font_stack = 0; + gl2ps->im_stack = 0; + gl2ps->trgroupobjects_stack = 0; + gl2ps->shader_stack = 0; + gl2ps->mshader_stack = 0; } static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro) { if(!gro) return; - + gro->ptrlist = NULL; - gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno - = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno + gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno + = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; } @@ -3475,7 +3469,7 @@ gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); gl2psInitTriangle(&lastt); - for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ + for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); switch(p->type){ case GL2PS_PIXMAP: @@ -3493,7 +3487,7 @@ gl2psListAdd(gl2ps->pdfgrouplist, &gro); break; case GL2PS_LINE: - if(lasttype != p->type || lastwidth != p->width || + if(lasttype != p->type || lastwidth != p->width || lastpattern != p->pattern || lastfactor != p->factor || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); @@ -3512,7 +3506,7 @@ lastrgba[2] = p->verts[0].rgba[2]; break; case GL2PS_POINT: - if(lasttype != p->type || lastwidth != p->width || + if(lasttype != p->type || lastwidth != p->width || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); @@ -3529,10 +3523,10 @@ break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); - lastTriangleWasNotSimpleWithSameColor = + lastTriangleWasNotSimpleWithSameColor = !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) || !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba); - if(lasttype == p->type && tmpt.prop == lastt.prop && + if(lasttype == p->type && tmpt.prop == lastt.prop && lastTriangleWasNotSimpleWithSameColor){ /* TODO Check here for last alpha */ gl2psListAdd(gro.ptrlist, &p); @@ -3547,7 +3541,7 @@ break; default: break; - } + } lasttype = p->type; } } @@ -3556,7 +3550,7 @@ { GL2PStriangle t; GL2PSprimitive *prim = NULL; - + if(!gro) return; @@ -3569,35 +3563,35 @@ return; gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); - - if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ - gro->gsno = gl2ps->extgs_stack++; + + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack ++; } - else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->shno = gl2ps->shader_stack++; + gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->shno = gl2ps->shader_stack++; + gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; - gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; @@ -3630,14 +3624,14 @@ gl2ps->streamlength += gl2psPrintf("1 J\n"); gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintf("%f %f m %f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } - gl2ps->streamlength += gl2psPrintf("S\n"); + gl2ps->streamlength += gl2psPrintf("S\n"); gl2ps->streamlength += gl2psPrintf("0 J\n"); break; case GL2PS_LINE: @@ -3648,10 +3642,10 @@ gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d"); /* start new path */ - gl2ps->streamlength += - gl2psPrintf("%f %f m\n", + gl2ps->streamlength += + gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - + for(j = 1; j <= lastel; ++j){ prev = prim; prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); @@ -3659,38 +3653,38 @@ /* the starting point of the new segment does not match the end point of the previous line, so we end the current path and start a new one */ - gl2ps->streamlength += - gl2psPrintf("%f %f l\n", + gl2ps->streamlength += + gl2psPrintf("%f %f l\n", prev->verts[1].xyz[0], prev->verts[1].xyz[1]); - gl2ps->streamlength += - gl2psPrintf("%f %f m\n", + gl2ps->streamlength += + gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } else{ /* the two segements are connected, so we just append to the current path */ - gl2ps->streamlength += + gl2ps->streamlength += gl2psPrintf("%f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } } /* end last path */ - gl2ps->streamlength += - gl2psPrintf("%f %f l\n", + gl2ps->streamlength += + gl2psPrintf("%f %f l\n", prim->verts[1].xyz[0], prim->verts[1].xyz[1]); gl2ps->streamlength += gl2psPrintf("S\n"); break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); gl2psSortOutTrianglePDFgroup(gro); - + /* No alpha and const color: Simple PDF draw orders */ - if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ - gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); - for(j = 0; j <= lastel; ++j){ + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ + gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3700,17 +3694,17 @@ t.vertex[2].xyz[0], t.vertex[2].xyz[1]); } } - /* Const alpha < 1 and const color: Simple PDF draw orders + /* Const alpha < 1 and const color: Simple PDF draw orders and an extra extended Graphics State for the alpha const */ - else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n", gro->gsno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3721,19 +3715,19 @@ } gl2ps->streamlength += gl2psPrintf("Q\n"); } - /* Variable alpha and const color: Simple PDF draw orders - and an extra extended Graphics State + Xobject + Shader + /* Variable alpha and const color: Simple PDF draw orders + and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ - else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n", gro->gsno, gro->trgroupno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3746,23 +3740,23 @@ } /* Variable color and no alpha: Shader Object for the colored triangle(s) */ - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno); } - /* Variable color and const alpha < 1: Shader Object for the - colored triangle(s) and an extra extended Graphics State + /* Variable color and const alpha < 1: Shader Object for the + colored triangle(s) and an extra extended Graphics State for the alpha const */ - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/Sh%d sh\n" "Q\n", gro->gsno, gro->shno); } - /* Variable alpha and color: Shader Object for the colored - triangle(s) and an extra extended Graphics State + /* Variable alpha and color: Shader Object for the colored + triangle(s) and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ - else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n" @@ -3774,12 +3768,12 @@ case GL2PS_PIXMAP: for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], + gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } break; case GL2PS_TEXT: - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0], @@ -3788,7 +3782,7 @@ break; default: break; - } + } } } @@ -3801,15 +3795,15 @@ int i; offs += fprintf(gl2ps->stream, - "/ExtGState\n" + "/ExtGState\n" "<<\n" "/GSa 7 0 R\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->gsno >= 0) offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno); } - offs += fprintf(gl2ps->stream, ">>\n"); + offs += fprintf(gl2ps->stream, ">>\n"); return offs; } @@ -3824,14 +3818,14 @@ offs += fprintf(gl2ps->stream, "/Shading\n" "<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->shno >= 0) offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno); if(gro->maskshno >= 0) offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno); } - offs += fprintf(gl2ps->stream,">>\n"); + offs += fprintf(gl2ps->stream,">>\n"); return offs; } @@ -3848,8 +3842,8 @@ "/XObject\n" "<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); @@ -3881,8 +3875,8 @@ offs += fprintf(gl2ps->stream, "/Font\n<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->fontno < 0) continue; gro->fontobjno = gl2ps->objects_stack++; @@ -3897,11 +3891,11 @@ { int i; GL2PSpdfgroup *gro = NULL; - + if(!gl2ps->pdfgrouplist) return; - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); gl2psListDelete(gro->ptrlist); } @@ -3917,10 +3911,10 @@ int offs; time_t now; struct tm *newtime; - + time(&now); newtime = gmtime(&now); - + offs = fprintf(gl2ps->stream, "1 0 obj\n" "<<\n" @@ -3930,20 +3924,20 @@ gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer); - + if(!newtime){ - offs += fprintf(gl2ps->stream, + offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); return offs; } - - offs += fprintf(gl2ps->stream, + + offs += fprintf(gl2ps->stream, "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" ">>\n" "endobj\n", - newtime->tm_year+1900, - newtime->tm_mon+1, + newtime->tm_year+1900, + newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, @@ -3955,7 +3949,7 @@ static int gl2psPrintPDFCatalog(void) { - return fprintf(gl2ps->stream, + return fprintf(gl2ps->stream, "2 0 obj\n" "<<\n" "/Type /Catalog\n" @@ -3966,9 +3960,9 @@ static int gl2psPrintPDFPages(void) { - return fprintf(gl2ps->stream, + return fprintf(gl2ps->stream, "3 0 obj\n" - "<<\n" + "<<\n" "/Type /Pages\n" "/Kids [6 0 R]\n" "/Count 1\n" @@ -3981,13 +3975,13 @@ static int gl2psOpenPDFDataStream(void) { int offs = 0; - - offs += fprintf(gl2ps->stream, + + offs += fprintf(gl2ps->stream, "4 0 obj\n" - "<<\n" + "<<\n" "/Length 5 0 R\n" ); offs += gl2psPrintPDFCompressorType(); - offs += fprintf(gl2ps->stream, + offs += fprintf(gl2ps->stream, ">>\n" "stream\n"); return offs; @@ -4000,13 +3994,13 @@ int offs; offs = gl2psPrintf("/GSa gs\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ offs += gl2psPrintPDFFillColor(gl2ps->bgcolor); offs += gl2psPrintf("%d %d %d %d re\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - offs += gl2psPrintf("f\n"); + offs += gl2psPrintf("f\n"); } return offs; } @@ -4019,26 +4013,26 @@ gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); gl2psPDFstacksInit(); - gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); + gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); } -#endif +#endif gl2ps->xreflist[0] = 0; offs += fprintf(gl2ps->stream, "%%PDF-1.4\n"); gl2ps->xreflist[1] = offs; - + offs += gl2psPrintPDFInfo(); gl2ps->xreflist[2] = offs; - + offs += gl2psPrintPDFCatalog(); gl2ps->xreflist[3] = offs; - + offs += gl2psPrintPDFPages(); gl2ps->xreflist[4] = offs; - + offs += gl2psOpenPDFDataStream(); gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */ gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); @@ -4050,7 +4044,7 @@ { GL2PSprimitive *prim = *(GL2PSprimitive**)data; - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; prim = gl2psCopyPrimitive(prim); /* deep copy */ @@ -4062,7 +4056,7 @@ static int gl2psClosePDFDataStream(void) { int offs = 0; - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()) @@ -4070,13 +4064,13 @@ else fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); gl2ps->streamlength += gl2ps->compress->destLen; - + offs += gl2ps->streamlength; gl2psFreeCompress(); } -#endif - - offs += fprintf(gl2ps->stream, +#endif + + offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); return offs; @@ -4097,27 +4091,27 @@ static int gl2psPrintPDFOpenPage(void) { int offs; - + /* Write fixed part */ - - offs = fprintf(gl2ps->stream, + + offs = fprintf(gl2ps->stream, "6 0 obj\n" - "<<\n" + "<<\n" "/Type /Page\n" "/Parent 3 0 R\n" "/MediaBox [%d %d %d %d]\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - + if(gl2ps->options & GL2PS_LANDSCAPE) offs += fprintf(gl2ps->stream, "/Rotate -90\n"); - + offs += fprintf(gl2ps->stream, "/Contents 4 0 R\n" - "/Resources\n" - "<<\n" + "/Resources\n" + "<<\n" "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); - + return offs; /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ @@ -4126,19 +4120,19 @@ static int gl2psPDFgroupListWriteVariableResources(void) { int offs = 0; - + /* a) Graphics States for shader alpha masks*/ - offs += gl2psPDFgroupListWriteGStateResources(); - - /* b) Shader and shader masks */ - offs += gl2psPDFgroupListWriteShaderResources(); - + offs += gl2psPDFgroupListWriteGStateResources(); + + /* b) Shader and shader masks */ + offs += gl2psPDFgroupListWriteShaderResources(); + /* c) XObjects (Images & Shader Masks) */ offs += gl2psPDFgroupListWriteXObjectResources(); - + /* d) Fonts */ offs += gl2psPDFgroupListWriteFontResources(); - + /* End resources and page */ offs += fprintf(gl2ps->stream, ">>\n" @@ -4169,10 +4163,10 @@ /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ -static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, - size_t size), - GLfloat dx, GLfloat dy, +static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, + size_t (*action)(unsigned long data, + size_t size), + GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin) { int offs = 0; @@ -4188,7 +4182,7 @@ /* The Shader stream in PDF requires to be in a 'big-endian' order */ - + if(GL2PS_ZERO(dx * dy)){ offs += (*action)(0, 4); offs += (*action)(0, 4); @@ -4201,7 +4195,7 @@ diff = 0.0F; imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); - + diff = (vertex->xyz[1] - ymin) / dy; if(diff > 1) diff = 1.0F; @@ -4210,14 +4204,14 @@ imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); } - + return offs; } /* Put vertex' rgb value (8bit for every component) in shader stream */ static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, + size_t (*action)(unsigned long data, size_t size)) { int offs = 0; @@ -4229,20 +4223,20 @@ imap = (unsigned long)((vertex->rgba[0]) * dmax); offs += (*action)(imap, 1); - + imap = (unsigned long)((vertex->rgba[1]) * dmax); offs += (*action)(imap, 1); - + imap = (unsigned long)((vertex->rgba[2]) * dmax); offs += (*action)(imap, 1); - + return offs; } /* Put vertex' alpha (8/16bit) in shader stream */ -static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, +static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, + size_t (*action)(unsigned long data, size_t size), int sigbyte) { @@ -4255,48 +4249,48 @@ if(sigbyte != 8 && sigbyte != 16) sigbyte = 8; - + sigbyte /= 8; - + imap = (unsigned long)((vertex->rgba[3]) * dmax); - + offs += (*action)(imap, sigbyte); - + return offs; } /* Put a triangles raw data in shader stream */ -static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, - GLfloat dx, GLfloat dy, +static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, + GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin, - size_t (*action)(unsigned long data, + size_t (*action)(unsigned long data, size_t size), int gray) { int i, offs = 0; GL2PSvertex v; - + if(gray && gray != 8 && gray != 16) gray = 8; - + for(i = 0; i < 3; ++i){ offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action, dx, dy, xmin, ymin); - if(gray){ + if(gray){ v = triangle->vertex[i]; - offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); + offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); } else{ offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action); } } - + return offs; } -static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, - GLfloat *ymin, GLfloat *ymax, +static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, + GLfloat *ymin, GLfloat *ymax, GL2PStriangle *triangles, int cnt) { int i, j; @@ -4305,7 +4299,7 @@ *xmax = triangles[0].vertex[0].xyz[0]; *ymin = triangles[0].vertex[0].xyz[1]; *ymax = triangles[0].vertex[0].xyz[1]; - + for(i = 0; i < cnt; ++i){ for(j = 0; j < 3; ++j){ if(*xmin > triangles[i].vertex[j].xyz[0]) @@ -4320,17 +4314,17 @@ } } -/* Writes shaded triangle +/* Writes shaded triangle gray == 0 means write RGB triangles gray == 8 8bit-grayscale (for alpha masks) gray == 16 16bit-grayscale (for alpha masks) */ -static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, +static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, int size, int gray) { int i, offs = 0, vertexbytes, done = 0; GLfloat xmin, xmax, ymin, ymax; - + switch(gray){ case 0: vertexbytes = 1+4+4+1+1+1; @@ -4346,9 +4340,9 @@ vertexbytes = 1+4+4+1; break; } - + gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<< " @@ -4359,18 +4353,18 @@ "/BitsPerFlag 8 " "/Decode [%f %f %f %f 0 1 %s] ", obj, - (gray) ? "/DeviceGray" : "/DeviceRGB", + (gray) ? "/DeviceGray" : "/DeviceRGB", (gray) ? gray : 8, xmin, xmax, ymin, ymax, (gray) ? "" : "0 1 0 1"); - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress(vertexbytes * size * 3); for(i = 0; i < size; ++i) gl2psPrintPDFShaderStreamData(&triangles[i], - xmax-xmin, ymax-ymin, xmin, ymin, + xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ @@ -4380,8 +4374,8 @@ ">>\n" "stream\n", (int)gl2ps->compress->destLen); - offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, - gl2ps->compress->destLen, + offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, + gl2ps->compress->destLen, 1, gl2ps->stream); done = 1; } @@ -4402,11 +4396,11 @@ xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndian, gray); } - + offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); - + return offs; } @@ -4415,7 +4409,7 @@ static int gl2psPrintPDFShaderMask(int obj, int childobj) { int offs = 0, len; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4427,11 +4421,11 @@ obj, (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - - len = (childobj>0) + + len = (childobj>0) ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 - : strlen("/TrSh0 sh\n"); - + : strlen("/TrSh0 sh\n"); + offs += fprintf(gl2ps->stream, "/Length %d\n" ">>\n" @@ -4443,7 +4437,7 @@ offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); - + return offs; } @@ -4454,16 +4448,16 @@ static int gl2psPrintPDFShaderExtGS(int obj, int childobj) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n", obj); - + offs += fprintf(gl2ps->stream, "/SMask << /S /Alpha /G %d 0 R >> ", childobj); - + offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); @@ -4475,7 +4469,7 @@ static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4489,8 +4483,8 @@ /* Similar groups of functions for pixmaps and text */ static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, - size_t (*action)(unsigned long data, - size_t size), + size_t (*action)(unsigned long data, + size_t size), int gray) { int x, y, shift; @@ -4503,7 +4497,7 @@ gray = 8; gray /= 8; - + shift = (sizeof(unsigned long) - 1) * 8; for(y = 0; y < im->height; ++y){ @@ -4534,10 +4528,10 @@ if(gray && gray !=8 && gray != 16) gray = 8; - + if(gray) - sigbytes = gray / 8; - + sigbytes = gray / 8; + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4555,13 +4549,13 @@ "/SMask %d 0 R\n", childobj); } - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress((int)(im->width * im->height * sigbytes)); - + gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray); - + if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); offs += fprintf(gl2ps->stream, @@ -4576,7 +4570,7 @@ gl2psFreeCompress(); } #endif - + if(!done){ /* no compression, or too long after compression, or compress error -> write non-compressed entry */ @@ -4587,18 +4581,18 @@ (int)(im->width * im->height * sigbytes)); offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray); } - + offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); - + return offs; } static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4626,9 +4620,9 @@ if(!gl2ps->pdfgrouplist) return offs; - - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); @@ -4640,7 +4634,7 @@ case GL2PS_TRIANGLE: size = gl2psListNbr(gro->ptrlist); triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); - for(j = 0; j < size; ++j){ + for(j = 0; j < size; ++j){ p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); } @@ -4682,7 +4676,7 @@ break; default: break; - } + } } return offs; } @@ -4693,29 +4687,29 @@ static void gl2psPrintPDFFooter(void) { - int i, offs; + int i, offs; gl2psPDFgroupListInit(); gl2psPDFgroupListWriteMainStream(); - - offs = gl2ps->xreflist[5] + gl2ps->streamlength; + + offs = gl2ps->xreflist[5] + gl2ps->streamlength; offs += gl2psClosePDFDataStream(); gl2ps->xreflist[5] = offs; - + offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); gl2ps->xreflist[6] = offs; gl2ps->streamlength = 0; - + offs += gl2psPrintPDFOpenPage(); offs += gl2psPDFgroupListWriteVariableResources(); gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist, sizeof(int) * (gl2ps->objects_stack + 1)); gl2ps->xreflist[7] = offs; - + offs += gl2psPrintPDFGSObject(); gl2ps->xreflist[8] = offs; - - gl2ps->xreflist[gl2ps->objects_stack] = + + gl2ps->xreflist[gl2ps->objects_stack] = gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); /* Start cross reference table. The file has to been opened in @@ -4724,13 +4718,13 @@ "xref\n" "0 %d\n" "%010d 65535 f \n", gl2ps->objects_stack, 0); - + for(i = 1; i < gl2ps->objects_stack; ++i) fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]); - + fprintf(gl2ps->stream, "trailer\n" - "<<\n" + "<<\n" "/Size %d\n" "/Info 1 0 R\n" "/Root 2 0 R\n" @@ -4738,13 +4732,13 @@ "startxref\n%d\n" "%%%%EOF\n", gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); - - /* Free auxiliary lists and arrays */ + + /* Free auxiliary lists and arrays */ gl2psFree(gl2ps->xreflist); gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive); gl2psListDelete(gl2ps->pdfprimlist); gl2psPDFgroupListDelete(); - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psFreeCompress(); @@ -4762,16 +4756,16 @@ GLint index; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; - + glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintPDFHeader(); gl2ps->header = GL_FALSE; } offs += gl2psPrintf("q\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); @@ -4791,18 +4785,18 @@ } else{ offs += gl2psPrintf("%d %d %d %d re\n" - "W\n" + "W\n" "n\n", - x, y, w, h); - } - + x, y, w, h); + } + gl2ps->streamlength += offs; } static GLint gl2psPrintPDFEndViewport(void) { GLint res; - + res = gl2psPrintPrimitives(); gl2ps->streamlength += gl2psPrintf("Q\n"); return res; @@ -4825,13 +4819,13 @@ "Portable Document Format" }; -/********************************************************************* +/********************************************************************* * * SVG routines * *********************************************************************/ -static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, +static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, GL2PSxyz *xyz, GL2PSrgba *rgba) { int i, j; @@ -4861,9 +4855,9 @@ int x, y, width, height; char col[32]; time_t now; - + time(&now); - + if (gl2ps->options & GL2PS_LANDSCAPE){ x = (int)gl2ps->viewport[1]; y = (int)gl2ps->viewport[0]; @@ -4876,10 +4870,10 @@ width = (int)gl2ps->viewport[2]; height = (int)gl2ps->viewport[3]; } - + /* Compressed SVG files (.svgz) are simply gzipped SVG files */ gl2psPrintGzipHeader(); - + gl2psPrintf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); gl2psPrintf("<svg xmlns=\"http://www.w3.org/2000/svg\"\n"); gl2psPrintf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n" @@ -4899,9 +4893,9 @@ if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psSVGGetColorString(gl2ps->bgcolor, col); gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } @@ -4924,52 +4918,52 @@ gl2psSVGGetColorString(rgba[0], col); gl2psPrintf("<polygon fill=\"%s\" ", col); if(rgba[0][3] < 1.0F) gl2psPrintf("fill-opacity=\"%g\" ", rgba[0][3]); - gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], + gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); } else{ /* subdivide into 4 subtriangles */ for(i = 0; i < 3; i++){ - xyz2[0][i] = xyz[0][i]; + xyz2[0][i] = xyz[0][i]; xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ - rgba2[0][i] = rgba[0][i]; + rgba2[0][i] = rgba[0][i]; rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); - xyz2[1][i] = xyz[1][i]; + xyz2[1][i] = xyz[1][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); - rgba2[1][i] = rgba[1][i]; + rgba2[1][i] = rgba[1][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]); - xyz2[1][i] = xyz[2][i]; + xyz2[1][i] = xyz[2][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]); - rgba2[1][i] = rgba[2][i]; + rgba2[1][i] = rgba[2][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); - xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); + xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); - rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); + rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); @@ -4995,7 +4989,7 @@ { int i; if(gl2ps->lastvertex.rgba[0] >= 0.){ - gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], + gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]); for(i = 0; i < 3; i++) gl2ps->lastvertex.xyz[i] = -1.; @@ -5017,7 +5011,7 @@ file), we need to encode the pixmap into PNG in memory, then encode it into base64. */ - png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, + png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, sizeof(unsigned char)); gl2psConvertPixmapToPNG(pixmap, png); gl2psListEncodeBase64(png); @@ -5086,7 +5080,7 @@ gl2ps->lastfactor = prim->factor; if(newline){ gl2psSVGGetColorString(rgba[0], col); - gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", + gl2psPrintf("<polyline fill=\"none\" stroke=\"%s\" stroke-width=\"%g\" ", col, prim->width); if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]); gl2psPrintSVGDash(prim->pattern, prim->factor); @@ -5112,42 +5106,6 @@ if(prim->data.text->angle) gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ", -prim->data.text->angle, xyz[0][0], xyz[0][1]); - switch(prim->data.text->alignment){ - case GL2PS_TEXT_C: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_CL: - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_CR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_B: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"0\" "); - break; - case GL2PS_TEXT_BR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"0\" "); - break; - case GL2PS_TEXT_T: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_TL: - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_TR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_BL: - default: /* same as GL2PS_TEXT_BL */ - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"0\" "); - break; - } if(!strcmp(prim->data.text->fontname, "Times-Roman")) gl2psPrintf("font-family=\"Times\">"); else if(!strcmp(prim->data.text->fontname, "Times-Bold")) @@ -5186,8 +5144,8 @@ static void gl2psPrintSVGFooter(void) { gl2psPrintf("</g>\n"); - gl2psPrintf("</svg>\n"); - + gl2psPrintf("</svg>\n"); + gl2psPrintGzipFooter(); } @@ -5199,7 +5157,7 @@ int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintSVGHeader(); gl2ps->header = GL_FALSE; @@ -5217,18 +5175,18 @@ rgba[3] = 1.0F; } gl2psSVGGetColorString(rgba, col); - gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, - x, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - (y + h), + gl2psPrintf("<polygon fill=\"%s\" points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", col, + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); } gl2psPrintf("<clipPath id=\"cp%d%d%d%d\">\n", x, y, w, h); - gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", - x, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - (y + h), + gl2psPrintf(" <polygon points=\"%d,%d %d,%d %d,%d %d,%d\"/>\n", + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); gl2psPrintf("</clipPath>\n"); gl2psPrintf("<g clip-path=\"url(#cp%d%d%d%d)\">\n", x, y, w, h); @@ -5282,7 +5240,7 @@ time(&now); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" @@ -5336,7 +5294,7 @@ case GL2PS_TEXT_T : return "north"; case GL2PS_TEXT_TL : return "north west"; case GL2PS_TEXT_TR : return "north east"; - case GL2PS_TEXT_BL : + case GL2PS_TEXT_BL : default : return "south west"; } } @@ -5351,7 +5309,7 @@ case GL2PS_POINT : /* Points in openGL are rectangular */ gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", prim->verts[0].xyz[0]-0.5*prim->width, @@ -5365,7 +5323,7 @@ fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); } gl2psPrintPGFDash(prim->pattern, prim->factor); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgfusepath{stroke}\n", @@ -5378,7 +5336,7 @@ fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); } gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" @@ -5447,14 +5405,14 @@ rgba[3] = 1.0F; } gl2psPrintPGFColor(rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{fill}\n", x, y, w, h); } - - fprintf(gl2ps->stream, + + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{clip}\n", @@ -5486,7 +5444,7 @@ "PGF Latex Graphics" }; -/********************************************************************* +/********************************************************************* * * General primitive printing routine * @@ -5521,7 +5479,7 @@ if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); } -} +} static GLint gl2psPrintPrimitives(void) { @@ -5542,7 +5500,7 @@ gl2psRescaleAndOffset(); if(gl2ps->header){ - if(gl2psListNbr(gl2ps->primitives) && + if(gl2psListNbr(gl2ps->primitives) && (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; @@ -5584,7 +5542,7 @@ gl2psAddInImageTree, 1); gl2psFreeBspImageTree(&gl2ps->imagetree); } - gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, + gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, gl2psbackends[gl2ps->format]->printPrimitive, 0); gl2psFreeBspTree(&root); /* reallocate the primitive list (it's been deleted by @@ -5597,13 +5555,13 @@ return GL2PS_SUCCESS; } -/********************************************************************* +/********************************************************************* * * Public routines * *********************************************************************/ -GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, +GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, @@ -5671,7 +5629,7 @@ if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){ gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)", - gl2ps->viewport[0], gl2ps->viewport[1], + gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3]); gl2psFree(gl2ps); gl2ps = NULL; @@ -5695,11 +5653,11 @@ gl2ps->lastfactor = 0; gl2ps->imagetree = NULL; gl2ps->primitivetoadd = NULL; - gl2ps->zerosurfacearea = GL_FALSE; + gl2ps->zerosurfacearea = GL_FALSE; gl2ps->pdfprimlist = NULL; gl2ps->pdfgrouplist = NULL; gl2ps->xreflist = NULL; - + /* get default blending mode from current OpenGL state (enabled by default for SVG) */ gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND); @@ -5742,7 +5700,7 @@ gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char)); strcpy(gl2ps->title, title); } - + if(!producer){ gl2ps->producer = (char*)gl2psMalloc(sizeof(char)); gl2ps->producer[0] = '\0'; @@ -5751,7 +5709,7 @@ gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char)); strcpy(gl2ps->producer, producer); } - + if(!filename){ gl2ps->filename = (char*)gl2psMalloc(sizeof(char)); gl2ps->filename[0] = '\0'; @@ -5765,7 +5723,7 @@ gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*)); gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat)); glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback); - glRenderMode(GL_FEEDBACK); + glRenderMode(GL_FEEDBACK); return GL2PS_SUCCESS; } @@ -5780,7 +5738,7 @@ if(res != GL2PS_OVERFLOW) (gl2psbackends[gl2ps->format]->printFooter)(); - + fflush(gl2ps->stream); gl2psListDelete(gl2ps->primitives); @@ -5802,7 +5760,7 @@ if(!gl2ps) return GL2PS_UNINITIALIZED; (gl2psbackends[gl2ps->format]->beginViewport)(viewport); - + return GL2PS_SUCCESS; } @@ -5820,7 +5778,7 @@ return res; } -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle); @@ -5838,11 +5796,11 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, - GLenum format, GLenum type, + GLenum format, GLenum type, const void *pixels) { int size, i; - GLfloat pos[4], *piv, zoom_x, zoom_y; + GLfloat pos[4], *piv; GL2PSprimitive *prim; GLboolean valid; @@ -5862,8 +5820,6 @@ if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - glGetFloatv(GL_ZOOM_X, &zoom_x); - glGetFloatv(GL_ZOOM_Y, &zoom_y); prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_PIXMAP; @@ -5882,8 +5838,6 @@ prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); prim->data.image->width = width; prim->data.image->height = height; - prim->data.image->zoom_x = zoom_x; - prim->data.image->zoom_y = zoom_y; prim->data.image->format = format; prim->data.image->type = type; @@ -5897,9 +5851,9 @@ piv = (GLfloat*)pixels; for(i = 0; i < size; ++i, ++piv){ prim->data.image->pixels[i] = *piv; - if(!((i + 1) % 3)) + if(!((i+1)%3)) ++piv; - } + } } else{ size = height * width * 4; @@ -5926,11 +5880,11 @@ const unsigned char *imagemap){ int size, i; int sizeoffloat = sizeof(GLfloat); - + if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED; if((width <= 0) || (height <= 0)) return GL2PS_ERROR; - + size = height + height * ((width - 1) / 8); glPassThrough(GL2PS_IMAGEMAP_TOKEN); glBegin(GL_POINTS); @@ -6010,7 +5964,7 @@ glPassThrough(GL2PS_POINT_SIZE_TOKEN); glPassThrough(value); - + return GL2PS_SUCCESS; }
--- a/src/gl2ps.h +++ b/src/gl2ps.h @@ -139,9 +139,9 @@ #define GL2PS_BLEND 4 /* Text alignment (o=raster position; default mode is BL): - +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o - | o | o | | o | | | | | | | | | | | | - +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ + +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o + | o | o | | o | | | | | | | | | | | | + +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ C CL CR B BL BR T TL TR */ #define GL2PS_TEXT_C 1 @@ -160,10 +160,10 @@ extern "C" { #endif -GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, +GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, - GLint colorsize, GL2PSrgba *colormap, + GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, FILE *stream, const char *filename); GL2PSDLL_API GLint gl2psEndPage(void); @@ -171,9 +171,9 @@ GL2PSDLL_API GLint gl2psGetOptions(GLint *options); GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]); GL2PSDLL_API GLint gl2psEndViewport(void); -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize); -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle); GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
--- a/src/graphics.cc +++ b/src/graphics.cc @@ -3172,6 +3172,7 @@ ticklength.add_constraint (dim_vector (1, 2)); tightinset.add_constraint (dim_vector (1, 4)); looseinset.add_constraint (dim_vector (1, 4)); + update_font (); x_zlim.resize (1, 2); @@ -3263,13 +3264,119 @@ void axes::properties::sync_positions (void) { + Matrix ref_linset = looseinset.get ().matrix_value (); + if (autopos_tag_is ("subplot")) + { + graphics_object parent_obj = gh_manager::get_object (get_parent ()); + if (parent_obj.isa ("figure")) + { + // FIXME: temporarily changed units should be protected + // from interrupts + std::string fig_units = parent_obj.get ("units").string_value (); + parent_obj.set ("units", "pixels"); + + Matrix ref_outbox = outerposition.get ().matrix_value (); + ref_outbox(2) += ref_outbox(0); + ref_outbox(3) += ref_outbox(1); + + // Find those subplots that are left, right, bottom and top aligned + // with the current subplot + Matrix kids = parent_obj.get_properties ().get_children (); + std::vector<octave_value> aligned; + std::vector<bool> l_aligned, b_aligned, r_aligned, t_aligned; + for (octave_idx_type i = 0; i < kids.numel (); i++) + { + graphics_object go = gh_manager::get_object (kids(i)); + if (go.isa ("axes")) + { + axes::properties& props = + dynamic_cast<axes::properties&> (go.get_properties ()); + if (props.autopos_tag_is("subplot")) + { + Matrix outpos = go.get ("outerposition").matrix_value (); + bool l_align=(std::abs (outpos(0)-ref_outbox(0)) < 1e-15); + bool b_align=(std::abs (outpos(1)-ref_outbox(1)) < 1e-15); + bool r_align=(std::abs (outpos(0)+outpos(2)-ref_outbox(2)) < 1e-15); + bool t_align=(std::abs (outpos(1)+outpos(3)-ref_outbox(3)) < 1e-15); + if (l_align || b_align || r_align || t_align) + { + aligned.push_back(kids(i)); + l_aligned.push_back(l_align); + b_aligned.push_back(b_align); + r_aligned.push_back(r_align); + t_aligned.push_back(t_align); + // FIXME: the temporarily deleted tags should be + // protected from interrupts + props.set_autopos_tag ("none"); + } + } + } + } + // Determine a minimum box which aligns the subplots + Matrix ref_box(1, 4, 0.); + ref_box(2) = 1.; + ref_box(3) = 1.; + for (size_t i = 0; i < aligned.size (); i++) + { + graphics_object go = gh_manager::get_object (aligned[i]); + axes::properties& props = + dynamic_cast<axes::properties&> (go.get_properties ()); + Matrix linset = props.get_looseinset ().matrix_value (); + if (l_aligned[i]) + linset(0) = std::min (0., linset(0)-0.01); + if (b_aligned[i]) + linset(1) = std::min (0., linset(1)-0.01); + if (r_aligned[i]) + linset(2) = std::min (0., linset(2)-0.01); + if (t_aligned[i]) + linset(3) = std::min (0., linset(3)-0.01); + props.set_looseinset (linset); + Matrix pos = props.get_position ().matrix_value (); + if (l_aligned[i]) + ref_box(0) = std::max (ref_box(0), pos(0)); + if (b_aligned[i]) + ref_box(1) = std::max (ref_box(1), pos(1)); + if (r_aligned[i]) + ref_box(2) = std::min (ref_box(2), pos(0)+pos(2)); + if (t_aligned[i]) + ref_box(3) = std::min (ref_box(3), pos(1)+pos(3)); + } + // Set common looseinset values for all aligned subplots and + // revert their tag values + for (size_t i = 0; i < aligned.size (); i++) + { + graphics_object go = gh_manager::get_object (aligned[i]); + axes::properties& props = + dynamic_cast<axes::properties&> (go.get_properties ()); + Matrix outpos = props.get_outerposition ().matrix_value (); + Matrix linset = props.get_looseinset ().matrix_value (); + if (l_aligned[i]) + linset(0) = (ref_box(0)-outpos(0))/outpos(2); + if (b_aligned[i]) + linset(1) = (ref_box(1)-outpos(1))/outpos(3); + if (r_aligned[i]) + linset(2) = (outpos(0)+outpos(2)-ref_box(2))/outpos(2); + if (t_aligned[i]) + linset(3) = (outpos(1)+outpos(3)-ref_box(3))/outpos(3); + props.set_looseinset (linset); + props.set_autopos_tag ("subplot"); + } + parent_obj.set ("units", fig_units); + } + } + else + sync_positions (ref_linset); +} + +void +axes::properties::sync_positions (const Matrix& linset) +{ Matrix pos = position.get ().matrix_value (); Matrix outpos = outerposition.get ().matrix_value (); - Matrix lins = looseinset.get ().matrix_value (); - double lratio = lins(0); - double bratio = lins(1); - double wratio = 1-lins(0)-lins(2); - double hratio = 1-lins(1)-lins(3); + double lratio = linset(0); + double bratio = linset(1); + double wratio = 1-linset(0)-linset(2); + double hratio = 1-linset(1)-linset(3); if (activepositionproperty.is ("outerposition")) { pos = outpos; @@ -4223,15 +4330,22 @@ update_title_position (); } +static bool updating_xlabel_position = false; + void axes::properties::update_xlabel_position (void) { + if (updating_xlabel_position) + return; + text::properties& xlabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_xlabel ()).get_properties ()); - bool is_empty = xlabel_props.get_string ().empty (); - - xlabel_props.set_autopos_tag ("none"); + bool is_empty = xlabel_props.get_string ().is_empty (); + + unwind_protect frame; + frame.protect_var (updating_xlabel_position); + updating_xlabel_position = true; if (! is_empty) { @@ -4305,19 +4419,24 @@ xlabel_props.set_rotationmode ("auto"); } } - - xlabel_props.set_autopos_tag ("xlabel"); -} +} + +static bool updating_ylabel_position = false; void axes::properties::update_ylabel_position (void) { + if (updating_ylabel_position) + return; + text::properties& ylabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_ylabel ()).get_properties ()); - bool is_empty = ylabel_props.get_string ().empty (); - - ylabel_props.set_autopos_tag ("none"); + bool is_empty = ylabel_props.get_string ().is_empty (); + + unwind_protect frame; + frame.protect_var (updating_ylabel_position); + updating_ylabel_position = true; if (! is_empty) { @@ -4391,20 +4510,25 @@ ylabel_props.set_rotationmode ("auto"); } } - - ylabel_props.set_autopos_tag ("ylabel"); -} +} + +static bool updating_zlabel_position = false; void axes::properties::update_zlabel_position (void) { + if (updating_zlabel_position) + return; + text::properties& zlabel_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_zlabel ()).get_properties ()); bool camAuto = cameraupvectormode_is ("auto"); - bool is_empty = zlabel_props.get_string ().empty (); - - zlabel_props.set_autopos_tag ("none"); + bool is_empty = zlabel_props.get_string ().is_empty (); + + unwind_protect frame; + frame.protect_var (updating_zlabel_position); + updating_zlabel_position = true; if (! is_empty) { @@ -4499,17 +4623,22 @@ zlabel_props.set_rotationmode ("auto"); } } - - zlabel_props.set_autopos_tag ("zlabel"); -} +} + +static bool updating_title_position = false; void axes::properties::update_title_position (void) { + if (updating_title_position) + return; + text::properties& title_props = reinterpret_cast<text::properties&> (gh_manager::get_object (get_title ()).get_properties ()); - title_props.set_autopos_tag ("none"); + unwind_protect frame; + frame.protect_var (updating_title_position); + updating_title_position = true; if (title_props.positionmode_is ("auto")) { @@ -4523,8 +4652,6 @@ title_props.set_position (p.extract_n(0, 3).transpose ()); title_props.set_positionmode ("auto"); } - - title_props.set_autopos_tag ("title"); } void @@ -4693,6 +4820,19 @@ } } +void +axes::properties::update_font (void) +{ +#ifdef HAVE_FREETYPE +#ifdef HAVE_FONTCONFIG + text_renderer.set_font (get ("fontname").string_value (), + get ("fontweight").string_value (), + get ("fontangle").string_value (), + get ("fontsize").double_value ()); +#endif +#endif +} + // The INTERNAL flag defines whether position or outerposition is used. Matrix @@ -4756,7 +4896,7 @@ Matrix text_pos = text_props.get_position ().matrix_value (); text_pos = xform.transform (text_pos(0), text_pos(1), text_pos(2)); - if (text_props.get_string ().empty ()) + if (text_props.get_string ().is_empty ()) { ext(0) = std::min (ext(0), text_pos(0)); ext(1) = std::min (ext(1), text_pos(1)); @@ -5196,14 +5336,7 @@ const string_vector& ticklabels, const Matrix& limits) { -#ifdef HAVE_FREETYPE - //FIXME: text_renderer could be cached - ft_render text_renderer; - text_renderer.set_font (get ("fontname").string_value (), - get ("fontweight").string_value (), - get ("fontangle").string_value (), - get ("fontsize").double_value ()); -#else +#ifndef HAVE_FREETYPE double fontsize = get ("fontsize").double_value (); #endif @@ -5856,11 +5989,9 @@ } void -text::properties::update_text_extent (void) +text::properties::update_font (void) { #ifdef HAVE_FREETYPE - - // FIXME: font and color should be set only when modified, for efficiency #ifdef HAVE_FONTCONFIG renderer.set_font (get ("fontname").string_value (), get ("fontweight").string_value (), @@ -5868,6 +5999,13 @@ get ("fontsize").double_value ()); #endif renderer.set_color (get_color_rgb ()); +#endif +} + +void +text::properties::update_text_extent (void) +{ +#ifdef HAVE_FREETYPE int halign = 0, valign = 0; @@ -5884,11 +6022,17 @@ valign = 1; Matrix bbox; + // FIXME: string should be parsed only when modified, for efficiency - renderer.text_to_pixels (get_string (), pixels, bbox, + + octave_value string_prop = get_string (); + + string_vector sv = string_prop.all_strings (); + + renderer.text_to_pixels (sv.join ("\n"), pixels, bbox, halign, valign, get_rotation ()); - set_extent (bbox); + #endif if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") || @@ -6909,6 +7053,12 @@ if (nargin == 1 || nargin == 2) { + if (args(0).is_empty()) + { + retval = Matrix (); + return retval; + } + ColumnVector hcv (args(0).vector_value ()); if (! error_state)
--- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -33,6 +33,7 @@ #include <list> #include <map> #include <set> +#include <sstream> #include <string> #include "caseless-str.h" @@ -692,6 +693,178 @@ // --------------------------------------------------------------------- +class text_label_property : public base_property +{ +public: + enum type { char_t, cellstr_t }; + + text_label_property (const std::string& s, const graphics_handle& h, + const std::string& val = "") + : base_property (s, h), value (val), stored_type (char_t) + { } + + text_label_property (const std::string& s, const graphics_handle& h, + const NDArray& nda) + : base_property (s, h), stored_type (char_t) + { + octave_idx_type nel = nda.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + std::ostringstream buf; + buf << nda(i); + value[i] = buf.str (); + } + } + + text_label_property (const std::string& s, const graphics_handle& h, + const Cell& c) + : base_property (s, h), stored_type (cellstr_t) + { + octave_idx_type nel = c.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value tmp = c(i); + + if (tmp.is_string ()) + value[i] = c(i).string_value (); + else + { + double d = c(i).double_value (); + + if (! error_state) + { + std::ostringstream buf; + buf << d; + value[i] = buf.str (); + } + else + break; + } + } + } + + text_label_property (const text_label_property& p) + : base_property (p), value (p.value), stored_type (p.stored_type) + { } + + bool empty (void) const + { + octave_value tmp = get (); + return tmp.is_empty (); + } + + octave_value get (void) const + { + if (stored_type == char_t) + return octave_value (char_value ()); + else + return octave_value (cell_value ()); + } + + std::string string_value (void) const + { + return value.empty () ? std::string () : value[0]; + } + + string_vector string_vector_value (void) const { return value; } + + charMatrix char_value (void) const { return charMatrix (value, ' '); } + + Cell cell_value (void) const {return Cell (value); } + + text_label_property& operator = (const octave_value& val) + { + set (val); + return *this; + } + + base_property* clone (void) const { return new text_label_property (*this); } + +protected: + + bool do_set (const octave_value& val) + { + if (val.is_string ()) + { + value = val.all_strings (); + + stored_type = char_t; + } + else if (val.is_cell ()) + { + Cell c = val.cell_value (); + + octave_idx_type nel = c.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value tmp = c(i); + + if (tmp.is_string ()) + value[i] = c(i).string_value (); + else + { + double d = c(i).double_value (); + + if (! error_state) + { + std::ostringstream buf; + buf << d; + value[i] = buf.str (); + } + else + return false; + } + } + + stored_type = cellstr_t; + } + else + { + NDArray nda = val.array_value (); + + if (! error_state) + { + octave_idx_type nel = nda.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + std::ostringstream buf; + buf << nda(i); + value[i] = buf.str (); + } + + stored_type = char_t; + } + else + { + error ("set: invalid string property value for \"%s\"", + get_name ().c_str ()); + + return false; + } + } + + return true; + } + +private: + string_vector value; + type stored_type; +}; + +// --------------------------------------------------------------------- + class radio_values { public: @@ -3206,6 +3379,11 @@ bool x2Dtop, y2Dright, layer2Dtop; bool xySym, xyzSym, zSign, nearhoriz; +#if HAVE_FREETYPE + // freetype renderer, used for calculation of text (tick labels) size + ft_render text_renderer; +#endif + void set_text_child (handle_property& h, const std::string& who, const octave_value& v); @@ -3288,11 +3466,11 @@ radio_property cameraviewanglemode , "{auto}|manual" array_property currentpoint , Matrix (2, 3, 0.0) radio_property drawmode , "{normal}|fast" - radio_property fontangle , "{normal}|italic|oblique" - string_property fontname , OCTAVE_DEFAULT_FONTNAME - double_property fontsize , 10 + radio_property fontangle u , "{normal}|italic|oblique" + string_property fontname u , OCTAVE_DEFAULT_FONTNAME + double_property fontsize u , 10 radio_property fontunits SU , "{points}|normalized|inches|centimeters|pixels" - radio_property fontweight , "{normal}|light|demi|bold" + radio_property fontweight u , "{normal}|light|demi|bold" radio_property gridlinestyle , "-|--|{:}|-.|none" string_array_property linestyleorder , "-" double_property linewidth , 0.5 @@ -3318,6 +3496,8 @@ row_vector_property zmtick h , Matrix () // hidden properties for inset array_property looseinset hu , Matrix (1, 4, 0.0) + // hidden properties for alignment of subplots + radio_property autopos_tag h , "{none}|subplot" END_PROPERTIES protected: @@ -3411,7 +3591,15 @@ calc_ticklabels (ztick, zticklabel, zscale.is ("log")); } + void update_font (void); + void update_fontname (void) { update_font (); } + void update_fontsize (void) { update_font (); } + void update_fontangle (void) { update_font (); } + void update_fontweight (void) { update_font (); } + + void sync_positions (const Matrix& linset); void sync_positions (void); + void update_outerposition (void) { set_activepositionproperty ("outerposition"); @@ -3671,7 +3859,7 @@ // properties declarations. BEGIN_PROPERTIES (text) - string_property string u , "" + text_label_property string u , "" radio_property units u , "{data}|pixels|normalized|inches|centimeters|points" array_property position mu , Matrix (1, 3, 0.0) double_property rotation mu , 0 @@ -3712,7 +3900,7 @@ Matrix get_extent_matrix (void) const; const uint8NDArray& get_pixels (void) const { return pixels; } #if HAVE_FREETYPE - // freetype render, used for text rendering + // freetype renderer, used for calculation of text size ft_render renderer; #endif @@ -3722,6 +3910,7 @@ position.add_constraint (dim_vector (1, 2)); position.add_constraint (dim_vector (1, 3)); cached_units = get_units (); + update_font (); } private: @@ -3757,13 +3946,14 @@ void update_horizontalalignmentmode (void) { request_autopos (); } void update_verticalalignmentmode (void) { request_autopos (); } + void update_font (void); void update_string (void) { request_autopos (); update_text_extent (); } void update_rotation (void) { update_text_extent (); } - void update_color (void) { update_text_extent (); } - void update_fontname (void) { update_text_extent (); } - void update_fontsize (void) { update_text_extent (); } - void update_fontangle (void) { update_text_extent (); } - void update_fontweight (void) { update_text_extent (); } + void update_color (void) { update_font (); } + void update_fontname (void) { update_font (); update_text_extent (); } + void update_fontsize (void) { update_font (); update_text_extent (); } + void update_fontangle (void) { update_font (); update_text_extent (); } + void update_fontweight (void) { update_font (); update_text_extent (); } void update_interpreter (void) { update_text_extent (); } void update_horizontalalignment (void) { update_text_extent (); } void update_verticalalignment (void) { update_text_extent (); }
--- a/src/help.cc +++ b/src/help.cc @@ -749,6 +749,9 @@ const string_vector bif = symbol_table::built_in_function_names (); const int bif_len = bif.length (); + const string_vector cfl = symbol_table::cmdline_function_names (); + const int cfl_len = cfl.length (); + const string_vector lcl = symbol_table::variable_names (); const int lcl_len = lcl.length (); @@ -758,7 +761,8 @@ const string_vector afl = autoloaded_functions (); const int afl_len = afl.length (); - const int total_len = key_len + bif_len + lcl_len + ffl_len + afl_len; + const int total_len + = key_len + bif_len + cfl_len + lcl_len + ffl_len + afl_len; string_vector list (total_len); @@ -772,6 +776,9 @@ for (i = 0; i < bif_len; i++) list[j++] = bif[i]; + for (i = 0; i < cfl_len; i++) + list[j++] = cfl[i]; + for (i = 0; i < lcl_len; i++) list[j++] = lcl[i];
--- a/src/input.cc +++ b/src/input.cc @@ -686,93 +686,88 @@ frame.protect_var (VPS1); VPS1 = prompt; - if (stdin_is_tty) + if (! (interactive || forced_interactive) + || (reading_fcn_file + || reading_classdef_file + || reading_script_file + || get_input_from_eval_string + || input_from_startup_file + || input_from_command_line_file)) { - if (! (interactive || forced_interactive) - || (reading_fcn_file - || reading_classdef_file - || reading_script_file - || get_input_from_eval_string - || input_from_startup_file - || input_from_command_line_file)) - { - frame.protect_var (forced_interactive); - forced_interactive = true; + frame.protect_var (forced_interactive); + forced_interactive = true; + + frame.protect_var (reading_fcn_file); + reading_fcn_file = false; + + frame.protect_var (reading_classdef_file); + reading_classdef_file = false; + + frame.protect_var (reading_script_file); + reading_script_file = false; - frame.protect_var (reading_fcn_file); - reading_fcn_file = false; + frame.protect_var (input_from_startup_file); + input_from_startup_file = false; + + frame.protect_var (input_from_command_line_file); + input_from_command_line_file = false; - frame.protect_var (reading_classdef_file); - reading_classdef_file = false; + frame.protect_var (get_input_from_eval_string); + get_input_from_eval_string = false; + + YY_BUFFER_STATE old_buf = current_buffer (); + YY_BUFFER_STATE new_buf = create_buffer (get_input_from_stdin ()); + + // FIXME: are these safe? + frame.add_fcn (switch_to_buffer, old_buf); + frame.add_fcn (delete_buffer, new_buf); - frame.protect_var (reading_script_file); - reading_script_file = false; + switch_to_buffer (new_buf); + } + + while (Vdebugging) + { + reset_error_handler (); + + reset_parser (); - frame.protect_var (input_from_startup_file); - input_from_startup_file = false; + // Save current value of global_command. + frame.protect_var (global_command); + + global_command = 0; - frame.protect_var (input_from_command_line_file); - input_from_command_line_file = false; + // Do this with an unwind-protect cleanup function so that the + // forced variables will be unmarked in the event of an interrupt. + symbol_table::scope_id scope = symbol_table::top_scope (); + frame.add_fcn (symbol_table::unmark_forced_variables, scope); - frame.protect_var (get_input_from_eval_string); - get_input_from_eval_string = false; + // This is the same as yyparse in parse.y. + int retval = octave_parse (); - YY_BUFFER_STATE old_buf = current_buffer (); - YY_BUFFER_STATE new_buf = create_buffer (get_input_from_stdin ()); + if (retval == 0 && global_command) + { + global_command->accept (*current_evaluator); - // FIXME: are these safe? - frame.add_fcn (switch_to_buffer, old_buf); - frame.add_fcn (delete_buffer, new_buf); + // FIXME -- To avoid a memory leak, global_command should be + // deleted, I think. But doing that here causes trouble if + // an error occurs while executing a debugging command + // (dbstep, for example). It's not clear to me why that + // happens. + // + // delete global_command; + // + // global_command = 0; - switch_to_buffer (new_buf); + if (octave_completion_matches_called) + octave_completion_matches_called = false; } - while (Vdebugging) - { - reset_error_handler (); - - reset_parser (); - - // Save current value of global_command. - frame.protect_var (global_command); - - global_command = 0; - - // Do this with an unwind-protect cleanup function so that the - // forced variables will be unmarked in the event of an interrupt. - symbol_table::scope_id scope = symbol_table::top_scope (); - frame.add_fcn (symbol_table::unmark_forced_variables, scope); - - // This is the same as yyparse in parse.y. - int retval = octave_parse (); - - if (retval == 0 && global_command) - { - global_command->accept (*current_evaluator); + // Unmark forced variables. + // Restore previous value of global_command. + frame.run_top (2); - // FIXME -- To avoid a memory leak, global_command should be - // deleted, I think. But doing that here causes trouble if - // an error occurs while executing a debugging command - // (dbstep, for example). It's not clear to me why that - // happens. - // - // delete global_command; - // - // global_command = 0; - - if (octave_completion_matches_called) - octave_completion_matches_called = false; - } - - // Unmark forced variables. - // Restore previous value of global_command. - frame.run_top (2); - - octave_quit (); - } + octave_quit (); } - else - warning ("invalid attempt to debug script read from stdin"); } // If the user simply hits return, this will produce an empty matrix. @@ -956,14 +951,11 @@ unwind_protect frame; - // FIXME -- we shouldn't need both the - // command_history object and the - // Vsaving_history variable... + frame.add_fcn (command_history::ignore_entries, + command_history::ignoring_entries ()); + command_history::ignore_entries (false); - frame.add_fcn (command_history::ignore_entries, ! Vsaving_history); - - frame.protect_var (Vsaving_history); frame.protect_var (Vdebugging); frame.add_fcn (octave_call_stack::restore_frame, @@ -975,7 +967,6 @@ // tree_print_code tpc (octave_stdout); // stmt.accept (tpc); - Vsaving_history = true; Vdebugging = true; std::string prompt = "debug> ";
--- a/src/lex.ll +++ b/src/lex.ll @@ -164,13 +164,13 @@ } \ while (0) -#define BIN_OP_RETURN(tok, convert, bos) \ +#define BIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ do \ { \ yylval.tok_val = new token (input_line_number, current_input_column); \ token_stack.push (yylval.tok_val); \ current_input_column += yyleng; \ - lexer_flags.quote_is_transpose = false; \ + lexer_flags.quote_is_transpose = qit; \ lexer_flags.convert_spaces_to_comma = convert; \ lexer_flags.looking_for_object_index = false; \ lexer_flags.at_beginning_of_statement = bos; \ @@ -178,6 +178,21 @@ } \ while (0) +#define XBIN_OP_RETURN_INTERNAL(tok, convert, bos, qit) \ + do \ + { \ + gripe_matlab_incompatible_operator (yytext); \ + BIN_OP_RETURN_INTERNAL (tok, convert, bos, qit); \ + } \ + while (0) + +#define BIN_OP_RETURN(tok, convert, bos) \ + do \ + { \ + BIN_OP_RETURN_INTERNAL (tok, convert, bos, false); \ + } \ + while (0) + #define XBIN_OP_RETURN(tok, convert, bos) \ do \ { \ @@ -896,8 +911,8 @@ ".^" { LEXER_DEBUG (".^"); BIN_OP_RETURN (EPOW, false, false); } ".**" { LEXER_DEBUG (".**"); XBIN_OP_RETURN (EPOW, false, false); } ".'" { LEXER_DEBUG (".'"); do_comma_insert_check (); BIN_OP_RETURN (TRANSPOSE, true, false); } -"++" { LEXER_DEBUG ("++"); do_comma_insert_check (); XBIN_OP_RETURN (PLUS_PLUS, true, false); } -"--" { LEXER_DEBUG ("--"); do_comma_insert_check (); XBIN_OP_RETURN (MINUS_MINUS, true, false); } +"++" { LEXER_DEBUG ("++"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (PLUS_PLUS, true, false, true); } +"--" { LEXER_DEBUG ("--"); do_comma_insert_check (); XBIN_OP_RETURN_INTERNAL (MINUS_MINUS, true, false, true); } "<=" { LEXER_DEBUG ("<="); BIN_OP_RETURN (EXPR_LE, false, false); } "==" { LEXER_DEBUG ("=="); BIN_OP_RETURN (EXPR_EQ, false, false); } "~=" { LEXER_DEBUG ("~="); BIN_OP_RETURN (EXPR_NE, false, false); } @@ -3435,6 +3450,14 @@ return retval; } +/* + +%!assert (iskeyword ("for")) +%!assert (iskeyword ("fort"), false) +%!assert (iskeyword ("fft"), false) + +*/ + void prep_lexer_for_script_file (void) {
new file mode 100644 --- /dev/null +++ b/src/link-deps.mk @@ -0,0 +1,38 @@ +include ../liboctave/link-deps.mk + +if AMCOND_ENABLE_DYNAMIC_LINKING + LIBOCTINTERP_LINK_DEPS = +else + LIBOCTINTERP_LINK_DEPS = $(DLD_FUNCTIONS_LIBS) +endif + +LIBOCTINTERP_LINK_DEPS += \ + $(GRAPHICS_LIBS) \ + $(FT2_LIBS) \ + $(HDF5_LIBS) \ + $(Z_LIBS) \ + $(OPENGL_LIBS) \ + $(X11_LIBS) \ + $(CARBON_LIBS) + +LIBOCTINTERP_LINK_OPTS = \ + $(GRAPHICS_LDFLAGS) \ + $(FT2_LDFLAGS) \ + $(HDF5_LDFLAGS) \ + $(Z_LDFLAGS) \ + $(REGEX_LDFLAGS) + +OCT_LINK_DEPS = + +OCT_LINK_OPTS = $(LDFLAGS) + +if AMCOND_LINK_ALL_DEPS + LIBOCTINTERP_LINK_DEPS += $(LIBOCTAVE_LINK_DEPS) + LIBOCTINTERP_LINK_OPTS += $(LIBOCTAVE_LINK_OPTS) + + OCTAVE_LINK_DEPS = $(LIBOCTINTERP_LINK_DEPS) + OCTAVE_LINK_OPTS = $(LIBOCTINTERP_LINK_OPTS) + + OCT_LINK_DEPS += $(LIBOCTINTERP_LINK_DEPS) + OCT_LINK_OPTS += $(LIBOCTINTERP_LINK_OPTS) +endif
--- a/src/load-save.cc +++ b/src/load-save.cc @@ -545,6 +545,9 @@ @deftypefnx {Command} {} load options file\n\ @deftypefnx {Command} {} load options file v1 v2 @dots{}\n\ @deftypefnx {Command} {S =} load (\"options\", \"file\", \"v1\", \"v2\", @dots{})\n\ +@deftypefnx {Command} {} load file options\n\ +@deftypefnx {Command} {} load file options v1 v2 @dots{}\n\ +@deftypefnx {Command} {S =} load (\"file\", \"options\", \"v1\", \"v2\", @dots{})\n\ Load the named variables @var{v1}, @var{v2}, @dots{}, from the file\n\ @var{file}. If no variables are specified then all variables found in the\n\ file will be loaded. As with @code{save}, the list of variables to extract\n\ @@ -642,6 +645,16 @@ if (error_state) return retval; + int i = 1; + std::string orig_fname = ""; + + // Function called with Matlab-style ["filename", options] syntax + if (argv[1].at(0) != '-') + { + orig_fname = argv[1]; + i++; + } + // It isn't necessary to have the default load format stored in a // user preference variable since we can determine the type of file // as we are reading. @@ -651,8 +664,8 @@ bool list_only = false; bool verbose = false; - int i; - for (i = 1; i < argc; i++) + //for (i; i < argc; i++) + for (; i < argc; i++) { if (argv[i] == "-force" || argv[i] == "-f") { @@ -710,19 +723,24 @@ break; } - if (i == argc) + if (orig_fname == "") { - print_usage (); - return retval; + if (i == argc) + { + print_usage (); + return retval; + } + else + orig_fname = argv[i]; } - - std::string orig_fname = argv[i]; + else + i--; oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; bool swap = false; - if (argv[i] == "-") + if (orig_fname == "-") { i++; @@ -747,7 +765,7 @@ } else { - std::string fname = file_ops::tilde_expand (argv[i]); + std::string fname = file_ops::tilde_expand (orig_fname); fname = find_file_to_load (fname, orig_fname);
--- a/src/ls-mat5.cc +++ b/src/ls-mat5.cc @@ -1225,21 +1225,29 @@ else { octave_class* cls = new octave_class (m, classname); - cls->reconstruct_exemplar (); - - if (! cls->reconstruct_parents ()) - warning ("load: unable to reconstruct object inheritance"); - - tc = cls; - if (load_path::find_method (classname, "loadobj") != - std::string()) + + if (cls->reconstruct_exemplar ()) { - octave_value_list tmp = feval ("loadobj", tc, 1); - - if (! error_state) - tc = tmp(0); - else - goto data_read_error; + + if (! cls->reconstruct_parents ()) + warning ("load: unable to reconstruct object inheritance"); + + tc = cls; + if (load_path::find_method (classname, "loadobj") != + std::string()) + { + octave_value_list tmp = feval ("loadobj", tc, 1); + + if (! error_state) + tc = tmp(0); + else + goto data_read_error; + } + } + else + { + tc = m; + warning ("load: element has been converted to a structure"); } } }
--- a/src/mkoctfile.cc.in +++ b/src/mkoctfile.cc.in @@ -219,7 +219,6 @@ vars["DL_LD"] = get_variable ("DL_LD", %OCTAVE_CONF_DL_LD%); vars["DL_LDFLAGS"] = get_variable ("DL_LDFLAGS", %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%); - vars["RLD_FLAG"] = get_variable ("RLD_FLAG", %OCTAVE_CONF_RLD_FLAG%); vars["RDYNAMIC_FLAG"] = get_variable ("RDYNAMIC_FLAG", %OCTAVE_CONF_RDYNAMIC_FLAG%); vars["LIBOCTAVE"] = "-loctave"; vars["LIBOCTINTERP"] = "-loctinterp"; @@ -233,6 +232,10 @@ vars["FFTW3F_LIBS"] = get_variable ("FFTW3F_LIBS", %OCTAVE_CONF_FFTW3F_LIBS%); vars["LIBS"] = get_variable ("LIBS", %OCTAVE_CONF_LIBS%); vars["FLIBS"] = get_variable ("FLIBS", %OCTAVE_CONF_FLIBS%); + vars["OCTAVE_LINK_DEPS"] = get_variable ("FLIBS", %OCTAVE_CONF_OCTAVE_LINK_DEPS%); + vars["OCT_LINK_DEPS"] = get_variable ("FLIBS", %OCTAVE_CONF_OCT_LINK_DEPS%); + vars["FLIBS"] = get_variable ("FLIBS", %OCTAVE_CONF_FLIBS%); + vars["LD_CXX"] = get_variable ("LD_CXX", %OCTAVE_CONF_LD_CXX%); vars["LDFLAGS"] = get_variable ("LDFLAGS", %OCTAVE_CONF_LDFLAGS%); vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG", %OCTAVE_CONF_LD_STATIC_FLAG%); @@ -296,25 +299,30 @@ " -p VAR, --print VAR Print configuration variable VAR. Recognized\n" " variables are:\n" "\n" -" ALL_CFLAGS FLIBS\n" -" ALL_CXXFLAGS FPICFLAG\n" -" ALL_FFLAGS INCFLAGS\n" -" ALL_LDFLAGS LAPACK_LIBS\n" -" BLAS_LIBS LDFLAGS\n" -" CC LD_CXX\n" -" CFLAGS LD_STATIC_FLAG\n" -" CPICFLAG LFLAGS\n" -" CPPFLAGS LIBCRUFT\n" -" CXX LIBOCTAVE\n" -" CXXFLAGS LIBOCTINTERP\n" -" CXXPICFLAG LIBS\n" -" DEPEND_EXTRA_SED_PATTERN OCTAVE_LIBS\n" -" DEPEND_FLAGS RDYNAMIC_FLAG\n" -" DL_LD READLINE_LIBS\n" -" DL_LDFLAGS RLD_FLAG\n" -" F77 SED\n" -" FFLAGS XTRA_CFLAGS\n" -" FFTW_LIBS XTRA_CXXFLAGS\n" +" ALL_CFLAGS FLIBS\n" +" ALL_CXXFLAGS FPICFLAG\n" +" ALL_FFLAGS INCFLAGS\n" +" ALL_LDFLAGS LAPACK_LIBS\n" +" BLAS_LIBS LDFLAGS\n" +" CC LD_CXX\n" +" CFLAGS LD_STATIC_FLAG\n" +" CPICFLAG LFLAGS\n" +" CPPFLAGS LIBCRUFT\n" +" CXX LIBOCTAVE\n" +" CXXFLAGS LIBOCTINTERP\n" +" CXXPICFLAG LIBS\n" +" DEPEND_EXTRA_SED_PATTERN OCTAVE_LIBS\n" +" DEPEND_FLAGS OCTAVE_LINK_DEPS\n" +" DL_LD OCTAVE_LINK_OPTS\n" +" DL_LDFLAGS OCT_LINK_DEPS\n" +" EXEEXT OCT_LINK_OPTS\n" +" F77 RDYNAMIC_FLAG\n" +" F77_INTEGER_8_FLAG READLINE_LIBS\n" +" FFLAGS SED\n" +" FFTW3_LDFLAGS XTRA_CFLAGS\n" +" FFTW3_LIBS XTRA_CXXFLAGS\n" +" FFTW3F_LDFLAGS\n" +" FFTW3F_LIBS\n" "\n" " --link-stand-alone Link a stand-alone executable file.\n" "\n" @@ -742,11 +750,10 @@ + vars["ALL_CXXFLAGS"] + " " + vars["RDYNAMIC_FLAG"] + " " + vars["ALL_LDFLAGS"] + " " + pass_on_options + " " + output_option + " " + objfiles + " " + libfiles - + " " + ldflags + " " + vars["LFLAGS"] + " " - + vars["RLD_FLAG"] + " " + vars["OCTAVE_LIBS"] + " " - + vars["LAPACK_LIBS"] + " " + vars["BLAS_LIBS"] + " " - + vars["FFTW_LIBS"] + " " + vars["READLINE_LIBS"] + " " - + vars["LIBS"] + " " + vars["FLIBS"]; + + " " + ldflags + " " + vars["LFLAGS"] + + " -loctinterp -loctave -lcruft " + + " " + vars["OCT_LINK_OPTS"] + + " " + vars["OCTAVE_LINK_DEPS"]; result = run_command (cmd); } else @@ -758,12 +765,11 @@ } else { - string LINK_DEPS = vars["LFLAGS"] + " " + vars["OCTAVE_LIBS"] - + " " + vars["LDFLAGS"] + " " + vars["BLAS_LIBS"] + " " - + vars["FFTW_LIBS"] + " " + vars["LIBS"] + " " + vars["FLIBS"]; string cmd = vars["DL_LD"] + " " + vars["DL_LDFLAGS"] + " " + pass_on_options + " -o " + octfile + " " + objfiles + " " - + libfiles + " " + ldflags + " " + LINK_DEPS; + + libfiles + " " + ldflags + " " + vars["LFLAGS"] + + " -loctinterp -loctave -lcruft " + + vars["OCT_LINK_OPTS"] + " " + vars["OCT_LINK_DEPS"]; result = run_command (cmd); }
--- a/src/mkoctfile.in +++ b/src/mkoctfile.in @@ -85,7 +85,6 @@ : ${DL_LD=%OCTAVE_CONF_DL_LD%} : ${DL_LDFLAGS=%OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%} -: ${RLD_FLAG=%OCTAVE_CONF_RLD_FLAG%} : ${RDYNAMIC_FLAG=%OCTAVE_CONF_RDYNAMIC_FLAG%} : ${LIBOCTAVE=-loctave} : ${LIBOCTINTERP=-loctinterp} @@ -99,6 +98,10 @@ : ${FFTW3F_LIBS=%OCTAVE_CONF_FFTW3F_LIBS%} : ${LIBS=%OCTAVE_CONF_LIBS%} : ${FLIBS=%OCTAVE_CONF_FLIBS%} +: ${OCTAVE_LINK_DEPS=%OCTAVE_CONF_OCTAVE_LINK_DEPS%} +: ${OCTAVE_LINK_DEPS=%OCTAVE_CONF_OCTAVE_LINK_OPTS%} +: ${OCT_LINK_DEPS=%OCTAVE_CONF_MKOCTFILE_OCT_LINK_DEPS%} +: ${OCT_LINK_DEPS=%OCTAVE_CONF_MKOCTFILE_OCT_LINK_OPTS%} : ${LD_CXX=%OCTAVE_CONF_LD_CXX%} : ${LDFLAGS=%OCTAVE_CONF_LDFLAGS%} : ${LD_STATIC_FLAG=%OCTAVE_CONF_LD_STATIC_FLAG%} @@ -221,7 +224,7 @@ -s, --strip Strip output file. - --mex Create a MEX file. + --mex Create a MEX file. Set the default output extension to ".mex". -o FILE, --output FILE Output file name. Default extension is .oct @@ -231,28 +234,29 @@ -p VAR, --print VAR Print configuration variable VAR. Recognized variables are: - ALL_CFLAGS FFTW3F_LDFLAGS - ALL_CXXFLAGS FFTW3F_LIBS - ALL_FFLAGS FLIBS - ALL_LDFLAGS FPICFLAG - BLAS_LIBS INCFLAGS - CC LAPACK_LIBS - CFLAGS LDFLAGS - CPICFLAG LD_CXX - CPPFLAGS LD_STATIC_FLAG - CXX LFLAGS - CXXFLAGS LIBCRUFT - CXXPICFLAG LIBOCTAVE - DEPEND_EXTRA_SED_PATTERN LIBOCTINTERP - DEPEND_FLAGS LIBS - DL_LD OCTAVE_LIBS - DL_LDFLAGS RDYNAMIC_FLAG - EXEEXT READLINE_LIBS - F77 RLD_FLAG + ALL_CFLAGS FFTW3F_LIBS + ALL_CXXFLAGS FLIBS + ALL_FFLAGS FPICFLAG + ALL_LDFLAGS INCFLAGS + BLAS_LIBS LAPACK_LIBS + CC LDFLAGS + CFLAGS LD_CXX + CPICFLAG LD_STATIC_FLAG + CPPFLAGS LFLAGS + CXX LIBCRUFT + CXXFLAGS LIBOCTAVE + CXXPICFLAG LIBOCTINTERP + DEPEND_EXTRA_SED_PATTERN LIBS + DEPEND_FLAGS OCTAVE_LIBS + DL_LD OCTAVE_LINK_DEPS + DL_LDFLAGS OCT_LINK_DEPS + EXEEXT RDYNAMIC_FLAG + F77 READLINE_LIBS F77_INTEGER_8_FLAG SED FFLAGS XTRA_CFLAGS FFTW3_LDFLAGS XTRA_CXXFLAGS FFTW3_LIBS + FFTW3F_LDFLAGS -v, --verbose Echo commands as they are executed. @@ -529,7 +533,7 @@ if $link && [ -n "$objfiles" ]; then if $link_stand_alone; then if [ -n "$LD_CXX" ]; then - cmd="$LD_CXX $CPPFLAGS $ALL_CXXFLAGS $RDYNAMIC_FLAG $ALL_LDFLAGS $pass_on_options $output_option $objfiles $libfiles $ldflags $LFLAGS $RLD_FLAG $OCTAVE_LIBS $LAPACK_LIBS $BLAS_LIBS $FFTW_LIBS $READLINE_LIBS $LIBS $FLIBS" + cmd="$LD_CXX $CPPFLAGS $ALL_CXXFLAGS $RDYNAMIC_FLAG $ALL_LDFLAGS $pass_on_options $output_option $objfiles $libfiles $ldflags $LFLAGS -loctinterp -loctave -lcruft $OCTAVE_LINK_OPTS $OCTAVE_LINK_DEPS" $dbg $cmd eval $cmd else @@ -537,8 +541,7 @@ exit 1 fi else - LINK_DEPS="$LFLAGS $OCTAVE_LIBS $LDFLAGS $LAPACK_LIBS $BLAS_LIBS $FFTW_LIBS $LIBS $FLIBS" - cmd="$DL_LD $DL_LDFLAGS $pass_on_options -o $octfile $objfiles $libfiles $ldflags $LINK_DEPS" + cmd="$DL_LD $DL_LDFLAGS $pass_on_options -o $octfile $objfiles $libfiles $ldflags $LFLAGS -loctinterp -loctave -lcruft $OCT_LINK_OPTS $OCT_LINK_DEPS" $dbg $cmd eval $cmd fi
--- a/src/oct-conf.h.in +++ b/src/oct-conf.h.in @@ -376,6 +376,14 @@ #define OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS% #endif +#ifndef OCTAVE_CONF_OCTAVE_LINK_DEPS +#define OCTAVE_CONF_OCTAVE_LINK_DEPS %OCTAVE_CONF_OCTAVE_LINK_DEPS% +#endif + +#ifndef OCTAVE_CONF_OCTAVE_LINK_OPTS +#define OCTAVE_CONF_OCTAVE_LINK_OPTS %OCTAVE_CONF_OCTAVE_LINK_OPTS% +#endif + #ifndef OCTAVE_CONF_OCTINCLUDEDIR #define OCTAVE_CONF_OCTINCLUDEDIR %OCTAVE_CONF_OCTINCLUDEDIR% #endif @@ -384,6 +392,14 @@ #define OCTAVE_CONF_OCTLIBDIR %OCTAVE_CONF_OCTLIBDIR% #endif +#ifndef OCTAVE_CONF_OCT_LINK_DEPS +#define OCTAVE_CONF_OCT_LINK_DEPS %OCTAVE_CONF_OCT_LINK_DEPS% +#endif + +#ifndef OCTAVE_CONF_OCT_LINK_OPTS +#define OCTAVE_CONF_OCT_LINK_OPTS %OCTAVE_CONF_OCT_LINK_OPTS% +#endif + #ifndef OCTAVE_CONF_OPENGL_LIBS #define OCTAVE_CONF_OPENGL_LIBS %OCTAVE_CONF_OPENGL_LIBS% #endif @@ -440,10 +456,6 @@ #define OCTAVE_CONF_REGEX_LIBS %OCTAVE_CONF_REGEX_LIBS% #endif -#ifndef OCTAVE_CONF_RLD_FLAG -#define OCTAVE_CONF_RLD_FLAG %OCTAVE_CONF_RLD_FLAG% -#endif - #ifndef OCTAVE_CONF_SED #define OCTAVE_CONF_SED %OCTAVE_CONF_SED% #endif
--- a/src/oct-hist.cc +++ b/src/oct-hist.cc @@ -88,9 +88,6 @@ return file; } -// Where history is saved. -static std::string Vhistory_file = default_history_file (); - static int default_history_size (void) { @@ -109,27 +106,6 @@ return size; } -// The number of lines to keep in the history file. -static int Vhistory_size = default_history_size (); - -static std::string -default_history_control (void) -{ - std::string retval; - - std::string env_histcontrol = octave_env::getenv ("OCTAVE_HISTCONTROL"); - - if (! env_histcontrol.empty ()) - { - return env_histcontrol; - } - - return retval; -} - -// The number of lines to keep in the history file. -static std::string Vhistory_control = default_history_control (); - static std::string default_history_timestamp_format (void) { @@ -146,9 +122,6 @@ static std::string Vhistory_timestamp_format_string = default_history_timestamp_format (); -// TRUE if we are saving history. -bool Vsaving_history = true; - // Display, save, or load history. Stolen and modified from bash. // // Arg of -w FILENAME means write file, arg of -r FILENAME @@ -160,6 +133,10 @@ { int numbered_output = 1; + unwind_protect frame; + + frame.add_fcn (command_history::set_file, command_history::file ()); + int i; for (i = 1; i < argc; i++) { @@ -537,8 +514,10 @@ void initialize_history (bool read_history_file) { - command_history::initialize (read_history_file, Vhistory_file, Vhistory_size, - Vhistory_control); + command_history::initialize (read_history_file, + default_history_file (), + default_history_size (), + octave_env::getenv ("OCTAVE_HISTCONTROL")); } void @@ -691,12 +670,15 @@ @seealso{history_file, history_size, history_timestamp_format_string, saving_history}\n\ @end deftypefn") { - std::string saved_history_control = Vhistory_control; + std::string old_history_control = command_history::histcontrol (); + + std::string tmp = old_history_control; - octave_value retval = SET_INTERNAL_VARIABLE (history_control); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_control"); - if (Vhistory_control != saved_history_control) - command_history::process_histcontrol (Vhistory_control); + if (tmp != old_history_control) + command_history::process_histcontrol (tmp); return retval; } @@ -711,13 +693,15 @@ @seealso{history_file, history_timestamp_format_string, saving_history}\n\ @end deftypefn") { - int saved_history_size = Vhistory_size; + int old_history_size = command_history::size (); + + int tmp = old_history_size; - octave_value retval - = SET_INTERNAL_VARIABLE_WITH_LIMITS (history_size, -1, INT_MAX); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_size", -1, INT_MAX); - if (Vhistory_size != saved_history_size) - command_history::set_size (Vhistory_size); + if (tmp != old_history_size) + command_history::set_size (tmp); return retval; } @@ -733,12 +717,15 @@ @seealso{history_size, saving_history, history_timestamp_format_string}\n\ @end deftypefn") { - std::string saved_history_file = Vhistory_file; + std::string old_history_file = command_history::file (); + + std::string tmp = old_history_file; - octave_value retval = SET_INTERNAL_VARIABLE (history_file); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_file"); - if (Vhistory_file != saved_history_file) - command_history::set_file (Vhistory_file); + if (tmp != old_history_file) + command_history::set_file (tmp); return retval; } @@ -770,9 +757,15 @@ @seealso{history_control, history_file, history_size, history_timestamp_format_string}\n\ @end deftypefn") { - octave_value retval = SET_INTERNAL_VARIABLE (saving_history); + bool old_saving_history = ! command_history::ignoring_entries (); + + bool tmp = old_saving_history; - command_history::ignore_entries (! Vsaving_history); + octave_value retval = set_internal_variable (tmp, args, nargout, + "saving_history"); + + if (tmp != old_saving_history) + command_history::ignore_entries (! tmp); return retval; }
--- a/src/oct-hist.h +++ b/src/oct-hist.h @@ -35,7 +35,4 @@ // TRUE means input is coming from temporary history file. extern bool input_from_tmp_history_file; -// TRUE if we are saving history. -extern bool Vsaving_history; - #endif
--- a/src/oct-parse.yy +++ b/src/oct-parse.yy @@ -471,7 +471,7 @@ %type <tree_matrix_type> matrix_rows matrix_rows1 %type <tree_cell_type> cell_rows cell_rows1 %type <tree_expression_type> matrix cell -%type <tree_expression_type> primary_expr postfix_expr prefix_expr binary_expr +%type <tree_expression_type> primary_expr oper_expr %type <tree_expression_type> simple_expr colon_expr assign_expr expression %type <tree_identifier_type> identifier fcn_name magic_tilde %type <tree_identifier_type> superclass_identifier meta_identifier @@ -514,7 +514,6 @@ %type <dummy_type> class_body // Precedence and associativity. -%left ';' ',' '\n' %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ %left EXPR_OR_OR %left EXPR_AND_AND @@ -525,8 +524,9 @@ %left ':' %left '-' '+' EPLUS EMINUS %left '*' '/' LEFTDIV EMUL EDIV ELEFTDIV -%left UNARY PLUS_PLUS MINUS_MINUS EXPR_NOT +%right UNARY EXPR_NOT %left POW EPOW QUOTE TRANSPOSE +%right PLUS_PLUS MINUS_MINUS %left '(' '.' '{' // Where to start. @@ -796,69 +796,61 @@ { lexer_flags.looking_at_indirect_ref = true; } ; -postfix_expr : primary_expr +oper_expr : primary_expr { $$ = $1; } - | postfix_expr '(' ')' + | oper_expr PLUS_PLUS + { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } + | oper_expr MINUS_MINUS + { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } + | oper_expr '(' ')' { $$ = make_index_expression ($1, 0, '('); } - | postfix_expr '(' arg_list ')' + | oper_expr '(' arg_list ')' { $$ = make_index_expression ($1, $3, '('); } - | postfix_expr '{' '}' + | oper_expr '{' '}' { $$ = make_index_expression ($1, 0, '{'); } - | postfix_expr '{' arg_list '}' + | oper_expr '{' arg_list '}' { $$ = make_index_expression ($1, $3, '{'); } - | postfix_expr PLUS_PLUS - { $$ = make_postfix_op (PLUS_PLUS, $1, $2); } - | postfix_expr MINUS_MINUS - { $$ = make_postfix_op (MINUS_MINUS, $1, $2); } - | postfix_expr QUOTE + | oper_expr QUOTE { $$ = make_postfix_op (QUOTE, $1, $2); } - | postfix_expr TRANSPOSE + | oper_expr TRANSPOSE { $$ = make_postfix_op (TRANSPOSE, $1, $2); } - | postfix_expr indirect_ref_op STRUCT_ELT + | oper_expr indirect_ref_op STRUCT_ELT { $$ = make_indirect_ref ($1, $3->text ()); } - | postfix_expr indirect_ref_op '(' expression ')' + | oper_expr indirect_ref_op '(' expression ')' { $$ = make_indirect_ref ($1, $4); } - ; - -prefix_expr : postfix_expr - { $$ = $1; } - | binary_expr - { $$ = $1; } - | PLUS_PLUS prefix_expr %prec UNARY + | PLUS_PLUS oper_expr %prec UNARY { $$ = make_prefix_op (PLUS_PLUS, $2, $1); } - | MINUS_MINUS prefix_expr %prec UNARY + | MINUS_MINUS oper_expr %prec UNARY { $$ = make_prefix_op (MINUS_MINUS, $2, $1); } - | EXPR_NOT prefix_expr %prec UNARY + | EXPR_NOT oper_expr %prec UNARY { $$ = make_prefix_op (EXPR_NOT, $2, $1); } - | '+' prefix_expr %prec UNARY + | '+' oper_expr %prec UNARY { $$ = make_prefix_op ('+', $2, $1); } - | '-' prefix_expr %prec UNARY + | '-' oper_expr %prec UNARY { $$ = make_prefix_op ('-', $2, $1); } - ; - -binary_expr : prefix_expr POW prefix_expr + | oper_expr POW oper_expr { $$ = make_binary_op (POW, $1, $2, $3); } - | prefix_expr EPOW prefix_expr + | oper_expr EPOW oper_expr { $$ = make_binary_op (EPOW, $1, $2, $3); } - | prefix_expr '+' prefix_expr + | oper_expr '+' oper_expr { $$ = make_binary_op ('+', $1, $2, $3); } - | prefix_expr '-' prefix_expr + | oper_expr '-' oper_expr { $$ = make_binary_op ('-', $1, $2, $3); } - | prefix_expr '*' prefix_expr + | oper_expr '*' oper_expr { $$ = make_binary_op ('*', $1, $2, $3); } - | prefix_expr '/' prefix_expr + | oper_expr '/' oper_expr { $$ = make_binary_op ('/', $1, $2, $3); } - | prefix_expr EPLUS prefix_expr + | oper_expr EPLUS oper_expr { $$ = make_binary_op ('+', $1, $2, $3); } - | prefix_expr EMINUS prefix_expr + | oper_expr EMINUS oper_expr { $$ = make_binary_op ('-', $1, $2, $3); } - | prefix_expr EMUL prefix_expr + | oper_expr EMUL oper_expr { $$ = make_binary_op (EMUL, $1, $2, $3); } - | prefix_expr EDIV prefix_expr + | oper_expr EDIV oper_expr { $$ = make_binary_op (EDIV, $1, $2, $3); } - | prefix_expr LEFTDIV prefix_expr + | oper_expr LEFTDIV oper_expr { $$ = make_binary_op (LEFTDIV, $1, $2, $3); } - | prefix_expr ELEFTDIV prefix_expr + | oper_expr ELEFTDIV oper_expr { $$ = make_binary_op (ELEFTDIV, $1, $2, $3); } ; @@ -866,9 +858,9 @@ { $$ = finish_colon_expression ($1); } ; -colon_expr1 : prefix_expr +colon_expr1 : oper_expr { $$ = new tree_colon_expression ($1); } - | colon_expr1 ':' prefix_expr + | colon_expr1 ':' oper_expr { if (! ($$ = $1->append ($3))) ABORT_PARSE; @@ -2908,6 +2900,7 @@ } fcn->stash_function_name (id_name); + fcn->stash_fcn_location (input_line_number, current_input_column); if (! help_buf.empty () && current_function_depth == 1 && ! parsing_subfunctions) @@ -3348,11 +3341,10 @@ break; case '\n': - current_input_column = 0; + current_input_column = 1; break; default: - current_input_column--; reader.ungetc (c); goto done; } @@ -3479,18 +3471,11 @@ parsing_subfunctions = false; endfunction_found = false; - // The next four lines must be in this order. - frame.add_fcn (command_history::ignore_entries, ! Vsaving_history); - - // FIXME -- we shouldn't need both the - // command_history object and the - // Vsaving_history variable... + frame.add_fcn (command_history::ignore_entries, + command_history::ignoring_entries ()); + command_history::ignore_entries (); - frame.protect_var (Vsaving_history); - - Vsaving_history = false; - FILE *ffile = get_input_from_file (ff, 0); frame.add_fcn (safe_fclose, ffile);
--- a/src/oct-stream.cc +++ b/src/oct-stream.cc @@ -1227,158 +1227,9 @@ if (c1 != EOF) { - if (c1 == 'N') - { - int c2 = is.get (); - - if (c2 != EOF) - { - if (c2 == 'A') - { - int c3 = is.get (); - - if (c3 != EOF) - { - is.putback (c3); - - if (isspace (c3) || ispunct (c3)) - ref = octave_NA; - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_NA; - } - } - else if (c2 == 'a') - { - int c3 = is.get (); - - if (c3 != EOF) - { - if (c3 == 'N') - { - int c4 = is.get (); - - if (c4 != EOF) - { - is.putback (c4); - - if (isspace (c4) || ispunct (c4)) - ref = octave_NaN; - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_NaN; - } - } - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - else if (c1 == 'I') - { - int c2 = is.get (); - - if (c2 != EOF) - { - if (c2 == 'n') - { - int c3 = is.get (); - - if (c3 != EOF) - { - if (c3 == 'f') - { - int c4 = is.get (); - - if (c4 != EOF) - { - is.putback (c4); - - if (isspace (c4) || ispunct (c4)) - ref = octave_Inf; - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.clear (); - - ref = octave_Inf; - } - } - else - { - is.putback (c3); - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - else - { - is.putback (c2); - is.putback (c1); - - is >> ref; - } - } - } - else - { - is.putback (c1); - - is >> ref; - } + is.putback (c1); + + ref = octave_read_value<double> (is); } } break; @@ -3011,38 +2862,60 @@ { clearerr (); + // Find current position so we can return to it if needed. + long orig_pos = rep->tell (); - status = rep->seek (offset, origin); + // Move to end of file. If successful, find the offset of the end. + + status = rep->seek (0, SEEK_END); if (status == 0) { - long save_pos = rep->tell (); - - rep->seek (0, SEEK_END); - - long pos_eof = rep->tell (); - - // I don't think save_pos can be less than zero, but we'll - // check anyway... - - if (save_pos > pos_eof || save_pos < 0) + long eof_pos = rep->tell (); + + if (origin == SEEK_CUR) + { + // Move back to original position, otherwise we will be + // seeking from the end of file which is probably not the + // original location. + + rep->seek (orig_pos, SEEK_SET); + } + + // Attempt to move to desired position; may be outside bounds + // of existing file. + + status = rep->seek (offset, origin); + + if (status == 0) { - // Seek outside bounds of file. Failure should leave - // position unchanged. + // Where are we after moving to desired position? + + long desired_pos = rep->tell (); + + // I don't think save_pos can be less than zero, but we'll + // check anyway... + + if (desired_pos > eof_pos || desired_pos < 0) + { + // Seek outside bounds of file. Failure should leave + // position unchanged. + + rep->seek (orig_pos, SEEK_SET); + + status = -1; + } + } + else + { + // Seeking to the desired position failed. Move back to + // original position and return failure status. rep->seek (orig_pos, SEEK_SET); status = -1; } - else - { - // Is it possible for this to fail? We are just - // returning to a position after the first successful - // seek. - - rep->seek (save_pos, SEEK_SET); - } } }
--- a/src/octave.cc +++ b/src/octave.cc @@ -971,6 +971,11 @@ return retval; } +/* +%!error argv (1); +%!assert (iscellstr (argv ())); +*/ + DEFUN (program_invocation_name, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} program_invocation_name ()\n\ @@ -993,6 +998,11 @@ return retval; } +/* +%!error program_invocation_name (1); +%!assert (ischar (program_invocation_name ())); +*/ + DEFUN (program_name, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} program_name ()\n\ @@ -1010,3 +1020,8 @@ return retval; } + +/* +%!error program_name (1); +%!assert (ischar (program_name ())); +*/
--- a/src/ov-base.cc +++ b/src/ov-base.cc @@ -1548,3 +1548,16 @@ { return SET_INTERNAL_VARIABLE (sparse_auto_mutate); } + +/* + +%!test + s = speye(3); + sparse_auto_mutate (false); + s(:, 1) = 1; + assert (typeinfo (s), "sparse matrix"); + sparse_auto_mutate (true); + s(1, :) = 1; + assert (typeinfo (s), "matrix"); + +*/
--- a/src/ov-builtin.cc +++ b/src/ov-builtin.cc @@ -29,6 +29,7 @@ #include "oct-obj.h" #include "ov-builtin.h" #include "ov.h" +#include "profiler.h" #include "toplev.h" #include "unwind-prot.h" @@ -125,6 +126,8 @@ try { + BEGIN_PROFILER_BLOCK (profiler_name ()) + retval = (*f) (args, nargout); // Do not allow null values to be returned from functions. // FIXME -- perhaps true builtins should be allowed? @@ -137,6 +140,8 @@ // the idiom is very common, so we solve that here. if (retval.length () == 1 && retval.xelem (0).is_undefined ()) retval.clear (); + + END_PROFILER_BLOCK } catch (octave_execution_exception) {
--- a/src/ov-fcn.h +++ b/src/ov-fcn.h @@ -60,6 +60,9 @@ virtual bool is_system_fcn_file (void) const { return false; } virtual std::string fcn_file_name (void) const { return std::string (); } + + // The name to show in the profiler (also used as map-key). + virtual std::string profiler_name (void) const { return name (); } virtual std::string parent_fcn_name (void) const { return std::string (); }
--- a/src/ov-flt-re-mat.cc +++ b/src/ov-flt-re-mat.cc @@ -839,3 +839,32 @@ return octave_value (); } + +/* + +%!assert (class (single(1)), "single") +%!assert (class (single(1 + i)), "single") +%!assert (class (single (int8 (1))), "single") +%!assert (class (single (uint8 (1))), "single") +%!assert (class (single (int16 (1))), "single") +%!assert (class (single (uint16 (1))), "single") +%!assert (class (single (int32 (1))), "single") +%!assert (class (single (uint32 (1))), "single") +%!assert (class (single (int64 (1))), "single") +%!assert (class (single (uint64 (1))), "single") +%!assert (class (single (true)), "single") +%!assert (class (single ("A")), "single") +%!error (single (sparse (1))) +%!test +%! x = diag ([1 3 2]); +%! y = single (x); +%! assert (class (x), "double"); +%! assert (class (y), "single"); +%!test +%! x = diag ([i 3 2]); +%! y = single (x); +%! assert (class (x), "double"); +%! assert (class (y), "single"); + +*/ +
--- a/src/ov-int16.cc +++ b/src/ov-int16.cc @@ -82,3 +82,15 @@ { OCTAVE_TYPE_CONV_BODY (int16); } + +/* + +%!assert (class (int16 (1)), "int16") +%!assert (int16 (1.25), int16 (1)) +%!assert (int16 (1.5), int16 (2)) +%!assert (int16 (-1.5), int16 (-2)) +%!assert (int16 (2^17), int16 (2^16-1)) +%!assert (int16 (-2^17), int16 (-2^16)) + +*/ +
--- a/src/ov-int32.cc +++ b/src/ov-int32.cc @@ -82,3 +82,15 @@ { OCTAVE_TYPE_CONV_BODY (int32); } + +/* + +%!assert (class (int32 (1)), "int32") +%!assert (int32 (1.25), int32 (1)) +%!assert (int32 (1.5), int32 (2)) +%!assert (int32 (-1.5), int32 (-2)) +%!assert (int32 (2^33), int32 (2^32-1)) +%!assert (int32 (-2^33), int32 (-2^32)) + +*/ +
--- a/src/ov-int64.cc +++ b/src/ov-int64.cc @@ -82,3 +82,15 @@ { OCTAVE_TYPE_CONV_BODY (int64); } + +/* + +%!assert (class (int64 (1)), "int64") +%!assert (int64 (1.25), int64 (1)) +%!assert (int64 (1.5), int64 (2)) +%!assert (int64 (-1.5), int64 (-2)) +%!assert (int64 (2^65), int64 (2^64-1)) +%!assert (int64 (-2^65), int64 (-2^64)) + +*/ +
--- a/src/ov-int8.cc +++ b/src/ov-int8.cc @@ -82,3 +82,14 @@ { OCTAVE_TYPE_CONV_BODY (int8); } + +/* + +%!assert (class (int8 (1)), "int8") +%!assert (int8 (1.25), int8 (1)) +%!assert (int8 (1.5), int8 (2)) +%!assert (int8 (-1.5), int8 (-2)) +%!assert (int8 (2^9), int8 (2^8-1)) +%!assert (int8 (-2^9), int8 (-2^8)) + +*/
--- a/src/ov-mex-fcn.cc +++ b/src/ov-mex-fcn.cc @@ -33,6 +33,7 @@ #include "oct-obj.h" #include "ov-mex-fcn.h" #include "ov.h" +#include "profiler.h" #include "toplev.h" #include "unwind-prot.h" @@ -147,7 +148,9 @@ try { + BEGIN_PROFILER_BLOCK (profiler_name ()) retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this); + END_PROFILER_BLOCK } catch (octave_execution_exception) {
--- a/src/ov-null-mat.cc +++ b/src/ov-null-mat.cc @@ -118,3 +118,17 @@ return retval; } +/* + +%!assert (isnull ([]), true) +%!assert (isnull ([1]), false) +%!assert (isnull (zeros (0,3)), false) +%!assert (isnull (""), true) +%!assert (isnull ("A"), false) +%!assert (isnull (''), true) +%!assert (isnull ('A'), false) +%!test +%! x = []; +%! assert (isnull (x), false); + +*/
--- a/src/ov-range.cc +++ b/src/ov-range.cc @@ -655,3 +655,16 @@ { return SET_INTERNAL_VARIABLE (allow_noninteger_range_as_index); } + +/* +%!test +%! x = 0:10; +%! save = allow_noninteger_range_as_index (0); +%! fail ('x(2.1:5)'); +%! assert (x(2:5), 1:4); +%! allow_noninteger_range_as_index (1); +%! assert (x(2.49:5), 1:3); +%! assert (x(2.5:5), 2:4); +%! assert (x(2.51:5), 2:4); +%! allow_noninteger_range_as_index (save); +*/
--- a/src/ov-re-mat.cc +++ b/src/ov-re-mat.cc @@ -979,3 +979,36 @@ return octave_value (); } + +/* + +%!assert (class (double (single (1))), "double") +%!assert (class (double (single (1 + i))), "double") +%!assert (class (double (int8 (1))), "double") +%!assert (class (double (uint8 (1))), "double") +%!assert (class (double (int16 (1))), "double") +%!assert (class (double (uint16 (1))), "double") +%!assert (class (double (int32 (1))), "double") +%!assert (class (double (uint32 (1))), "double") +%!assert (class (double (int64 (1))), "double") +%!assert (class (double (uint64 (1))), "double") +%!assert (class (double (true)), "double") +%!assert (class (double ("A")), "double") +%!test +%! x = sparse (logical ([1 0; 0 1])); +%! y = double (x); +%! assert (class (x), "logical"); +%! assert (class (y), "double"); +%! assert (issparse (y)); +%!test +%! x = diag (single ([1 3 2])); +%! y = double (x); +%! assert (class (x), "single"); +%! assert (class (y), "double"); +%!test +%! x = diag (single ([i 3 2])); +%! y = double (x); +%! assert (class (x), "single"); +%! assert (class (y), "double"); + +*/
--- a/src/ov-uint16.cc +++ b/src/ov-uint16.cc @@ -82,3 +82,15 @@ { OCTAVE_TYPE_CONV_BODY (uint16); } + +/* + +%!assert (class (uint16 (1)), "uint16") +%!assert (uint16 (1.25), uint16 (1)) +%!assert (uint16 (1.5), uint16 (2)) +%!assert (uint16 (-1.5), uint16 (0)) +%!assert (uint16 (2^17), uint16 (2^16-1)) +%!assert (uint16 (-2^17), uint16 (0)) + +*/ +
--- a/src/ov-uint32.cc +++ b/src/ov-uint32.cc @@ -82,3 +82,14 @@ { OCTAVE_TYPE_CONV_BODY (uint32); } + +/* + +%!assert (class (uint32 (1)), "uint32") +%!assert (uint32 (1.25), uint32 (1)) +%!assert (uint32 (1.5), uint32 (2)) +%!assert (uint32 (-1.5), uint32 (0)) +%!assert (uint32 (2^33), uint32 (2^32-1)) +%!assert (uint32 (-2^33), uint32 (0)) + +*/
--- a/src/ov-uint64.cc +++ b/src/ov-uint64.cc @@ -82,3 +82,14 @@ { OCTAVE_TYPE_CONV_BODY (uint64); } + +/* + +%!assert (class (uint64 (1)), "uint64") +%!assert (uint64 (1.25), uint64 (1)) +%!assert (uint64 (1.5), uint64 (2)) +%!assert (uint64 (-1.5), uint64 (0)) +%!assert (uint64 (2^65), uint64 (2^64-1)) +%!assert (uint64 (-2^65), uint64 (0)) + +*/
--- a/src/ov-uint8.cc +++ b/src/ov-uint8.cc @@ -82,3 +82,14 @@ { OCTAVE_TYPE_CONV_BODY (uint8); } + +/* + +%!assert (class (uint8 (1)), "uint8") +%!assert (uint8 (1.25), uint8 (1)) +%!assert (uint8 (1.5), uint8 (2)) +%!assert (uint8 (-1.5), uint8 (0)) +%!assert (uint8 (2^9), uint8 (2^8-1)) +%!assert (uint8 (-2^9), uint8 (0)) + +*/
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -24,6 +24,8 @@ #include <config.h> #endif +#include <sstream> + #include "str-vec.h" #include <defaults.h> @@ -47,6 +49,7 @@ #include "unwind-prot.h" #include "utils.h" #include "parse.h" +#include "profiler.h" #include "variables.h" // Whether to optimize subsasgn method calls. @@ -131,7 +134,9 @@ frame.protect_var (tree_evaluator::statement_context); tree_evaluator::statement_context = tree_evaluator::script; + BEGIN_PROFILER_BLOCK (profiler_name ()) cmd_list->accept (*current_evaluator); + END_PROFILER_BLOCK if (tree_return_command::returning) tree_return_command::returning = 0; @@ -176,6 +181,7 @@ : octave_user_code (std::string (), std::string ()), param_list (pl), ret_list (rl), cmd_list (cl), lead_comm (), trail_comm (), file_name (), + location_line (0), location_column (0), parent_name (), t_parsed (static_cast<time_t> (0)), t_checked (static_cast<time_t> (0)), system_fcn_file (false), call_depth (-1), @@ -217,6 +223,22 @@ file_name = nm; } +std::string +octave_user_function::profiler_name (void) const +{ + std::ostringstream result; + + if (is_inline_function ()) + result << "anonymous@" << fcn_file_name () + << ":" << location_line << ":" << location_column; + else if (is_subfunction ()) + result << parent_fcn_name () << ">" << name (); + else + result << name (); + + return result.str (); +} + void octave_user_function::mark_as_system_fcn_file (void) { @@ -431,6 +453,8 @@ bool special_expr = (is_inline_function () || cmd_list->is_anon_function_body ()); + BEGIN_PROFILER_BLOCK (profiler_name ()) + if (special_expr) { assert (cmd_list->length () == 1); @@ -448,6 +472,8 @@ else cmd_list->accept (*current_evaluator); + END_PROFILER_BLOCK + if (echo_commands) print_code_function_trailer ();
--- a/src/ov-usr-fcn.h +++ b/src/ov-usr-fcn.h @@ -189,6 +189,12 @@ void stash_fcn_file_name (const std::string& nm); + void stash_fcn_location (int line, int col) + { + location_line = line; + location_column = col; + } + void stash_parent_fcn_name (const std::string& p) { parent_name = p; } void stash_parent_fcn_scope (symbol_table::scope_id ps) { parent_scope = ps; } @@ -207,6 +213,8 @@ std::string fcn_file_name (void) const { return file_name; } + std::string profiler_name (void) const; + std::string parent_fcn_name (void) const { return parent_name; } symbol_table::scope_id parent_fcn_scope (void) const { return parent_scope; } @@ -344,6 +352,10 @@ // The name of the file we parsed. std::string file_name; + // Location where this function was defined. + int location_line; + int location_column; + // The name of the parent function, if any. std::string parent_name;
new file mode 100644 --- /dev/null +++ b/src/profiler.cc @@ -0,0 +1,416 @@ +/* + +Copyright (C) 2011 Daniel Kraft + +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 <cstddef> +#include <iostream> + +#include "defun.h" +#include "oct-time.h" +#include "ov-struct.h" +#include "pager.h" +#include "profiler.h" + +profile_data_accumulator::enter::enter (profile_data_accumulator& a, + const std::string& f) + : acc (a) +{ + if (acc.is_active ()) + { + fcn = f; + acc.enter_function (fcn); + } + else + fcn = ""; +} + +profile_data_accumulator::enter::~enter () +{ + if (fcn != "") + acc.exit_function (fcn); +} + +profile_data_accumulator::stats::stats () + : time (0.0), calls (0), recursive (false), + parents (), children () +{} + +octave_value +profile_data_accumulator::stats::function_set_value (const function_set& list) +{ + const octave_idx_type n = list.size (); + + RowVector retval (n); + octave_idx_type i = 0; + for (function_set::const_iterator p = list.begin (); p != list.end (); ++p) + { + retval(i) = *p; + ++i; + } + assert (i == n); + + return retval; +} + +profile_data_accumulator::tree_node::tree_node (tree_node* p, octave_idx_type f) + : parent (p), fcn_id (f), children (), time (0.0), calls (0) +{} + +profile_data_accumulator::tree_node::~tree_node () +{ + for (child_map::iterator i = children.begin (); i != children.end (); ++i) + delete i->second; +} + +profile_data_accumulator::tree_node* +profile_data_accumulator::tree_node::enter (octave_idx_type fcn) +{ + tree_node* retval; + + child_map::iterator pos = children.find (fcn); + if (pos == children.end ()) + { + retval = new tree_node (this, fcn); + children[fcn] = retval; + } + else + retval = pos->second; + + ++retval->calls; + return retval; +} + +profile_data_accumulator::tree_node* +profile_data_accumulator::tree_node::exit (octave_idx_type fcn) +{ + assert (parent); + assert (fcn_id == fcn); + + return parent; +} + +void +profile_data_accumulator::tree_node::build_flat (flat_profile& data) const +{ + // If this is not the top-level node, update profile entry for this function. + if (fcn_id != 0) + { + stats& entry = data[fcn_id - 1]; + + entry.time += time; + entry.calls += calls; + + assert (parent); + if (parent->fcn_id != 0) + { + entry.parents.insert (parent->fcn_id); + data[parent->fcn_id - 1].children.insert (fcn_id); + } + + if (!entry.recursive) + for (const tree_node* i = parent; i; i = i->parent) + if (i->fcn_id == fcn_id) + { + entry.recursive = true; + break; + } + } + + // Recurse on children. + for (child_map::const_iterator i = children.begin (); + i != children.end (); ++i) + i->second->build_flat (data); +} + +octave_value +profile_data_accumulator::tree_node::get_hierarchical (void) const +{ + /* Note that we don't generate the entry just for this node, but rather + a struct-array with entries for all children. This way, the top-node + (for which we don't want a real entry) generates already the final + hierarchical profile data. */ + + const octave_idx_type n = children.size (); + + Cell rv_indices (n, 1); + Cell rv_times (n, 1); + Cell rv_calls (n, 1); + Cell rv_children (n, 1); + + octave_idx_type i = 0; + for (child_map::const_iterator p = children.begin (); + p != children.end (); ++p) + { + const tree_node& entry = *p->second; + + rv_indices(i) = octave_value (p->first); + rv_times(i) = octave_value (entry.time); + rv_calls(i) = octave_value (entry.calls); + rv_children(i) = entry.get_hierarchical (); + + ++i; + } + assert (i == n); + + Octave_map retval; + + retval.assign ("Index", rv_indices); + retval.assign ("SelfTime", rv_times); + retval.assign ("NumCalls", rv_calls); + retval.assign ("Children", rv_children); + + return retval; +} + +profile_data_accumulator::profile_data_accumulator () + : known_functions (), fcn_index (), + enabled (false), call_tree (NULL), last_time (-1.0) +{} + +profile_data_accumulator::~profile_data_accumulator () +{ + if (call_tree) + delete call_tree; +} + +void +profile_data_accumulator::set_active (bool value) +{ + if (value) + { + // Create a call-tree top-node if there isn't yet one. + if (!call_tree) + call_tree = new tree_node (NULL, 0); + + // Let the top-node be the active one. This ensures we have a clean + // fresh start collecting times. + active_fcn = call_tree; + } + else + { + // Make sure we start with fresh timing if we're re-enabled later. + last_time = -1.0; + } + + enabled = value; +} + +void +profile_data_accumulator::enter_function (const std::string& fcn) +{ + // The enter class will check and only call us if the profiler is active. + assert (is_active ()); + assert (call_tree); + + // If there is already an active function, add to its time before + // pushing the new one. + if (active_fcn != call_tree) + add_current_time (); + + // Map the function's name to its index. + octave_idx_type fcn_idx; + fcn_index_map::iterator pos = fcn_index.find (fcn); + if (pos == fcn_index.end ()) + { + known_functions.push_back (fcn); + fcn_idx = known_functions.size (); + fcn_index[fcn] = fcn_idx; + } + else + fcn_idx = pos->second; + + active_fcn = active_fcn->enter (fcn_idx); + last_time = query_time (); +} + +void +profile_data_accumulator::exit_function (const std::string& fcn) +{ + assert (call_tree); + assert (active_fcn != call_tree); + + // Usually, if we are disabled this function is not even called. But the + // call disabling the profiler is an exception. So also check here + // and only record the time if enabled. + if (is_active ()) + add_current_time (); + + fcn_index_map::iterator pos = fcn_index.find (fcn); + assert (pos != fcn_index.end ()); + active_fcn = active_fcn->exit (pos->second); + + // If this was an "inner call", we resume executing the parent function + // up the stack. So note the start-time for this! + last_time = query_time (); +} + +void +profile_data_accumulator::reset (void) +{ + if (is_active ()) + { + error ("Can't reset active profiler."); + return; + } + + known_functions.clear (); + fcn_index.clear (); + + if (call_tree) + { + delete call_tree; + call_tree = NULL; + } + + last_time = -1.0; +} + +octave_value +profile_data_accumulator::get_flat (void) const +{ + const octave_idx_type n = known_functions.size (); + + flat_profile flat (n); + assert (call_tree); + call_tree->build_flat (flat); + + Cell rv_names (n, 1); + Cell rv_times (n, 1); + Cell rv_calls (n, 1); + Cell rv_recursive (n, 1); + Cell rv_parents (n, 1); + Cell rv_children (n, 1); + + for (octave_idx_type i = 0; i != n; ++i) + { + rv_names(i) = octave_value (known_functions[i]); + rv_times(i) = octave_value (flat[i].time); + rv_calls(i) = octave_value (flat[i].calls); + rv_recursive(i) = octave_value (flat[i].recursive); + rv_parents(i) = stats::function_set_value (flat[i].parents); + rv_children(i) = stats::function_set_value (flat[i].children); + } + + Octave_map retval; + + retval.assign ("FunctionName", rv_names); + retval.assign ("TotalTime", rv_times); + retval.assign ("NumCalls", rv_calls); + retval.assign ("IsRecursive", rv_recursive); + retval.assign ("Parents", rv_parents); + retval.assign ("Children", rv_children); + + return retval; +} + +octave_value +profile_data_accumulator::get_hierarchical (void) const +{ + assert (call_tree); + return call_tree->get_hierarchical (); +} + +double +profile_data_accumulator::query_time (void) const +{ + octave_time now; + return now.double_value (); +} + +void +profile_data_accumulator::add_current_time (void) +{ + const double t = query_time (); + assert (last_time >= 0.0 && last_time <= t); + + assert (call_tree && active_fcn != call_tree); + active_fcn->add_time (t - last_time); +} + +profile_data_accumulator profiler; + +// Enable or disable the profiler data collection. +DEFUN (__profiler_enable__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Function File} __profiler_enable ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + + const int nargin = args.length (); + if (nargin > 0) + { + if (nargin > 1) + { + print_usage (); + return retval; + } + + profiler.set_active (args(0).bool_value ()); + } + + retval(0) = profiler.is_active (); + + return retval; +} + +// Clear all collected profiling data. +DEFUN (__profiler_reset__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Function File} __profiler_reset ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + const int nargin = args.length (); + + if (nargin > 0) + warning ("profiler_reset: ignoring extra arguments"); + + profiler.reset (); + + return retval; +} + +// Query the timings collected by the profiler. +DEFUN (__profiler_data__, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Function File} __profiler_data ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + const int nargin = args.length (); + + if (nargin > 0) + warning ("profiler_data: ignoring extra arguments"); + + retval(0) = profiler.get_flat (); + if (nargout > 1) + retval(1) = profiler.get_hierarchical (); + + return retval; +}
new file mode 100644 --- /dev/null +++ b/src/profiler.h @@ -0,0 +1,185 @@ +/* + +Copyright (C) 2011 Daniel Kraft + +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_profiler_h) +#define octave_profiler_h 1 + +#include <map> +#include <set> +#include <string> +#include <vector> + +class octave_value; + +class +OCTAVE_API +profile_data_accumulator +{ +public: + + // This is a utility class that can be used to call the enter/exit + // functions in a manner protected from stack unwinding. + class enter + { + private: + + profile_data_accumulator& acc; + std::string fcn; + + public: + + enter (profile_data_accumulator&, const std::string&); + virtual ~enter (void); + + private: + + // No copying! + enter (const enter&); + enter& operator = (const enter&); + }; + + profile_data_accumulator (void); + virtual ~profile_data_accumulator (); + + bool is_active (void) const { return enabled; } + void set_active (bool); + + void reset (void); + + octave_value get_flat (void) const; + octave_value get_hierarchical (void) const; + +private: + + // One entry in the flat profile (i.e., a collection of data for a single + // function). This is filled in when building the flat profile from the + // hierarchical call tree. + struct stats + { + stats (); + + double time; + unsigned calls; + + bool recursive; + + typedef std::set<octave_idx_type> function_set; + function_set parents; + function_set children; + + // Convert a function_set list to an Octave array of indices. + static octave_value function_set_value (const function_set&); + }; + + typedef std::vector<stats> flat_profile; + + // Store data for one node in the call-tree of the hierarchical profiler + // data we collect. + class tree_node + { + public: + + tree_node (tree_node*, octave_idx_type); + virtual ~tree_node (); + + void add_time (double dt) { time += dt; } + + // Enter a child function. It is created in the list of children if it + // wasn't already there. The now-active child node is returned. + tree_node* enter (octave_idx_type); + + // Exit function. As a sanity-check, it is verified that the currently + // active function actually is the one handed in here. Returned is the + // then-active node, which is our parent. + tree_node* exit (octave_idx_type); + + void build_flat (flat_profile&) const; + octave_value get_hierarchical (void) const; + + private: + + tree_node* parent; + octave_idx_type fcn_id; + + typedef std::map<octave_idx_type, tree_node*> child_map; + child_map children; + + // This is only time spent *directly* on this level, excluding children! + double time; + + unsigned calls; + + // No copying! + tree_node (const tree_node&); + tree_node& operator = (const tree_node&); + }; + + // Each function we see in the profiler is given a unique index (which + // simply counts starting from 1). We thus have to map profiler-names to + // those indices. For all other stuff, we identify functions by their index. + + typedef std::vector<std::string> function_set; + typedef std::map<std::string, octave_idx_type> fcn_index_map; + + function_set known_functions; + fcn_index_map fcn_index; + + bool enabled; + + tree_node* call_tree; + tree_node* active_fcn; + + // Store last timestamp we had, when the currently active function was called. + double last_time; + + // These are private as only the unwind-protecting inner class enter + // should be allowed to call them. + void enter_function (const std::string&); + void exit_function (const std::string&); + + // Query a timestamp, used for timing calls (obviously). + // This is not static because in the future, maybe we want a flag + // in the profiler or something to choose between cputime, wall-time, + // user-time, system-time, ... + double query_time () const; + + // Add the time elapsed since last_time to the function we're currently in. + // This is called from two different positions, thus it is useful to have + // it as a seperate function. + void add_current_time (void); + + // No copying! + profile_data_accumulator (const profile_data_accumulator&); + profile_data_accumulator& operator = (const profile_data_accumulator&); +}; + +// The instance used. +extern profile_data_accumulator profiler; + +// Helper macro to profile a block of code. +#define BEGIN_PROFILER_BLOCK(name) \ + { \ + profile_data_accumulator::enter pe (profiler, (name)); +#define END_PROFILER_BLOCK \ + } + +#endif
--- a/src/pt-binop.cc +++ b/src/pt-binop.cc @@ -28,6 +28,7 @@ #include "defun.h" #include "oct-obj.h" #include "ov.h" +#include "profiler.h" #include "pt-binop.h" #include "pt-bp.h" #include "pt-walk.h" @@ -120,10 +121,20 @@ if (! error_state && b.is_defined ()) { + BEGIN_PROFILER_BLOCK ("binary " + oper ()) + + // Note: The profiler does not catch the braindead + // short-circuit evaluation code above, but that should be + // ok. The evaluation of operands and the operator itself + // is entangled and it's not clear where to start/stop + // timing the operator to make it reasonable. + retval = ::do_binary_op (etype, a, b); if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } } @@ -183,6 +194,11 @@ bool result = false; + // This evaluation is not caught by the profiler, since we can't find + // a reasonable place where to time. Note that we don't want to + // include evaluation of LHS or RHS into the timing, but this is + // entangled together with short-circuit evaluation here. + if (op_lhs) { octave_value a = op_lhs->rvalue1 (); @@ -279,3 +295,19 @@ { return SET_INTERNAL_VARIABLE (do_braindead_shortcircuit_evaluation); } + +/* + +%!test +%! x = 0; +%! do_braindead_shortcircuit_evaluation (0); +%! if (1 | (x = 1)) +%! endif +%! assert (x, 1); +%! do_braindead_shortcircuit_evaluation (1); +%! if (1 | (x = 0)) +%! endif +%! assert (x, 1); + +*/ +
--- a/src/pt-eval.cc +++ b/src/pt-eval.cc @@ -1202,6 +1202,17 @@ return SET_INTERNAL_VARIABLE (max_recursion_depth); } +/* +%!error (max_recursion_depth (1, 2)); +%!test +%! orig_val = max_recursion_depth (); +%! old_val = max_recursion_depth (2*orig_val); +%! assert (orig_val, old_val); +%! assert (max_recursion_depth (), 2*orig_val); +%! max_recursion_depth (orig_val); +%! assert (max_recursion_depth (), orig_val); +*/ + DEFUN (silent_functions, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} silent_functions ()\n\ @@ -1214,3 +1225,14 @@ { return SET_INTERNAL_VARIABLE (silent_functions); } + +/* +%!error (silent_functions (1, 2)); +%!test +%! orig_val = silent_functions (); +%! old_val = silent_functions (! orig_val); +%! assert (orig_val, old_val); +%! assert (silent_functions (), ! orig_val); +%! silent_functions (orig_val); +%! assert (silent_functions (), orig_val); +*/
--- a/src/pt-fcn-handle.cc +++ b/src/pt-fcn-handle.cc @@ -127,6 +127,7 @@ } uf->mark_as_inline_function (); + uf->stash_fcn_location (line (), column ()); octave_value ov_fcn (uf);
--- a/src/pt-mat.cc +++ b/src/pt-mat.cc @@ -1146,3 +1146,18 @@ { return SET_INTERNAL_VARIABLE (string_fill_char); } + +/* +%!error (string_fill_char (1, 2)); +%% string_fill_char() function call must be outside of %!test block +%% due to the way a %!test block is wrapped inside a function +%!shared orig_val, old_val +%! orig_val = string_fill_char (); +%! old_val = string_fill_char ("X"); +%!test +%! assert (orig_val, old_val); +%! assert (string_fill_char (), "X"); +%! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]); +%! string_fill_char (orig_val); +%! assert (string_fill_char (), orig_val); +*/
--- a/src/pt-unop.cc +++ b/src/pt-unop.cc @@ -28,6 +28,7 @@ #include "oct-obj.h" #include "oct-lvalue.h" #include "ov.h" +#include "profiler.h" #include "pt-bp.h" #include "pt-unop.h" #include "pt-walk.h" @@ -72,10 +73,14 @@ if (! error_state) { + BEGIN_PROFILER_BLOCK ("prefix " + oper ()) + ref.do_unary_op (etype); if (! error_state) retval = ref.value (); + + END_PROFILER_BLOCK } } else @@ -84,6 +89,8 @@ if (! error_state && val.is_defined ()) { + BEGIN_PROFILER_BLOCK ("prefix " + oper ()) + // Attempt to do the operation in-place if it is unshared // (a temporary expression). if (val.get_count () == 1) @@ -93,6 +100,8 @@ if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } } @@ -153,7 +162,9 @@ { retval = ref.value (); + BEGIN_PROFILER_BLOCK ("postfix " + oper ()) ref.do_unary_op (etype); + END_PROFILER_BLOCK } } else @@ -162,10 +173,14 @@ if (! error_state && val.is_defined ()) { + BEGIN_PROFILER_BLOCK ("postfix " + oper ()) + retval = ::do_unary_op (etype, val); if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } }
--- a/src/sighandlers.cc +++ b/src/sighandlers.cc @@ -945,6 +945,12 @@ return retval; } +/* +%!error SIG (1); +%!assert (isstruct (SIG ())); +%!assert (! isempty (SIG ())); +*/ + DEFUN (debug_on_interrupt, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} debug_on_interrupt ()\n\ @@ -958,6 +964,17 @@ return SET_INTERNAL_VARIABLE (debug_on_interrupt); } +/* +%!error (debug_on_interrupt (1, 2)); +%!test +%! orig_val = debug_on_interrupt (); +%! old_val = debug_on_interrupt (! orig_val); +%! assert (orig_val, old_val); +%! assert (debug_on_interrupt (), ! orig_val); +%! debug_on_interrupt (orig_val); +%! assert (debug_on_interrupt (), orig_val); +*/ + DEFUN (sighup_dumps_octave_core, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} sighup_dumps_octave_core ()\n\ @@ -970,6 +987,17 @@ return SET_INTERNAL_VARIABLE (sighup_dumps_octave_core); } +/* +%!error (sighup_dumps_octave_core (1, 2)); +%!test +%! orig_val = sighup_dumps_octave_core (); +%! old_val = sighup_dumps_octave_core (! orig_val); +%! assert (orig_val, old_val); +%! assert (sighup_dumps_octave_core (), ! orig_val); +%! sighup_dumps_octave_core (orig_val); +%! assert (sighup_dumps_octave_core (), orig_val); +*/ + DEFUN (sigterm_dumps_octave_core, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} sigterm_dumps_octave_core ()\n\ @@ -981,3 +1009,14 @@ { return SET_INTERNAL_VARIABLE (sigterm_dumps_octave_core); } + +/* +%!error (sigterm_dumps_octave_core (1, 2)); +%!test +%! orig_val = sigterm_dumps_octave_core (); +%! old_val = sigterm_dumps_octave_core (! orig_val); +%! assert (orig_val, old_val); +%! assert (sigterm_dumps_octave_core (), ! orig_val); +%! sigterm_dumps_octave_core (orig_val); +%! assert (sigterm_dumps_octave_core (), orig_val); +*/
--- a/src/symtab.h +++ b/src/symtab.h @@ -790,6 +790,11 @@ return rep->built_in_function; } + octave_value find_cmdline_function (void) const + { + return rep->cmdline_function; + } + octave_value find_autoload (void) { return rep->find_autoload (); @@ -1787,6 +1792,25 @@ return retval; } + static std::list<std::string> cmdline_function_names (void) + { + std::list<std::string> retval; + + for (fcn_table_const_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + octave_value fcn = p->second.find_cmdline_function (); + + if (fcn.is_defined ()) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); + + return retval; + } + static bool is_local_variable (const std::string& name) { if (xcurrent_scope == xglobal_scope)
--- a/src/sysdep.cc +++ b/src/sysdep.cc @@ -586,8 +586,16 @@ return retval; } + DEFALIAS (setenv, putenv); +/* +%!assert (ischar (getenv ("OCTAVE_HOME"))); +%!test +%! setenv ("dummy_variable_that_cannot_matter", "foobar"); +%! assert (getenv ("dummy_variable_that_cannot_matter"), "foobar"); +*/ + // FIXME -- perhaps kbhit should also be able to print a prompt? DEFUN (kbhit, args, , @@ -695,6 +703,12 @@ return retval; } +/* +%!error (pause (1, 2)); +%!test +%! pause (1); +*/ + DEFUN (sleep, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} sleep (@var{seconds})\n\ @@ -724,6 +738,13 @@ return retval; } +/* +%!error (sleep ()); +%!error (sleep (1, 2)); +%!test +%! sleep (1); +*/ + DEFUN (usleep, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} usleep (@var{microseconds})\n\ @@ -760,6 +781,13 @@ return retval; } +/* +%!error (usleep ()); +%!error (usleep (1, 2)); +%!test +%! usleep (1000); +*/ + // FIXME -- maybe this should only return 1 if IEEE floating // point functions really work. @@ -776,6 +804,10 @@ || flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); } +/* +%!assert (islogical (isieee ())); +*/ + DEFUN (native_float_format, , , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} native_float_format ()\n\ @@ -787,6 +819,10 @@ return octave_value (oct_mach_info::float_format_as_string (flt_fmt)); } +/* +%!assert (ischar (native_float_format ())); +*/ + DEFUN (tilde_expand, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} tilde_expand (@var{string})\n\ @@ -835,3 +871,14 @@ return retval; } + +/* +%!test +%! if (isempty (getenv ("HOME"))) +%! setenv ("HOME", "foobar"); +%! endif +%! home = getenv ("HOME"); +%! assert (tilde_expand ("~/foobar"), fullfile (home, "foobar")); +%! assert (tilde_expand ("/foo/bar"), "/foo/bar"); +%! assert (tilde_expand ("foo/bar"), "foo/bar"); +*/
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -39,6 +39,7 @@ #include <unistd.h> #include "cmd-edit.h" +#include "cmd-hist.h" #include "file-ops.h" #include "lo-error.h" #include "lo-mappers.h" @@ -1001,6 +1002,20 @@ DEFALIAS (shell_cmd, system); +/* +%!error (system ()); +%!error (system (1, 2, 3)); +%!test +%! if (ispc ()) +%! cmd = "dir"; +%! else +%! cmd = "ls"; +%! endif +%! [status, output] = system (cmd); +%! assert (ischar (output)); +%! assert (! isempty (output)); +*/ + // FIXME -- this should really be static, but that causes // problems on some systems. std::list<std::string> octave_atexit_functions; @@ -1039,7 +1054,7 @@ SAFE_CALL (octave_history_write_timestamp, ()) - if (Vsaving_history) + if (! command_history::ignoring_entries ()) SAFE_CALL (command_history::clean_up_and_save, ()) SAFE_CALL (close_files, ()) @@ -1285,6 +1300,10 @@ { false, "MAGICK_LDFLAGS", OCTAVE_CONF_MAGICK_LDFLAGS }, { false, "MAGICK_LIBS", OCTAVE_CONF_MAGICK_LIBS }, { false, "MKOCTFILE_DL_LDFLAGS", OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS }, + { false, "OCTAVE_LINK_DEPS", OCTAVE_CONF_OCTAVE_LINK_DEPS }, + { false, "OCTAVE_LINK_OPTS", OCTAVE_CONF_OCTAVE_LINK_OPTS }, + { false, "OCT_LINK_DEPS", OCTAVE_CONF_OCT_LINK_DEPS }, + { false, "OCT_LINK_OPTS", OCTAVE_CONF_OCT_LINK_OPTS }, { false, "OPENGL_LIBS", OCTAVE_CONF_OPENGL_LIBS }, { false, "PTHREAD_CFLAGS", OCTAVE_CONF_PTHREAD_CFLAGS }, { false, "PTHREAD_LIBS", OCTAVE_CONF_PTHREAD_LIBS }, @@ -1298,7 +1317,6 @@ { false, "RDYNAMIC_FLAG", OCTAVE_CONF_RDYNAMIC_FLAG }, { false, "READLINE_LIBS", OCTAVE_CONF_READLINE_LIBS }, { false, "REGEX_LIBS", OCTAVE_CONF_REGEX_LIBS }, - { false, "RLD_FLAG", OCTAVE_CONF_RLD_FLAG }, { false, "SED", OCTAVE_CONF_SED }, { false, "SHARED_LIBS", OCTAVE_CONF_SHARED_LIBS }, { false, "SHLEXT", OCTAVE_CONF_SHLEXT }, @@ -1439,6 +1457,15 @@ return retval; } +/* +%!error octave_config_info (1, 2); +%!assert (ischar (octave_config_info ("version"))); +%!test +%! x = octave_config_info (); +%! assert (isstruct (x)); +%! assert (! isempty (x)); +*/ + #if defined (__GNUG__) && defined (DEBUG_NEW_DELETE) int debug_new_delete = 0;
--- a/src/txt-eng-ft.cc +++ b/src/txt-eng-ft.cc @@ -202,7 +202,8 @@ ft_render::ft_render (void) : text_processor (), face (0), bbox (1, 4, 0.0), - xoffset (0), yoffset (0), mode (MODE_BBOX), + xoffset (0), yoffset (0), multiline_halign (0), + multiline_align_xoffsets(), mode (MODE_BBOX), red (0), green (0), blue (0) { } @@ -270,15 +271,23 @@ { if (face) { + int line_index = 0; + FT_UInt box_line_width = 0; std::string str = e.string_value (); FT_UInt glyph_index, previous = 0; + if (mode == MODE_BBOX) + multiline_align_xoffsets.clear(); + else if (mode == MODE_RENDER) + xoffset += multiline_align_xoffsets[line_index]; + for (size_t i = 0; i < str.length (); i++) { glyph_index = FT_Get_Char_Index (face, str[i]); - if (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + if (str[i] != '\n' + && (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) ::warning ("ft_render: skipping missing glyph for character `%c'", str[i]); else @@ -286,7 +295,21 @@ switch (mode) { case MODE_RENDER: - if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL)) + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index(face, ' '); + if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + ::warning ("ft_render: skipping missing glyph for character ` '"); + } + else + { + line_index++; + xoffset = multiline_align_xoffsets[line_index]; + yoffset -= (face->size->metrics.height >> 6); + } + } + else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL)) ::warning ("ft_render: unable to render glyph for character `%c'", str[i]); else @@ -304,6 +327,14 @@ x0 = xoffset+face->glyph->bitmap_left; y0 = yoffset+face->glyph->bitmap_top; + + // 'w' seems to have a negative -1 + // face->glyph->bitmap_left, this is so we don't + // index out of bound, and assumes we we allocated + // the right amount of horizontal space in the bbox. + if (x0 < 0) + x0 = 0; + for (int r = 0; r < bitmap.rows; r++) for (int c = 0; c < bitmap.width; c++) { @@ -327,43 +358,89 @@ break; case MODE_BBOX: - // width - if (previous) + if (str[i] == '\n') { - FT_Vector delta; - - FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - bbox(2) += (delta.x >> 6); - } - bbox(2) += (face->glyph->advance.x >> 6); - - int asc, desc; - - if (false /*tight*/) + glyph_index = FT_Get_Char_Index(face, ' '); + if (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + ::warning ("ft_render: skipping missing glyph for character ` '"); + } + else + { + multiline_align_xoffsets.push_back(box_line_width); + // Reset the pixel width for this newline, so we don't + // allocate a bounding box larger than the horizontal + // width of the multi-line + box_line_width = 0; + bbox(1) -= (face->size->metrics.height >> 6); + } + } + else { - desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; - asc = face->glyph->metrics.horiBearingY; - } - else - { - asc = face->size->metrics.ascender; - desc = face->size->metrics.descender; - } + // width + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta); + + box_line_width += (delta.x >> 6); + } + + box_line_width += (face->glyph->advance.x >> 6); + + int asc, desc; - asc = yoffset + (asc >> 6); - desc = yoffset + (desc >> 6); + if (false /*tight*/) + { + desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; + asc = face->glyph->metrics.horiBearingY; + } + else + { + asc = face->size->metrics.ascender; + desc = face->size->metrics.descender; + } - if (desc < bbox(1)) - { - bbox(3) += (bbox(1) - desc); - bbox(1) = desc; - } - if (asc > (bbox(3)+bbox(1))) - bbox(3) = asc-bbox(1); + asc = yoffset + (asc >> 6); + desc = yoffset + (desc >> 6); + + if (desc < bbox(1)) + { + bbox(3) += (bbox(1) - desc); + bbox(1) = desc; + } + if (asc > (bbox(3)+bbox(1))) + bbox(3) = asc-bbox(1); + if (bbox(2) < box_line_width) + bbox(2) = box_line_width; + } break; } + if (str[i] == '\n') + previous = 0; + else + previous = glyph_index; + } + } + if (mode == MODE_BBOX) + { + /* Push last the width associated with the last line */ + multiline_align_xoffsets.push_back(box_line_width); - previous = glyph_index; + for (unsigned int i = 0; i < multiline_align_xoffsets.size(); i++) + { + /* Center align */ + if (multiline_halign == 1) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2; + /* Right align */ + else if (multiline_halign == 2) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]); + /* Left align */ + else + multiline_align_xoffsets[i] = 0; } } } @@ -506,6 +583,8 @@ { // FIXME: clip "rotation" between 0 and 360 int rot_mode = rotation_to_mode (rotation); + + multiline_halign = halign; text_element *elt = text_parser_none ().parse (txt); pixels_ = render (elt, box, rot_mode);
--- a/src/txt-eng-ft.h +++ b/src/txt-eng-ft.h @@ -25,6 +25,8 @@ #if HAVE_FREETYPE +#include <vector> + #include <ft2build.h> #include FT_FREETYPE_H @@ -94,6 +96,8 @@ uint8NDArray pixels; int xoffset; int yoffset; + int multiline_halign; + std::vector<int> multiline_align_xoffsets; int mode; uint8_t red, green, blue; };
--- a/src/variables.cc +++ b/src/variables.cc @@ -1043,11 +1043,12 @@ const std::string& expr_str = std::string (), const octave_value& expr_val = octave_value ()) : name (expr_str.empty () ? sr.name () : expr_str), + varval (expr_val.is_undefined () ? sr.varval () : expr_val), is_automatic (sr.is_automatic ()), + is_complex (varval.is_complex_type ()), is_formal (sr.is_formal ()), is_global (sr.is_global ()), - is_persistent (sr.is_persistent ()), - varval (expr_val.is_undefined () ? sr.varval () : expr_val) + is_persistent (sr.is_persistent ()) { } void display_line (std::ostream& os, @@ -1117,13 +1118,14 @@ { case 'a': { - char tmp[5]; + char tmp[6]; tmp[0] = (is_automatic ? 'a' : ' '); - tmp[1] = (is_formal ? 'f' : ' '); - tmp[2] = (is_global ? 'g' : ' '); - tmp[3] = (is_persistent ? 'p' : ' '); - tmp[4] = 0; + tmp[1] = (is_complex ? 'c' : ' '); + tmp[2] = (is_formal ? 'f' : ' '); + tmp[3] = (is_global ? 'g' : ' '); + tmp[4] = (is_persistent ? 'p' : ' '); + tmp[5] = 0; os << tmp; } @@ -1172,11 +1174,12 @@ } std::string name; + octave_value varval; bool is_automatic; + bool is_complex; bool is_formal; bool is_global; bool is_persistent; - octave_value varval; }; public: @@ -1333,6 +1336,9 @@ for (size_t i = 0; i < param_string.length (); i++) param_length(i) = param_names(i) . length (); + // The attribute column needs size 5. + param_length(pos_a) = 5; + // Calculating necessary spacing for name column, // bytes column, elements column and class column @@ -1798,6 +1804,9 @@ Automatic variable. An automatic variable is one created by the\n\ interpreter, for example @code{argn}.\n\ \n\ +@item @code{c}\n\ +Variable of complex type.\n\ +\n\ @item @code{f}\n\ Formal parameter (function argument).\n\ \n\
--- a/src/xpow.cc +++ b/src/xpow.cc @@ -49,6 +49,8 @@ #include "utils.h" #include "xpow.h" +#include "bsxfun.h" + #ifdef _OPENMP #include <omp.h> #endif @@ -1243,8 +1245,21 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + //Potentially complex results + NDArray xa = octave_value_extract<NDArray> (a); + NDArray xb = octave_value_extract<NDArray> (b); + if (! xb.all_integers () && xa.any_element_is_negative ()) + return octave_value (bsxfun_pow (ComplexNDArray (xa), xb)); + else + return octave_value (bsxfun_pow (xa, xb)); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } int len = a.length (); @@ -1318,8 +1333,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); @@ -1410,8 +1432,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); @@ -1453,8 +1482,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); @@ -2562,8 +2598,21 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + //Potentially complex results + FloatNDArray xa = octave_value_extract<FloatNDArray> (a); + FloatNDArray xb = octave_value_extract<FloatNDArray> (b); + if (! xb.all_integers () && xa.any_element_is_negative ()) + return octave_value (bsxfun_pow (FloatComplexNDArray (xa), xb)); + else + return octave_value (bsxfun_pow (xa, xb)); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } int len = a.length (); @@ -2637,8 +2686,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } FloatComplexNDArray result (a_dims); @@ -2729,8 +2785,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } FloatComplexNDArray result (a_dims); @@ -2772,8 +2835,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } FloatComplexNDArray result (a_dims);
--- a/test/fntests.m +++ b/test/fntests.m @@ -97,6 +97,17 @@ endif endfunction +function retval = has_demos (f) + fid = fopen (f); + if (fid >= 0) + str = fread (fid, "*char")'; + fclose (fid); + retval = ! isempty (regexp (str, '^%!demo', "lineanchors")); + else + error ("fopen failed: %s", f); + endif +endfunction + function [dp, dn, dxf, dsk] = run_test_dir (fid, d); global files_with_tests; global files_with_no_tests; @@ -113,6 +124,8 @@ [p, n, xf, sk] = test (nm(1:(end-2)), "quiet", fid); print_pass_fail (n, p); files_with_tests(end+1) = ffnm; + elseif (has_demos (ffnm)) + files_with_tests(end+1) = ffnm; else files_with_no_tests(end+1) = ffnm; endif @@ -164,6 +177,8 @@ dxf += xf; dsk += sk; files_with_tests(end+1) = f; + elseif (has_demos (f)) + files_with_tests(end+1) = f; elseif (has_functions (f)) ## To reduce the list length, only mark .cc files that contain ## DEFUN definitions. @@ -192,20 +207,15 @@ endfunction function n = num_elts_matching_pattern (lst, pat) - n = 0; - for i = 1:length (lst) - if (! isempty (regexp (lst{i}, pat, "once"))) - n++; - endif - endfor + n = sum (cellfun (@(x) !isempty (x), regexp (lst, pat, 'once'))); endfunction function report_files_with_no_tests (with, without, typ) - pat = cstrcat ("\\", typ, "$"); + pat = cstrcat ('\', typ, "$"); n_with = num_elts_matching_pattern (with, pat); n_without = num_elts_matching_pattern (without, pat); n_tot = n_with + n_without; - printf ("\n%d (of %d) %s files have no tests.\n", n_without, n_tot, typ); + printf ("\n%d (of %d) %s files have no tests or demos.\n", n_without, n_tot, typ); endfunction pso = page_screen_output (); @@ -258,6 +268,12 @@ puts ("because the needed libraries were not present when Octave was built.\n"); endif + ## Weed out deprecated and private functions + weed_idx = cellfun (@isempty, regexp (files_with_tests, '\bdeprecated\b|\bprivate\b', 'once')); + files_with_tests = files_with_tests(weed_idx); + weed_idx = cellfun (@isempty, regexp (files_with_no_tests, '\bdeprecated\b|\bprivate\b', 'once')); + files_with_no_tests = files_with_no_tests(weed_idx); + report_files_with_no_tests (files_with_tests, files_with_no_tests, ".m"); report_files_with_no_tests (files_with_tests, files_with_no_tests, ".cc");
--- a/test/test_io.m +++ b/test/test_io.m @@ -245,6 +245,27 @@ %!assert (sscanf ('123456', '%10c'), '123456') %!assert (sscanf ('123456', '%10s'), '123456') +%!test +%! [val, count, msg, pos] = sscanf ("3I2", "%f"); +%! assert (val, 3); +%! assert (count, 1); +%! assert (msg, ""); +%! assert (pos, 2); + +%!test +%! [val, count, msg, pos] = sscanf ("3In2", "%f"); +%! assert (val, 3); +%! assert (count, 1); +%! assert (msg, ""); +%! assert (pos, 2); + +%!test +%! [val, count, msg, pos] = sscanf ("3Inf2", "%f"); +%! assert (val, [3; Inf; 2]); +%! assert (count, 3); +%! assert (msg, ""); +%! assert (pos, 6); + %% test/octave.test/io/sscanf-1.m %!test %! [a, b, c] = sscanf ("1.2 3 foo", "%f%d%s", "C");
--- a/test/test_parser.m +++ b/test/test_parser.m @@ -28,142 +28,222 @@ %!assert ({1 2,{3,4}}, {1,2,{3,4}}) %!assert ({1,2,{3 4}}, {1,2,{3,4}}) -%# Tests for operator precedence as documented in section 8.8 of manual -%# There are 11 levels of precedence from "exponentiation" (highest) down to -%# "statement operators" (lowest). -%# -%# Level 11 (exponentiation) overrides all others +## Tests for operator precedence as documented in section 8.8 of manual +## There are 13 levels of precedence from "parentheses and indexing" (highest) +## down to "statement operators" (lowest). +## +## Level 13 (parentheses and indexing) +## Overrides all other levels +%!test +%! a.b = 1; +%! assert (a. b++, 1) +%! assert (a.b, 2) +%! clear a; +%! a.b = [0 1]; +%! b = 2; +%! assert (a.b', [0;1]) +%! assert (!a .b, logical ([1 0])) +%! assert (3*a .b, [0 3]) +%! assert (a. b-1, [-1 0]) +%! assert (a. b:3, 0:3) +%! assert (a. b>0.5, logical ([0 1])) +%! assert (a. b&0, logical ([0 0])) +%! assert (a. b|0, logical ([0 1])) +%! a.b = [1 2]; +%! assert (a. b&&0, false) +%! assert (a. b||0, true) +%! a.b += a. b*2; +%! assert (a.b, [3 6]) +## Level 12 (postfix increment and decrement) %!test -%! assert (-2^2, -4) -%! assert (!0^0, false); -# FIXME: This test is failing. Transpose mistakenly has higher priority. -%!# assert ([2 3].^2', [4; 9]) -%! assert (2*3^2, 18) -%! assert (2+3^2, 11) -%! assert ([1:10](1:2^2), [1 2 3 4]) -%! assert (3 > 2^2, false) -%! assert (1 & 0^0, true) -%! assert (1 && 0^0, true) +%! a = [3 5]; +%! assert (2.^a ++, [8 32]) +%! assert (a, [4 6]) +%! assert (a--', [4; 6]) +%! assert (a, [3 5]) +%! a = 0; +%! assert (!a --, true) +%! assert (-a ++, 1) +%! assert (3*a ++, 0) +%! assert (a++-2, -1) +%! assert (1:a ++, 1:2) +%! assert (4>a++, true) +%! a = [0 -1]; +%! assert ([1 1] & a++, logical ([0 1])) +%! assert ([0 0] | a++, logical ([1 0])) +%! a = 0; +%! assert (1 && a ++, false) +%! assert (0 || a --, true) +%! a = 5; b = 2; +%! b +=a ++; +%! assert (b, 7) + +## Level 11 (transpose and exponentiation) +%!test +%! assert (-2 ^2, -4) +%! assert (!0 ^0, false) +%! assert (2*3 ^2, 18) +%! assert (2+3 ^2, 11) +%! assert ([1:10](1:2 ^2), [1 2 3 4]) +%! assert (3>2 ^2, false) +%! assert (1&0 ^0, true) +%! assert (0|0 ^0, true) +%! assert (1&&0 ^0, true) +%! assert (0||0 ^0, true) %! a = 3; -%! a *= 0^0; +%! a *= 0 ^0; %! assert (a, 3) -%# Level 10 (unary plus, increment, not) +## Level 10 (unary plus/minus, prefix increment/decrement, not) %!test -# FIXME: No test for increment and transpose that I can think of. %! a = 2; -%! assert (++a*3, 9) -%! assert (a++-2, 1) -%! assert (a, 4) -%! assert ([1:10](1:++a), [1:5]) -%! assert (5 == a++, true) -%! assert (7 == ++a, true) +%! assert (++ a*3, 9) +%! assert (-- a-2, 0) +%! assert (a, 2) +%! assert (! a-2, -2) +%! assert ([1:10](++ a:5), 3:5) +%! a = [1 0]; +%! assert (! a>=[1 0], [false true]) %! a = 0; -%! assert (1 & a++, false) -%! assert (a, 1) -%! assert (1 && --a, false) +%! assert (++ a&1, true) +%! assert (-- a|0, false) +%! assert (-- a&&1, true) +%! assert (++ a||0, false) %! a = 3; -%! a *= a++; -%! assert (a, 12) -%# Level 9 (transpose) +%! a *= ++a; +%! assert (a, 16) +## Level 9 (multiply, divide) %!test -%! assert ([1 2]*[3 4]', 11) -%! assert ([1 2]'+[3 4]', [4; 6]) -%! assert (1:5', 1:5) -%! assert ([1; 2] == [1 2]', [true; true]) -%! assert ([1; 0] & [1 0]', [true; false]) -# FIXME: No test for transpose and short-circuit operator that I can think of. -%! a = [1 2]; -%! a *= [3 4]'; -%! assert (a, 11) -%# Level 8 (multiply, divide) -%!test -%! assert (3 + 4 * 5, 23) -%! assert (3 + 4 * 5, 23) -%! assert (5*1:6, [5 6]) -%! assert (3 > 1 * 5, false) -%! assert (1 & 1 * 0, false) -%! assert (1 && 1 * 0, false) +%! assert (3+4 * 5, 23) +%! assert (5 * 1:6, [5 6]) +%! assert (3>1 * 5, false) +%! assert (1&1 * 0, false) +%! assert (1|1 * 0, true) +%! assert (1&&1 * 0, false) +%! assert (1||1 * 0, true) %! a = 3; %! a /= a * 2; %! assert (a, 0.5) -%# Level 7 (add, subtract) +## Level 8 (add, subtract) %!test %! assert ([2 + 1:6], 3:6) -%! assert (3 > 1 + 5, false) -%! assert (1 & 1 - 1, false) -%! assert (1 && 1 - 1, false) +%! assert (3>1 + 5, false) +%! assert (1&1 - 1, false) +%! assert (0|1 - 2, true) +%! assert (1&&1 - 1, false) +%! assert (0||1 - 2, true) %! a = 3; %! a *= 1 + 1; %! assert (a, 6) -%# Level 6 (colon) +## Level 7 (colon) %!test -%! assert (5:-1: 3 > 4, [true false false]) -%! assert (1: 3 & 1, [true true true]) -%! assert (-1: 3 && 1, false) +%! assert (5:-1: 3>4, [true false false]) +%! assert (1: 3&1, [true true true]) +%! assert (1: 3|0, [true true true]) +%! assert (-1: 3&&1, false) +%! assert (-1: 3||0, false) %! a = [1:3]; %! a += 3 : 5; %! assert (a, [4 6 8]) -%# Level 5 (relational) +## Level 6 (relational) %!test -%! assert (0 == -1 & 0, false) -%! assert (0 == -1 && 0, false) +%! assert (0 == -1&0, false) +%! assert (1 == -1|0, false) +%! assert (0 == -1&&0, false) +%! assert (1 == -1||0, false) %! a = 2; %! a *= 3 > 1; %! assert (a, 2) -%# Level 4 (element-wise and, or) +## Level 5 (element-wise and) %!test -%! assert (0 & 1 || 1, true) -%! assert (0 == -1 && 0, false) +%! assert (0 & 1|1, true) +%! assert ([0 1] & 1&&1, false) +%! assert (0 & 1||1, true) %! a = 2; %! a *= 3 & 1; %! assert (a, 2) -%# Level 3 (logical and, or) +## Level 4 (element-wise or) %!test +%! assert ([0 1] | 1&&0, false) +%! assert ([0 1] | 1||0, true) +%! a = 2; +%! a *= 0 | 1; +%! assert (a, 2) +## Level 3 (logical and) +%!test +%! assert (0 && 1||1, true) %! a = 2; %! a *= 3 && 1; %! assert (a, 2) +## Level 2 (logical or) +%!test +%! a = 2; +%! a *= 0 || 1; +%! assert (a, 2) -%# Tests for operator precedence within each level where ordering should -%# be left to right except for exponents and assignments. -%# Level 11 (exponentiation) +## Tests for operator precedence within each level where ordering should +## be left to right except for postfix and assignment operators. + +## Level 13 (parentheses and indexing) %!test -%# FIXME : Exponentiation seems to work left to right, despite the -%# documentation and ordinary mathematical rules of precedence. -%!# assert (2^3**2, 512) -%# Level 10 (unary plus, increment, not) +%! a.b1 = 2; +%! assert (a.(strcat('b','1'))++, 2) +%! assert (a.b1, 3) +%! b = {1 2 3 4 5}; +%! assert (b{(a. b1 + 1)}, 4) +%! b = 1:5; +%! assert (b(a. b1 + 1), 4) +%! assert ([2 3].^2', [4; 9]) +## Level 12 (postfix increment and decrement) +## No tests possible since a++-- is not valid +## Level 11 (transpose and exponentiation) +## Note: Exponentiation works left to right for compatibility with Matlab. +%! assert (2^3**2, 64) +%! assert ([2 3].^2.', [4;9]) +%! assert ([2 3].'.^2, [4;9]) +%! assert (3*4i'.', 0 - 12i) +%! assert (3*4i.'.', 0 + 12i) +## Level 10 (unary plus/minus, prefix increment/decrement, not) %!test %! assert (+-+1, -1) -%! a = 0; -%# FIXME : Should we test for this corner case at all? -%# (unary minus)(auto-decrement operator) -%!# assert (---a, 1); %! a = -1; %! assert (!++a, true) %! assert (a, 0) %! assert (-~a, -1) -%! assert (!~a++, false) -%! assert (a, 1) -%# Level 9 (transpose) +%! assert (!~--a, true) +%! assert (a, -1) +## Level 9 (multiply, divide) %!test -%! assert (3*4i'.', 0 - 12i) -%! assert (3*4i.'.', 0 + 12i) -%# Level 8 (multiply, divide) +%! assert (3 * 4 / 5, 2.4) +%! assert (3 ./ 4 .* 5, 3.75) +%! assert (2 * 4 \ 6, 0.75) +%! assert (2 .\ 4 .* 6, 12) +## Level 8 (add, subtract) %!test -%!assert (3 * 4 / 5, 2.4) -%!assert (3 ./ 4 .* 5, 3.75) -%# Level 7 (add, subtract) -%!test -%!assert (-3 - 4 + 1 + 3 * 2, 0) -%# Level 5 (relational) +%! assert (-3 - 4 + 1 + 3 * 2, 0) +## Level 7 (colon) +## No tests possible because colon operator can't be combined with second colon operator +## Level 6 (relational) %!test %! assert (0 < 1 <= 0.5 == 0 >= 0.5 > 0, true) %! assert (1 < 1 == 0 != 0, true) %! assert (1 < 1 == 0 ~= 0, true) -%# Level 4 (element-wise and, or) +## Level 5 (element-wise and) +## No tests possible. Only one operator (&) at this precedence level and operation is associative. +## Level 4 (element-wise or) +## No tests possible. Only one operator (|) at this precedence level and operation is associative. +## Level 3 (logical and) %!test -%! assert ([ 1 0] & [0 1] | [1 0], [true false]) -%# Level 2 (assignment) +%! a = 1; +%! assert (1 && 0 && ++a, false) +%! assert (a, 1) +## Level 2 (logical or) +%!test +%! a = 1; +%! assert (0 || 1 || ++a, true) +%! assert (a, 1) +## Level 1 (assignment) %!test %! a = 2; b = 5; c = 7; %! assert (a += b *= c += 1, 42) %! assert (b == 40 && c == 8) +