pax_global_header00006660000000000000000000000064130352565310014515gustar00rootroot0000000000000052 comment=4d8f0ecac763251231ff3f3461949c68266f436a OptimPackLegacy-release-1.4.0/000077500000000000000000000000001303525653100161515ustar00rootroot00000000000000OptimPackLegacy-release-1.4.0/.dir-locals.el000066400000000000000000000006761303525653100206130ustar00rootroot00000000000000((nil . ((indent-tabs-mode . nil) (tab-width . 8) (fill-column . 79) (ispell-local-dictionary . "american"))) (c-mode . ((c-file-style . "bsd") (c-basic-offset . 2))) (java-mode . ((c-basic-offset . 4))) (julia-mode . ()) (makefile-gmake-mode . ((indent-tabs-mode . t))) (sh-mode . ((sh-basic-offset . 4))) (tcl-mode . ((tcl-default-application . "wish") (tcl-indent-level . 2))) (yorick-mode . ((c-basic-offset . 2))) ) OptimPackLegacy-release-1.4.0/.gitignore000066400000000000000000000001511303525653100201360ustar00rootroot00000000000000*~ *.bak *.o *.lo *.la lib*.a *.so *.dll *.tar.gz *.txz *.tar.bz2 *.zip *.log yorick/ywrap.c RCS/ devel/ OptimPackLegacy-release-1.4.0/AUTHORS000066400000000000000000000001031303525653100172130ustar00rootroot00000000000000Eric Thiébaut (Centre de Recherche Astrophysique de Lyon, France) OptimPackLegacy-release-1.4.0/LICENSE000066400000000000000000000431331303525653100171620ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. OptimPackLegacy-release-1.4.0/Makefile000066400000000000000000000061041303525653100176120ustar00rootroot00000000000000# # Makefile -- # # Makefile for OptimPackLegacy. # #------------------------------------------------------------------------------ # # Copyright (c) 2003, 2016 Éric Thiébaut. # # This file is part of OptimPack . # # OptimPack 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. # # OptimPack 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 OptimPack (file "LICENSE" in the top source directory); if not, # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA # #------------------------------------------------------------------------------ srcdir = . VERSION = `sed < VERSION -e 's/ //g'` SUBDIRS = yorick idl src DISTRIB_SRC = $(srcdir) DISTRIB_FILES = AUTHORS LICENSE Makefile NEWS.md README.md TODO.md \ optimpack.bib CODE_SRC = $(srcdir)/src CODE_FILES = opl_algebra.c opl_lnsrch.c opl_vmlmb.c opl_utils.c \ opl_limits.h opl_private.h optimpacklegacy.h YORICK_SRC = $(srcdir)/yorick YORICK_FILES = Makefile opl_yorick.c optimpacklegacy.i \ optimpacklegacy-start.i \ optimpacklegacy-tests.i optimpacklegacy-tests.out all: @echo "No default target" distrib: @version=$(VERSION); \ if test "x$$version" = "x"; then \ echo >&2 "bad VERSION"; \ return 1; \ fi; \ pkgdir=OptimPackLegacy-$$version; \ archive=$$pkgdir.tar.bz2; \ if test -e "$$pkgdir"; then \ echo >&2 "error: $$pkgdir already exists"; \ return 1; \ fi; \ if test -e "$$archive"; then \ echo >&2 "error: $$archive already exists"; \ return 1; \ fi; \ dstdir=$$pkgdir/yorick; \ mkdir -p "$$dstdir"; \ chmod 755 "$$dstdir"; \ for file in $(YORICK_FILES); do \ src=$(YORICK_SRC)/$$file; \ dst=$$dstdir/$$file; \ cp -p "$$src" "$$dst"; \ chmod 644 "$$dst"; \ done; \ dstdir=$$pkgdir; \ mkdir -p "$$dstdir"; \ chmod 755 "$$dstdir"; \ for file in $(DISTRIB_FILES); do \ src=$(DISTRIB_SRC)/$$file; \ dst=$$dstdir/$$file; \ cp -p "$$src" "$$dst"; \ chmod 644 "$$dst"; \ done; \ dst=$$dstdir/VERSION; \ echo "$$version" >"$$dst"; \ chmod 644 "$$dst"; \ dstdir=$$pkgdir/src; \ mkdir -p "$$dstdir"; \ chmod 755 "$$dstdir"; \ for file in $(CODE_FILES); do \ src=$(CODE_SRC)/$$file; \ dst=$$dstdir/$$file; \ cp -p "$$src" "$$dst"; \ chmod 644 "$$dst"; \ done; \ tar cf - "$$pkgdir" | bzip2 -9 > "$$archive"; \ rm -rf "$$pkgdir"; \ echo "archive $$archive created"; \ return 0 clean: $(RM) *~ for dir in $(SUBDIRS); do \ if [ -f "$$dir/Makefile" ]; then \ (cd $$dir; make clean); \ fi; \ done distclean: clean for dir in $(SUBDIRS); do \ if [ -f "$$dir/Makefile" ]; then \ (cd $$dir; make distclean); \ fi; \ done OptimPackLegacy-release-1.4.0/NEWS.md000066400000000000000000000055641303525653100172610ustar00rootroot00000000000000## Version 1.4.0 (2017-01-10) * VMLMB workspace is now a single opaque handle. All needed data can be saved in a single block of memory (*monolithic* workspace) provided by the caller or allocated by the library (and possibly split in small blocks). This simplifies the use of VMLMB both in C and in other programming languages and add flexibility for very large problems. * In case of early stopping (i.e., during a line search), it is now posible to restore the variables at the start of the line search. This is expected to be nearly the best ones so far. * Rewrite VMLMB code for better readability, to remove unecessary variables and avoid unecessary computations. This also fixes some inconsistencies. Opaque structures are now used instead of arrays of values, hopefully not to the detriment of portability. * IDL port has been temporarily removed (will be back soon). ## Version 1.3.3 (2016-12-13) * Parameter `delta > 0` is used to specify a relative small step size. * Parameter `epsilon ≥ 0` is used to check for the sufficient descent condition. Seems to speed up convergence in many cases. * In Yorick interface: - The norm of the *projected* gradient is displayed and used to check for the convergence when there are bounds. - New `op_vmlmb` interface in Yorick which controls the convergence based on the gradient via keywords `gatol` and `grtol`. - The `op_mnb` driver is deprecated in favor of `op_vmlmb`. - By default, the best solution found so far is returned by `op_vmlmb` (see keyword `savebest`). convergence when there are bounds. * Code cleanup: get rid of non-linear conjugate gradients (never implemented in this version). * `make distrib VERSION=...` can be used to archive the sources. * Move sources to `src` and update make target/rules. * OptimPack (version 1) is now on GitHub at https://github.com/emmt/OptimPackLegacy **Version 1.3.2 (2010-05-07)** * Makefile fixed thanks to Michael Williamson. **Version 1.3.1 (2009-09-23)** * Bugs fixed in Yorick interface with the size of workspace arrays ISAVE and DSAVE. **Version 1.3.0 (2009-05-14)** * `fmin` is now an optional parameter. Functions `op_get/set_fmin` and `op_vmlmb_first` have changed. Accordingly, the Yorick interface have changed. * IDL interface needs to be updated... **Version 1.2.0 (2008-01-31)** **Version 1.1.0 (2008-01-30)** * Yorick interface to OptimPack reworked. * In IDL interface, some fixes by Laurent Mugnier: - syntax errors in `op_vmlmb_msg.pro`; - bugs in parsing of arguments in `op_idl.c` (function `op_idl_vmlmb_next`). - New function `fmin_op` in directory `idl/contrib` by Laurent Mugnier (license is CeCILL not GPL). * GNU Public License updated. * Integrate changes made by Laurent Mugnier (thanks to him!) in IDL interface to support for Linux and 64 bit machines. **Version 1.0.0 (2003-04-22)** OptimPackLegacy-release-1.4.0/README.md000066400000000000000000000071731303525653100174400ustar00rootroot00000000000000# OptimPackLegacy (version 1) This is **OptimPackLegacy**, a C library for optimization of large scale problems possibly with bound constraints. This version implements: - Moré and Thuente method for inexact line search; - VMLMB algorithm by Éric Thiébaut which is a limited memory BFGS (variable metric) method possibly with bound constraints and/or preconditioning. In order to make embedding OptimPackLegacy into another language as easy as possible, the routines use reverse communication: all local variables needed by the optimization routines get saved into workspace structures (allocated by the library or provided by the caller) and the optimization routines never explicitely call the penalty function to optimize. Most of the documention is in the header file [optimpacklegacy.h](src/optimpacklegacy.h). Another version of OptimPack is under development and available [here](https://github.com/emmt/OptimPack). This new version implements a completely different memory management system to be more flexible and allow for various kinds of storage (standard memory, distributed memory, GPU, *etc.*). Directory [yorick](yorick) contains an implementation of OptimPack support in Yorick. ## References * Jorge J. Moré and David J. Thuente, "*Line search algorithms with guaranteed sufficient decrease*" in ACM Transactions on Mathematical Software (TOMS) Volume **20**, Issue 3, Pages 286-307 (September 1994). * Éric Thiébaut, "*Optimization issues in blind deconvolution algorithms*", SPIE Conf. Astronomical Data Analysis II, **4847**, 174-183 (2002). ## Installation To install the library (not needed for Yorick nor for IDL): 1. Edit the file `src/Makefile` (see "Portability Issues" below). 2. Compile the library: cd src make 3. Optionaly install the software, for instance: make PREFIX=/usr/local install which will copy: liboptimpacklegacy.a into /usr/local/lib optimpacklegacy.h into /usr/local/include and creates directory `/usr/local/doc/OptimPack-${VERSION}` with some documentation and legal stuff. ## Yorick Installation 1. Go to directory `yorick`. 2. Setup for compilation and compile the plugin code: yorick -batch make.i make clean make 3. Optionaly install plugin in Yorick tree: make install ## Portability Issues OptimPackLegacy is written in standard ANSI-C and should pose no problem of portability. However, in order to match the data types used in your software, you may have to set the values of the following macros: OPL_INTEGER = data type used to store array indices OPL_LOGICAL = data type of the result of a logical test This must be done *before* `optimpacklegacy.h` get included. If these macros are not defined, the default assumed in `optimpacklegacy.h` is: OPL_INTEGER = int OPL_LOGICAL = int For instance, one should write: #define OPL_INTEGER long #define OPL_LOGICAL int #include "optimpacklegacy.h" ... Of course, the installed OptimPackLegacy library must have been compiled with the correct data types. Another possibility is to define these macros when calling CPP (the C preprocessor), *e.g.* in `src/Makefile`: CPPFLAGS = -DOPL_INTEGER=long -DOPL_LOGICAL=int -I. a final possibility is to edit `optimpacklegacy.h` and to adjust the default values of these macros (at the very beginning of this file). If you plan to install in your system, the best is probably to fix the definitions in `optimpacklegacy.h`, then compile the library and finally install the library and the header file `optimpacklegacy.h` in proper system directories (*e.g.* with `make install PREFIX=...`). OptimPackLegacy-release-1.4.0/TODO.md000066400000000000000000000012241303525653100172370ustar00rootroot00000000000000* Update documentation (use Doxygen?). * Implement gradient-based convergence test. * Use `fmin`. * `gamma` should be computed (and applied) when there is a preconditioner. * Backtrack (using Armijo's rule) when at least one bound constraint becomes active along the line search. * Implement damped BFGS updating, see Nocédal & Wright p. 537. * Scale initial gradient. Perhaps use a typical value for the step norm * Safeguard the step. * Implement BLMVM. * Saving best variables so far can be very cheap: it is sufficient to remember the best step length, and corresponding function value and gradient norm. Not applicable with constraints. OptimPackLegacy-release-1.4.0/VERSION000066400000000000000000000000131303525653100172130ustar00rootroot000000000000001.4.0-pre1 OptimPackLegacy-release-1.4.0/optimpack.bib000066400000000000000000000022401303525653100206140ustar00rootroot00000000000000@Article{More_Thente-1994-line_search, Author = {Jorge J. Mor{\'e} and David J. Thuente}, Title = {Line search algorithms with guaranteed sufficient decrease}, Journal = {ACM Transactions on Mathematical Software (TOMS)}, Volume = {20}, Number = {3}, Year = {1994}, Issn = {0098-3500}, Pages = {286--307}, Doi = {10.1145/192115.192132}, Publisher = {ACM Press} } @InProceedings{Thiebaut-2002-optimization, Title = {Optimization issues in blind deconvolution algorithms}, Author = {{\'E}ric Thiébaut}, Booktitle = {Astronomical Data Analysis {II}}, Year = {2002}, Address = {Bellingham, Washington}, Editor = {Jean-Luc Starck and Fionn D. Murtagh}, Organization = {SPIE}, Pages = {174--183}, Volume = {4847}, Bibcode = {2002SPIE.4847..174T}, Doi = {10.1117/12.461151}, File = {Thiebaut-2002-optim_bdec.pdf:Thiebaut-2002-optim_bdec.pdf:PDF}, Keywords = {large-scale optimization; VMLM-B; VMLMB; blind deconvolution} } OptimPackLegacy-release-1.4.0/src/000077500000000000000000000000001303525653100167405ustar00rootroot00000000000000OptimPackLegacy-release-1.4.0/src/Makefile000066400000000000000000000044321303525653100204030ustar00rootroot00000000000000# # Makefile -- # # Makefile for OptimPackLegacy. # #------------------------------------------------------------------------------ # # Copyright (c) 2003, 2016 Éric Thiébaut. # # This file is part of OptimPack . # # OptimPack 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. # # OptimPack 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 OptimPack (file "LICENSE" in the top source directory); if not, # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA # #------------------------------------------------------------------------------ srcdir = . PREFIX = DESTDIR = INSTALL = cp -p CC = gcc -pipe #CPPFLAGS = -I. -DOP_INTEGER=long -DOP_LOGICAL=int CPPFLAGS = -I. CFLAGS = -O2 -Wall RM = rm -f AR = ar ARFLAGS = rv LIBNAME = liboptimpacklegacy.a VERSION = `sed < $(srcdir)/../VERSION -e 's/ //g'` OBJS = opl_algebra.o opl_lnsrch.o opl_utils.o opl_vmlmb.o all: $(LIBNAME) install: $(LIBNAME) @version=$(VERSION); \ if test "x$(PREFIX)" = "x"; then \ echo "You must define PREFIX macro, e.g.:"; \ echo " > make PREFIX=/usr/local install"; \ else \ test -d "$(PREFIX)/lib" || mkdir -p "$(PREFIX)/lib"; \ $(INSTALL) $(LIBNAME) "$(PREFIX)/lib/."; \ test -d "$(PREFIX)/include" || mkdir -p "$(PREFIX)/include"; \ $(INSTALL) optimpacklegacy.h "$(PREFIX)/include/."; \ test -d "$(PREFIX)/doc/OptimPack-$${version}" || \ mkdir -p "$(PREFIX)/doc/OptimPack-$${version}"; \ $(INSTALL) $(srcdir)/../README.md $(srcdir)/../AUTHORS \ $(srcdir)/../LICENSE $(srcdir)/optimpacklegacy.h \ "$(PREFIX)/doc/OptimPack-$${version}/."; \ fi clean: $(RM) *~ $(OBJS) $(LIBNAME) distclean: clean $(LIBNAME): $(OBJS) $(RM) $(LIBNAME) $(AR) $(ARFLAGS) $(LIBNAME) $(OBJS) %.o: %.c opl_private.h optimpacklegacy.h $(CC) $(CFLAGS) $(CPPFLAGS) -c $(@:.o=.c) -o $@ OptimPackLegacy-release-1.4.0/src/opl_algebra.c000066400000000000000000000205031303525653100213530ustar00rootroot00000000000000/* * opl_algebra.c -- * * Basic linear algebra routines for OptimPackLegacy library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #include #include #include "opl_private.h" /*---------------------------------------------------------------------------*/ /* APPLY BOUND CONSTRAINTS */ #define ISFREE_LO_GRD(x, lo, g) ((x) > (lo) || (g) < zero) #define ISFREE_HI_GRD(x, hi, g) ((x) < (hi) || (g) > zero) #define ISFREE_LO_DIR(x, lo, d) ((x) > (lo) || (d) > zero) #define ISFREE_HI_DIR(x, hi, d) ((x) < (hi) || (d) < zero) opl_integer_t opl_bounds_check(opl_integer_t n, const double xmin[], const double xmax[]) { opl_integer_t i; if (xmin && xmax) { for (i = 0; i < n; ++i) { if (xmin[i] > xmax[i]) { return i; } } } return -1; } void opl_bounds_apply(opl_integer_t n, double x[], const double xmin[], const double xmax[]) { opl_integer_t i; if (xmin) { if (xmax) { /* Lower _and_ upper bounds. */ for (i = 0; i < n; ++i) { if (x[i] < xmin[i]) { x[i] = xmin[i]; } if (x[i] > xmax[i]) { x[i] = xmax[i]; } } } else { /* Only lower bounds. */ for (i = 0; i < n; ++i) { if (x[i] < xmin[i]) { x[i] = xmin[i]; } } } } else if (xmax) { /* Only upper bounds. */ for (i = 0; i < n; ++i) { if (x[i] > xmax[i]) { x[i] = xmax[i]; } } } } void opl_bounds_free(opl_integer_t n, opl_logical_t isfree[], const double x[], const double g[], const double xmin[], const double xmax[]) { const double zero = 0.0; opl_integer_t i; if (xmin) { if (xmax) { /* Lower _and_ upper bounds. */ for (i = 0; i < n; ++i) { isfree[i] = (ISFREE_LO_GRD(x[i], xmin[i], g[i]) && ISFREE_HI_GRD(x[i], xmax[i], g[i])); } } else { /* Only lower bounds. */ for (i = 0; i < n; ++i) { isfree[i] = ISFREE_LO_GRD(x[i], xmin[i], g[i]); } } } else if (xmax) { /* Only upper bounds. */ for (i = 0; i < n; ++i) { isfree[i] = ISFREE_HI_GRD(x[i], xmax[i], g[i]); } } } void opl_lower_bound_apply(opl_integer_t n, double x[], double xmin) { opl_integer_t i; for (i = 0; i < n; ++i) { if (x[i] < xmin) { x[i] = xmin; } } } void opl_lower_bound_free(opl_integer_t n, opl_logical_t isfree[], const double x[], const double g[], double xmin) { const double zero = 0.0; opl_integer_t i; for (i = 0; i < n; ++i) { isfree[i] = ISFREE_LO_GRD(x[i], xmin, g[i]); } } void opl_upper_bound_apply(opl_integer_t n, double x[], double xmax) { opl_integer_t i; for (i = 0; i < n; ++i) { if (x[i] > xmax) { x[i] = xmax; } } } void opl_upper_bound_free(opl_integer_t n, opl_logical_t isfree[], const double x[], const double g[], double xmax) { const double zero = 0.0; opl_integer_t i; for (i = 0; i < n; ++i) { isfree[i] = ISFREE_HI_GRD(x[i], xmax, g[i]); } } void opl_interval_apply(opl_integer_t n, double x[], double a, double b) { opl_integer_t i; if (a > b) { double c = a; a = b; b = c; } for (i = 0; i < n; ++i) { if (x[i] < a) x[i] = a; if (x[i] > b) x[i] = b; } } void opl_interval_free(opl_integer_t n, opl_logical_t isfree[], const double x[], const double g[], double a, double b) { const double zero = 0.0; opl_integer_t i; if (a > b) { double c=a; a=b; b=c; } for (i = 0; i < n; ++i) { isfree[i] = (ISFREE_LO_GRD(x[i], a, g[i]) && ISFREE_HI_GRD(x[i], b, g[i])); } } /*---------------------------------------------------------------------------*/ /* VARIANTS OF LEVEL 1 BLAS ROUTINES */ double opl_dnrm2(opl_integer_t n, const double x[]) { const double one = 1.0, zero = 0.0; if (n > 1) { opl_integer_t i; double ssq = zero, scale = zero; for (i = 0; i < n; ++i) { if (x[i]) { double absxi = fabs(x[i]); if (scale < absxi) { double tmp = scale/absxi; ssq = one + ssq*tmp*tmp; scale = absxi; } else { double tmp = absxi/scale; ssq += tmp*tmp; } } } return scale*sqrt(ssq); } else if (n == 1) { return fabs(x[0]); } return zero; } void opl_dscal(opl_integer_t n, double a, double x[]) { opl_integer_t i; if (a == 0.0) { memset(x, 0, n*sizeof(double)); } else if (a == -1.0) { for (i = 0; i < n; ++i) { x[i] -= x[i]; } } else if (a != 1.0) { for (i = 0; i < n; ++i) { x[i] *= a; } } } void opl_dcopy(opl_integer_t n, const double x[], double y[]) { memcpy(y, x, n*sizeof(double)); } void opl_dcopy_free(opl_integer_t n, const double x[], double y[], const opl_logical_t isfree[]) { if (isfree != NULL) { const double zero = 0.0; opl_integer_t i; for (i = 0; i < n; ++i) { y[i] = (isfree[i] ? x[i] : zero); } } else { memcpy(y, x, n*sizeof(double)); } } void opl_daxpy(opl_integer_t n, double a, const double x[], double y[]) { opl_integer_t i; if (a == 1.0) { for (i = 0; i < n; ++i) { y[i] += x[i]; } } else if (a == -1.0) { for (i = 0; i < n; ++i) { y[i] -= x[i]; } } else if (a != 0.0) { for (i = 0; i < n; ++i) { y[i] += a*x[i]; } } } void opl_daxpy_free(opl_integer_t n, double a, const double x[], double y[], const opl_logical_t isfree[]) { opl_integer_t i; if (isfree != NULL) { if (a == 1.0) { for (i = 0; i < n; ++i) { if (isfree[i]) { y[i] += x[i]; } } } else if (a == -1.0) { for (i = 0; i < n; ++i) { if (isfree[i]) { y[i] -= x[i]; } } } else if (a != 0.0) { for (i = 0; i < n; ++i) { if (isfree[i]) { y[i] += a*x[i]; } } } } else { if (a == 1.0) { for (i = 0; i < n; ++i) { y[i] += x[i]; } } else if (a == -1.0) { for (i = 0; i < n; ++i) { y[i] -= x[i]; } } else if (a != 0.0) { for (i = 0; i < n; ++i) { y[i] += a*x[i]; } } } } double opl_ddot(opl_integer_t n, const double x[], const double y[]) { opl_integer_t i; double s = 0.0; for (i = 0; i < n; ++i) { s += x[i]*y[i]; } return s; } double opl_ddot_free(opl_integer_t n, const double x[], const double y[], const opl_logical_t isfree[]) { opl_integer_t i; double s = 0.0; if (isfree != NULL) { for (i = 0; i < n; ++i) { if (isfree[i]) { s += x[i]*y[i]; } } } else { for (i = 0; i < n; ++i) { s += x[i]*y[i]; } } return s; } /*---------------------------------------------------------------------------*/ /* YORICK-LIKE ROUTINES */ int opl_anyof(opl_integer_t n, const double x[]) { opl_integer_t i; for (i = 0; i < n; ++i) { if (x[i]) { return 1; } } return 0; } int opl_noneof(opl_integer_t n, const double x[]) { opl_integer_t i; for (i = 0; i < n; ++i) { if (x[i]) { return 0; } } return 1; } int opl_allof(opl_integer_t n, const double x[]) { opl_integer_t i; for (i = 0; i < n; ++i) { if (! x[i]) { return 0; } } return 1; } /*---------------------------------------------------------------------------*/ OptimPackLegacy-release-1.4.0/src/opl_limits.h000066400000000000000000000106751303525653100212750ustar00rootroot00000000000000/* * opl_limits.h -- * * Definitions to guess sizes of integers on this machine. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #ifndef _OPL_LIMITS_H #define _OPL_LIMITS_H 1 #include #define OPL_INT16_MIN (-32768) #define OPL_INT16_MAX 32767 #define OPL_UINT16_MAX 65535 #define OPL_INT32_MIN (-2147483648L) #define OPL_INT32_MAX 2147483647L #define OPL_UINT32_MAX 4294967295U #define OPL_INT64_MIN (-9223372036854775808L) #define OPL_INT64_MAX 9223372036854775807L #define OPL_UINT64_MAX 18446744073709551615UL #if ! defined (OPL_SHRT_BITS) && defined(USHRT_MAX) # if (USHRT_MAX == OPL_UINT16_MAX) # define OPL_SHRT_BITS 16 # else # if (USHRT_MAX == OPL_UINT32_MAX) # define OPL_SHRT_BITS 32 # else # if (USHRT_MAX == OPL_UINT64_MAX) # define OPL_SHRT_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_SHRT_BITS) && defined(SHRT_MIN) && defined(SHRT_MAX) # if (SHRT_MIN == OPL_INT16_MIN) && SHRT_MAX == OPL_INT16_MAX) # define OPL_SHRT_BITS 16 # else # if (SHRT_MIN == OPL_INT32_MIN) && SHRT_MAX == OPL_INT32_MAX) # define OPL_SHRT_BITS 32 # else # if (SHRT_MIN == OPL_INT64_MIN) && SHRT_MAX == OPL_INT64_MAX) # define OPL_SHRT_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_INT_BITS) && defined(UINT_MAX) # if (UINT_MAX == OPL_UINT16_MAX) # define OPL_INT_BITS 16 # else # if (UINT_MAX == OPL_UINT32_MAX) # define OPL_INT_BITS 32 # else # if (UINT_MAX == OPL_UINT64_MAX) # define OPL_INT_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_INT_BITS) && defined(INT_MIN) && defined(INT_MAX) # if (INT_MIN == OPL_INT16_MIN) && (INT_MAX == OPL_INT16_MAX) # define OPL_INT_BITS 16 # else # if (INT_MIN == OPL_INT32_MIN) && (INT_MAX == OPL_INT32_MAX) # define OPL_INT_BITS 32 # else # if (INT_MIN == OPL_INT64_MIN) && (INT_MAX == OPL_INT64_MAX) # define OPL_INT_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_LONG_BITS) && defined(ULONG_MAX) # if (ULONG_MAX == OPL_UINT16_MAX) # define OPL_LONG_BITS 16 # else # if (ULONG_MAX == OPL_UINT32_MAX) # define OPL_LONG_BITS 32 # else # if (ULONG_MAX == OPL_UINT64_MAX) # define OPL_LONG_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_LONG_BITS) && defined(LONG_MIN) && defined(LONG_MAX) # if (LONG_MIN == OPL_INT16_MIN) && (LONG_MAX == OPL_INT16_MAX) # define OPL_LONG_BITS 16 # else # if (LONG_MIN == OPL_INT32_MIN) && (LONG_MAX == OPL_INT32_MAX) # define OPL_LONG_BITS 32 # else # if (LONG_MIN == OPL_INT64_MIN) && (LONG_MAX == OPL_INT64_MAX) # define OPL_LONG_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_LLONG_BITS) && defined(ULLONG_MAX) # if (ULLONG_MAX == OPL_UINT16_MAX) # define OPL_LLONG_BITS 16 # else # if (ULLONG_MAX == OPL_UINT32_MAX) # define OPL_LLONG_BITS 32 # else # if (ULLONG_MAX == OPL_UINT64_MAX) # define OPL_LLONG_BITS 64 # endif # endif # endif #endif #if ! defined (OPL_LLONG_BITS) && defined(LLONG_MIN) && defined(LLONG_MAX) # if (LLONG_MIN == OPL_INT16_MIN) && (LLONG_MAX == OPL_INT16_MAX) # define OPL_LLONG_BITS 16 # else # if (LLONG_MIN == OPL_INT32_MIN) && (LLONG_MAX == OPL_INT32_MAX) # define OPL_LLONG_BITS 32 # else # if (LLONG_MIN == OPL_INT64_MIN) && (LLONG_MAX == OPL_INT64_MAX) # define OPL_LLONG_BITS 64 # endif # endif # endif #endif /*---------------------------------------------------------------------------*/ #endif /* _OPL_LIMITS_H */ OptimPackLegacy-release-1.4.0/src/opl_lnsrch.c000066400000000000000000000360641303525653100212600ustar00rootroot00000000000000/* * opl_lnsrch.c -- * * Line search routines for OptimPackLegacy library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #include #include #include #include #include "opl_private.h" /* Constants. */ static const double zero = 0.0; static const double xtrapl = 1.1; static const double xtrapu = 4.0; /*---------------------------------------------------------------------------*/ const size_t OPL_CSRCH_WORKSPACE_SIZE = OPL_ROUND_UP(sizeof(opl_csrch_workspace_t), sizeof(double)); size_t opl_csrch_get_workspace_size() { return OPL_CSRCH_WORKSPACE_SIZE; } opl_csrch_workspace_t* opl_csrch_create_workspace() { opl_csrch_workspace_t* ws = OPL_NEW(opl_csrch_workspace_t, 1); if (ws != NULL) { memset(ws, 0, sizeof(opl_csrch_workspace_t)); opl_initialize_context(&ws->context); } return ws; } void opl_csrch_destroy_workspace(opl_csrch_workspace_t* ws) { if (ws != NULL) { free((void*)ws); } } opl_task_t opl_csrch_get_task(opl_csrch_workspace_t* ws) { return (ws != NULL ? ws->task : OPL_TASK_ERROR); } opl_task_t opl_csrch_get_status(opl_csrch_workspace_t* ws) { return (ws != NULL ? ws->context.status : OPL_ILLEGAL_ADDRESS); } const char* opl_csrch_get_reason(opl_csrch_workspace_t* ws) { return (ws != NULL ? ws->context.message : "illegal workspace address"); } static opl_status_t report(opl_csrch_workspace_t* ws, opl_task_t task, opl_status_t status, const char* mesg) { ws->task = task; return opl_set_context((opl_context_t*)ws, status, mesg, OPL_PERMANENT); } opl_status_t opl_csrch_start(opl_csrch_workspace_t* ws, double f, double g, double stp, double ftol, double gtol, double xtol, double stpmin, double stpmax) { /* Minimal checking. */ if (ws == NULL) { errno = EFAULT; return OPL_ILLEGAL_ADDRESS; } /* Check the input arguments for errors. Exit if there are errors on input. */ #define ERROR(I,S) report(ws, OPL_TASK_ERROR, I, "opl_csrch_start: " S) if (stpmax < stpmin) { return ERROR(OPL_STPMAX_LT_STPMIN, "STPMAX < STPMIN"); } if (stpmin < zero) { return ERROR(OPL_STPMIN_LT_ZERO, "STPMIN < 0"); } if (xtol < zero) { return ERROR(OPL_XTOL_LT_ZERO, "XTOL < 0"); } if (ftol <= zero) { return ERROR(OPL_FTOL_LE_ZERO, "FTOL <= 0"); } if (gtol <= zero) { return ERROR(OPL_GTOL_LE_ZERO, "GTOL <= 0"); } if (g >= zero) { return ERROR(OPL_NOT_A_DESCENT, "initial G >= 0"); } if (stp > stpmax) { return ERROR(OPL_STP_GT_STPMAX, "STP > STPMAX"); } if (stp < stpmin) { return ERROR(OPL_STP_LT_STPMIN, "STP < STPMIN"); } #undef ERROR /* Initialize local variables. The variables STX, FX, GX contain the values of the step, function, and derivative at the best step. The variables STY, FY, GY contain the value of the step, function, and derivative at STY. The variables STP, F, G contain the values of the step, function, and derivative at STP. */ ws->ftol = ftol; ws->gtol = gtol; ws->xtol = xtol; ws->stpmin = stpmin; ws->stpmax = stpmax; ws->finit = f; ws->ginit = g; ws->stx = zero; ws->fx = f; ws->gx = g; ws->sty = zero; ws->fy = f; ws->gy = g; ws->stmin = zero; ws->stmax = stp + stp*xtrapu; ws->width = stpmax - stpmin; ws->width1 = 2.0*(stpmax - stpmin); ws->brackt = 0; ws->stage = 1; ws->task = OPL_TASK_FG; return opl_success((opl_context_t*)ws); } opl_status_t opl_csrch_iterate(opl_csrch_workspace_t* ws, double f, double g, double *stp_ptr) { /* Define macros to make the code simpler and easier to read. */ # define ftol (ws->ftol) # define gtol (ws->gtol) # define xtol (ws->xtol) # define stpmin (ws->stpmin) # define stpmax (ws->stpmax) # define finit (ws->finit) # define ginit (ws->ginit) # define stx (ws->stx) # define fx (ws->fx) # define gx (ws->gx) # define sty (ws->sty) # define fy (ws->fy) # define gy (ws->gy) # define stmin (ws->stmin) # define stmax (ws->stmax) # define width (ws->width) # define width1 (ws->width1) # define task (ws->task) # define stage (ws->stage) # define brackt (ws->brackt) /* Local variables. */ double ftest, gtest, stp; opl_status_t status; /* Minimal checking. */ if (ws == NULL) { errno = EFAULT; return OPL_ILLEGAL_ADDRESS; } /* Initialize local variables. */ stp = *stp_ptr; /* If psi(stp) <= 0 and f'(stp) >= 0 for some step, then the algorithm enters the second stage. */ gtest = ftol*ginit; ftest = finit + stp*gtest; if (stage == 1 && f <= ftest && g >= zero) { stage = 2; } /* Test for termination: convergence or warnings. */ if (f <= ftest && fabs(g) <= gtol*(-ginit)) { return report(ws, OPL_TASK_CONV, OPL_SUCCESS, "strong Wolfe conditions both satisfied"); } if (stp == stpmin && (f > ftest || g >= gtest)) { return report(ws, OPL_TASK_WARN, OPL_STP_EQ_STPMIN, "step at lower bound"); } if (stp == stpmax && f <= ftest && g <= gtest) { return report(ws, OPL_TASK_WARN, OPL_STP_EQ_STPMAX, "step at upper bound"); } if (brackt && stmax - stmin <= xtol*stmax) { return report(ws, OPL_TASK_WARN, OPL_XTOL_TEST_SATISFIED, "XTOL test satisfied"); } if (brackt && (stp <= stmin || stp >= stmax)) { return report(ws, OPL_TASK_WARN, OPL_ROUNDING_ERROR, "rounding errors prevent progress"); } /* A modified function is used to predict the step during the first stage if a lower function value has been obtained but the decrease is not sufficient. */ if (stage == 1 && f <= fx && f > ftest) { /* Define the modified function and derivative values. */ double fm = f - stp*gtest; double fxm = fx - stx*gtest; double fym = fy - sty*gtest; double gm = g - gtest; double gxm = gx - gtest; double gym = gy - gtest; /* Call opl_cstep to update STX, STY, and to compute the new step. */ status = opl_cstep((opl_context_t*)ws, &brackt, stmin, stmax, &stx, &fxm, &gxm, &sty, &fym, &gym, &stp, fm, gm); if (status != OPL_SUCCESS) { task = OPL_TASK_ERROR; return status; } /* Reset the function and derivative values for F. */ fx = fxm + stx*gtest; fy = fym + sty*gtest; gx = gxm + gtest; gy = gym + gtest; } else { /* Call opl_cstep to update STX, STY, and to compute the new step. */ status = opl_cstep((opl_context_t*)ws, &brackt, stmin, stmax, &stx, &fx, &gx, &sty, &fy, &gy, &stp, f, g); if (status != OPL_SUCCESS) { task = OPL_TASK_ERROR; return status; } } /* Decide if a bisection step is needed. */ if (brackt) { double wcur = fabs(sty - stx); if (wcur >= 0.66*width1) stp = stx + 0.5*(sty - stx); width1 = width; width = wcur; } /* Set the minimum and maximum steps allowed for STP. */ if (brackt) { if (stx <= sty) { stmin = stx; stmax = sty; } else { stmin = sty; stmax = stx; } } else { stmin = stp + xtrapl*(stp - stx); stmax = stp + xtrapu*(stp - stx); } /* Force the step to be within the bounds STPMAX and STPMIN. */ if (stp > stpmax) stp = stpmax; if (stp < stpmin) stp = stpmin; /* If further progress is not possible, let STP be the best point obtained during the search. */ if (brackt && (stp <= stmin || stp >= stmax || stmax - stmin <= xtol*stmax)) { stp = stx; } /* Save local variables. */ *stp_ptr = stp; /* Obtain another function and derivative. */ return report(ws, OPL_TASK_FG, OPL_SUCCESS, "compute f(x) and g(x)"); /* Undefine macros. */ # undef ftol # undef gtol # undef xtol # undef stpmin # undef stpmax # undef finit # undef ginit # undef stx # undef fx # undef gx # undef sty # undef fy # undef gy # undef stmin # undef stmax # undef width # undef width1 # undef task # undef stage # undef brackt } /*---------------------------------------------------------------------------*/ /* SAFEGUARDED CUBIC STEP */ opl_status_t opl_cstep(opl_context_t* ctx, opl_boolean_t *brackt, double stpmin, double stpmax, double *stx_ptr, double *fx_ptr, double *dx_ptr, double *sty_ptr, double *fy_ptr, double *dy_ptr, double *stp_ptr, double fp, double dp) { /* Get values of input/output variables. */ double stx = *stx_ptr, fx = *fx_ptr, dx = *dx_ptr; double sty = *sty_ptr, fy = *fy_ptr, dy = *dy_ptr; double stp = *stp_ptr; /* Local variables. */ double gamma, theta, p, q, r, s, t; double stpc; /* cubic step */ double stpq; /* quadratic step */ double sgnd, stpf; /* Check the input parameters for errors. */ # define REPORT(status, mesg) opl_set_context(ctx, status, \ "opl_cstep: " mesg, \ OPL_PERMANENT) if (*brackt && (stx < sty ? (stp <= stx || stp >= sty) : (stp >= stx || stp <= sty))) { return REPORT(OPL_OUT_OF_BOUNDS, "STP outside bracket (STX,STY)"); } else if (dx*(stp - stx) >= zero) { return REPORT(OPL_NOT_A_DESCENT, "descent condition violated"); } else if (stpmax < stpmin) { return REPORT(OPL_STPMAX_LT_STPMIN, "STPMAX < STPMIN"); return 0; } # undef REPORT /* Determine if the derivatives have opposite sign. */ sgnd = (dx/fabs(dx))*dp; if (fp > fx) { /* First case. A higher function value. The minimum is bracketed. If the cubic step is closer to STX than the quadratic step, the cubic step is taken, otherwise the average of the cubic and quadratic steps is taken. */ theta = 3.0*(fx - fp)/(stp - stx) + dx + dp; s = fabs(theta); if (s < (t = fabs(dx))) s = t; if (s < (t = fabs(dp))) s = t; t = theta/s; gamma = s*sqrt(t*t - (dx/s)*(dp/s)); if (stp < stx) gamma = -gamma; p = (gamma - dx) + theta; q = ((gamma - dx) + gamma) + dp; r = p/q; stpc = stx + r*(stp - stx); stpq = stx + ((dx/((fx - fp)/(stp - stx) + dx))/2.0)*(stp - stx); if (fabs(stpc - stx) < fabs(stpq - stx)) { stpf = stpc; } else { stpf = stpc + (stpq - stpc)/2.0; } *brackt = 1; } else if (sgnd < zero) { /* Second case. A lower function value and derivatives of opposite sign. The minimum is bracketed. If the cubic step is farther from STP than the secant (quadratic) step, the cubic step is taken, otherwise the secant step is taken. */ theta = 3.0*(fx - fp)/(stp - stx) + dx + dp; s = fabs(theta); if (s < (t = fabs(dx))) s = t; if (s < (t = fabs(dp))) s = t; t = theta/s; gamma = s*sqrt(t*t - (dx/s)*(dp/s)); if (stp > stx) gamma = -gamma; p = (gamma - dp) + theta; q = ((gamma - dp) + gamma) + dx; r = p/q; stpc = stp + r*(stx - stp); stpq = stp + (dp/(dp - dx))*(stx - stp); if (fabs(stpc - stp) > fabs(stpq - stp)) { stpf = stpc; } else { stpf = stpq; } *brackt = 1; } else if (fabs(dp) < fabs(dx)) { /* Third case. A lower function value, derivatives of the same sign, and the magnitude of the derivative decreases. The cubic step is computed only if the cubic tends to infinity in the direction of the step or if the minimum of the cubic is beyond STP. Otherwise the cubic step is defined to be the secant step. */ theta = 3.0*(fx - fp)/(stp - stx) + dx + dp; s = fabs(theta); if (s < (t = fabs(dx))) s = t; if (s < (t = fabs(dp))) s = t; /* The case GAMMA = 0 only arises if the cubic does not tend to infinity in the direction of the step. */ t = theta/s; t = t*t - (dx/s)*(dp/s); gamma = (t > zero ? s*sqrt(t) : zero); if (stp > stx) gamma = -gamma; p = (gamma - dp) + theta; /*q = ((gamma - dp) + gamma) + dx;*/ q = (gamma + (dx - dp)) + gamma; r = p/q; if (r < zero && gamma != zero) { stpc = stp + r*(stx - stp); } else if (stp > stx) { stpc = stpmax; } else { stpc = stpmin; } stpq = stp + (dp/(dp - dx))*(stx - stp); if (*brackt) { /* A minimizer has been bracketed. If the cubic step is closer to STP than the secant step, the cubic step is taken, otherwise the secant step is taken. */ stpf = fabs(stpc - stp) < fabs(stpq - stp) ? stpc : stpq; t = stp + 0.66*(sty - stp); if (stp > stx ? stpf > t : stpf < t) stpf = t; } else { /* A minimizer has not been bracketed. If the cubic step is farther from stp than the secant step, the cubic step is taken, otherwise the secant step is taken. */ stpf = fabs(stpc - stp) > fabs(stpq - stp) ? stpc : stpq; if (stpf > stpmax) stpf = stpmax; if (stpf < stpmin) stpf = stpmin; } } else { /* Fourth case. A lower function value, derivatives of the same sign, and the magnitude of the derivative does not decrease. If the minimum is not bracketed, the step is either STPMIN or STPMAX, otherwise the cubic step is taken. */ if (*brackt) { theta = 3.0*(fp - fy)/(sty - stp) + dy + dp; s = fabs(theta); if (s < (t = fabs(dy))) s = t; if (s < (t = fabs(dp))) s = t; t = theta/s; gamma = s*sqrt(t*t - (dy/s)*(dp/s)); if (stp > sty) gamma = -gamma; p = (gamma - dp) + theta; q = ((gamma - dp) + gamma) + dy; r = p/q; stpc = stp + r*(sty - stp); stpf = stpc; } else if (stp > stx) { stpf = stpmax; } else { stpf = stpmin; } } /* Update the interval which contains a minimizer and guess for next step. */ if (fp > fx) { *sty_ptr = stp; *fy_ptr = fp; *dy_ptr = dp; } else { if (sgnd < zero) { *sty_ptr = stx; *fy_ptr = fx; *dy_ptr = dx; } *stx_ptr = stp; *fx_ptr = fp; *dx_ptr = dp; } *stp_ptr = stpf; return opl_success(ctx); } /*---------------------------------------------------------------------------*/ OptimPackLegacy-release-1.4.0/src/opl_private.h000066400000000000000000000111741303525653100214410ustar00rootroot00000000000000/* * opl_private.h -- * * Private definitions for optimization routines implemented in Optimpacklegacy * library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #ifndef _OPL_PRIVATE_H #define _OPL_PRIVATE_H 1 #include "optimpacklegacy.h" /*---------------------------------------------------------------------------*/ /* USEFUL MACROS */ #ifndef _OPL_FORCE_INLINE # if defined(_MSC_VER) /* Microsoft Visual Studio */ # define _OPL_FORCE_INLINE __forceinline # elif defined(__GNUC__) /* GNU Compiler */ # define _OPL_FORCE_INLINE inline __attribute__((always_inline)) # elif defined( __cplusplus) /* C++ Compiler */ # define _OPL_FORCE_INLINE inline # endif #endif /* OPL_STRINGIFY takes an argument and wraps it in "" (double quotation marks), OPL_CONCAT concatenates two arguments. */ #ifdef __STDC__ # define OPL_STRINGIFY(x) #x # define OPL_CONCAT(a,b) a##b # define OPL_CONCAT2(a,b) a##b # define OPL_CONCAT3(a,b,c) a##b##c # define OPL_CONCAT4(a,b,c,d) a##b##c##d #else # define OPL_STRINGIFY(x) "x" # define OPL_CONCAT(a,b) a/**/b # define OPL_CONCAT2(a,b) a/**/b # define OPL_CONCAT3(a,b,c) a/**/b/**/c # define OPL_CONCAT4(a,b,c,d) a/**/b/**/c/**/d #endif /* Computes absolute value: */ #define OPL_ABS(a) ((a)>=0?(a):-(a)) /* Computes min/max values: */ #define OPL_MIN(a,b) ((a)<=(b)?(a):(b)) #define OPL_MAX(a,b) ((a)>=(b)?(a):(b)) /* Computes minimal number of chunks with M elements needed to store N elements: */ #define OPL_HOW_MANY(n, m) (((n)+((m)-1))/(m)) /* Returns N elements rounding up to a multiple of M elements: */ #define OPL_ROUND_UP(n, m) (OPL_HOW_MANY(n, m)*(m)) /* Offset (in bytes) of member M in structure S: */ #define OPL_OFFSET_OF(s, m) ((size_t) &((s *)0)->m) /* Allocate memory for a given number of elements of a given type. */ #define OPL_NEW(type, number) (type*)malloc((number)*sizeof(type)) /*---------------------------------------------------------------------------*/ /* STRUCTURES */ /** * The context structure. */ struct _opl_context { const char* message; /* Current message. */ opl_status_t status; /* Status code. */ int syserr; /* Value of `errno` if status is `OPL_SYSTEM_ERROR` */ char buffer[128]; /* Internal buffer */ }; /** Global message for successful operation. */ extern const char* _opl_success_message; /** * Set a context with a permanent message. */ #define _OPL_SET_CONTEXT(ctx, stat, mesg) \ ((ctx)->message = (mesg), (ctx)->status = stat) #ifdef _OPL_FORCE_INLINE opl_status_t _OPL_FORCE_INLINE _opl_success(opl_context_t* ctx) { return _OPL_SET_CONTEXT(ctx, OPL_SUCCESS, _opl_success_message); } #endif /** * Workspace data used for Moré & Thuente line search. */ struct _opl_csrch_workspace { opl_context_t context; double ftol, gtol, xtol; double stpmin, stpmax; double finit; double ginit; double stx, fx, gx; double sty, fy, gy; double stmin, stmax; double width, width1; opl_task_t task; int stage; opl_boolean_t brackt; }; /** * The workspace for VMLMB. */ struct _opl_vmlmb_workspace { opl_csrch_workspace_t lnsrch; opl_integer_t n; opl_integer_t m; opl_integer_t mp; opl_integer_t mark; opl_integer_t evaluations; opl_integer_t iterations; opl_integer_t restarts; unsigned int flags; void (*free)(void*); double frtol; double fatol; double fmin; double f0; double gd; double g0d; double stp; double delta; double epsilon; double gnorm; double g0norm; double* alpha; double* rho; double* d; double** S; double** Y; }; #endif /* _OPL_PRIVATE_H */ OptimPackLegacy-release-1.4.0/src/opl_utils.c000066400000000000000000000152251303525653100211230ustar00rootroot00000000000000/* * opl_utils.c -- * * Utilities routines for OptimPackLegacy library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #include #include #include #include #include "opl_private.h" /*---------------------------------------------------------------------------*/ /* CONTEXT MANAGEMENT AND ERROR REPORTING */ const char* _opl_success_message = "Successful operation"; static const char* _opl_insufficient_memory_message = "Insufficient memory"; static const char* _opl_illegal_address_message = "Illegal address"; static const char* _opl_invalid_argument_message = "Invalid argument"; static const char* _opl_out_of_bounds_message = "Out of bounds size or index"; static const char* _opl_corrupted_message = "Corrupted data"; static const char* _opl_overflow_message = "Numerical overflow"; #if 0 static const char* _opl_syntax_error_message = "Syntax error"; static const char* _opl_open_error_message = "Cannot open file"; static const char* _opl_close_error_message = "Error while closing file"; static const char* _opl_read_error_message = "Read error"; static const char* _opl_write_error_message = "Write error"; static const char* _opl_stat_error_message = "Cannot stat file"; static const char* _opl_file_exists_message = "File already exists"; static const char* _opl_zip_error_message = "Error with PkZip archive"; #endif extern void opl_initialize_context(opl_context_t* ctx) { ctx->message = _opl_success_message; ctx->status = OPL_SUCCESS; ctx->syserr = 0; } #define DEFINE_FUNCTION(name, NAME) \ opl_status_t \ opl_##name(opl_context_t* ctx) \ { \ return _OPL_SET_CONTEXT(ctx, OPL_##NAME, _opl_##name##_message); \ } DEFINE_FUNCTION(success, SUCCESS) DEFINE_FUNCTION(insufficient_memory, INSUFFICIENT_MEMORY) DEFINE_FUNCTION(illegal_address, ILLEGAL_ADDRESS) DEFINE_FUNCTION(invalid_argument, INVALID_ARGUMENT) DEFINE_FUNCTION(out_of_bounds, OUT_OF_BOUNDS) DEFINE_FUNCTION(corrupted, CORRUPTED) DEFINE_FUNCTION(overflow, OVERFLOW) #if 0 DEFINE_FUNCTION(syntax_error, SYNTAX_ERROR) DEFINE_FUNCTION(open_error, OPEN_ERROR) DEFINE_FUNCTION(close_error, CLOSE_ERROR) DEFINE_FUNCTION(read_error, READ_ERROR) DEFINE_FUNCTION(write_error, WRITE_ERROR) DEFINE_FUNCTION(stat_error, STAT_ERROR) DEFINE_FUNCTION(file_exists, FILE_EXISTS) DEFINE_FUNCTION(zip_error, ZIP_ERROR) #endif #undef DEFINE_FUNCTION opl_status_t opl_system_error(opl_context_t* ctx) { int syserr = errno; ctx->syserr = syserr; ctx->message = strerror(syserr); return (ctx->status = OPL_SYSTEM_ERROR); } opl_status_t opl_get_status(opl_context_t* ctx) { return ctx->status; } int opl_get_errno(opl_context_t* ctx) { return (ctx->status == OPL_SYSTEM_ERROR ? ctx->syserr : 0); } const char* opl_get_message(opl_context_t* ctx) { return ctx->message; } #define TRUNCATE(str, siz) \ (str)[(siz) - 6] = '['; \ (str)[(siz) - 5] = '.'; \ (str)[(siz) - 4] = '.'; \ (str)[(siz) - 3] = '.'; \ (str)[(siz) - 2] = ']'; \ (str)[(siz) - 1] = '\0' opl_status_t opl_set_context(opl_context_t* ctx, opl_status_t status, const char* message, opl_storage_type_t type) { if (type == OPL_PERMANENT) { ctx->message = message; } else { size_t size = sizeof(ctx->buffer); size_t nchars = (message == NULL ? 0 : strlen(message)); if (nchars <= 0) { ctx->buffer[0] = '\0'; } else if (nchars < size) { memcpy(ctx->buffer, message, nchars + 1); } else { memcpy(ctx->buffer, message, size); TRUNCATE(ctx->buffer, size); } ctx->message = ctx->buffer; } ctx->syserr = (status == OPL_SYSTEM_ERROR ? errno : 0); return (ctx->status = status); } opl_status_t opl_format_context(opl_context_t* ctx, opl_status_t status, const char* format, ...) { const size_t size = sizeof(ctx->buffer); va_list ap; size_t nchars; va_start(ap, format); nchars = vsnprintf(ctx->buffer, size, format, ap); va_end(ap); if (nchars >= size) { TRUNCATE(ctx->buffer, size); } ctx->message = ctx->buffer; ctx->syserr = (status == OPL_SYSTEM_ERROR ? errno : 0); return (ctx->status = status); } const char* opl_get_default_message(opl_status_t status) { switch(status) { case OPL_SUCCESS: return _opl_success_message; case OPL_INSUFFICIENT_MEMORY: return _opl_insufficient_memory_message; case OPL_ILLEGAL_ADDRESS: return _opl_illegal_address_message; case OPL_INVALID_ARGUMENT: return _opl_invalid_argument_message; case OPL_OUT_OF_BOUNDS: return _opl_out_of_bounds_message; case OPL_CORRUPTED: return _opl_corrupted_message; case OPL_OVERFLOW: return _opl_overflow_message; #if 0 case OPL_SYNTAX_ERROR: return _opl_syntax_error_message; case OPL_OPEN_ERROR: return _opl_open_error_message; case OPL_CLOSE_ERROR: return _opl_close_error_message; case OPL_READ_ERROR: return _opl_read_error_message; case OPL_WRITE_ERROR: return _opl_write_error_message; case OPL_STAT_ERROR: return _opl_stat_error_message; case OPL_FILE_EXISTS: return _opl_file_exists_message; case OPL_ZIP_ERROR: return _opl_zip_error_message; #endif default: return "Unknown status"; } } /*---------------------------------------------------------------------------*/ OptimPackLegacy-release-1.4.0/src/opl_vmlmb.c000066400000000000000000000572051303525653100211040ustar00rootroot00000000000000/* * opl_vmlmb.c -- * * Variable Metric Limited Memory with Bound constraints for OptimPackLegacy * library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003-2009, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #include #include #include #include #include #include #include "opl_private.h" typedef unsigned char byte_t; /* * Some constants. * * Ssee http://stackoverflow.com/questions/1923837/how-to-use-nan-and-inf-in-c * for a discussion about how to define NaN and infinite. Alternatives for Inf * and NaN: * * double NaN = strtod("NaN", NULL); * double Inf = strtod("Inf", NULL); * * but cannot be constants then. Some macros may be defined in (as * part of C99 standard): * * #include * #ifdef NAN * const double NaN = NAN; * #end * #ifdef INFINITY * const double Inf = INFINITY; * #end */ static const double zero = 0.0; static const double one = 1.0; static const double NaN = 0.0/0.0; static const double Inf = 1.0/0.0; /* Default settings. */ #define DEFAULT_STPMAX 1e20 #define DEFAULT_SFTOL 0.001 #define DEFAULT_SGTOL 0.9 #define DEFAULT_SXTOL 0.1 #define DEFAULT_FATOL 0.0 #define DEFAULT_FRTOL 1e-10 #define DEFAULT_DELTA 1e-3 #define DEFAULT_EPSILON 0.0 #define FLAG_FMIN (1 << 0) /* `task`, `context` and some other members are shared with the embedded line search structure. */ #define TASK(ws) (ws)->lnsrch.task #define CONTEXT(ws) (ws)->lnsrch.context #define STATUS(ws) (ws)->lnsrch.context.status #define SXTOL(ws) (ws)->lnsrch.xtol #define SFTOL(ws) (ws)->lnsrch.ftol #define SGTOL(ws) (ws)->lnsrch.gtol #define SXTOL(ws) (ws)->lnsrch.xtol #define STPMIN(ws) (ws)->lnsrch.stpmin #define STPMAX(ws) (ws)->lnsrch.stpmax /* Allocate an array of given type and size. */ #define NEW(type, number) ((type*)malloc((number)*sizeof(type))) /*---------------------------------------------------------------------------*/ /* PRIVATE FUNCTIONS */ static double min(double a, double b) { return (a <= b ? a : b); } static double max(double a, double b) { return (a >= b ? a : b); } /* Apply L-BFGS recursion to compute search direction. */ static void compute_direction(opl_vmlmb_workspace_t* ws, double d[], const opl_logical_t isfree[], const double h[]); /* Compute next step and set task. */ static opl_task_t next_step(opl_vmlmb_workspace_t* ws, double x[]); /* Check H and ISFREE arrays, possibly fix ISFREE, returns non-zero in case of error. */ static int check_free(opl_vmlmb_workspace_t* ws, opl_logical_t isfree[], const double h[]); /* Report a failure. */ static opl_task_t failure(opl_vmlmb_workspace_t* ws, opl_status_t status, const char* mesg) { opl_set_context(&CONTEXT(ws), status, mesg, OPL_PERMANENT); return (TASK(ws) = OPL_TASK_ERROR); } /* Report a success. */ static opl_task_t success(opl_vmlmb_workspace_t* ws, opl_task_t task, const char* mesg) { opl_set_context(&CONTEXT(ws), OPL_SUCCESS, mesg, OPL_PERMANENT); return (TASK(ws) = task); } /*---------------------------------------------------------------------------*/ #define GET_MEMBER(type, name, rvalue, invalid) \ type \ opl_vmlmb_get_##name(opl_vmlmb_workspace_t* ws) \ { \ if (ws == NULL) { \ errno = EFAULT; \ return invalid; \ } \ return rvalue; \ } GET_MEMBER(double, fmin, ws->fmin, NaN); GET_MEMBER(double, fatol, ws->fatol, NaN); GET_MEMBER(double, frtol, ws->frtol, NaN); GET_MEMBER(double, delta, ws->delta, NaN); GET_MEMBER(double, epsilon, ws->epsilon, NaN); GET_MEMBER(double, sxtol, SXTOL(ws), NaN); GET_MEMBER(double, sftol, SFTOL(ws), NaN); GET_MEMBER(double, sgtol, SGTOL(ws), NaN); GET_MEMBER(double, step, ws->stp, NaN); GET_MEMBER(double, gnorm, ws->gnorm, NaN); GET_MEMBER(opl_task_t, task, TASK(ws), OPL_TASK_ERROR); GET_MEMBER(opl_status_t, status, STATUS(ws), OPL_ILLEGAL_ADDRESS); GET_MEMBER(opl_integer_t, iterations, ws->iterations, -1); GET_MEMBER(opl_integer_t, evaluations, ws->evaluations, -1); GET_MEMBER(opl_integer_t, restarts, ws->restarts, -1); GET_MEMBER(const char*, reason, opl_get_message(&CONTEXT(ws)), NULL); #undef GET_MEMBER opl_status_t opl_vmlmb_set_fmin(opl_vmlmb_workspace_t* ws, double value) { if (ws == NULL) { errno = EFAULT; return OPL_ILLEGAL_ADDRESS; } if (isnan(value) || value < -DBL_MAX) { ws->flags &= ~FLAG_FMIN; ws->fmin = NaN; } else { ws->fmin = value; } return OPL_SUCCESS; } #define SET_MEMBER(name, lvalue, invalid) \ opl_status_t \ opl_vmlmb_set_##name(opl_vmlmb_workspace_t* ws, double value) \ { \ if (ws == NULL) { \ errno = EFAULT; \ return OPL_ILLEGAL_ADDRESS; \ } \ if (invalid) { \ errno = EINVAL; \ return OPL_INVALID_ARGUMENT; \ } \ lvalue = value; \ return OPL_SUCCESS; \ } SET_MEMBER(fatol, ws->fatol, value < 0.0); SET_MEMBER(frtol, ws->frtol, value < 0.0); SET_MEMBER(delta, ws->delta, value < 0.0); SET_MEMBER(epsilon, ws->epsilon, value < 0.0); SET_MEMBER(sxtol, SXTOL(ws), value <= 0.0 || value >= 1.0); SET_MEMBER(sftol, SFTOL(ws), value <= 0.0 || value >= 1.0); SET_MEMBER(sgtol, SGTOL(ws), value <= 0.0 || value >= 1.0); #undef SET_MEMBER opl_task_t opl_vmlmb_restart(opl_vmlmb_workspace_t* ws) { if (ws == NULL) { errno = EFAULT; return OPL_TASK_ERROR; } ws->evaluations = 0; ws->iterations = 0; ws->restarts = 0; ws->mark = -1; ws->mp = 0; ws->f0 = 0.0; ws->gd = 0.0; ws->g0d = 0.0; ws->stp = 0.0; STPMIN(ws) = 0.0; STPMAX(ws) = 0.0; ws->gnorm = -1.0; ws->g0norm = -1.0; return success(ws, OPL_TASK_FG, "compute f(x) and g(x)"); } opl_task_t opl_vmlmb_restore(opl_vmlmb_workspace_t* ws, double x[], double *f, double g[]) { if (ws == NULL || x == NULL || f == NULL || g == NULL) { errno = EFAULT; return OPL_TASK_ERROR; } if (TASK(ws) == OPL_TASK_FG && ws->evaluations > 0) { *f = ws->f0; ws->gnorm = ws->g0norm; opl_dcopy(ws->n, ws->S[ws->mark], x); opl_dcopy(ws->n, ws->Y[ws->mark], g); success(ws, OPL_TASK_NEWX, "restored solution available for inspection"); } return TASK(ws); } /*---------------------------------------------------------------------------*/ /* PERFORM NEXT VMLMB STEP */ opl_task_t opl_vmlmb_iterate(opl_vmlmb_workspace_t* ws, double x[], double *f, double g[], opl_logical_t isfree[], const double h[]) { /* Local variables. */ double stpmax; opl_integer_t m = ws->m; opl_integer_t n = ws->n; double* d = ws->d; double** S_ = ws->S; double** Y_ = ws->Y; double *Sm, *Ym; opl_integer_t i; int have_fmin = ((ws->flags & FLAG_FMIN) != 0); # define S(j) S_[j] # define Y(j) Y_[j] switch (TASK(ws)) { case OPL_TASK_FG: /* Caller has perfomed a new evaluation of the function and its gradient. */ ++ws->evaluations; if (have_fmin && *f <= ws->fmin) { return failure(ws, OPL_F_LE_FMIN, "initial F <= FMIN"); } if (ws->evaluations > 1) { opl_status_t status; opl_task_t task; /* Compute directional derivative for the line search. */ ws->gd = -opl_ddot(n, g, d); /* Call line search iterator to check for line search convergence. */ opl_csrch_iterate(&ws->lnsrch, *f, ws->gd, &ws->stp); task = TASK(ws); if (task == OPL_TASK_FG) { /* Line search has not converged. Compute a new iterate. */ return next_step(ws, x); } status = STATUS(ws); if (task == OPL_TASK_CONV || (task == OPL_TASK_WARN && (status == OPL_XTOL_TEST_SATISFIED || status == OPL_ROUNDING_ERROR))) { /* Line search has converged. */ ++ws->iterations; } else { /* Error or warning in line search (task and context should have been set so as to describe the problem). Restore solution at start of line search. */ opl_dcopy(n, S(ws->mark), x); opl_dcopy(n, Y(ws->mark), g); ws->gnorm = ws->g0norm; *f = ws->f0; break; } } /* Request the caller to compute the set of unbinded variables. */ return success(ws, OPL_TASK_FREEVARS, "determine free variables"); case OPL_TASK_FREEVARS: /* Copy the (projected) gradient into D and compute the norm of the (projected) gradient. */ if (check_free(ws, isfree, h) != 0) { break; } opl_dcopy_free(n, g, d, isfree); ws->gnorm = opl_dnrm2(n, d); if (ws->gnorm == zero) { return success(ws, OPL_TASK_CONV, "local minimum found"); } if (ws->evaluations > 1) { /* Compute the step and gradient change (i.e., update L-BFGS data). Note: we always compute the effective step (parameter difference) to account for bound constraints and, at least, numerical rounding or truncation errors. */ for (Ym = Y(ws->mark), i = 0; i < n; ++i) { Ym[i] -= g[i]; } for (Sm = S(ws->mark), i = 0; i < n; ++i) { Sm[i] -= x[i]; } if (isfree == NULL) { ws->rho[ws->mark] = opl_ddot(n, Y(ws->mark), S(ws->mark)); } if (ws->mp < m) { ++ws->mp; } /* Test for global convergence. */ if (opl_noneof(n, S(ws->mark))) { return success(ws, OPL_TASK_WARN, "no parameter change"); } else if (opl_noneof(n, Y(ws->mark))) { return success(ws, OPL_TASK_WARN, "no gradient change"); } else { double change = max(fabs(*f - ws->f0), fabs(ws->stp*ws->g0d)); if (change <= ws->frtol*fabs(ws->f0)) { return success(ws, OPL_TASK_CONV, "FRTOL test satisfied"); } else if (change <= ws->fatol) { return success(ws, OPL_TASK_CONV, "FATOL test satisfied"); } } } /* Set task to signal a new iterate. */ return success(ws, OPL_TASK_NEWX, "new improved solution available for inspection"); case OPL_TASK_NEWX: case OPL_TASK_CONV: case OPL_TASK_WARN: /* Compute a new search direction. D already contains the (projected) gradient. */ if (ws->mp > 0) { /* Apply L-BFGS recursion to compute a search direction. */ compute_direction(ws, d, isfree, h); if (ws->mp > 0) { /* Set initial step size and compute dot product of gradient and search direction. If L-BFGS recursion filed to produce a sufficient descent search direction, we restart the algorithm with steepest descent. */ int descent; ws->stp = 1.0; ws->gd = -opl_ddot(n, g, d); if (ws->epsilon > zero) { descent = (ws->gd <= -ws->epsilon*ws->gnorm*opl_dnrm2(n, d)); } else { descent = (ws->gd < zero); } if (! descent) { /* Manage to restart the L-BFGS with steepest descent. */ ws->mp = 0; opl_dcopy_free(n, g, d, isfree); } } if (ws->mp <= 0) { /* L-BFGS recursion has been restarter because it has failed to produce an acceptable search direction. */ ++ws->restarts; } } if (ws->mp == 0) { /* Compute initial search direction (or after a restart). D is already the (projected) gradient. */ if (h != NULL) { /* Use diagonal preconditioner to compute initial search direction. */ for (i = 0; i < n; ++i) { d[i] *= h[i]; } ws->stp = 1.0; ws->gd = -opl_ddot(n, g, d); if (ws->gd >= zero) { return failure(ws, OPL_NOT_POSITIVE_DEFINITE, "preconditioner is not positive definite"); } } else { /* No preconditioning, use a small step along the steepest descent. */ if (ws->delta > zero) { ws->stp = (opl_dnrm2(n, x)/ws->gnorm)*ws->delta; } else { ws->stp = zero; } if (ws->stp <= zero) { /* The following step length is quite arbitrary but to avoid this would require to know the typical size of the variables. */ ws->stp = one/ws->gnorm; } ws->gd = -ws->gnorm*ws->gnorm; } } /* Advance the mark and save point at start of line search. Note that this point has forcibly been projected so it is feasible. */ ws->mark = (ws->mark + 1)%m; ws->f0 = *f; ws->g0d = ws->gd; ws->g0norm = ws->gnorm; opl_dcopy(n, x, S(ws->mark)); /* save parameters X0 */ opl_dcopy(n, g, Y(ws->mark)); /* save gradient G0 */ /* Set step bounds and task to start line search. */ #if 1 stpmax = DEFAULT_STPMAX; #else if (have_fmin) { stpmax = (ws->fmin - ws->f0)/(SGTOL(ws)*ws->g0d); } else { double temp = fabs(ws->f0); if (temp < 1.0) { temp = 1.0; } stpmax = temp/(SGTOL(ws)*ws->g0d); } #endif ws->stp = min(ws->stp, stpmax); opl_csrch_start(&ws->lnsrch, *f, ws->gd, ws->stp, SFTOL(ws), SGTOL(ws), SXTOL(ws), zero, stpmax); if (TASK(ws) != OPL_TASK_FG) { /* Some error occured (task and context should have been set so as to describe the problem). */ break; } /* Compute the new iterate. */ return next_step(ws, x); case OPL_TASK_ERROR: /* Nothing to do then. */ break; default: /* Probably an error. */ return failure(ws, OPL_CORRUPTED, "corrupted workspace"); } return TASK(ws); # undef Y # undef S # undef SUCCESS # undef FAILURE } /* * Compute new search direction H(k).d(k) based on the two-loop recursion * L-BFGS formula (operation is done in-place). H(k) is the limited memory * BFGS approximation of the inverse Hessian, d(k) has been initialized with is * the (projected) gradient at k-th step. H(k) is approximated by using the M * last pairs (s, y) where: * * s(j) = x(j+1) - x(j) * y(j) = g(j+1) - g(j) * * or: * * s(j) = x(j) - x(j+1) * y(j) = g(j) - g(j+1) * * Indeed, the way the differences are computed does not matter (as far as all * differences are computed similarly), because: it has no influence on RHO(j), * and on dot products between S(j) and Y(j); it changes the sign of ALPHA(j) * and BETA but not that of ALPHA(j) - BETA times S(j) or Y(j). * * The two-loop recursion algorithm writes: * * 1- start with current gradient: * d := +/- g(k) * * 2- for j = k-1, ..., k-m * rho(j) = s(j)'.y(j) (save rho(j)) * alpha(j) = (s(j)'.d)/rho(j) (save alpha(j)) * d := d - alpha(j) y(j) * * 3- apply approximation of inverse k-th Hessian: * d := H0(k).d * for instance: * d := (rho(k-1)/(y(k-1)'.y(k-1))) d * * 4- for j = k-m, ..., k-1 * d := d + (alpha(j) - (y(j)'.d)/rho(j)) s(j) */ static void compute_direction(opl_vmlmb_workspace_t* ws, double d[], const opl_logical_t isfree[], const double h[]) { double gamma = zero; opl_integer_t m = ws->m; opl_integer_t mp = ws->mp; opl_integer_t n = ws->n; opl_integer_t off = ws->mark + m + 1; opl_integer_t i, j, k; double* rho = ws->rho; double* alpha = ws->alpha; double** S_ = ws->S; double** Y_ = ws->Y; # define S(j) S_[j] # define Y(j) Y_[j] /* First loop of the L-BFGS recursion. */ for (k = 1; k <= mp; ++k) { j = (off - k)%m; if (isfree != NULL) { rho[j] = opl_ddot_free(n, S(j), Y(j), isfree); } if (rho[j] > zero) { alpha[j] = opl_ddot(n, S(j), d)/rho[j]; opl_daxpy_free(n, -alpha[j], Y(j), d, isfree); if (gamma <= zero) { double yty = opl_ddot_free(n, Y(j), Y(j), isfree); if (yty > zero) { gamma = rho[j]/yty; } } } } /* Apply initial approximation of the inverse Hessian. */ if (h != NULL) { /* Apply diagonal preconditioner. */ for (i = 0; i < n; ++i) { d[i] *= h[i]; } } else if (gamma > zero) { /* Apply initial H (i.e. just scale D) and perform the second stage of the 2-loop recursion. */ opl_dscal(n, gamma, d); } else { /* All correction pairs are invalid: manage to restart the L-BFGS recursion. Note that D is left unchanged in that case. */ ++ws->restarts; ws->mp = 0; return; } /* Second loop of the L-BFGS recursion. */ for (k = mp; k >= 1; --k) { j = (off - k)%m; if (rho[j] > zero) { double beta = opl_ddot(n, Y(j), d)/rho[j]; opl_daxpy_free(n, alpha[j] - beta, S(j), d, isfree); } } # undef S # undef Y } static opl_task_t next_step(opl_vmlmb_workspace_t* ws, double x[]) { double stp = ws->stp; const double* d = ws->d; const double* x0 = ws->S[ws->mark]; opl_integer_t i, n = ws->n; /* Compute the new iterate. */ for (i = 0; i < n; ++i) { x[i] = x0[i] - stp*d[i]; } /* Require the caller to compute the function and its gradient. */ opl_set_context(&CONTEXT(ws), OPL_SUCCESS, "compute f(x) and g(x)", OPL_PERMANENT); return (TASK(ws) = OPL_TASK_FG); } static int check_free(opl_vmlmb_workspace_t* ws, opl_logical_t isfree[], const double h[]) { if (h != NULL) { const double zero = 0.0; opl_integer_t i, n = ws->n; if (isfree != NULL) { /* fix ISFREE array */ for (i = 0; i < n; ++i) { if (isfree[i] && h[i] <= zero) { isfree[i] = 0; } } } else { /* check that H is positive definite */ for (i = 0; i < n; ++i) { if (h[i] <= zero) { failure(ws, OPL_NOT_POSITIVE_DEFINITE, "initial inverse Hessian is not positive definite"); return -1; } } } } return 0; } /*---------------------------------------------------------------------------*/ /* MEMORY MANAGEMENT FOR VMLMB */ /* * A monolithic workspace is organized in memory as follows (starting from the * base address): * * base: workspace structure * padding for proper alignment * base + offset1: 2 arrays of M pointers (for S and Y) * padding for proper alignment * base + offset2: 2 arrays of M reals (for ALPHA and RHO) * 1 array of N reals (for D, the search direction) * 2*M arrays of N reals (for S and Y) */ static const size_t offset1 = OPL_ROUND_UP(sizeof(opl_vmlmb_workspace_t), sizeof(void*)); static size_t workspace_offset2(size_t m) { return OPL_ROUND_UP(offset1 + 2*m*sizeof(void*), sizeof(double)); } static size_t number_of_reals(size_t n, size_t m) { return (2*m*(n + 1) + n); } size_t opl_vmlmb_monolithic_workspace_size(opl_integer_t n, opl_integer_t m) { if (n <= 0 || m <= 0) { errno = EINVAL; return 0; } return workspace_offset2(m) + number_of_reals(n, m)*sizeof(double); } opl_vmlmb_workspace_t* opl_vmlmb_monolithic_workspace_init(void* buf, opl_integer_t n, opl_integer_t m) { size_t offset2, size; opl_integer_t k; opl_vmlmb_workspace_t* ws; double* arr; /* Check arguments. */ if (buf == NULL) { if (errno != ENOMEM) { errno = EFAULT; } return NULL; } if (n <= 0 || m <= 0) { errno = EINVAL; return NULL; } /* Compute offsets and size. Clear buffer. */ offset2 = workspace_offset2(m); size = offset2 + number_of_reals(n, m)*sizeof(double); memset(buf, 0, size); /* Instanciate workspace. */ ws = (opl_vmlmb_workspace_t*)buf; ws->m = m; ws->n = n; ws->S = (double**)((byte_t*)ws + offset1); ws->Y = ws->S + m; ws->alpha = (double*)((byte_t*)ws + offset2); ws->rho = ws->alpha + m; ws->d = ws->rho + m; arr = ws->d; for (k = 0; k < m; ++k) { ws->S[k] = (arr += n); ws->Y[k] = (arr += n); } opl_vmlmb_restart(ws); return opl_vmlmb_set_defaults(ws); } opl_vmlmb_workspace_t* opl_vmlmb_set_defaults(opl_vmlmb_workspace_t* ws) { SFTOL(ws) = DEFAULT_SFTOL; SGTOL(ws) = DEFAULT_SGTOL; SXTOL(ws) = DEFAULT_SXTOL; ws->fatol = DEFAULT_FATOL; ws->frtol = DEFAULT_FRTOL; ws->delta = DEFAULT_DELTA; ws->epsilon = DEFAULT_EPSILON; opl_vmlmb_set_fmin(ws, NaN); return ws; } static void free_split_workspace(void* ptr) { opl_vmlmb_workspace_t* ws = (opl_vmlmb_workspace_t*)ptr; opl_integer_t k, m = ws->m; double* tmp; if ((tmp = ws->d) != NULL) { ws->d = NULL; free(tmp); } for (k = 0; k < m; ++k) { if ((tmp = ws->S[k]) != NULL) { ws->S[k] = NULL; free(tmp); } if ((tmp = ws->Y[k]) != NULL) { ws->Y[k] = NULL; free(tmp); } } free(ws); } opl_vmlmb_workspace_t* opl_vmlmb_create(opl_integer_t n, opl_integer_t m) { size_t offset2, size; opl_integer_t k; opl_vmlmb_workspace_t* ws; if (n <= 0 || m <= 0) { errno = EINVAL; return 0; } if (m*n <= 10000) { /* For small problems, the workspace is allocated as a single block of memory. */ size = opl_vmlmb_monolithic_workspace_size(n, m); ws = opl_vmlmb_monolithic_workspace_init(malloc(size), n, m); if (ws == NULL) { return NULL; } ws->free = free; return ws; } else { /* For larger problems, the philosophy is to store the workspace structure and related small arrays in a single block of memory, while larger arrays (d, S and Y) are stored separately. */ offset2 = workspace_offset2(m); size = offset2 + 2*m*sizeof(double); ws = (opl_vmlmb_workspace_t*)malloc(size); if (ws == NULL) { return NULL; } memset(ws, 0, size); ws->free = free_split_workspace; ws->m = m; ws->n = n; ws->S = (double**)((byte_t*)ws + offset1); ws->Y = ws->S + m; ws->alpha = (double*)((byte_t*)ws + offset2); ws->rho = ws->alpha + m; if ((ws->d = NEW(double, n)) == NULL) { destroy: opl_vmlmb_destroy(ws); return NULL; } for (k = 0; k < m; ++k) { if ((ws->S[k] = NEW(double, n)) == NULL || (ws->Y[k] = NEW(double, n)) == NULL) { goto destroy; } } opl_vmlmb_restart(ws); return opl_vmlmb_set_defaults(ws); } } void opl_vmlmb_destroy(opl_vmlmb_workspace_t* ws) { if (ws != NULL) { if (ws->free == NULL) { fprintf(stderr, "*** ERROR *** %s\n", "attempt to destroy a foreign monolithic workspace, " "read the documentation!"); } else { ws->free(ws); } } } OptimPackLegacy-release-1.4.0/src/optimpacklegacy.h000066400000000000000000001161651303525653100222770ustar00rootroot00000000000000/* * optimpacklegacy.h -- * * Definitions for optimization routines implemented in Optimpacklegacy * library. * *----------------------------------------------------------------------------- * * Copyright (c) 2003, 2016 Éric Thiébaut. * * This file is part of OptimPack . * * OptimPack 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. * * OptimPack 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 * OptimPack (file "LICENSE" in the top source directory); if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * *----------------------------------------------------------------------------- */ #ifndef _OPTIMPACKLEGACY_H #define _OPTIMPACKLEGACY_H 1 /** * Customizable data types: * OPL_INTEGER = data type used to store array indices * OPL_LOGICAL = data type of the result of a logical test */ #ifndef OPL_INTEGER # define OPL_INTEGER int #endif #ifndef OPL_LOGICAL # define OPL_LOGICAL int #endif typedef OPL_INTEGER opl_integer_t; typedef OPL_LOGICAL opl_logical_t; /*---------------------------------------------------------------------------*/ /* USEFUL MACROS */ /* C++ needs to know that types and declarations are C, not C++. */ #ifdef __cplusplus # define _OPL_BEGIN_DECLS extern "C" { # define _OPL_END_DECLS } #else # define _OPL_BEGIN_DECLS /* empty */ # define _OPL_END_DECLS /* empty */ #endif _OPL_BEGIN_DECLS /** * Possible values for a boolean. */ typedef enum { OPL_FALSE = 0, OPL_TRUE = 1 } opl_boolean_t; /*---------------------------------------------------------------------------*/ /* STATUS AND ERROR REPORTING */ /** * Standard result codes * * @brief These constants are the standard value returned by most dynamic * buffer routines. */ typedef enum { /* Success. */ OPL_SUCCESS = 0, /* Warnings. */ OPL_STP_EQ_STPMIN, OPL_STP_EQ_STPMAX, OPL_XTOL_TEST_SATISFIED, OPL_ROUNDING_ERROR, /* Errors. */ OPL_STPMAX_LT_STPMIN, OPL_STPMIN_LT_ZERO, OPL_XTOL_LT_ZERO, OPL_FTOL_LE_ZERO, OPL_GTOL_LE_ZERO, OPL_NOT_A_DESCENT, OPL_STP_GT_STPMAX, /* OPL_OUT_OF_BOUNDS? */ OPL_STP_LT_STPMIN, /* OPL_OUT_OF_BOUNDS? */ OPL_F_LE_FMIN, OPL_NOT_POSITIVE_DEFINITE, OPL_INSUFFICIENT_MEMORY, OPL_ILLEGAL_ADDRESS, OPL_INVALID_ARGUMENT, OPL_OUT_OF_BOUNDS, OPL_CORRUPTED, OPL_OVERFLOW, #if 0 OPL_SYNTAX_ERROR, OPL_OPEN_ERROR, OPL_CLOSE_ERROR, OPL_READ_ERROR, OPL_WRITE_ERROR, OPL_STAT_ERROR, OPL_FILE_EXISTS, OPL_ZIP_ERROR, #endif OPL_SYSTEM_ERROR /* System error, use errno code. */ } opl_status_t; /** * The context opaque structure. */ typedef struct _opl_context opl_context_t; /** * Query status from context. * * @param ctx Context for error reporting. * * @return A status value. */ extern opl_status_t opl_get_status(opl_context_t* ctx); /** * Query system error code from context. * * @param ctx Context for error reporting. * * @return If current context status is `OPL_SYSTEM_ERROR`, the system error * code (a.k.a. `errno`) when the error occured is returned; otherwise, * 0 is returned. */ extern int opl_get_errno(opl_context_t* ctx); /** * Query message from context. * * @param ctx Context for error reporting. * * @return A human readable message. */ extern const char* opl_get_message(opl_context_t* ctx); /** * Query an explanation about a status code. * * @param status Status value. * * @return A human readable message. */ extern const char* opl_get_default_message(opl_status_t status); /** * Intialize a context. * * This function initializes a context to some consistent contents. It must * be called before using the context. * * @param ctx The address of the context. */ extern void opl_initialize_context(opl_context_t* ctx); /** * The different strorage types. */ typedef enum { OPL_VOLATILE = 0, /** Storage is volatile, a copy must be done. */ OPL_PERMANENT /** Storage is permanent, the same address can be used. */ } opl_storage_type_t; /** * Set a context contents. * * This function set the contents, that is the status and corresponding * message, of a given context and return the status value. * * The given message must be a null terminated string. If the storage type of * the message is `OPL_PERMANENT`, the context message will point to `message`; * otherwise, the context message will point to the internal buffer of `ctx` * after copying `message` in this buffer. In this latter case, if the message * is too long to fit in the buffer, it will be truncated and terminated by the * ellipsis text "[...]". * * @param ctx The address of the context. * @param status The value of the status. * @param message The message string. * @param type The storage type of the message string. * * @return The value of `status`. */ extern opl_status_t opl_set_context(opl_context_t* ctx, opl_status_t status, const char* message, opl_storage_type_t type); /** * Set a context with a formated message. * * This function set the contents, that is the status and corresponding * message, of a given context and return the status value. The message is * formatted using the same mechanism as `printf`. If the resulting message is * too long to fit in the internal buffer of the context, it will be truncated * and terminated by the ellipsis text "[...]". * * @param ctx The address of the context. * @param status The value of the status. * @param format The format string. * @param ... The arguments of the format. * * @return The value of `status`. */ extern opl_status_t opl_format_context(opl_context_t* ctx, opl_status_t status, const char* format, ...); /** * Report successful operation. * * This (inlined) function is equivalent to: * @code * opl_set_context(ctx, OPL_SUCCESS, * opl_get_default_message(OPL_SUCCESS), * OPL_PERMANENT) * @endcode * * @param ctx Context for error reporting. * * @return `OPL_SUCCESS`. */ extern opl_status_t opl_success(opl_context_t* ctx); /*---------------------------------------------------------------------------*/ /* LINE SEARCH */ /** * @addtogroup MoreThuenteLineSearch * @{ * * @page csrch Moré & Thuente line search * @tableofcontents * * Moré & Thuente line search method (@ref morethuente1984) finds a step that * satisfies a sufficient decrease condition and a curvature condition. * * The function @link #opl_csrch_start should be called at the start of a line * search to initiate the search. The function @link #opl_csrch_iterate should * then be called for each new tried point along the line search until the * convergence of the search. * * The method updates an interval with endpoints `stx` and `sty`. The * interval is initially chosen so that it contains a minimizer of the * modified function: * *
 *       psi(stp) = f(stp) - f(0) - ftol*stp*g(0)
 * 
* * where `f(0)` and `g(0) = f'(0)` are the value of the function and its * derivative for `stp = 0`. If `psi(stp) ≤ 0` and `g(stp) ≥ 0` for some step, * then the interval is chosen so that it contains a minimizer of `f(stp)`. * The algorithm is designed to find a step that satisfies the sufficient * decrease condition: * *
 *     f(stp) <= f(0) + ftol*stp*g(0),                            (1)
 * 
* * and the curvature condition: * *
 *     abs(g(stp)) <= gtol*abs(g(0)).                             (2)
 * 
* * Relations (1) and (2) are called the strong Wolfe conditions. If `ftol` is * less than `gtol` and if, for example, the function is bounded below, then * there is always a step which satisfies both conditions. If no step can be * found that satisfies both conditions, then the algorithm stops with a * warning. In this case `stp` only satisfies the sufficient decrease * condition. * * * @subsection example Example * * A typical invocation of the method has the following outline: * *
 * opl_csrch_create_workspace();
 * double f = ...;   // function value for STP=0
 * double g = ...;   // derivative value for STP=0
 * double stp = ...; // guess for next STP value to try (STP > 0.0)
 * double ftol = 1e-3;
 * double gtol = 0.9;
 * double xtol = 0.1;
 * double stpmin = 0;
 * double stpmax = 1e20*stp;
 * opl_csrch_start(ws, f, g, stp, ftol, gtol, xtol, stpmin, stpmax);
 * for (;;) {
 *     opl_task_t task = opl_csrch_get_task(ws);
 *     if (task == OPL_TASK_FG) {
 *         // Evaluate the function and the gradient at `stp`.
 *         f = func(stp);
 *         g = grad(stp);
 *     } else if (task == OPL_TASK_CONV) {
 *         // Search has converged.
 *         break;
 *     } else if (task == OPL_TASK_WARN) {
 *         // Some problem prevents further progress.
 *         fprintf(stderr, "warning in %s\n", opl_csrch_get_reason(ws));
 *         exit(1);
 *     } else {
 *         // An error occured.
 *         fprintf(stderr, "error in %s\n", , opl_csrch_get_reason(ws));
 *         exit(1);
 *     }
 * }
 * 
* * @subsection refs References * * @anchor morethuente1984 * Jorge J. Moré and David J. Thuente, "Line search algorithms with * guaranteed sufficient decrease" in ACM Transactions on Mathematical * Software (TOMS) Volume 20, Issue 3, Pages 286-307 (September 1994). * * * @subsection hist History * * MINPACK-1 Project. June 1983. * Argonne National Laboratory. * Jorge J. Moré and David J. Thuente. * * MINPACK-2 Project. November 1993. * Argonne National Laboratory and University of Minnesota. * Brett M. Averick, Richard G. Carter, and Jorge J. Moré. * * Yorick translation an improvements. October 2001. * C-version. February 2003. * Observatoire de Lyon (France). * Éric Thiébaut. * * New C version with structured workspace. * December 2016. * Centre de Recherche Astrophysique de Lyon (France). * Éric Thiébaut. */ /** * Possible values for an optimization task. */ typedef enum { OPL_TASK_START = 0, /*< start line search */ OPL_TASK_FG = 1, /*< caller has to compute function and gradient */ OPL_TASK_FREEVARS = 2, /*< caller has to determine the free variables */ OPL_TASK_NEWX = 3, /*< new variables available for inspection */ OPL_TASK_CONV = 4, /*< search has converged */ OPL_TASK_WARN = 5, /*< search aborted with warning */ OPL_TASK_ERROR = 6 /*< search aborted with error */ } opl_task_t; /** * Opaque workspace used for Moré & Thuente line search. */ typedef struct _opl_csrch_workspace opl_csrch_workspace_t; /** * Get the pending task of a line search instance. */ extern opl_task_t opl_csrch_get_task(opl_csrch_workspace_t* ws); /** * Get the status of the last operation on a line search instance. */ extern opl_task_t opl_csrch_get_status(opl_csrch_workspace_t* ws); /** * Get the message explaining the result of the last operation on a line search * instance. */ extern const char* opl_csrch_get_reason(opl_csrch_workspace_t* ws); /** * Get the size of a Moré & Thuente line search instance. * * This function can be used to determine the size (in bytes) of a Moré & * Thuente line search instance for applications which want to directly manage * memory. A line search instance can be stored into any memory block of * sufficient size and aligned on a multiple of the size of a `double`. * However, the line search workspace can be assumed to have been properly * initilaized only after a first call to @link #opl_csrch_start. * * @return The size in bytes of a Moré & Thuente line search instance. */ extern size_t opl_csrch_get_workspace_size(); /** * Create a new instance of Moré & Thuente line search. * * @return A new instance of Moré & Thuente line search. When no longer * needed, this instance must be destroyed with @link * #olp_csrch_destroy_workspace. `NULL` is returned in case of error * (i.e. insufficient memory). */ extern opl_csrch_workspace_t* opl_csrch_create_workspace(); /** * Destroy an instance of Moré & Thuente line search. * * This function should only be called on an instance created by @link * #opl_csrch_create_workspace. * * @param ws A line search instance created by @link * #opl_csrch_create_workspace. */ extern void opl_csrch_destroy_workspace(opl_csrch_workspace_t* ws); /** * Initiate a line search by Moré & Thuente method. * * @param ws The address of the line search workspace. * * @param f The value of the function at the start of the line search * (that is for `stp = 0`). * * @param g The value of the directional derivative at the start of the * line search (that is for `stp = 0`). * * @param stp The length of the first step to take along the search * direction. Must be a strictly positive value. * * @param ftol A nonnegative tolerance for the sufficient decrease condition. * One should take `0 < ftol < 1/2`. * * @param gtol A nonnegative tolerance for the curvature condition. One * should take `ftol < gtol < 1`. * * @param xtol A nonnegative relative tolerance for an acceptable step. * The line search will exit with a warning if the relative * difference between `sty` and `stx` is less than `xtol`. * * @param stpmin A nonnegative lower bound for the step. * * @param stpmax A nonnegative upper bound for the step. * * @return A standard status: `OPL_SUCCESS` or any other value to indicate the * error. */ extern opl_status_t opl_csrch_start(opl_csrch_workspace_t* ws, double f, double g, double stp, double ftol, double gtol, double xtol, double stpmin, double stpmax); /** * Iterate a line search by Moré & Thuente method. * * Upon return, @link #opl_csrch_get_task, @link #opl_csrch_get_status or @link * #opl_csrch_get_reason can be used to retrieve the next pending task, the * status of the last operation and the reason of the result of the las * operation. * * @param ws The address of the line search workspace. * * @param f The value of the function for the current step along the line * search. * * @param g The value of the derivative of the function for the current * step along the line search. * * @param stp The address of the variable with, on entry, the length of the * current step taken along the search direction. On exit with * task `OPL_TASK_FG`, the variable will be set with the next * step to take. On exit with task `OPL_TASK_CONV`, the variable * is left unchanged. * * @return The following status values can be returned: * * - `OPL_SUCCESS`, then the task returned by @link #opl_csrch_get_task * indicates the required action. If `task = OPL_TASK_FG`, then the callar * shall evaluate the function and derivative at `*stp` and call * `opl_csrch_iterate` again. If `task = OPL_TASK_CONV`, then the search is * successful. If `task = OPL_TASK_WARN` then the subroutine is not able to * satisfy the convergence conditions. The exit value of `*stp` contains the * best point found during the search. If `task = OPL_TASK_ERROR` then there * is an error in the input arguments. * * - `OPL_STP_EQ_STPMIN` with `task = OPL_TASK_WARN`: the search is blocked at * the lower bound. * * - `OPL_STP_EQ_STPMAX` with `task = OPL_TASK_WARN`: the search is blocked at * the upper bound. * * - `OPL_XTOL_TEST_SATISFIED` with `task = OPL_TASK_WARN`: `XTOL` test is * satisfied. * * - `OPL_TASK_WARN` with `task = OPL_TASK_WARN`: rounding errors prevent * progress. * * - `OPL_OUT_OF_BOUNDS` with `task = OPL_TASK_ERROR`: the step `*stp` is * outside bracket `(stx,sty)`. * * - `OPL_NOT_A_DESCENT` with `task = OPL_TASK_ERROR`: the descent condition * does not hold. * * - `OPL_STPMAX_LT_STPMIN` with `task = OPL_TASK_ERROR`: the search bounds are * incompatible. */ extern opl_status_t opl_csrch_iterate(opl_csrch_workspace_t* ws, double f, double g, double *stp); /** * Compute a safeguarded cubic step. * * This function computes a safeguarded step for a search procedure and updates * an interval that contains a step that satisfies a sufficient decrease and a * curvature condition [1]. * * The parameter `stx` contains the step with the least function value. If * `brackt` is set to true (i.e. non-zero) then a minimizer has been bracketed * in an interval with endpoints `stx` and `sty`. The parameter `stp` contains * the current step. The subroutine assumes that if `brackt` is true then: * *
 *     min(stx,sty) < stp < max(stx,sty),
 * 
* * and that the derivative at `stx` is negative in the direction of the step. * * On output, all the parameters passed by address are updated appropriately. * * @param ctx The address of a context structure for error reporting. * * @param brackt_ptr The addresses where the value of `brackt` is stored. * `brackt` is a logical variable. On entry, `brackt` * specifies if a minimizer has been bracketed. Initially * `brackt` must be set to false. On exit, `brackt` specifies * if a minimizer has been bracketed. When a minimizer is * bracketed, `brackt` (i.e. the value at address * `brackt_ptr`) is set to true. * * @param stpmin The lower bound for the step. * * @param stpmax The upper bound for the step. * * @param stx_ptr The address of `stx`, the best step obtained so far. * * @param fx_ptr The address of `fx`, the function at `stx`. * * @param dx_ptr The addresses of `dx`, the derivative at `stx` negative in * the direction of the step, that is, `dx` and `stp - stx` * must have opposite signs. * * @param sty_ptr The address of `sty`, the other endpoint of the interval * of uncertainty. * * @param fy_ptr The address of `fy`, the function at `sty`. * * @param dy_ptr The address of `dy`, the derivative at `sty`. * * @param stp_ptr The address where the value of `stp`, the current step, * is stored. If `brackt` is set true then on input `stp` * must be between `stx` and `sty`. On output, the value at * `stp_ptr` is set to the new step. * * @param fp The function at the current step. * * @param dp The derivative at the current step. * * @return The returned value indicates whether the operation was successful * (failure can only occur with wrong arguments). The context `ctx` is * used to report errors if any. */ extern opl_status_t opl_cstep(opl_context_t* ctx, opl_boolean_t *brackt, double stpmin, double stpmax, double *stx_ptr, double *fx_ptr, double *dx_ptr, double *sty_ptr, double *fy_ptr, double *dy_ptr, double *stp_ptr, double fp, double dp); /** * @} */ /*---------------------------------------------------------------------------*/ /** * @addtogroup VMLMB * @{ * * VMLMB is a limited memory variable metric method (BFGS) which can take into * account bound constraints */ /** * The opaque workspace for VMLMB. */ typedef struct _opl_vmlmb_workspace opl_vmlmb_workspace_t; /** * Return the size of a VMLMB workspace as one block. * * The returned size is a multiple of the size of a double precision floating * point value. It may be stored in an array of such values. * * Typical usage: *
 *    size = opl_vmlmb_monolithic_workspace_size(n, m);
 *    buffer = malloc(size);
 *    ws = opl_vmlmb_monolithic_workspace_init(buffer, n, m);
 *    ....;
 *    free(buffer);
 * 
* As it is guaranteed that the base address does not change, you can also do: * * size = opl_vmlmb_monolithic_workspace_size(n, m); * ws = opl_vmlmb_monolithic_workspace_init(malloc(size), n, m); * ....; * free(ws); *
 *
 * @param n   The number of variables.
 *
 * @param m   The number of memorized steps.
 *
 * @return The size in bytes of a monolithic workspace for VMLMB.  Zero is
 *         returned if the arguments are invalid (not strictly positive).
 */
extern size_t
opl_vmlmb_monolithic_workspace_size(opl_integer_t n, opl_integer_t m);

/**
 * Initialize a workspace allocated as one block.
 *
 * @param buf   The memory allocated by the caller of the workspace, it must
 *              have at least the size given by
 *              `opl_vmlmb_monolithic_workspace_size(n, m)`.
 *
 * @param n     The number of variables.
 *
 * @param m     The number of memorized steps.
 *
 * @return The workspace initialized with defaults.  `NULL` is returned
 *         if `buf` is not a valid address.
 */
extern opl_vmlmb_workspace_t*
opl_vmlmb_monolithic_workspace_init(void* buf,
                                    opl_integer_t n, opl_integer_t m);

extern opl_vmlmb_workspace_t*
opl_vmlmb_set_defaults(opl_vmlmb_workspace_t* ws);

extern opl_vmlmb_workspace_t*
opl_vmlmb_create(opl_integer_t n, opl_integer_t m);

extern void
opl_vmlmb_destroy(opl_vmlmb_workspace_t* ws);

/*
 * VMLM-B computes a local minimizer of a function of N variables by a limited
 * memory variable metric (BFGS) method; optionally, the parameters may be
 * bounded.  The user must evaluate the function and the gradient.
 *
 * VMLM-B is implemented via two functions: opl_vmlmb_setup for initialization
 * and opl_vmlmb_iterate for further iterations.  These functions use reverse
 * communication.  The user must choose an initial approximation X to the
 * minimizer, evaluate the function and the gradient at X, and make the initial
 * call with TASK set to OPL_TASK_FG.  On exit TASK indicates the required
 * action.
 *
 * The arguments are:
 *
 *   N is the number of parameters.
 *
 *   M is the number of correction pairs to remember in order to compute the
 *       limited memory variable metric (BFGS) approximation of the inverse of
 *       the Hessian.  For large problems, M = 3 to 5 gives good results.  For
 *       small problems, M should be less or equal N.  The larger is M (and N)
 *       the more computer memory will be needed to store the workspaces (see
 *       DSAVE).
 *
 *   FRTOL is the relative error desired in the function (e.g.  FRTOL=1e-8).
 *       Convergence occurs if the estimate of the relative error between F(X)
 *       and F(XSOL), where XSOL is a local minimizer, is less or equal FRTOL.
 *       FRTOL must have a non-negative floating point value.
 *
 *   FATOL is the absolute error desired in the function (e.g. FATOL=0.0).
 *       Convergence occurs if the estimate of the absolute error between F(X)
 *       and F(XSOL), where XSOL is a local minimizer, is less or equal FATOL.
 *       FATOL must have a non-negative floating point value.
 *
 *   SFTOL, SGTOL, and SXTOL are tolerances for the line search subroutine (see
 *       opl_csrch).   Recommended  values: SFTOL=0.001,  SGTOL=0.9,  SXTOL=0.1
 *       (other values  may be more  suitable for highly  non-quadratic penalty
 *       function).
 *
 *   DELTA is a small nonegative value used to compute a small initial step.
 *
 *   EPSILON is a small value, in the range [0,1), equals to the cosine of the
 *       maximum angle between the search direction and the anti-gradient.  The
 *       BFGS recursion is restarted, whenever the search direction is not
 *       sufficiently "descending".
 *
 *   CSAVE is a character workspace array of length OPL_VMLMB_CSAVE_NUMBER
 *       (same as OPL_MSG_SIZE) which is used to store additional information
 *       on exit with convergence, a warning or an error.
 *
 *   ISAVE is an integer workspace array of length OPL_VMLMB_ISAVE_NUMBER.
 *
 *   DSAVE is a floating point workspace array of length equal to the value
 *       returned by the macro OPL_VMLMB_DSAVE_NUMBER(N, M):
 *
 *           26 + N + 2*M*(N + 1).
 *
 *   X is a double precision array of length N.  On entry, X is an
 *       approximation to the solution.  On exit with TASK = OPL_TASK_CONV, X
 *       is the current approximation.
 *
 *   F is the address of a double precision variable.  On entry, F is the value
 *       of the function at X.  On final exit, F is the function value at X.
 *
 *   G is a double precision array of length N.  On entry, G is the value of
 *       the gradient at X.  On final exit, G is the value of the gradient at
 *       X.
 *
 *   ISFREE is an optional integer array with length N provided by the caller
 *       if the values in X have bounds.  If the parameters have no bounds,
 *       ISFREE should be NULL (unconstrained minimization).  Otherwise,
 *       elements set to zero in ISFREE indicate that the corresponding values
 *       in X has reached a bound and should not be changed during the next
 *       step because the gradient has the wrong sign (i.e.  the steepest
 *       descent direction would violate the bound constraints):
 *
 *           ISFREE[i] = 0 if i-th value has a lower bound XLO[i]
 *                         and X[i] = XLO[i] and G[i] >= 0
 *                       0 if i-th value has an upper bound XHI[i]
 *                         and X[i] = XHI[i] and G[i] <= 0
 *                       1 otherwise
 *
 *       ISFREE needs only to be computed when TASK = OPL_TASK_FREEVARS.  If X
 *       has (some) bounds, the caller is responsible for applying the bounds
 *       to X before evaluating the function value F and the gradient G (i.e.,
 *       when TASK = OPL_TASK_FG), e.g.:
 *
 *           if (X[i] < XLO[i]) X[i] = XLO[i];
 *           if (X[i] > XHI[i]) X[i] = XHI[i];
 *
 *       If H is not specified (i.e., H is NULL) or if H[i] > 0 for all i such
 *       that ISFREE[i] is non-zero, then ISFREE is left unchanged.
 *
 *   H is an optional double precision array with length N provided by the
 *       caller and such that diag(H) is an approximation of the inverse of the
 *       Hessian matrix.  If H is NULL, then the inverse of the Hessian is
 *       approximated by a simple rescaling using Shanno & Phua formula.
 *       Otherwise, if ISFREE is NULL, all elements of H must be strictly
 *       greater than zero; else ISFREE[i] is set to zero if H[i] <= 0 (this is
 *       the only case where ISFREE is modified).  As for ISFREE, H needs only
 *       to be specifed the first time opl_vmlmb is called and when JOB=2.
 *
 *   TASK is the value returned by opl_vmlmb_setup and opl_vmlmb_iterate.  It
 *       can have one of the following values:
 *
 *           OPL_TASK_FG - caller must evaluate the function and gradient at X
 *               and call opl_vmlm_next.
 *
 *           OPL_TASK_FREEVARS - if variables are bounded, caller must
 *               determine the set of free variables for the current variables
 *               X and update IFREE accordingly.
 *
 *           OPL_TASK_NEWX - a new iterate has been computed.  The
 *               approximation X, function F, and gradient G are available for
 *               examination.
 *
 *           OPL_TASK_CONV - the search is successful.  The solution, function
 *               value and gradient are available in X, F and G.
 *
 *           OPL_TASK_WARN - VMLMB is not able to satisfy the convergence
 *               conditions.  The exit value of X contains the best
 *               approximation found so far.  Warning message is available in
 *               CSAVE.
 *
 *           OPL_TASK_ERROR then there is an error in the input arguments.
 *               Error message is available in CSAVE.
 *
 * The caller must not modify the workspace arrays CSAVE, ISAVE and DSAVE
 * between calls to opl_vmlmb_setup and further calls to opl_vmlmb_iterate.
 *
 * A typical invocation of VMLMB for unconstrained minimization has the
 * following outline:
 *
 *    // Choose a starting vector:
 *    for (i=0 ; i XMIN[i] || G[i] < 0) && (X[i] < XMAX[i] || G[i] > 0) */

extern opl_integer_t opl_bounds_check(opl_integer_t n, const double xmin[],
                                      const double xmax[]);
/*	Check correctness of bounds XMIN and XMAX (see opl_bounds_apply for
	the definition of the arguments).  This function returns -1 if the
	bounds are such that XMIN[i] <= XMAX[i] for all i=0,...,N-1;
	otherwise, the function return the value i of the first index (i >=
	0) for which the condition is violated. */

extern void opl_lower_bound_apply(opl_integer_t n, double x[], double xmin);
extern void opl_lower_bound_free(opl_integer_t n, opl_logical_t isfree[],
                                 const double x[], const double g[],
                                 double xmin);
/*	These routines are similar to opl_bounds_apply and opl_bounds_free but
	for a scalar lower bound XMIN that is the same for all parameters X. */

extern void opl_upper_bound_apply(opl_integer_t n, double x[], double xmax);
extern void opl_upper_bound_free(opl_integer_t n, opl_logical_t isfree[],
                                 const double x[], const double g[],
                                 double xmax);
/*	These routines are similar to opl_bounds_apply and opl_bounds_free but
	for a scalar upper bound XMAX that is the same for all parameters X. */

extern void opl_interval_apply(opl_integer_t n, double x[], double a, double b);
extern void opl_interval_free(opl_integer_t n, opl_logical_t isfree[],
                              const double x[], const double g[],
                              double a, double b);
/*	These routines are similar to opl_bounds_apply and opl_bounds_free
	but for a scalar lower bound XMIN=min(A,B) and a scalar upper bound
	XMAX=max(A,B) that are the same for all parameters X. */

/*---------------------------------------------------------------------------*/
/* UTILITIES */

extern double opl_dnrm2(opl_integer_t n, const double x[]);
/* Returns the Euclidian norm of X: sqrt(X'.X), taking care of overflows. */


extern void opl_dcopy(opl_integer_t n, const double x[], double y[]);
extern void opl_dcopy_free(opl_integer_t n, const double x[],
                           double y[], const opl_logical_t isfree[]);
/* Copy elements of X into Y.  Does Y[i] = X[i] for i=0,...,N-1.  If ISFREE
   is non-NULL, only elements for which ISFREE[i] is true (non-zero) are
   taken into account. */

extern void opl_daxpy(opl_integer_t n, double a,
		     const double x[], double y[]);
extern void opl_daxpy_free(opl_integer_t n, double a,
                           const double x[], double y[],
                           const opl_logical_t isfree[]);
/* Does Y[i] += A*X[i] for i=0,...,N-1.  If ISFREE is non-NULL, only
   elements for which ISFREE[i] is true (non-zero) are taken into
   account. */

extern double opl_ddot(opl_integer_t n, const double x[], const double y[]);
extern double opl_ddot_free(opl_integer_t n, const double x[],
                            const double y[], const opl_logical_t isfree[]);
/* Computes dot product of N-element vectors X and Y. If ISFREE is
   non-NULL, only elements for which ISFREE[i] is true (non-zero) are taken
   into account. */

extern void opl_dscal(opl_integer_t n, double a, double x[]);
/* Scales N-element vector X by scalar A. */

/*---------------------------------------------------------------------------*/
/* YORICK-LIKE ROUTINES */

extern int opl_anyof(opl_integer_t n, const double x[]);
/* Returns true (non-zero) if any element of X is non-zero; returns faslse
   (zero) otherwise. N is the number of elements of X. */

extern int opl_noneof(opl_integer_t n, const double x[]);
/* Returns true (non-zero) if all elements of X are zero; returns faslse
   (zero) otherwise. N is the number of elements of X. */

extern int opl_allof(opl_integer_t n, const double x[]);
/* Returns true (non-zero) if all elements of X are non-zero; returns faslse
   (zero) otherwise. N is the number of elements of X. */

/*---------------------------------------------------------------------------*/
_OPL_END_DECLS
#endif /* _OPTIMPACKLEGACY_H */
OptimPackLegacy-release-1.4.0/yorick/000077500000000000000000000000001303525653100174515ustar00rootroot00000000000000OptimPackLegacy-release-1.4.0/yorick/Makefile000066400000000000000000000073201303525653100211130ustar00rootroot00000000000000#
# Makefile --
#
# Makefile for YOPL (Yorick + OptimPackLegacy).
#
#------------------------------------------------------------------------------
#
# Copyright (c) 2003, 2016 Éric Thiébaut.
#
# This file is part of OptimPack .
#
# OptimPack 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.
#
# OptimPack 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 OptimPack (file "LICENSE" in the top source directory); if not,
# write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
#
#------------------------------------------------------------------------------

srcdir = .

# ---------------------------------------------------------------- Yorick setup
# these values filled in by `yorick -batch make.i`
Y_MAKEDIR=
Y_EXE=
Y_EXE_PKGS=
Y_EXE_HOME=
Y_EXE_SITE=
Y_HOME_PKG=

# ---------------------------------------------------------- optimization flags

# options for make command line, e.g. `make COPT=-g TGT=exe`
COPT=$(COPT_DEFAULT)
TGT=$(DEFAULT_TGT)

# ----------------------------------------------------- macros for this package

PKG_NAME=optimpacklegacy
PKG_I=optimpacklegacy.i

OBJS= opl_algebra.o opl_lnsrch.o opl_utils.o opl_vmlmb.o opl_yorick.o

# change to give the executable a name other than yorick
PKG_EXENAME=yorick

# `PKG_DEPLIBS=-Lsomedir -lsomelib` for dependencies of this package
PKG_DEPLIBS=
# set compiler (or rarely loader) flags specific to this package
PKG_CFLAGS= -DOPL_INTEGER=long
PKG_LDFLAGS=

# list of additional package names you want in PKG_EXENAME
# (typically Y_EXE_PKGS should be first here)
EXTRA_PKGS=$(Y_EXE_PKGS)

# list of additional files for clean
PKG_CLEAN=

# autoload file for this package, if any
PKG_I_START= optimpacklegacy-start.i

# non-pkg.i include files for this package, if any
PKG_I_EXTRA=

# ------------------------------------- standard targets and rules (in Makepkg)

# set macros Makepkg uses in target and dependency names
# DLL_TARGETS, LIB_TARGETS, EXE_TARGETS
# are any additional targets (defined below) prerequisite to
# the plugin library, archive library, and executable, respectively
PKG_I_DEPS=$(PKG_I)
Y_DISTMAKE=distmake

ifeq (,$(strip $(Y_MAKEDIR)))
$(info *** WARNING: Y_MAKEDIR not defined, you may run 'yorick -batch make.i' first)
else
include $(Y_MAKEDIR)/Make.cfg
include $(Y_MAKEDIR)/Makepkg
include $(Y_MAKEDIR)/Make$(TGT)
endif

# override macros Makepkg sets for rules and other macros
# Y_HOME and Y_SITE in Make.cfg may not be correct (e.g.- relocatable)
Y_HOME=$(Y_EXE_HOME)
Y_SITE=$(Y_EXE_SITE)

# reduce chance of yorick-1.5 corrupting this Makefile
MAKE_TEMPLATE = protect-against-1.5

# ------------------------------------------ targets and rules for this package

# Directory where are the OptimPack sources:
OPT_SRC = $(srcdir)/../src

# simple example:
#myfunc.o: myapi.h
# more complex example (also consider using PKG_CFLAGS above):
#myfunc.o: myapi.h myfunc.c
#	$(CC) $(CPPFLAGS) $(CFLAGS) -DMY_SWITCH -o $@ -c myfunc.c

opl_yorick.o: $(srcdir)/opl_yorick.c $(OPT_SRC)/optimpacklegacy.h
	$(CC) $(CPPFLAGS) -I$(OPT_SRC) $(CFLAGS) -o $@ -c $<

opl_%.o: $(OPT_SRC)/opl_%.c $(OPT_SRC)/opl_private.h $(OPT_SRC)/optimpacklegacy.h
	$(CC) $(CPPFLAGS) -I$(OPT_SRC) $(CFLAGS) -o $@ -c $<

# ------------------------------------------------------------- end of Makefile
OptimPackLegacy-release-1.4.0/yorick/opl_yorick.c000066400000000000000000000417771303525653100220070ustar00rootroot00000000000000/*
 * opl_yorick.c --
 *
 * Yorick interface for OptimPackLegacy library.
 *
 *-----------------------------------------------------------------------------
 *
 * Copyright (c) 2003, 2016 Éric Thiébaut.
 *
 * This file is part of OptimPack .
 *
 * OptimPack 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.
 *
 * OptimPack 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
 * OptimPack (file "LICENSE" in the top source directory); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *
 *-----------------------------------------------------------------------------
 */

#include 
#include 
#include 
#include 
#include 

/* Yorick API. */
#include 
#include 
#include 

#include "optimpacklegacy.h"

/* Define some macros to get rid of some GNU extensions when not compiling
   with GCC. */
#if ! (defined(__GNUC__) && __GNUC__ > 1)
#   define __attribute__(x)
#   define __inline__
#   define __FUNCTION__        ""
#   define __PRETTY_FUNCTION__ ""
#endif

#define TRUE  1
#define FALSE 0

PLUG_API void y_error(const char *) __attribute__ ((noreturn));
static void error(const char *, ...) __attribute__ ((noreturn));

/*---------------------------------------------------------------------------*/
/* PRIVATE FUNCTIONS AND DATA */

/* Indexes for fast parsing of keywords/members. */
static long index_of_dims = -1;
static long index_of_size = -1;
static long index_of_mem = -1;
static long index_of_task = -1;
static long index_of_evaluations = -1;
static long index_of_iterations = -1;
static long index_of_restarts = -1;
static long index_of_step = -1;
static long index_of_gnorm = -1;
static long index_of_fmin = -1;
static long index_of_fatol = -1;
static long index_of_frtol = -1;
static long index_of_sftol = -1;
static long index_of_sgtol = -1;
static long index_of_sxtol = -1;
static long index_of_delta = -1;
static long index_of_epsilon = -1;
static long index_of_status = -1;
static long index_of_reason = -1;

static void
error(const char* format, ...)
{
  char buffer[256];
  const size_t size = sizeof(buffer);
  va_list ap;
  size_t nchars;

  va_start(ap, format);
  nchars = vsnprintf(buffer, size, format, ap);
  va_end(ap);
  if (nchars >= size) {
    buffer[size - 6] = '[';
    buffer[size - 5] = '.';
    buffer[size - 4] = '.';
    buffer[size - 3] = '.';
    buffer[size - 2] = ']';
    buffer[size - 1] = '\0';
  }
  y_error(buffer);
}

/* Push a string on top of the stack. */
static void
push_string(const char* str)
{
  ypush_q(NULL)[0] = p_strcpy(str);
}

/* Define a Yorick global symbol with a long value. */
static void
define_long_const(const char* name, long value)
{
  ypush_long(value);
  yput_global(yget_global(name, 0), 0);
  yarg_drop(1);
}

/* Get Yorick type name. */
static const char*
type_name(int type)
{
  switch (type) {
  case Y_CHAR: return "char";
  case Y_SHORT: return "short";
  case Y_INT: return "int";
  case Y_LONG: return "long";
  case Y_FLOAT: return "float";
  case Y_DOUBLE: return "double";
  case Y_COMPLEX: return "complex";
  case Y_STRING: return "string";
  case Y_POINTER: return "pointer";
  case Y_STRUCT: return "struct";
  case Y_RANGE: return "range";
  case Y_VOID: return "void";
  case Y_FUNCTION: return "function";
  case Y_BUILTIN: return "builtin";
  case Y_STRUCTDEF: return "structdef";
  case Y_STREAM: return "stream";
  case Y_OPAQUE: return "opaque";
  default: return "";
  }
}

/* Get an array of given type and dimensions. */
static void*
get_array(int iarg, int type, const long dims[],
          const char* name, int nil_ok)
{
  int argtype = yarg_typeid(iarg);
  if (argtype == type) {
    long argdims[Y_DIMSIZE];
    long i, rank;
    void* ptr = ygeta_any(iarg, NULL, argdims, NULL);
    if (argdims[0] != (rank = dims[0])) {
      error("bad number of dimensions for argument `%s`", name);
    }
    for (i = 1; i <= rank; ++i) {
      if (argdims[i] != dims[i]) {
        error("bad dimension(s) for argument `%s`", name);
      }
    }
    return ptr;
  } else if (nil_ok && argtype == Y_VOID) {
    return NULL;
  } else {
    error("bad data type for argument `%s`", name);
  }
  error("argument `%s` must be a %ld-D array of `%s`%s",
        name, dims[0], type_name(type), (nil_ok ? " our nil" : ""));
  return NULL;
}

/* Get a dimension list from the stack. */
static long
get_dims(int iarg, long dims[])
{
  int type = yarg_typeid(iarg);
  if (type <= Y_LONG) {
    long j, n, ntot,  rank;
    long* arr = ygeta_l(iarg, &n, dims);
    if (dims[0] == 0 || (dims[0] == 1 && arr[0] == n - 1)) {
      if (dims[0] == 0) {
        /* Got a scalar dimension. */
        rank = 1;
        arr -= 1; /* offset for indexing with j */
      } else {
        /* Got a vector of dimensions. */
        if (n > Y_DIMSIZE) {
          y_error("too many dimensions");
        }
        rank = n - 1;
      }
      ntot = 1;
      dims[0] = rank;
      for (j = 1; j <= rank; ++j) {
        long len = arr[j];
        if (len < 1) {
          y_error("invalid dimension(s)");
        }
        dims[j] = len;
        ntot *= len;
      }
      return ntot;
    }
  } else if (type == Y_VOID) {
    dims[0] = 0;
    return 1;
  }
  y_error("invalid dimension list");
  return -1;
}

/* Function to call before critical code to lower the risk of being
   interrupted. */
static void
critical()
{
  if (p_signalling) {
    p_abort();
  }
}


/*---------------------------------------------------------------------------*/
/* IMPLEMENTATION OF VMLMB INSTANCE */

/* Virtual methods for a VMLMB object. */
static void vmlmb_free(void* ptr);
static void vmlmb_print(void* ptr);
static void vmlmb_eval(void* ptr, int argc);
static void vmlmb_extract(void* ptr, char* name);

/* VMLMB handle type. */
static struct y_userobj_t vmlmb_type = {
  "VMLMB workspace", vmlmb_free, vmlmb_print, vmlmb_eval, vmlmb_extract, NULL
};

/* VMLMB handle instance. (FIXME: save the dimensions as well). */
typedef struct _vmlmb_object {
  opl_vmlmb_workspace_t* ws;
  long n, m;
  long dims[Y_DIMSIZE];
} vmlmb_object_t;

static void
vmlmb_free(void* ptr)
{
  opl_vmlmb_destroy(((vmlmb_object_t*)ptr)->ws);
}

static void
vmlmb_print(void* ptr)
{
  char buffer[128];
  vmlmb_object_t* obj = (vmlmb_object_t*)ptr;
  long i, rank = obj->dims[0];
  sprintf(buffer, "%s with size=%ld, dims=[",
          vmlmb_type.type_name, obj->n);
  y_print(buffer, FALSE);
  for (i = 0; i <= rank; ++i) {
    sprintf(buffer, (i == 0 ? "%ld" : ",%ld"), obj->dims[i]);
    y_print(buffer, FALSE);
  }
  sprintf(buffer, "], mem=%ld, task=%d",
          obj->m, opl_vmlmb_get_task(obj->ws));
  y_print(buffer, TRUE);
}

static void
vmlmb_eval(void* ptr, int argc)
{
  ypush_nil();
}

static void
vmlmb_extract(void* ptr, char* name)
{
  vmlmb_object_t* obj = (vmlmb_object_t*)ptr;
  long index = yget_global(name, 0);
  if (index == index_of_iterations) {
    ypush_long(opl_vmlmb_get_iterations(obj->ws));
  } else if (index == index_of_evaluations) {
    ypush_long(opl_vmlmb_get_evaluations(obj->ws));
  } else if (index == index_of_restarts) {
    ypush_long(opl_vmlmb_get_restarts(obj->ws));
  } else if (index == index_of_task) {
    ypush_long(opl_vmlmb_get_task(obj->ws));
  } else if (index == index_of_step) {
    ypush_double(opl_vmlmb_get_step(obj->ws));
  } else if (index == index_of_gnorm) {
    ypush_double(opl_vmlmb_get_gnorm(obj->ws));
  } else if (index == index_of_fmin) {
    ypush_double(opl_vmlmb_get_fmin(obj->ws));
  } else if (index == index_of_fatol) {
    ypush_double(opl_vmlmb_get_fatol(obj->ws));
  } else if (index == index_of_frtol) {
    ypush_double(opl_vmlmb_get_frtol(obj->ws));
  } else if (index == index_of_sftol) {
    ypush_double(opl_vmlmb_get_sftol(obj->ws));
  } else if (index == index_of_sgtol) {
    ypush_double(opl_vmlmb_get_sgtol(obj->ws));
  } else if (index == index_of_sxtol) {
    ypush_double(opl_vmlmb_get_sxtol(obj->ws));
  } else if (index == index_of_delta) {
    ypush_double(opl_vmlmb_get_delta(obj->ws));
  } else if (index == index_of_epsilon) {
    ypush_double(opl_vmlmb_get_epsilon(obj->ws));
  } else if (index == index_of_size) {
    ypush_long(obj->n);
  } else if (index == index_of_mem) {
    ypush_long(obj->m);
  } else if (index == index_of_dims) {
    long i, rank = obj->dims[0];
    long dims[2];
    long* arr;
    dims[0] = 1;
    dims[1] = rank + 1;
    arr = ypush_l(dims);
    for (i = 0; i <= rank; ++i) {
      arr[i] = obj->dims[i];
    }
  } else if (index == index_of_status) {
    ypush_long(opl_vmlmb_get_status(obj->ws));
  } else if (index == index_of_reason) {
    push_string(opl_vmlmb_get_reason(obj->ws));
  } else {
    y_error("unknown member");
  }
}

static vmlmb_object_t*
get_vmlmb(int iarg)
{
  return (vmlmb_object_t*)yget_obj(iarg, &vmlmb_type);
}

/*---------------------------------------------------------------------------*/
/* BUILTIN FUNCTIONS */

void
Y_opl_vmlmb_create(int argc)
{
  long i, rank, m = -1, n = -1;
  long dims[Y_DIMSIZE];
  vmlmb_object_t* obj;
  int iarg;
  int fmin_iarg = -1;
  int fatol_iarg = -1;
  int frtol_iarg = -1;
  int sftol_iarg = -1;
  int sgtol_iarg = -1;
  int sxtol_iarg = -1;
  int delta_iarg = -1;
  int epsilon_iarg = -1;

  /* Parse arguments. */
  for (iarg = argc - 1; iarg >= 0; --iarg) {
    long index = yarg_key(iarg);
    if (index < 0) {
      /* Positional argument. */
      if (n == -1) {
        n = get_dims(iarg, dims);
      } else if (m == -1) {
        m = ygets_l(iarg);
        if (m <= 0) {
          y_error("invalid number of steps to memorize");
        }
        if (m > n) {
          m = n;
        }
      } else {
        y_error("too many arguments");
      }
    } else {
      /* Keyword argument (skip its value). */
      --iarg;
      if (index == index_of_fmin) {
        fmin_iarg = iarg;
      } else if (index == index_of_fatol) {
        fatol_iarg = iarg;
      } else if (index == index_of_frtol) {
        frtol_iarg = iarg;
      } else if (index == index_of_sftol) {
        sftol_iarg = iarg;
      } else if (index == index_of_sgtol) {
        sgtol_iarg = iarg;
      } else if (index == index_of_sxtol) {
        sxtol_iarg = iarg;
      } else if (index == index_of_delta) {
        delta_iarg = iarg;
      } else if (index == index_of_epsilon) {
        epsilon_iarg = iarg;
      } else {
        y_error("unsupported keyword");
      }
    }
  }
  if (n == -1) {
    y_error("missing dimension list of variables");
  }
  if (m == -1) {
    y_error("missing number of steps to memorize");
  }

  /* Create VMLMB instance. */
  obj = (vmlmb_object_t*)ypush_obj(&vmlmb_type, sizeof(vmlmb_object_t));
  critical();
  obj->ws = opl_vmlmb_create(n, m);
  if (obj->ws == NULL) {
    if (errno == ENOMEM) {
      y_error("insufficient memory");
    } else {
      y_error("unknown error");
    }
  }
  obj->n = n;
  obj->m = m;
  rank = dims[0];
  for (i = 0; i <= rank; ++i) {
    obj->dims[i] = dims[i];
  }

  /* Configure VMLMB instance (adding +1 to iarg's because an element has been
     pushed on top of the stack).. */
# define SET_ATTRIBUTE(name, invalid)                           \
  if (name##_iarg >= 0 && ! yarg_nil(name##_iarg + 1)) {        \
    double value = ygets_d(name##_iarg + 1);                    \
    if ((invalid) ||                                            \
        opl_vmlmb_set_##name(obj->ws, value) != OPL_SUCCESS) {  \
      y_error("invalid value for `" #name "`");                 \
    }                                                           \
  }
  SET_ATTRIBUTE(fmin, FALSE);
  SET_ATTRIBUTE(fatol, value < 0);
  SET_ATTRIBUTE(frtol, value < 0);
  SET_ATTRIBUTE(sftol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(sgtol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(sxtol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(delta, value < 0);
  SET_ATTRIBUTE(epsilon, value < 0);
# undef SET_ATTRIBUTE

}

void
Y_opl_vmlmb_configure(int argc)
{
  vmlmb_object_t* obj = NULL;
  int iarg;
  int ndrop = 0;
  int fmin_iarg = -1;
  int fatol_iarg = -1;
  int frtol_iarg = -1;
  int sftol_iarg = -1;
  int sgtol_iarg = -1;
  int sxtol_iarg = -1;
  int delta_iarg = -1;
  int epsilon_iarg = -1;

  /* Parse arguments. */
  for (iarg = argc - 1; iarg >= 0; --iarg) {
    long index = yarg_key(iarg);
    if (index < 0) {
      /* Positional argument. */
      ndrop += 1;
      if (obj == NULL) {
        obj = get_vmlmb(iarg);
        ndrop = 0;
      } else {
        y_error("too many arguments");
      }
    } else {
      /* Keyword argument (skip its value). */
      ndrop += 2;
      --iarg;
      if (index == index_of_fmin) {
        fmin_iarg = iarg;
      } else if (index == index_of_fatol) {
        fatol_iarg = iarg;
      } else if (index == index_of_frtol) {
        frtol_iarg = iarg;
      } else if (index == index_of_sftol) {
        sftol_iarg = iarg;
      } else if (index == index_of_sgtol) {
        sgtol_iarg = iarg;
      } else if (index == index_of_sxtol) {
        sxtol_iarg = iarg;
      } else if (index == index_of_delta) {
        delta_iarg = iarg;
      } else if (index == index_of_epsilon) {
        epsilon_iarg = iarg;
      } else {
        y_error("unsupported keyword");
      }
    }
  }
  if (obj == NULL) {
    y_error("missing VMLMB workspace");
  }

  /* Set attributes. */
# define SET_ATTRIBUTE(name, invalid)                           \
  if (name##_iarg >= 0 && ! yarg_nil(name##_iarg)) {            \
    double value = ygets_d(name##_iarg);                        \
    if ((invalid) ||                                            \
        opl_vmlmb_set_##name(obj->ws, value) != OPL_SUCCESS) {  \
      y_error("invalid value for `" #name "`");                 \
    }                                                           \
  }
  SET_ATTRIBUTE(fmin, FALSE);
  SET_ATTRIBUTE(fatol, value < 0);
  SET_ATTRIBUTE(frtol, value < 0);
  SET_ATTRIBUTE(sftol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(sgtol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(sxtol, value <= 0 || value >= 1);
  SET_ATTRIBUTE(delta, value < 0);
  SET_ATTRIBUTE(epsilon, value < 0);
# undef SET_ATTRIBUTE

  /* Manage to left WS on top of the stack. */
  if (ndrop > 0) {
    yarg_drop(ndrop);
  }
}

void
Y_opl_vmlmb_iterate(int argc)
{
  double f;
  vmlmb_object_t* obj;
  int* isfree;
  double* x;
  double* g;
  double* h;
  opl_task_t task;
  long fref;
  int iarg;

  if (argc < 4 || argc > 6) {
    y_error("expecting between 4 and 6 arguments");
  }
  iarg = argc;
  obj = get_vmlmb(--iarg);
  x = (double*)get_array(--iarg, Y_DOUBLE, obj->dims, "x", FALSE);
  fref = yget_ref(--iarg);
  if (fref < 0) {
    y_error("expecting a simple variable reference for argument `f`");
  }
  f = ygets_d(iarg);
  g = (double*)get_array(--iarg, Y_DOUBLE, obj->dims, "g", FALSE);
  if (argc >= 5) {
    isfree = (int*)get_array(--iarg, Y_INT, obj->dims, "isfree", TRUE);
  } else {
    isfree = NULL;
  }
  if (argc >= 6) {
    h = (double*)get_array(--iarg, Y_DOUBLE, obj->dims, "h", TRUE);
  } else {
    h = NULL;
  }
  task = opl_vmlmb_iterate(obj->ws, x, &f, g, isfree, h);
  ypush_double(f);
  yput_global(fref, 0);
  ypush_long(task);
}

void
Y_opl_vmlmb_restart(int argc)
{
  vmlmb_object_t* obj;

  if (argc != 1) {
    y_error("expecting exactly one argument");
  }
  obj = get_vmlmb(0);
  opl_vmlmb_restart(obj->ws);
  ypush_long(opl_vmlmb_get_task(obj->ws));
}

void
Y_opl_vmlmb_restore(int argc)
{
  double f;
  vmlmb_object_t* obj;
  double* x;
  double* g;
  long fref;
  int iarg;

  if (argc != 4) {
    y_error("expecting exactly 4 arguments");
  }
  iarg = argc;
  obj = get_vmlmb(--iarg);
  x = (double*)get_array(--iarg, Y_DOUBLE, obj->dims, "x", FALSE);
  fref = yget_ref(--iarg);
  if (fref < 0) {
    y_error("expecting a simple variable reference for argument `f`");
  }
  g = (double*)get_array(--iarg, Y_DOUBLE, obj->dims, "g", FALSE);
  opl_vmlmb_restore(obj->ws, x, &f, g);
  ypush_double(f);
  yput_global(fref, 0);
  ypush_long(opl_vmlmb_get_task(obj->ws));
}

void
Y__opl_init(int argc)
{
  /* Define constants. */
#define DEFINE_LONG_CONST(c) define_long_const(#c, c)
  DEFINE_LONG_CONST(OPL_TASK_START);
  DEFINE_LONG_CONST(OPL_TASK_FG);
  DEFINE_LONG_CONST(OPL_TASK_FREEVARS);
  DEFINE_LONG_CONST(OPL_TASK_NEWX);
  DEFINE_LONG_CONST(OPL_TASK_CONV);
  DEFINE_LONG_CONST(OPL_TASK_WARN);
  DEFINE_LONG_CONST(OPL_TASK_ERROR);
#undef DEFINE_LONG_CONST

  /* Define fast keyword/member indexes. */
#define INIT(s) if (index_of_##s == -1L) index_of_##s = yget_global(#s, 0)
  INIT(dims);
  INIT(size);
  INIT(mem);
  INIT(task);
  INIT(evaluations);
  INIT(iterations);
  INIT(restarts);
  INIT(step);
  INIT(gnorm);
  INIT(fmin);
  INIT(fatol);
  INIT(frtol);
  INIT(sftol);
  INIT(sgtol);
  INIT(sxtol);
  INIT(delta);
  INIT(epsilon);
  INIT(status);
  INIT(reason);
#undef INIT

  /* In case of... */
  ypush_nil();
}

OptimPackLegacy-release-1.4.0/yorick/optimpacklegacy-start.i000066400000000000000000000004211303525653100241270ustar00rootroot00000000000000autoload, "optimpacklegacy.i",
  opl_vmlmb,
  opl_vmlmb_configure,
  opl_vmlmb_create,
  opl_vmlmb_iterate,
  opl_vmlmb_restore,
  opl_vmlmb_restart,
  OPL_TASK_START,
  OPL_TASK_FG,
  OPL_TASK_FREEVARS,
  OPL_TASK_NEWX,
  OPL_TASK_CONV,
  OPL_TASK_WARN,
  OPL_TASK_ERROR;
OptimPackLegacy-release-1.4.0/yorick/optimpacklegacy-tests.i000066400000000000000000000644171303525653100241530ustar00rootroot00000000000000/*
 * optimpacklegacy-tests.i --
 *
 * Various tests from MINPACK suite for the optimization routines in
 * OptimPackLegacy extension for Yorick.
 *
 *-----------------------------------------------------------------------------
 *
 * This file is part of OptimPack .
 *
 * Copyright (c) 2003-2009, 2016 Éric Thiébaut.
 *
 * OptimPack 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.
 *
 * OptimPack 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
 * OptimPack (file "LICENSE" in the top source directory); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *
 *-----------------------------------------------------------------------------
 */

require, "optimpacklegacy.i";

#if 0
#include "optimpacklegacy-tests.i"
opl_runtests, "optimpacklegacy-tests.out.new";

// Since the CPU time may change, you can compare the outputs
// with:
//   sed -e 's/^\( *[0-9]* *[0-9]*\) *[^ ]*/\1/'
//
#endif

func opl_runtests(output)
{
  for (i = 1; i <= 18; ++i) {
    opl_test_um, prob=i, method=0, verb=1, output=output;
  }
}

local opl_rosenbrock_nevals;
opl_rosenbrock_nevals=0;

func opl_test_rosenbrock(nil, start=, method=, ndirs=, frtol=)
/* DOCUMENT opl_test_rosenbrock, ...;
     Test opl_driver with Rosenbrock function.

   SEE ALSO: opl_test_rosenbrock_func. */
{
  x = is_void(start) ? [0.0, 0.0] : start;
  return opl_driver(opl_test_rosenbrock_func,
                    (is_void(start) ? [0.0, 0.0] : start),
                    method=method, fmin=0.0, verb=1, ndirs=ndirs,
                    frtol=frtol);
}

func opl_test_rosenbrock_func(x, &g)
{
  // Rosenbrock:
  //    f  = 100*(x2 - x1^2)^2 + (1 - x1)^2
  x1 = x(1);
  u = x(2) - x1*x1;
  v = 1.0 - x1;
  f = 100.0*u*u + v*v;
  g = [-400.0*u*x1 - 2.0*v, 200.0*u];
  ++opl_rosenbrock_nevals;
  return f;
}

func opl_test_quad(x, &g)
{
  u = (x - [1.0, 1.0, 1.0]);
  w = [3.0, 7.0, 2.0];
  g = 2.0*w*u;
  return sum(w*u*u);
}

func opl_test_um(prob=, n=, method=, ndir=, verb=, factor=,
                maxiter=, maxeval=, frtol=, fatol=,
                sftol=, sgtol=, sxtol=,
                output=)
/* DOCUMENT opl_test_um(...)
     Check various optimization methods for eighteen nonlinear unconstrained
     minimization problems.

   SEE ALSO: optim_vmlm, optim_cgmn, minpack1_umobj. */
{
  /* Output array. */
  local result;

  /* Output stream. */
  if (! is_void(output)) {
    if (structof(output) == string) {
      output = open(output, "a");
    } else if (typeof(output) != "text_stream") {
      error, "bad value for keyword OUTPUT";
    }
  }

  /* Check compatibility of arguments N and PROB. */
  if (prob == 1) {
    name = "Helical valley function.";
    if (is_void(n)) n = 3;
    else if (n != 3) error, "N must be 3 for problem #1";
  } else if (prob == 2) {
    name = "Biggs exp6 function.";
    if (is_void(n)) n = 6;
    else if (n != 6) error, "N must be 6 for problem #2";
  } else if (prob == 3) {
    name = "Gaussian function.";
    if (is_void(n)) n = 3;
    else if (n != 3) error, "N must be 3 for problem #3";
  } else if (prob == 4) {
    name = "Powell badly scaled function.";
    if (is_void(n)) n = 2;
    else if (n != 2) error, "N must be 2 for problem #4";
  } else if (prob == 5) {
    name = "Box 3-dimensional function.";
    if (is_void(n)) n = 3;
    else if (n != 3) error, "N must be 3 for problem #5";
  } else if (prob == 6) {
    name = "Variably dimensioned function.";
    if (is_void(n)) n = 10;
    else if (n < 1) error, "N must be >= 1 in problem #6";
  } else if (prob == 7) {
    name = "Watson function.";
    msg = "N may be 2 or greater but is usually 6 or 9 for problem #7";
    if (is_void(n)) {
      write, msg;
      n = 6;
    } else if (n < 2) error, msg;
  } else if (prob == 8) {
    name = "Penalty function I.";
    if (is_void(n)) n = 10;
    else if (n < 1) error, "N must be >= 1 in problem #8";
  } else if (prob == 9) {
    name = "Penalty function II.";
    if (is_void(n)) n = 10;
    else if (n < 1) error, "N must be >= 1 in problem #9";
  } else if (prob == 10) {
    name = "Brown badly scaled function.";
    if (is_void(n)) n = 2;
    else if (n != 2) error, "N must be 2 for problem #10";
  } else if (prob == 11) {
    name = "Brown and Dennis function.";
    if (is_void(n)) n = 4;
    else if (n != 4) error, "N must be 4 for problem #11";
  } else if (prob == 12) {
    name = "Gulf research and development function.";
    if (is_void(n)) n = 3;
    else if (n != 3) error, "N must be 3 for problem #12";
  } else if (prob == 13) {
    name = "Trigonometric function.";
    if (is_void(n)) n = 10;
    else if (n < 1) error, "N must be >= 1 in problem #13";
  } else if (prob == 14) {
    name = "Extended Rosenbrock function.";
    if (is_void(n)) n = 10;
    else if (n < 1 || n%2 != 0)
      error, "N must be a multiple of 2 in problem #14";
  } else if (prob == 15) {
    name = "Extended Powell function.";
    if (is_void(n)) n = 12;
    else if (n < 1 || n%4 != 0)
      error, "N must be a multiple of 4 in problem #15";
  } else if (prob == 16) {
    name = "Beale function.";
    if (is_void(n)) n = 2;
    else if (n != 2) error, "N must be 2 for problem #16";
  } else if (prob == 17) {
    name = "Wood function.";
    if (is_void(n)) n = 4;
    else if (n != 4) error, "N must be 4 for problem #17";
  } else if (prob == 18) {
    name = "Chebyquad function.";
    if (is_void(n)) n = 25;
    else if (n<1 || n>50) error, "N must be <=50 for problem #18";
  } else error, "PROB must be an integer between 1 and 18";

  /* Maximum number of iterations and function evaluations. */
  if (is_void(maxiter)) maxiter = 100*n;
  if (is_void(maxeval)) maxeval = 10*maxiter;

  /* Starting vector. */
  x = minpack1_umipt(n, prob, factor);
  dims = dimsof(x);

  /* Choose minimization method. */
  if (! method) {
    /* Variable metric. */
    method = 0;
    if (is_void(ndir)) ndir = n;
    method_name = swrite(format="Limited Memory BFGS (VMLM with NDIR=%d)",
                         ndir);
    ws = opl_vmlmb_create(dimsof(x), ndir, fmin=0.0,
                          fatol=fatol, frtol=frtol,
                          sftol=sftol, sgtol=sgtol, sxtol=sxtol);
  } else {
    error, "bad METHOD";
  }
  step = 0.0;
  eval = iter = 0;
  elapsed = array(double, 3);
  timer, elapsed;
  cpu_start = elapsed(1);
  task = ws.task;
  for (;;) {
    if (task == OPL_TASK_FG) {
      /* Evaluate function and gradient. */
      f = minpack1_umobj(x, prob);
      g = minpack1_umgrd(x, prob);
      ++eval;
    }

    /* Check for convergence. */
    if (task >= OPL_TASK_NEWX) {
      too_many_eval = (maxeval >= 1 && eval > maxeval);
      too_many_iter = (maxiter >= 1 && iter > maxiter);
      timer, elapsed;
      cpu = elapsed(1) - cpu_start;
      gnorm = ws.gnorm; // sqrt(sum(g*g));
      if (verb) {
        if (eval == 1) {
          write, output, format="#\n# Problem %d (N=%d): %s\n",
            prob, n, name;
          write, output, format="# Method %d (NDIR=%d): %s\n#\n",
            method, ndir, method_name;
          write, output, format="# %s\n# %s\n",
            "ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN",
            "---------------------------------------------------------------";
        }
        write, output, format=" %5d %5d %10.3f  %+-24.15e%-9.1e%-9.1e\n",
          iter, eval, 1e3*cpu, f, gnorm, step;
      }
      if (! am_subroutine()) grow, result, [[iter, eval, 1e3*cpu, f,
                                             gnorm, step]];
      if (task >= OPL_TASK_CONV) {
        msg = ws.reason;
        break;
      }
      if (maxiter >= 0 && iter > maxiter) {
        task = OPL_TASK_WARN;
        msg = swrite(format="warning: too many iterations (%d)\n", iter);
        break;
      }
      if (maxeval >= 0 && eval > maxeval) {
        task = OPL_TASK_WARN;
        msg = swrite(format="warning: too many function evaluation (%d)\n",
                     eval);
        break;
      }
    }

    /* Call optimizer. */
    task = opl_vmlmb_iterate(ws, x, f, g);
    iter = ws.iterations;
    step = ws.step;
  }

  write, output, format=(verb?"# %s\n#\n":"*** %s\n"), msg;
  return result;
}

/*---------------------------------------------------------------------------*/
/* NONLINEAR UNCONSTRAINED MINIMIZATION PROBLEMS
 *
 *   This suite of problems is taken from the MINPACK Project.
 *
 *   HISTORY:
 *     - Argonne National Laboratory. MINPACK Project. March 1980.
 *       Burton S. Garbow, Kenneth E. Hillstrom, Jorge J. More.
 *     - Conversion to Yorick. November 2001. Eric Thiebaut.
 */
_um_y = [9.0e-4,   4.4e-3,   1.75e-2,  5.4e-2,   1.295e-1,
         2.42e-1,  3.521e-1, 3.989e-1, 3.521e-1, 2.42e-1,
         1.295e-1, 5.4e-2,   1.75e-2,  4.4e-3,   9.0e-4];

func minpack1_umobj(x, prob)
/* DOCUMENT minpack1_umobj(x, prob)
     Returns  the objective functions  of eighteen  nonlinear unconstrained
     minimization problems.  X  is the parameter array: a  vector of length
     N, PROB is the problem number (a positive integer between 1 and 18).

     The  values  of  N  for  functions 1,2,3,4,5,10,11,12,16  and  17  are
     3,6,3,2,3,2,4,3,2 and 4, respectively.  For  function 7, n may be 2 or
     greater but is usually 6 or 9.  For functions 6,8,9,13,14,15 and 18, N
     may be variable,  however it must be even for  function 14, a multiple
     of 4 for function 15, and not greater than 50 for function 18.

   SEE ALSO: minpack1_umgrd, minpack1_umipt. */
{
  n = numberof(x);

  /* Function routine selector. */
  if (prob == 1) {
    /* Helical valley function. */
    tpi = 8.0*atan(1.0);
    if      (x(1) > 0.0) th = atan(x(2)/x(1))/tpi;
    else if (x(1) < 0.0) th = atan(x(2)/x(1))/tpi + 0.5;
    else                 th = (x(2) >= 0.0 ? 0.25 : -0.25);
    arg = x(1)*x(1) + x(2)*x(2);
    r = sqrt(arg);
    t = x(3) - 10.0*th;
    f = 100.0*(t*t + (r - 1.0)*(r - 1.0)) + x(3)*x(3);
    return f;
  } else if (prob == 2) {
    /* Biggs exp6 function. */
    f = 0.0;
    for (i=1 ; i<=13 ; i+=1) {
      d1 = double(i)/10.0;
      d2 = exp(-d1) - 5.0*exp(-10.0*d1) + 3.0*exp(-4.0*d1);
      s1 = exp(-d1*x(1));
      s2 = exp(-d1*x(2));
      s3 = exp(-d1*x(5));
      t = x(3)*s1 - x(4)*s2 + x(6)*s3 - d2;
      f += t*t;
    }
    return f;
  } else if (prob == 3) {
    /* Gaussian function. */
    f = 0.0;
    for (i=1 ; i<=15 ; i+=1) {
      d1 = 0.5*double(i-1);
      d2 = 3.5 - d1 - x(3);
      arg = -0.5*x(2)*d2*d2;
      r = exp(arg);
      t = x(1)*r - _um_y(i);
      f += t*t;
    }
    return f;
  } else if (prob == 4) {
    /* Powell badly scaled function. */
    t1 = 1e4*x(1)*x(2) - 1.0;
    s1 = exp(-x(1));
    s2 = exp(-x(2));
    t2 = s1 + s2 - 1.0001;
    f = t1*t1 + t2*t2;
    return f;
  } else if (prob == 5) {
    /* Box 3-dimensional function. */
    f = 0.0;
    for (i=1 ; i<=10 ; i+=1) {
      d1 = double(i);
      d2 = d1/10.0;
      s1 = exp(-d2*x(1));
      s2 = exp(-d2*x(2));
      s3 = exp(-d2) - exp(-d1);
      t = s1 - s2 - s3*x(3);
      f += t*t;
    }
    return f;
  } else if (prob == 6) {
    /* Variably dimensioned function. */
    t1 = 0.0;
    t2 = 0.0;
    for (j=1 ; j<=n ; j+=1) {
      t1 += double(j)*(x(j) - 1.0);
      t = x(j) - 1.0;
      t2 += t*t;
    }
    t = t1*t1;
    f = t2 + t*(1.0 + t);
    return f;
  } else if (prob == 7) {
    /* Watson function. */
    f = 0.0;
    for (i=1 ; i<=29 ; i+=1) {
      d1 = double(i)/29.0;
      s1 = 0.0;
      d2 = 1.0;
      for (j=2 ; j<=n ; j+=1) {
	s1 += double(j-1)*d2*x(j);
	d2 = d1*d2;
      }
      s2 = 0.0;
      d2 = 1.0;
      for (j=1 ; j<=n ; j+=1) {
	s2 += d2*x(j);
	d2 = d1*d2;
      }
      t = s1 - s2*s2 - 1.0;
      f += t*t;
    }
    t = x(1)*x(1);
    t1 = x(2) - t - 1.0;
    f += t + t1*t1;
    return f;
  } else if (prob == 8) {
    /* Penalty function I. */
    t1 = -0.25;
    t2 = 0.0;
    for (j=1 ; j<=n ; j+=1) {
      t1 += x(j)*x(j);
      t = x(j) - 1.0;
      t2 += t*t;
    }
    f = 1e-5*t2 + t1*t1;
    return f;
  } else if (prob == 9) {
    /* Penalty function II. */
    t1 = -1.0;
    t2 = 0.0;
    t3 = 0.0;
    d1 = exp(0.1);
    d2 = 1.0;
    s2 = 0.0; /* avoid compiler warning about `s2' used uninitialized */
    for (j=1 ; j<=n ; j+=1) {
      t1 += double(n-j+1)*x(j)*x(j);
      s1 = exp(x(j)/10.0);
      if (j > 1) {
	s3 = s1 + s2 - d2*(d1 + 1.0);
	t2 += s3*s3;
	t = (s1 - 1.0/d1);
	t3 += t*t;
      }
      s2 = s1;
      d2 = d1*d2;
    }
    t = (x(1) - 0.2);
    f = 1e-5*(t2 + t3) + t1*t1 + t*t;
    return f;
  } else if (prob == 10) {
    /* Brown badly scaled function. */
    t1 = x(1) - 1e6;
    t2 = x(2) - 2e-6;
    t3 = x(1)*x(2) - 2.0;
    f = t1*t1 + t2*t2 + t3*t3;
    return f;
  } else if (prob == 11) {
    /* Brown and Dennis function. */
    f = 0.0;
    for (i=1 ; i<=20 ; i+=1) {
      d1 = double(i)/5.0;
      d2 = sin(d1);
      t1 = x(1) + d1*x(2) - exp(d1);
      t2 = x(3) + d2*x(4) - cos(d1);
      t = t1*t1 + t2*t2;
      f += t*t;
    }
    return f;
  } else if (prob == 12) {
    /* Gulf research and development function. */
    f = 0.0;
    d1 = 2.0/3.0;
    for (i=1 ; i<=99 ; i+=1) {
      arg = double(i)/100.0;
      r = (-50.0*log(arg))^d1 + 25.0 - x(2);
      t1 = (abs(r)^x(3))/x(1);
      t2 = exp(-t1);
      t = t2 - arg;
      f += t*t;
    }
    return f;
  } else if (prob == 13) {
    /* Trigonometric function. */
    s1 = 0.0;
    for (j=1 ; j<=n ; j+=1) {
      s1 += cos(x(j));
    }
    f = 0.0;
    for (j=1 ; j<=n ; j+=1) {
      t = double(n+j) - sin(x(j)) - s1 - double(j)*cos(x(j));
      f += t*t;
    }
    return f;
  } else if (prob == 14) {
    /* Extended Rosenbrock function. */
    f = 0.0;
    for (j=1 ; j<=n ; j+=2) {
      t1 = 1.0 - x(j);
      t2 = 10.0*(x(j+1) - x(j)*x(j));
      f += t1*t1 + t2*t2;
    }
    return f;
  } else if (prob == 15) {
    /* Extended Powell function. */
    f = 0.0;
    for (j=1 ; j<=n ; j+=4) {
      t = x(j) + 10.0*x(j+1);
      t1 = x(j+2) - x(j+3);
      s1 = 5.0*t1;
      t2 = x(j+1) - 2.0*x(j+2);
      s2 = t2*t2*t2;
      t3 = x(j) - x(j+3);
      s3 = 10.0*t3*t3*t3;
      f += t*t + s1*t1 + s2*t2 + s3*t3;
    }
    return f;
  } else if (prob == 16) {
    /* Beale function. */
    s1 = 1.0 - x(2);
    t1 = 1.5 - x(1)*s1;
    s2 = 1.0 - x(2)*x(2);
    t2 = 2.25 - x(1)*s2;
    s3 = 1.0 - x(2)*x(2)*x(2);
    t3 = 2.625 - x(1)*s3;
    f = t1*t1 + t2*t2 + t3*t3;
    return f;
  } else if (prob == 17) {
    /* Wood function. */
    s1 = x(2) - x(1)*x(1);
    s2 = 1.0 - x(1);
    s3 = x(2) - 1.0;
    t1 = x(4) - x(3)*x(3);
    t2 = 1.0 - x(3);
    t3 = x(4) - 1.0;
    f = 100.0*s1*s1 + s2*s2 + 90.0*t1*t1 + t2*t2 + \
      10.0*(s3 + t3)*(s3 + t3) + (s3 - t3)*(s3 - t3)/10.0;
    return f;
  } else if (prob == 18) {
    /* Chebyquad function. */
    fvec = array(0.0, n);
    for (j=1 ; j<=n ; j+=1) {
      t1 = 1.0;
      t2 = 2.0*x(j) - 1.0;
      t = 2.0*t2;
      for (i=1 ; i<=n ; i+=1) {
	fvec(i) += t2;
	th = t*t2 - t1;
	t1 = t2;
	t2 = th;
      }
    }
    f = 0.0;
    d1 = 1.0/double(n);
    iev = -1;
    for (i=1 ; i<=n ; i+=1) {
      t = d1*fvec(i);
      if (iev > 0) t += 1.0/(double(i)*double(i) - 1.0);
      f += t*t;
      iev = -iev;
    }
    return f;
  }
  return 0.0;
}

func minpack1_umgrd(x, prob)
/* DOCUMENT minpack1_umgrd(x, prob)
     Returns  the  gradient  vectors  of eighteen  nonlinear  unconstrained
     minimization problems. The problem  dimensions are as described in the
     prologue comments of minpack1_umobj.

   SEE ALSO: minpack1_umobj, minpack1_umipt. */
{
  n = numberof(x);
  g = array(double, n);

  /* Gradient routine selector. */
  if (prob == 1) {
    /* Helical valley function. */
    tpi = 8.0*atan(1.0);
    if      (x(1) > 0.0) th = atan(x(2)/x(1))/tpi;
    else if (x(1) < 0.0) th = atan(x(2)/x(1))/tpi + 0.5;
    else                 th = (x(2) >= 0.0 ? 0.25 : -0.25);
    arg = x(1)*x(1) + x(2)*x(2);
    r = sqrt(arg);
    t = x(3) - 10.0*th;
    s1 = 10.0*t/(tpi*arg);
    g(1) = 200.0*(x(1) - x(1)/r + x(2)*s1);
    g(2) = 200.0*(x(2) - x(2)/r - x(1)*s1);
    g(3) = 2.0*(100.0*t + x(3));
  } else if (prob == 2) {
    /* Biggs exp6 function. */
    for (j=1 ; j<=6 ; ++j) g(j) = 0.0;
    for (i=1 ; i<=13 ; ++i) {
      d1 = double(i)/10.0;
      d2 = exp(-d1) - 5.0*exp(-10.0*d1) + 3.0*exp(-4.0*d1);
      s1 = exp(-d1*x(1));
      s2 = exp(-d1*x(2));
      s3 = exp(-d1*x(5));
      t = x(3)*s1 - x(4)*s2 + x(6)*s3 - d2;
      th = d1*t;
      g(1) = g(1) - s1*th;
      g(2) = g(2) + s2*th;
      g(3) = g(3) + s1*t;
      g(4) = g(4) - s2*t;
      g(5) = g(5) - s3*th;
      g(6) = g(6) + s3*t;
    }
    g(1) = 2.0*x(3)*g(1);
    g(2) = 2.0*x(4)*g(2);
    g(3) = 2.0*g(3);
    g(4) = 2.0*g(4);
    g(5) = 2.0*x(6)*g(5);
    g(6) = 2.0*g(6);
  } else if (prob == 3) {
    /* Gaussian function. */
    g(1) = 0.0;
    g(2) = 0.0;
    g(3) = 0.0;
    for (i=1 ; i<=15 ; ++i) {
      d1 = 0.5*double(i-1);
      d2 = 3.5 - d1 - x(3);
      arg = -0.5*x(2)*d2*d2;
      r = exp(arg);
      t = x(1)*r - _um_y(i);
      s1 = r*t;
      s2 = d2*s1;
      g(1) = g(1) + s1;
      g(2) = g(2) - d2*s2;
      g(3) = g(3) + s2;
    }
    g(1) = 2.0*g(1);
    g(2) = x(1)*g(2);
    g(3) = 2.0*x(1)*x(2)*g(3);
  } else if (prob == 4) {
    /* Powell badly scaled function. */
    t1 = 1e4*x(1)*x(2) - 1.0;
    s1 = exp(-x(1));
    s2 = exp(-x(2));
    t2 = s1 + s2 - 1.0001;
    g(1) = 2.0*(1e4*x(2)*t1 - s1*t2);
    g(2) = 2.0*(1e4*x(1)*t1 - s2*t2);
  } else if (prob == 5) {
    /* Box 3-dimensional function. */
    g(1) = 0.0;
    g(2) = 0.0;
    g(3) = 0.0;
    for (i=1 ; i<=10 ; ++i) {
      d1 = double(i);
      d2 = d1/10.0;
      s1 = exp(-d2*x(1));
      s2 = exp(-d2*x(2));
      s3 = exp(-d2) - exp(-d1);
      t = s1 - s2 - s3*x(3);
      th = d2*t;
      g(1) = g(1) - s1*th;
      g(2) = g(2) + s2*th;
      g(3) = g(3) - s3*t;
    }
    g(1) = 2.0*g(1);
    g(2) = 2.0*g(2);
    g(3) = 2.0*g(3);
  } else if (prob == 6) {
    /* Variably dimensioned function. */
    t1 = 0.0;
    for (j=1 ; j<=n ; ++j) {
      t1 += double(j)*(x(j) - 1.0);
    }
    t = t1*(1.0 + 2.0*t1*t1);
    for (j=1 ; j<=n ; ++j) {
      g(j) = 2.0*(x(j) - 1.0 + double(j)*t);
    }
  } else if (prob == 7) {
    /* Watson function. */
    for (j=1 ; j<=n ; ++j) {
      g(j) = 0.0;
    }
    for (i=1 ; i<=29 ; ++i) {
      d1 = double(i)/29.0;
      s1 = 0.0;
      d2 = 1.0;
      for (j=2 ; j<=n ; ++j) {
	s1 += double(j-1)*d2*x(j);
	d2 = d1*d2;
      }
      s2 = 0.0;
      d2 = 1.0;
      for (j=1 ; j<=n ; ++j) {
	s2 += d2*x(j);
	d2 = d1*d2;
      }
      t = s1 - s2*s2 - 1.0;
      s3 = 2.0*d1*s2;
      d2 = 2.0/d1;
      for (j=1 ; j<=n ; ++j) {
	g(j) = g(j) + d2*(double(j-1) - s3)*t;
	d2 = d1*d2;
      }
    }
    t1 = x(2) - x(1)*x(1) - 1.0;
    g(1) = g(1) + x(1)*(2.0 - 4.0*t1);
    g(2) = g(2) + 2.0*t1;
  } else if (prob == 8) {
    /* Penalty function I. */
    t1 = -0.25;
    for (j=1 ; j<=n ; ++j) {
      t1 += x(j)*x(j);
    }
    d1 = 2.0*1e-5;
    th = 4.0*t1;
    for (j=1 ; j<=n ; ++j) {
      g(j) = d1*(x(j) - 1.0) + x(j)*th;
    }
  } else if (prob == 9) {
    /* Penalty function II. */
    s2 = 0.0; /* avoid compiler warning about `s2' used uninitialized */
    t1 = -1.0;
    for (j=1 ; j<=n ; ++j) {
      t1 += double(n-j+1)*x(j)*x(j);
    }
    d1 = exp(0.1);
    d2 = 1.0;
    th = 4.0*t1;
    for (j=1 ; j<=n ; ++j) {
      g(j) = double(n-j+1)*x(j)*th;
      s1 = exp(x(j)/10.0);
      if (j > 1) {
	s3 = s1 + s2 - d2*(d1 + 1.0);
	g(j) = g(j) + 1e-5*s1*(s3 + s1 - 1.0/d1)/5.0;
	g(j-1) = g(j-1) + 1e-5*s2*s3/5.0;
      }
      s2 = s1;
      d2 = d1*d2;
    }
    g(1) = g(1) + 2.0*(x(1) - 0.2);
  } else if (prob == 10) {
    /* Brown badly scaled function. */
    t1 = x(1) - 1e6;
    t2 = x(2) - 2e-6;
    t3 = x(1)*x(2) - 2.0;
    g(1) = 2.0*(t1 + x(2)*t3);
    g(2) = 2.0*(t2 + x(1)*t3);
  } else if (prob == 11) {
    /* Brown and Dennis function. */
    g(1) = 0.0;
    g(2) = 0.0;
    g(3) = 0.0;
    g(4) = 0.0;
    for (i=1 ; i<=20 ; ++i) {
      d1 = double(i)/5.0;
      d2 = sin(d1);
      t1 = x(1) + d1*x(2) - exp(d1);
      t2 = x(3) + d2*x(4) - cos(d1);
      t = t1*t1 + t2*t2;
      s1 = t1*t;
      s2 = t2*t;
      g(1) = g(1) + s1;
      g(2) = g(2) + d1*s1;
      g(3) = g(3) + s2;
      g(4) = g(4) + d2*s2;
    }
    g(1) = 4.0*g(1);
    g(2) = 4.0*g(2);
    g(3) = 4.0*g(3);
    g(4) = 4.0*g(4);
  } else if (prob == 12) {
    /* Gulf research and development function. */
    g(1) = 0.0;
    g(2) = 0.0;
    g(3) = 0.0;
    d1 = 2.0/3.0;
    for (i=1 ; i<=99 ; ++i) {
      arg = double(i)/100.0;
      r = (-50.0*log(arg))^d1 + 25.0 - x(2);
      t1 = (abs(r)^x(3))/x(1);
      t2 = exp(-t1);
      t = t2 - arg;
      s1 = t1*t2*t;
      g(1) = g(1) + s1;
      g(2) = g(2) + s1/r;
      g(3) = g(3) - s1*log(abs(r));
    }
    g(1) = 2.0*g(1)/x(1);
    g(2) = 2.0*x(3)*g(2);
    g(3) = 2.0*g(3);
  } else if (prob == 13) {
    /* Trigonometric function. */
    s1 = 0.0;
    for (j=1 ; j<=n ; ++j) {
      g(j) = cos(x(j));
      s1 += g(j);
    }
    s2 = 0.0;
    for (j=1 ; j<=n ; ++j) {
      th = sin(x(j));
      t = double(n+j) - th - s1 - double(j)*g(j);
      s2 += t;
      g(j) = (double(j)*th - g(j))*t;
    }
    for (j=1 ; j<=n ; ++j) {
      g(j) = 2.0*(g(j) + sin(x(j))*s2);
    }
  } else if (prob == 14) {
    /* Extended Rosenbrock function. */
    for (j=1 ; j<=n ; j+=2) {
      t1 = 1.0 - x(j);
      g(j+1) = 200.0*(x(j+1) - x(j)*x(j));
      g(j) = -2.0*(x(j)*g(j+1) + t1);
    }
  } else if (prob == 15) {
    /* Extended Powell function. */
    for (j=1 ; j<=n ; j+=4) {
      t = x(j) + 10.0*x(j+1);
      t1 = x(j+2) - x(j+3);
      s1 = 5.0*t1;
      t2 = x(j+1) - 2.0*x(j+2);
      s2 = 4.0*t2*t2*t2;
      t3 = x(j) - x(j+3);
      s3 = 20.0*t3*t3*t3;
      g(j) = 2.0*(t + s3);
      g(j+1) = 20.0*t + s2;
      g(j+2) = 2.0*(s1 - s2);
      g(j+3) = -2.0*(s1 + s3);
    }
  } else if (prob == 16) {
    /* Beale function. */
    s1 = 1.0 - x(2);
    t1 = 1.5 - x(1)*s1;
    s2 = 1.0 - x(2)*x(2);
    t2 = 2.25 - x(1)*s2;
    s3 = 1.0 - x(2)*x(2)*x(2);
    t3 = 2.625 - x(1)*s3;
    g(1) = -2.0*(s1*t1 + s2*t2 + s3*t3);
    g(2) = 2.0*x(1)*(t1 + x(2)*(2.0*t2 + 3.0*x(2)*t3));
  } else if (prob == 17) {
    /* Wood function. */
    s1 = x(2) - x(1)*x(1);
    s2 = 1.0 - x(1);
    s3 = x(2) - 1.0;
    t1 = x(4) - x(3)*x(3);
    t2 = 1.0 - x(3);
    t3 = x(4) - 1.0;
    g(1) = -2.0*(200.0*x(1)*s1 + s2);
    g(2) = 200.0*s1 + 20.2*s3 + 19.8*t3;
    g(3) = -2.0*(180.0*x(3)*t1 + t2);
    g(4) = 180.0*t1 + 20.2*t3 + 19.8*s3;
  } else if (prob == 18) {
    /* Chebyquad function. */
    fvec = array(0.0, n);
    for (j=1 ; j<=n ; ++j) {
      t1 = 1.0;
      t2 = 2.0*x(j) - 1.0;
      t = 2.0*t2;
      for (i=1 ; i<=n ; ++i) {
	fvec(i) += t2;
	th = t*t2 - t1;
	t1 = t2;
	t2 = th;
      }
    }
    d1 = 1.0/double(n);
    iev = -1;
    for (i=1 ; i<=n ; ++i) {
      fvec(i) *= d1;
      if (iev > 0) fvec(i) += 1.0/(double(i)*double(i) - 1.0);
      iev = -iev;
    }
    for (j=1 ; j<=n ; ++j) {
      g(j) = 0.0;
      t1 = 1.0;
      t2 = 2.0*x(j) - 1.0;
      t = 2.0*t2;
      s1 = 0.0;
      s2 = 2.0;
      for (i=1 ; i<=n ; ++i) {
	g(j) = g(j) + fvec(i)*s2;
	th = 4.0*t2 + t*s2 - s1;
	s1 = s2;
	s2 = th;
	th = t*t2 - t1;
	t1 = t2;
	t2 = th;
      }
    }
    d2 = 2.0*d1;
    for (j=1 ; j<=n ; ++j) g(j) *= d2;
  }
  return g;
}

func minpack1_umipt(n, prob, factor)
/* DOCUMENT minpack1_umipt(n, prob, factor)
     Returns  the standard  starting points  for the  functions  defined by
     subroutine  minpack1_umobj.  The  function  returns a  vector  X of  N
     elements, X is a multiple  (times FACTOR, default 1.0) of the standard
     starting point.  For the  seventh function the standard starting point
     is 0.0,  so in this  case, if FACTOR  is not unity, then  the function
     returns  X  filled with  FACTOR.   PROB has  the  same  meaning as  in
     minpack1_umobj.

   SEE ALSO: minpack1_umobj, minpack1_umipt. */
{
  if (is_void(factor)) factor = 1.0;
  x = array(double, n);

  /* Selection of initial point. */
  if (prob == 1) {
    /* Helical valley function. */
    x(1) = -1.0;
    x(2) = 0.0;
    x(3) = 0.0;
  } else if (prob == 2) {
    /* Biggs exp6 function. */
    x(1) = 1.0;
    x(2) = 2.0;
    x(3) = 1.0;
    x(4) = 1.0;
    x(5) = 1.0;
    x(6) = 1.0;
  } else if (prob == 3) {
    /* Gaussian function. */
    x(1) = 0.4;
    x(2) = 1.0;
    x(3) = 0.0;
  } else if (prob == 4) {
    /* Powell badly scaled function. */
    x(1) = 0.0;
    x(2) = 1.0;
  } else if (prob == 5) {
    /* Box 3-dimensional function. */
    x(1) = 0.0;
    x(2) = 10.0;
    x(3) = 20.0;
  } else if (prob == 6) {
    /* Variably dimensioned function. */
    h = 1.0/double(n);
    for (j=1 ; j<=n ; ++j) x(j) = 1.0 - double(j)*h;
  } else if (prob == 7) {
    /* Watson function. */
    for (j=1 ; j<=n ; ++j) x(j) = 0.0;
  } else if (prob == 8) {
    /* Penalty function I. */
    for (j=1 ; j<=n ; ++j) x(j) = double(j);
  } else if (prob == 9) {
    /* Penalty function II. */
    for (j=1 ; j<=n ; ++j) x(j) = 0.5;
  } else if (prob == 10) {
    /* Brown badly scaled function. */
    x(1) = 1.0;
    x(2) = 1.0;
  } else if (prob == 11) {
    /* Brown and Dennis function. */
    x(1) = 25.0;
    x(2) = 5.0;
    x(3) = -5.0;
    x(4) = -1.0;
  } else if (prob == 12) {
    /* Gulf research and development function. */
    x(1) = 5.0;
    x(2) = 2.5;
    x(3) = 0.15;
  } else if (prob == 13) {
    /* Trigonometric function. */
    h = 1.0/double(n);
    for (j=1 ; j<=n ; ++j) x(j) = h;
  } else if (prob == 14) {
    /* Extended Rosenbrock function. */
    for (j=1 ; j<=n ; j+=2) {
      x(j) = -1.2;
      x(j+1) = 1.0;
    }
  } else if (prob == 15) {
    /* Extended Powell singular function. */
    for (j=1 ; j<=n ; j+=4) {
      x(j) = 3.0;
      x(j+1) = -1.0;
      x(j+2) = 0.0;
      x(j+3) = 1.0;
    }
  } else if (prob == 16) {
    /* Beale function. */
    x(1) = 1.0;
    x(2) = 1.0;
  } else if (prob == 17) {
    /* Wood function. */
    x(1) = -3.0;
    x(2) = -1.0;
    x(3) = -3.0;
    x(4) = -1.0;
  } else if (prob == 18) {
    /* Chebyquad function. */
    h = 1.0/double(n+1);
    for (j=1 ; j<=n ; ++j) x(j) = double(j)*h;
  }

  /* Compute multiple of initial point. */
  if (factor != 1.0) {
    if (prob == 7) {
      for (j=1 ; j<=n ; ++j) x(j) = factor;
    } else {
      for (j=1 ; j<=n ; ++j) x(j) *= factor;
    }
  }
  return x;
}
OptimPackLegacy-release-1.4.0/yorick/optimpacklegacy-tests.out000066400000000000000000002407071303525653100245300ustar00rootroot00000000000000#
# Problem 1 (N=3): Helical valley function.
# Method 0 (NDIR=3): Limited Memory BFGS (VMLM with NDIR=3)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +2.500000000000000e+03  1.9e+03  0.0e+00  
     1     2      0.000  +1.132008103520547e+03  1.1e+03  1.0e+00  
     2     3      0.000  +3.073911905701987e+02  4.7e+02  7.8e-01  
     3     4      0.000  +8.534071352331746e+01  2.1e+02  9.3e-01  
     4     5      0.000  +3.541502648995344e+01  1.1e+02  1.0e+00  
     5     6      0.000  +1.762519408308565e+01  7.3e+01  1.0e+00  
     6     7      0.000  +6.010226268823216e+00  1.7e+01  9.0e-01  
     7     8      0.000  +5.492716897495775e+00  6.3e+00  1.0e+00  
     8     9      0.000  +5.425503969579507e+00  4.3e+00  1.0e+00  
     9    10      0.000  +5.265630629847704e+00  7.5e+00  1.0e+00  
    10    11      0.000  +4.809839791888933e+00  1.9e+01  1.0e+00  
    11    12      0.000  +3.522455208281464e+00  3.0e+01  1.0e+00  
    12    14      0.000  +3.068297969073592e+00  2.7e+01  1.3e-01  
    13    15      0.000  +2.100951192748246e+00  1.5e+01  1.0e+00  
    14    16      0.000  +1.706672666076662e+00  1.3e+01  1.0e+00  
    15    17      0.000  +8.286257916242681e-01  6.9e+00  1.0e+00  
    16    18      4.001  +5.922941003132391e-01  9.6e+00  1.0e+00  
    17    20      4.001  +5.103420996864492e-01  1.1e+01  4.4e-01  
    18    21      4.001  +2.916460245825456e-01  7.0e+00  1.0e+00  
    19    22      4.001  +1.004295671502106e-01  3.3e+00  1.0e+00  
    20    23      4.001  +4.654709712389724e-02  1.3e+00  8.3e-01  
    21    24      4.001  +1.427494728803810e-02  2.6e+00  4.6e-01  
    22    25      4.001  +4.543295602689820e-03  1.0e-00  4.3e-01  
    23    26      4.001  +1.007118040044901e-03  4.6e-01  9.2e-01  
    24    27      4.001  +2.061213550356601e-04  1.9e-01  6.1e-01  
    25    28      4.001  +4.141146958118607e-05  9.1e-02  5.9e-01  
    26    29      4.001  +9.246362768846678e-06  4.6e-02  5.6e-01  
    27    30      4.001  +3.194411530932206e-06  3.5e-02  3.1e-01  
    28    31      4.001  +6.501783574339488e-07  1.4e-02  5.4e-01  
    29    32      4.001  +1.343722348096534e-07  5.4e-03  5.9e-01  
    30    33      4.001  +2.750162245743687e-08  2.3e-03  5.9e-01  
    31    34      4.001  +6.952580275602280e-09  3.8e-04  5.4e-01  
    32    35      4.001  +1.473890736071037e-09  2.1e-04  4.1e-01  
    33    36      4.001  +3.751052304854505e-10  2.5e-04  4.4e-01  
    34    37      4.001  +7.625216557423310e-11  9.0e-05  5.1e-01  
    35    38      4.001  +1.622952431278697e-11  6.6e-05  5.2e-01  
    36    39      4.001  +7.337759316133232e-12  3.6e-05  2.9e-01  
    37    40      4.001  +1.484824633556255e-12  1.6e-05  5.6e-01  
    38    41      4.001  +4.578352609117974e-13  1.2e-05  4.6e-01  
    39    42      4.001  +9.211331598248391e-14  4.8e-06  4.1e-01  
    40    43      4.001  +1.831236718906136e-14  2.5e-06  5.5e-01  
    41    44      4.001  +5.028878022134398e-15  2.4e-07  5.2e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 2 (N=6): Biggs exp6 function.
# Method 0 (NDIR=6): Limited Memory BFGS (VMLM with NDIR=6)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +7.790700756559702e-01  2.6e+00  0.0e+00  
     1     3      4.000  +6.063399881248565e-01  1.4e+00  1.4e-01  
     2     4      4.000  +5.345518690614532e-01  1.2e+00  1.0e+00  
     3     5      4.000  +3.079086646397058e-01  4.0e-01  1.0e+00  
     4     6      4.000  +2.937191017970756e-01  1.2e-01  1.0e+00  
     5     7      4.000  +2.921168291268924e-01  3.4e-02  1.0e+00  
     6     8      4.000  +2.918462455582488e-01  4.3e-02  1.0e+00  
     7     9      4.000  +2.907755492762679e-01  9.9e-02  1.0e+00  
     8    10      4.000  +2.881208307389913e-01  1.7e-01  1.0e+00  
     9    11      4.000  +2.777833991389049e-01  4.6e-01  1.0e+00  
    10    13      4.000  +2.612679403981057e-01  6.3e-01  5.2e-01  
    11    14      4.000  +2.469361666977165e-01  9.9e-01  1.0e+00  
    12    15      4.000  +2.036078330726717e-01  1.0e-00  1.0e+00  
    13    16      4.000  +7.767306534374016e-02  3.6e-01  3.7e-01  
    14    17      4.000  +5.174481985556744e-02  2.1e-01  1.0e+00  
    15    18      4.000  +4.438442687186699e-02  3.2e-02  1.0e+00  
    16    19      4.000  +4.327020633870218e-02  2.0e-02  1.0e+00  
    17    20      4.000  +4.270533262117948e-02  2.0e-02  1.0e+00  
    18    21      4.000  +3.969619752160380e-02  2.1e-01  1.0e+00  
    19    22      4.000  +3.608256498897430e-02  2.2e-01  1.0e+00  
    20    23      8.000  +2.496078630339771e-02  8.7e-03  1.0e+00  
    21    25      8.000  +2.354604949127677e-02  1.2e-01  2.2e-01  
    22    26      8.000  +1.888593515049183e-02  1.4e-01  1.0e+00  
    23    27      8.000  +1.155437130469526e-02  7.9e-02  1.0e+00  
    24    28      8.000  +8.080802739733741e-03  4.6e-02  1.0e+00  
    25    30      8.000  +7.156021780018340e-03  1.1e-01  4.9e-01  
    26    31      8.000  +6.273418884507282e-03  7.0e-02  1.0e+00  
    27    32      8.000  +5.939819199276478e-03  9.8e-03  1.0e+00  
    28    33      8.000  +5.908026441632852e-03  1.0e-02  1.0e+00  
    29    35      8.000  +5.859754857684088e-03  1.0e-02  2.8e-02  
    30    36      8.000  +5.765713460425574e-03  7.4e-03  1.0e+00  
    31    37      8.000  +5.675434828171089e-03  7.0e-03  1.0e+00  
    32    38      8.000  +5.657523454643495e-03  3.2e-03  1.0e+00  
    33    39      8.000  +5.655833463796146e-03  4.4e-04  1.0e+00  
    34    40      8.000  +5.655671174917713e-03  2.4e-04  1.0e+00  
    35    42      8.000  +5.655652521284395e-03  1.2e-04  3.3e-01  
    36    43      8.000  +5.655650195207963e-03  3.0e-05  1.0e+00  
    37    44     12.000  +5.655649926013700e-03  6.4e-07  1.0e+00  
    38    45     12.000  +5.655649925527675e-03  2.3e-07  1.0e+00  
    39    46     12.000  +5.655649925502423e-03  9.0e-08  1.0e+00  
# op_vmlmb_next: FRTOL test satisfied
#
#
# Problem 3 (N=3): Gaussian function.
# Method 0 (NDIR=3): Limited Memory BFGS (VMLM with NDIR=3)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +3.888106991166885e-06  7.5e-03  0.0e+00  
     1     2      0.000  +7.716984735720412e-07  3.3e-03  5.8e-04  
     2     3      0.000  +1.561242789005403e-07  1.4e-03  5.6e-01  
     3     4      0.000  +3.476004610942878e-08  5.7e-04  6.0e-01  
     4     5      0.000  +1.232954447864692e-08  9.3e-05  8.4e-01  
     5     6      0.000  +1.171122486137217e-08  1.1e-05  1.0e+00  
     6     8      0.000  +1.163182146077833e-08  1.2e-05  5.0e+00  
     7     9      0.000  +1.130733360163093e-08  1.6e-05  1.0e+00  
     8    10      0.000  +1.127985527183232e-08  2.7e-06  1.0e+00  
     9    11      0.000  +1.127932791925235e-08  4.0e-08  1.0e+00  
    10    12      0.000  +1.127932769618526e-08  8.6e-12  1.0e+00  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 4 (N=2): Powell badly scaled function.
# Method 0 (NDIR=2): Limited Memory BFGS (VMLM with NDIR=2)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.135261717348378e+00  2.0e+04  0.0e+00  
     1     2      0.000  +2.716142498422306e-01  7.4e+03  6.3e-05  
     2     3      0.000  +1.351881720546067e-01  2.7e-01  1.0e+00  
     3    14      0.000  +1.347499857711354e-01  1.7e+02  1.4e+06  
     4    15      0.000  +1.325667967357710e-01  6.0e+02  1.0e+00  
     5    16      0.000  +1.268168829890248e-01  1.4e+03  1.0e+00  
     6    17      0.000  +1.130266725138436e-01  2.2e+03  1.0e+00  
     7    18      0.000  +7.189847553126569e-02  2.1e+03  1.0e+00  
     8    20      0.000  +6.626840795010225e-02  7.5e+01  3.3e-03  
     9    21      0.000  +4.050790583682891e-02  5.5e+02  1.0e+00  
    10    22      0.000  +2.603122017596488e-02  2.9e+03  1.0e+00  
    11    23      0.000  +1.344335372038092e-02  1.8e+03  8.0e-01  
    12    24      0.000  +7.754280961808157e-03  1.8e+03  1.0e+00  
    13    25      0.000  +6.035962443792143e-03  6.0e+02  1.0e+00  
    14    26      0.000  +3.520105110849622e-03  2.7e+02  1.0e+00  
    15    27      0.000  +2.370401920922337e-03  1.3e+03  1.0e+00  
    16    28      0.000  +1.111838810799019e-03  5.4e+02  8.5e-01  
    17    30      0.000  +7.562658146984992e-04  4.1e+02  4.8e-01  
    18    31      0.000  +6.291294727585325e-04  7.2e+02  1.0e+00  
    19    32      0.000  +4.125929545959699e-04  4.0e+02  1.0e+00  
    20    33      0.000  +2.786252603932807e-04  2.3e+02  1.0e+00  
    21    34      0.000  +1.865344312220937e-04  6.5e+01  1.0e+00  
    22    36      0.000  +1.746213097705067e-04  2.7e+02  1.2e-01  
    23    37      0.000  +1.311007032893237e-04  3.1e+02  1.0e+00  
    24    38      0.000  +8.604790308724185e-05  9.6e+01  1.0e+00  
    25    40      0.000  +6.713643137639769e-05  1.5e+02  3.7e-01  
    26    41      0.000  +6.009576963699230e-05  3.4e+02  1.0e+00  
    27    42      0.000  +4.592112785957327e-05  1.3e+02  1.0e+00  
    28    43      0.000  +3.318733434604557e-05  1.3e+02  1.0e+00  
    29    45      0.000  +3.153928824477498e-05  7.9e-01  2.0e-04  
    30    46      0.000  +2.316717042185159e-05  1.3e+02  1.0e+00  
    31    47      0.000  +1.983842227523587e-05  1.8e+02  1.0e+00  
    32    48      0.000  +1.370511800174228e-05  1.2e+02  1.0e+00  
    33    50      0.000  +1.002231977553119e-05  2.0e+01  3.7e-01  
    34    52      4.001  +9.448845461709604e-06  7.8e+01  3.1e-01  
    35    53      4.001  +8.796547092034665e-06  8.8e+01  1.0e+00  
    36    54      4.001  +6.012203046585967e-06  3.7e+00  1.0e+00  
    37    56      4.001  +5.591031631209653e-06  5.2e+01  2.2e-01  
    38    57      4.001  +5.042798867261178e-06  8.1e+01  1.0e+00  
    39    58      4.001  +4.037916381025496e-06  4.9e+01  1.0e+00  
    40    59      4.001  +3.325226275541043e-06  2.6e+01  1.0e+00  
    41    61      4.001  +3.145813424606391e-06  5.4e+01  2.7e-01  
    42    62      4.001  +2.620153892100086e-06  5.5e+01  1.0e+00  
    43    64      4.001  +2.415748503691216e-06  2.5e+00  2.2e-02  
    44    65      4.001  +2.007550819175101e-06  3.0e+01  1.0e+00  
    45    67      4.001  +1.890695485188910e-06  5.1e+01  4.5e-01  
    46    68      4.001  +1.536361962738215e-06  3.0e+01  1.0e+00  
    47    69      4.001  +1.311168885938422e-06  2.0e+01  1.0e+00  
    48    70      4.001  +1.246078119694974e-06  4.5e+01  1.0e+00  
    49    72      4.001  +9.491335127465187e-07  7.2e+00  3.3e-01  
    50    74      4.001  +8.891242770948279e-07  2.8e+01  6.9e-02  
    51    75      4.001  +8.700737460692882e-07  1.9e+01  1.0e+00  
    52    76      4.001  +7.774251370222714e-07  7.0e+00  1.0e+00  
    53    78      4.001  +7.054120977646890e-07  1.4e+01  3.9e-01  
    54    80      4.001  +6.079579263162548e-07  2.2e+01  3.9e-01  
    55    81      4.001  +4.495947084220561e-07  1.7e+01  1.0e+00  
    56    83      4.001  +3.956164009642611e-07  6.9e+00  5.9e-02  
    57    85      4.001  +3.842041614956623e-07  1.6e+01  4.7e-01  
    58    86      4.001  +3.650291414806386e-07  2.0e+01  1.0e+00  
    59    87      4.001  +2.977310422144736e-07  1.0e+01  1.0e+00  
    60    88      4.001  +2.645228220544150e-07  8.7e+00  1.0e+00  
    61    90      4.001  +2.625753218665754e-07  2.1e+00  1.3e-02  
    62    92      4.001  +2.351392468128754e-07  7.8e+00  5.3e-01  
    63    94      4.001  +2.228437274607579e-07  1.5e+01  3.0e-01  
    64    95      4.001  +1.908884988619849e-07  1.6e+01  1.0e+00  
    65    97      4.001  +1.775213596206642e-07  1.5e+00  7.7e-02  
    66    98      4.001  +1.563404116641290e-07  9.7e+00  1.0e+00  
    67   100      4.001  +1.512029496166810e-07  1.4e+01  4.4e-01  
    68   101      4.001  +1.307607535470326e-07  9.5e+00  1.0e+00  
    69   102      4.001  +1.175169650897558e-07  2.0e+00  1.0e+00  
    70   104      4.001  +1.072392194161219e-07  5.1e+00  2.9e-01  
    71   106      4.001  +1.037392963035747e-07  9.8e+00  2.9e-01  
    72   107      4.001  +9.620878417591773e-08  1.0e+01  1.0e+00  
    73   109      4.001  +9.039151653346654e-08  1.6e+00  8.0e-02  
    74   110      4.001  +8.006176991138113e-08  8.3e+00  1.0e+00  
    75   111      4.001  +7.595885339417243e-08  1.0e+01  1.0e+00  
    76   112      4.001  +6.314410560360231e-08  4.1e-01  1.0e+00  
    77   114      4.001  +6.008323382664185e-08  5.3e+00  2.6e-01  
    78   115      4.001  +5.774858820209131e-08  1.1e+01  1.0e+00  
    79   116      4.001  +5.227214564981060e-08  4.5e+00  1.0e+00  
    80   117      4.001  +4.671286653797208e-08  7.9e+00  1.0e+00  
    81   118      4.001  +4.218605795772740e-08  4.0e+00  1.0e+00  
    82   120      4.001  +3.978787254803439e-08  7.2e+00  5.2e-01  
    83   121      4.001  +3.475025245891024e-08  4.6e+00  1.0e+00  
    84   122      4.001  +3.131608455766981e-08  8.5e-01  1.0e+00  
    85   124      4.001  +2.975290789910577e-08  4.2e+00  1.9e-01  
    86   125      4.001  +2.844598223236710e-08  8.2e+00  1.0e+00  
    87   126      4.001  +2.529667836942072e-08  2.4e+00  1.0e+00  
    88   127      4.001  +2.285266654491062e-08  5.8e+00  1.0e+00  
    89   128      4.001  +2.110270876321310e-08  3.4e+00  1.0e+00  
    90   130      4.001  +1.982830112972024e-08  4.6e+00  4.7e-01  
    91   131      4.001  +1.556088550165383e-08  1.6e-01  1.0e+00  
    92   133      4.001  +1.509931751153993e-08  2.7e+00  1.1e-01  
    93   134      4.001  +1.441420778804029e-08  3.7e+00  1.0e+00  
    94   135      4.001  +1.303715234141585e-08  4.6e+00  1.0e+00  
    95   137      4.001  +1.183143970298517e-08  1.5e+00  1.6e-01  
    96   139      4.001  +1.083047880278837e-08  4.3e-01  4.4e-01  
    97   141      4.001  +1.033931695032363e-08  3.5e+00  1.4e-01  
    98   142      4.001  +9.955899460561576e-09  2.8e+00  1.0e+00  
    99   143      4.001  +8.883196616290377e-09  4.3e+00  1.0e+00  
   100   145      4.001  +7.742742776189192e-09  2.1e+00  2.7e-01  
   101   147      4.001  +6.834754461132445e-09  9.3e-01  4.0e-01  
   102   149      4.001  +6.666959323631201e-09  2.3e+00  1.9e-01  
   103   150      4.001  +6.411180662499273e-09  2.8e+00  1.0e+00  
   104   151      4.001  +5.435981187381998e-09  2.0e+00  1.0e+00  
   105   153      4.001  +5.283745805222238e-09  1.1e-01  2.0e-01  
   106   154      4.001  +4.667635231009192e-09  2.4e+00  1.0e+00  
   107   155      4.001  +4.374389490301682e-09  2.4e+00  1.0e+00  
   108   157      8.001  +4.163941820284297e-09  7.6e-02  1.3e-02  
   109   158      8.001  +3.677160794243351e-09  1.7e+00  1.0e+00  
   110   160      8.001  +3.556463460936755e-09  2.4e+00  4.1e-01  
   111   161      8.001  +3.036430367400247e-09  1.7e+00  1.0e+00  
   112   162      8.001  +2.784362981880398e-09  1.2e+00  1.0e+00  
   113   164      8.001  +2.406505899582082e-09  6.4e-01  4.2e-01  
   114   166      8.001  +2.340080591653236e-09  1.5e+00  1.6e-01  
   115   167      8.001  +2.232707735696947e-09  1.8e+00  1.0e+00  
   116   168      8.001  +1.807669675248058e-09  8.9e-01  1.0e+00  
   117   169      8.001  +1.621579861725144e-09  1.5e+00  1.0e+00  
   118   171      8.001  +1.260526356088865e-09  4.8e-01  3.1e-01  
   119   173      8.001  +1.158748732953299e-09  1.3e+00  1.3e-01  
   120   174      8.001  +1.091888811725686e-09  1.0e+00  1.0e+00  
   121   175      8.001  +9.252174759540841e-10  1.4e+00  1.0e+00  
   122   177      8.001  +8.177332024184264e-10  5.0e-01  7.1e-02  
   123   180      8.001  +6.877682728262519e-10  9.4e-01  6.3e-01  
   124   181      8.001  +6.521162246605309e-10  1.4e+00  1.0e+00  
   125   182      8.001  +5.245455884270034e-10  5.8e-01  1.0e+00  
   126   183      8.001  +4.740039908668378e-10  1.4e+00  1.0e+00  
   127   184      8.001  +3.675734148905452e-10  1.5e-01  1.0e+00  
   128   186      8.001  +3.278212930002444e-10  7.1e-01  4.5e-01  
   129   187      8.001  +2.991826277801766e-10  1.1e+00  1.0e+00  
   130   188      8.001  +2.261615323913900e-10  2.1e-01  1.0e+00  
   131   190      8.001  +1.996749791891283e-10  6.8e-01  5.4e-01  
   132   191      8.001  +1.748408381668149e-10  7.5e-01  1.0e+00  
   133   193      8.001  +1.441186976349858e-10  2.6e-01  3.3e-01  
   134   195      8.001  +1.168134759399082e-10  1.2e-01  5.0e-01  
   135   197      8.001  +1.065919364144133e-10  4.5e-01  1.6e-01  
   136   198      8.001  +9.624408438738366e-11  5.9e-01  1.0e+00  
   137   199      8.001  +6.522624230099676e-11  2.6e-01  1.0e+00  
   138   200      8.001  +5.382979150929681e-11  5.4e-01  1.0e+00  
   139   201      8.001  +2.357595065249005e-11  5.6e-02  9.4e-01  
   140   203      8.001  +2.194863217396652e-11  2.2e-01  2.0e-01  
   141   204      8.001  +1.824678260827043e-11  2.6e-01  1.0e+00  
   142   205      8.001  +1.007427717509816e-11  1.8e-01  1.0e+00  
   143   207      8.001  +9.240366653486143e-12  1.5e-02  1.2e-01  
   144   208      8.001  +5.277029415816368e-12  1.3e-01  1.0e+00  
   145   209      8.001  +4.150258646119530e-12  2.7e-01  1.0e+00  
   146   210      8.001  +1.419227552276263e-12  3.3e-02  6.6e-01  
   147   211      8.001  +6.157107277445726e-13  6.3e-02  1.0e+00  
   148   212      8.001  +2.164773422247019e-13  5.5e-02  1.0e+00  
   149   213      8.001  +1.645865002459103e-13  2.4e-02  3.0e-02  
   150   214      8.001  +3.516759308772241e-14  4.5e-03  8.8e-01  
   151   215      8.001  +1.152075456477990e-14  1.4e-02  7.0e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 5 (N=3): Box 3-dimensional function.
# Method 0 (NDIR=3): Limited Memory BFGS (VMLM with NDIR=3)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.031153810609398e+03  1.5e+02  0.0e+00  
     1     4      0.000  +5.051751883930287e+02  1.4e+02  3.2e+00  
     2     7      0.000  +4.693698123274796e+02  6.3e+01  9.6e-03  
     3     8      0.000  +4.196780145077672e+02  7.3e+01  1.0e+00  
     4     9      0.000  +9.577851908664192e+01  7.3e+01  6.4e-01  
     5    10      0.000  +2.963077540829067e+01  6.2e+01  8.2e-01  
     6    11      0.000  +1.472450551152400e+01  1.0e+01  1.3e-01  
     7    12      0.000  +4.692489499264585e+00  1.1e+01  9.0e-01  
     8    13      0.000  +2.930070582447900e+00  9.1e+00  1.0e+00  
     9    14      0.000  +1.626093588037745e+00  5.9e+00  1.0e+00  
    10    15      0.000  +6.607304557529599e-01  1.5e+00  1.0e+00  
    11    16      0.000  +2.360905443567035e-01  1.2e+00  1.0e+00  
    12    17      0.000  +9.771929015861618e-02  7.4e-01  1.0e+00  
    13    18      4.000  +2.921048390382599e-02  3.1e-01  1.0e+00  
    14    19      4.000  +7.162028854070950e-03  1.4e-01  1.0e+00  
    15    20      4.000  +1.918627248183639e-03  3.8e-02  8.5e-01  
    16    21      4.000  +5.706147462900988e-04  4.1e-02  5.0e-01  
    17    22      4.000  +1.767122289515497e-04  5.9e-03  6.7e-01  
    18    23      4.000  +1.388438676986920e-04  1.1e-03  1.0e+00  
    19    24      4.000  +1.380987151663160e-04  1.5e-03  1.0e+00  
    20    25      4.000  +1.375596494219131e-04  1.6e-03  1.0e+00  
    21    26      4.000  +1.348123100471587e-04  2.7e-03  1.0e+00  
    22    27      4.000  +1.273751593447703e-04  2.4e-03  1.0e+00  
    23    29      4.000  +1.236844681639359e-04  8.5e-03  3.4e-01  
    24    30      4.000  +1.111624159031401e-04  6.1e-03  1.0e+00  
    25    31      4.000  +7.709438714814043e-05  4.2e-03  1.0e+00  
    26    32      4.000  +3.555022908765118e-05  5.5e-03  1.0e+00  
    27    33      4.000  +1.388449576270083e-05  1.2e-02  8.4e-01  
    28    34      4.000  +3.499447500852135e-06  4.8e-03  2.5e-01  
    29    35      4.000  +7.802810396086031e-07  1.7e-03  7.4e-01  
    30    36      4.000  +1.797026655239720e-07  4.0e-04  6.9e-01  
    31    37      4.000  +4.113226590053436e-08  1.4e-04  6.9e-01  
    32    38      4.000  +1.170488139789506e-08  6.3e-06  5.5e-01  
    33    39      4.000  +8.860893531384294e-09  2.9e-04  7.0e-01  
    34    40      4.000  +3.295705185007528e-09  6.7e-05  1.0e+00  
    35    41      4.000  +1.824061308183375e-09  2.4e-05  1.0e+00  
    36    42      4.000  +4.894303628176848e-10  4.1e-05  8.8e-01  
    37    43      4.000  +1.063838077120574e-10  2.6e-05  7.7e-01  
    38    44      4.000  +2.936005901492016e-11  4.7e-06  4.7e-01  
    39    45      4.000  +7.520001768792375e-12  1.9e-06  6.8e-01  
    40    46      4.000  +3.232186206428190e-12  2.7e-06  1.0e+00  
    41    47      4.000  +2.382259476974284e-12  7.7e-07  1.0e+00  
    42    48      4.000  +1.627836101802466e-12  7.8e-07  1.0e+00  
    43    49      4.000  +8.722135008897642e-13  1.8e-06  1.0e+00  
    44    50      4.000  +3.181054605846769e-13  1.3e-06  1.0e+00  
    45    51      4.000  +1.819403692094123e-13  5.7e-07  1.0e+00  
    46    52      4.000  +1.552379827036547e-13  2.8e-07  1.0e+00  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 6 (N=10): Variably dimensioned function.
# Method 0 (NDIR=10): Limited Memory BFGS (VMLM with NDIR=10)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +2.198551162500000e+06  4.5e+06  0.0e+00  
     1     2      0.000  +5.982233536014224e+05  1.7e+06  5.5e-01  
     2     3      0.000  +2.077189332476444e+05  7.6e+05  1.0e+00  
     3     4      4.000  +6.578142669110338e+04  3.2e+05  1.0e+00  
     4     5      4.000  +2.160249233159776e+04  1.4e+05  1.0e+00  
     5     6      4.000  +7.004735376311746e+03  6.0e+04  1.0e+00  
     6     7      4.000  +2.287386781801080e+03  2.6e+04  1.0e+00  
     7     8      4.000  +7.476983219073760e+02  1.1e+04  1.0e+00  
     8     9      4.000  +2.458538169695109e+02  4.8e+03  1.0e+00  
     9    10      4.000  +8.149749297306352e+01  2.1e+03  1.0e+00  
    10    11      4.000  +2.737280609091122e+01  9.0e+02  1.0e+00  
    11    12      4.000  +9.362878818503740e+00  3.9e+02  1.0e+00  
    12    13      4.000  +3.269284473674885e+00  1.7e+02  1.0e+00  
    13    14      4.000  +1.153504000090763e+00  7.7e+01  1.0e+00  
    14    15      4.000  +3.936136413645998e-01  3.5e+01  1.0e+00  
    15    16      4.000  +1.147737756239351e-01  1.5e+01  1.0e+00  
    16    17      4.000  +2.581587916978744e-02  6.5e+00  9.1e-01  
    17    18      4.000  +5.303642148696754e-03  2.9e+00  7.0e-01  
    18    19      4.000  +1.056848632834968e-03  1.3e+00  5.9e-01  
    19    20      4.000  +2.091314644328269e-04  5.7e-01  5.6e-01  
    20    21      4.000  +4.132449788388705e-05  2.5e-01  5.6e-01  
    21    22      4.000  +8.163433357518874e-06  1.1e-01  5.6e-01  
    22    23      4.000  +1.612552275601864e-06  5.0e-02  5.6e-01  
    23    24      4.000  +3.185297119742180e-07  2.2e-02  5.6e-01  
    24    25      4.000  +6.291948312422135e-08  9.9e-03  5.6e-01  
    25    26      4.000  +1.242854119682474e-08  4.4e-03  5.6e-01  
    26    27      4.000  +2.455020534958202e-09  1.9e-03  5.6e-01  
    27    28      4.000  +4.849423299090284e-10  8.7e-04  5.6e-01  
    28    29      4.000  +9.579107757034683e-11  3.8e-04  5.6e-01  
    29    30      4.000  +1.892169434557917e-11  1.7e-04  5.6e-01  
    30    31      4.000  +3.737618638352018e-12  7.6e-05  5.6e-01  
    31    32      4.000  +7.382950396510434e-13  3.4e-05  5.6e-01  
    32    33      4.000  +1.458360569885202e-13  1.5e-05  5.6e-01  
    33    34      4.000  +2.880712217942045e-14  6.7e-06  5.6e-01  
    34    35      4.000  +5.690295862135377e-15  3.0e-06  5.6e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 7 (N=6): Watson function.
# Method 0 (NDIR=6): Limited Memory BFGS (VMLM with NDIR=6)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +3.000000000000000e+01  1.4e+02  0.0e+00  
     1     2      0.000  +1.153491761608158e+01  3.6e+01  2.4e-01  
     2     3      0.000  +8.662294302946657e+00  2.7e+01  1.0e+00  
     3     4      0.000  +2.159765745956006e+00  1.3e+01  1.0e+00  
     4     5      0.000  +9.370932269174013e-01  9.6e+00  6.9e-01  
     5     6      0.000  +6.260360367334762e-01  2.7e+00  1.0e+00  
     6     7      0.000  +5.588208440197413e-01  2.9e+00  1.0e+00  
     7     8      0.000  +4.320129246513010e-01  4.0e+00  1.0e+00  
     8     9      0.000  +1.782329757356047e-01  4.6e+00  1.0e+00  
     9    10      4.001  +4.357179339744174e-02  1.6e+00  6.4e-01  
    10    11      4.001  +2.446191487403206e-02  4.8e-01  1.0e+00  
    11    12      4.001  +2.250413138430174e-02  3.4e-01  1.0e+00  
    12    13      4.001  +2.111722399878381e-02  5.5e-01  1.0e+00  
    13    14      4.001  +1.606205485982599e-02  8.0e-01  1.0e+00  
    14    16      8.001  +1.060663387077928e-02  1.8e-01  5.1e-01  
    15    17      8.001  +1.023711762982278e-02  2.1e-01  1.0e+00  
    16    18      8.001  +1.014232386791980e-02  2.5e-02  1.0e+00  
    17    19      8.001  +1.012808413731048e-02  3.0e-02  1.0e+00  
    18    20      8.001  +1.011416301337225e-02  1.9e-02  1.0e+00  
    19    21     12.001  +1.010622490501859e-02  1.7e-02  1.0e+00  
    20    22     12.001  +1.005354212767259e-02  2.5e-02  1.0e+00  
    21    23     12.001  +9.914998965299265e-03  4.3e-02  1.0e+00  
    22    24     12.001  +9.633255378335592e-03  5.2e-02  1.0e+00  
    23    25     12.001  +9.435981241419105e-03  3.2e-01  1.0e+00  
    24    26     12.001  +9.074119841420146e-03  9.2e-02  1.0e+00  
    25    27     16.001  +8.948864483207091e-03  2.6e-02  1.0e+00  
    26    28     16.001  +8.942033313705005e-03  9.7e-03  1.0e+00  
    27    29     16.001  +8.940317436619535e-03  7.6e-03  1.0e+00  
    28    30     16.001  +8.936673299222047e-03  1.6e-02  1.0e+00  
    29    31     16.001  +8.932411285273037e-03  2.3e-02  1.0e+00  
    30    32     16.001  +8.923876594747306e-03  2.4e-02  1.0e+00  
    31    34     20.002  +8.919738995782814e-03  6.0e-02  1.4e-01  
    32    35     20.002  +8.900791041922290e-03  5.2e-02  1.0e+00  
    33    36     20.002  +8.821982716914249e-03  5.8e-02  1.0e+00  
    34    37     20.002  +8.676125612127840e-03  4.9e-02  1.0e+00  
    35    38     20.002  +8.443320768310978e-03  3.1e-01  1.0e+00  
    36    39     24.002  +7.962339610876239e-03  1.2e-01  1.0e+00  
    37    40     24.002  +7.700051635114865e-03  9.5e-02  1.0e+00  
    38    41     24.002  +7.564775888244103e-03  9.7e-02  1.0e+00  
    39    43     24.002  +7.490280990021314e-03  2.0e-01  8.1e-02  
    40    44     24.002  +7.225853155050442e-03  1.1e-01  1.0e+00  
    41    45     28.002  +7.027986857610604e-03  6.7e-02  1.0e+00  
    42    46     28.002  +6.898992549696143e-03  1.2e-01  1.0e+00  
    43    47     28.002  +6.696669267370094e-03  1.1e-01  1.0e+00  
    44    48     28.002  +6.521394247682940e-03  3.6e-01  1.0e+00  
    45    49     28.002  +5.900564228855348e-03  1.5e-01  1.0e+00  
    46    50     28.002  +5.436162501033610e-03  1.2e-01  1.0e+00  
    47    51     32.002  +5.185527792214816e-03  1.9e-01  1.0e+00  
    48    52     32.002  +4.977046075759494e-03  1.4e-01  1.0e+00  
    49    53     32.002  +4.658566016994147e-03  7.2e-02  1.0e+00  
    50    54     32.002  +4.308711947089532e-03  1.0e-01  1.0e+00  
    51    55     32.002  +3.919697403900082e-03  1.9e-01  1.0e+00  
    52    56     32.002  +3.280783714973028e-03  1.9e-01  1.0e+00  
    53    57     36.003  +2.520432499557056e-03  1.6e-01  1.0e+00  
    54    59     36.003  +2.457626981592080e-03  1.4e-01  2.8e-02  
    55    60     36.003  +2.311981662769732e-03  5.2e-02  1.0e+00  
    56    61     36.003  +2.289345802013666e-03  6.1e-03  1.0e+00  
    57    62     36.003  +2.288985893595373e-03  2.9e-03  1.0e+00  
    58    63     40.003  +2.288455672536768e-03  2.7e-03  1.0e+00  
    59    64     40.003  +2.287793236670549e-03  1.9e-03  1.0e+00  
    60    65     40.003  +2.287695261121659e-03  1.5e-03  1.0e+00  
    61    67     40.003  +2.287684367911231e-03  6.3e-04  4.8e-01  
    62    68     40.003  +2.287676176945362e-03  3.6e-04  1.0e+00  
    63    70     44.003  +2.287675098559974e-03  2.0e-04  3.4e-01  
    64    71     44.003  +2.287673953644514e-03  6.5e-05  1.0e+00  
    65    72     44.003  +2.287673573776456e-03  5.8e-05  1.0e+00  
    66    73     44.003  +2.287672636686810e-03  1.3e-04  1.0e+00  
    67    74     44.003  +2.287671819591959e-03  1.5e-04  1.0e+00  
    68    76     48.003  +2.287671215406123e-03  3.4e-04  3.9e-01  
    69    77     48.003  +2.287670175158950e-03  7.6e-05  1.0e+00  
    70    78     48.003  +2.287670069963467e-03  3.0e-05  1.0e+00  
    71    79     48.003  +2.287670055842873e-03  1.1e-05  1.0e+00  
    72    80     48.003  +2.287670054951157e-03  7.6e-06  1.0e+00  
    73    81     52.004  +2.287670054462369e-03  2.6e-06  1.0e+00  
    74    82     52.004  +2.287670054258627e-03  1.8e-06  1.0e+00  
    75    83     52.004  +2.287670053768855e-03  4.4e-06  1.0e+00  
    76    85     52.004  +2.287670053701440e-03  2.1e-06  3.5e-01  
# op_vmlmb_next: FRTOL test satisfied
#
#
# Problem 8 (N=10): Penalty function I.
# Method 0 (NDIR=10): Limited Memory BFGS (VMLM with NDIR=10)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.480325653500000e+05  3.0e+04  0.0e+00  
     1     2      0.000  +1.200672187926850e+05  2.6e+04  1.0e+00  
     2     3      0.000  +3.265992616691508e+04  9.7e+03  8.8e-01  
     3     4      0.000  +1.132290692299289e+04  4.4e+03  1.0e+00  
     4     5      0.000  +3.577134652544013e+03  1.9e+03  1.0e+00  
     5     6      0.000  +1.169681852985238e+03  8.0e+02  1.0e+00  
     6     7      0.000  +3.764229133643723e+02  3.4e+02  1.0e+00  
     7     8      4.000  +1.213086610658549e+02  1.5e+02  1.0e+00  
     8     9      4.000  +3.874731549111131e+01  6.3e+01  1.0e+00  
     9    10      4.000  +1.223737772730658e+01  2.7e+01  1.0e+00  
    10    11      4.000  +3.782057667252822e+00  1.2e+01  1.0e+00  
    11    12      4.000  +1.125513580941122e+00  4.9e+00  1.0e+00  
    12    13      4.000  +3.129446120087767e-01  2.0e+00  1.0e+00  
    13    14      4.000  +7.756206235205798e-02  8.1e-01  1.0e-00  
    14    15      4.000  +1.827422007113406e-02  3.3e-01  9.2e-01  
    15    16      4.000  +4.085118985926949e-03  1.4e-01  8.1e-01  
    16    17      4.000  +8.877332480334356e-04  6.0e-02  7.2e-01  
    17    18      4.000  +2.065403882446298e-04  2.4e-02  6.9e-01  
    18    19      4.000  +7.703710321289555e-05  3.2e-03  9.3e-01  
    19    20      4.000  +7.446943015394475e-05  1.1e-04  1.0e+00  
    20    21      4.000  +7.446618591447701e-05  2.9e-05  1.0e+00  
    21    23      4.000  +7.446415870380601e-05  5.2e-05  5.0e+00  
    22    24      4.000  +7.445657592228791e-05  1.2e-04  1.0e+00  
    23    25      4.000  +7.442752521815094e-05  2.8e-04  1.0e+00  
    24    26      4.000  +7.434003956432855e-05  5.2e-04  1.0e+00  
    25    29      4.000  +7.349631102481636e-05  6.1e-04  5.9e-01  
    26    31      4.000  +7.349026117318990e-05  4.7e-04  2.2e-01  
    27    33      4.000  +7.331713301296246e-05  4.0e-04  5.0e+00  
    28    35      4.000  +7.310908109664723e-05  5.5e-04  4.7e-01  
    29    36      4.000  +7.281998859159809e-05  8.1e-04  1.0e+00  
    30    37      4.000  +7.250779119403938e-05  2.0e-04  1.0e+00  
    31    39      4.000  +7.230694011645983e-05  2.8e-04  3.9e-01  
    32    41      4.000  +7.225525250357204e-05  5.3e-04  2.7e-01  
    33    42      4.000  +7.216099121388021e-05  5.7e-04  1.0e+00  
    34    43      4.000  +7.193027784341741e-05  4.0e-04  1.0e+00  
    35    44      4.000  +7.175919696417940e-05  1.9e-04  1.0e+00  
    36    46      4.000  +7.170723123651528e-05  4.2e-04  2.5e-01  
    37    47      4.000  +7.158287428953024e-05  7.8e-04  1.0e+00  
    38    48      4.000  +7.144374877244074e-05  2.2e-04  1.0e+00  
    39    49      4.000  +7.133466251468262e-05  1.7e-04  1.0e+00  
    40    51      4.000  +7.131147537304108e-05  3.4e-04  2.7e-01  
    41    52      4.000  +7.127028433699874e-05  3.7e-04  1.0e+00  
    42    53      4.000  +7.117077758835362e-05  2.6e-04  1.0e+00  
    43    54      4.000  +7.110140571775857e-05  9.8e-05  1.0e+00  
    44    56      4.000  +7.108040834207843e-05  2.5e-04  2.2e-01  
    45    57      4.000  +7.103394859713061e-05  3.8e-04  1.0e+00  
    46    58      4.000  +7.098405566611185e-05  1.8e-05  1.0e+00  
    47    59      4.000  +7.095277805502977e-05  2.3e-04  1.0e+00  
    48    60      4.000  +7.093698079764311e-05  1.3e-04  1.0e+00  
    49    62      4.000  +7.092411497593044e-05  1.6e-04  3.6e-01  
    50    63      4.000  +7.090081388960589e-05  8.4e-05  1.0e+00  
    51    64      4.000  +7.089092762586513e-05  7.5e-05  1.0e+00  
    52    65      4.000  +7.088414527104555e-05  8.0e-05  1.0e+00  
    53    67      4.000  +7.087881487192198e-05  7.0e-06  1.7e-01  
    54    69      4.000  +7.087808649792271e-05  4.1e-05  4.0e-01  
    55    70      8.000  +7.087756682229364e-05  3.7e-05  1.0e+00  
    56    71      8.000  +7.087666490410433e-05  6.3e-06  1.0e+00  
    57    72      8.000  +7.087654244772589e-05  9.0e-06  1.0e+00  
    58    73      8.000  +7.087651609138998e-05  1.9e-06  1.0e+00  
    59    74      8.000  +7.087651467883146e-05  1.2e-07  1.0e+00  
    60    75      8.000  +7.087651467090616e-05  2.6e-09  1.0e+00  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 9 (N=10): Penalty function II.
# Method 0 (NDIR=10): Limited Memory BFGS (VMLM with NDIR=10)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.626527765659671e+02  5.0e+02  0.0e+00  
     1     2      0.000  +4.478644776655588e+01  1.9e+02  3.6e-01  
     2     3      0.000  +1.567407090737728e+01  8.6e+01  1.0e+00  
     3     4      0.000  +4.595268667402950e+00  3.5e+01  1.0e+00  
     4     5      0.000  +1.269158916418052e+00  1.5e+01  1.0e+00  
     5     6      0.000  +3.110713197933571e-01  5.8e+00  9.7e-01  
     6     7      0.000  +7.571688000474813e-02  2.3e+00  9.0e-01  
     7     8      0.000  +2.213120188520761e-02  6.8e-01  9.4e-01  
     8     9      0.000  +1.485561199109297e-02  2.3e-01  1.0e+00  
     9    10      0.000  +1.306075025095904e-02  2.3e-01  1.0e+00  
    10    11      0.000  +8.330391266572293e-03  2.9e-01  1.0e+00  
    11    12      0.000  +2.118643374119330e-03  1.6e-01  5.4e-01  
    12    13      0.000  +1.676859414703804e-03  2.0e-01  1.0e+00  
    13    14      0.000  +6.085265554844259e-04  7.2e-02  1.0e+00  
    14    15      0.000  +3.602520091513869e-04  2.9e-02  1.0e+00  
    15    16      0.000  +3.000429994250958e-04  1.2e-02  1.0e+00  
    16    17      0.000  +2.942768976757234e-04  1.9e-03  1.0e+00  
    17    18      0.000  +2.941190006037160e-04  2.6e-03  1.0e+00  
    18    19      0.000  +2.940276365124544e-04  4.2e-05  1.0e+00  
    19    20      0.000  +2.940276143217213e-04  7.9e-06  1.0e+00  
    20    22      0.000  +2.940276088743079e-04  1.3e-05  5.0e+00  
    21    23      0.000  +2.940275674459129e-04  4.1e-05  1.0e+00  
    22    24      0.000  +2.940274684490467e-04  8.4e-05  1.0e+00  
    23    25      0.000  +2.940272019219013e-04  1.6e-04  1.0e+00  
    24    26      0.000  +2.940265308678704e-04  2.7e-04  1.0e+00  
    25    27      0.000  +2.940249257417753e-04  4.6e-04  1.0e+00  
    26    28      0.000  +2.940218267746400e-04  7.0e-04  1.0e+00  
    27    29      0.000  +2.940167114119969e-04  9.1e-04  1.0e+00  
    28    30      0.000  +2.940057396280275e-04  1.0e-03  1.0e+00  
    29    31      0.000  +2.939847652858170e-04  6.7e-04  1.0e+00  
    30    32      0.000  +2.939671940695009e-04  3.5e-04  1.0e+00  
    31    34      4.000  +2.939605724251989e-04  7.1e-04  3.6e-01  
    32    35      4.000  +2.939456480560964e-04  1.3e-03  1.0e+00  
    33    36      4.000  +2.939328151552932e-04  8.5e-04  1.0e+00  
    34    37      4.000  +2.939141108236152e-04  2.0e-04  1.0e+00  
    35    39      4.000  +2.939111211303367e-04  5.4e-04  3.7e-01  
    36    40      4.000  +2.939053168820111e-04  6.0e-04  1.0e+00  
    37    41      4.000  +2.938883629324550e-04  6.3e-04  1.0e+00  
    38    42      4.000  +2.938747221912601e-04  2.5e-05  1.0e+00  
    39    44      4.000  +2.938682139412850e-04  4.2e-04  2.0e-01  
    40    46      4.000  +2.938639778872194e-04  7.4e-04  5.2e-01  
    41    47      4.000  +2.938560543957402e-04  6.0e-04  1.0e+00  
    42    48      4.000  +2.938431790575485e-04  1.9e-04  1.0e+00  
    43    50      4.000  +2.938394172992321e-04  5.0e-04  1.9e-01  
    44    51      4.000  +2.938332461245707e-04  9.1e-04  1.0e+00  
    45    52      4.000  +2.938232087891656e-04  9.5e-05  1.0e+00  
    46    53      4.000  +2.938162192572837e-04  3.1e-04  1.0e+00  
    47    54      4.000  +2.938134286486824e-04  7.5e-04  1.0e+00  
    48    55      4.000  +2.938046050490839e-04  1.2e-04  1.0e+00  
    49    56      4.000  +2.937958615389975e-04  2.5e-04  1.0e+00  
    50    58      4.000  +2.937915280165045e-04  5.2e-04  4.3e-01  
    51    59      4.000  +2.937829339096076e-04  3.9e-04  1.0e+00  
    52    60      4.000  +2.937787756979532e-04  1.2e-04  1.0e+00  
    53    62      4.000  +2.937767478240379e-04  3.5e-04  2.1e-01  
    54    63      4.000  +2.937740704182577e-04  5.8e-04  1.0e+00  
    55    64      4.000  +2.937692673453995e-04  3.0e-04  1.0e+00  
    56    66      4.000  +2.937653648012842e-04  4.2e-04  4.6e-01  
    57    67      4.000  +2.937586070665360e-04  6.9e-04  1.0e+00  
    58    69      4.000  +2.937544459124473e-04  8.5e-05  4.5e-01  
    59    70      4.000  +2.937530885438273e-04  1.3e-04  1.0e+00  
    60    72      4.000  +2.937500033638618e-04  3.4e-04  4.1e-01  
    61    73      8.001  +2.937462650101101e-04  4.1e-04  1.0e+00  
    62    74      8.001  +2.937436103075173e-04  7.7e-05  1.0e+00  
    63    76      8.001  +2.937411292974525e-04  1.1e-04  4.1e-01  
    64    78      8.001  +2.937396821963436e-04  3.1e-04  1.7e-01  
    65    79      8.001  +2.937381391529797e-04  3.8e-04  1.0e+00  
    66    80      8.001  +2.937365816728961e-04  1.4e-04  1.0e+00  
    67    81      8.001  +2.937347185972254e-04  2.4e-04  1.0e+00  
    68    82      8.001  +2.937318532989324e-04  3.7e-04  1.0e+00  
    69    83      8.001  +2.937287934342775e-04  4.3e-05  1.0e+00  
    70    85      8.001  +2.937271147643474e-04  2.1e-04  5.1e-01  
    71    87      8.001  +2.937263798718626e-04  3.0e-04  5.2e-01  
    72    88      8.001  +2.937246531357029e-04  2.2e-04  1.0e+00  
    73    89      8.001  +2.937232048142877e-04  1.0e-04  1.0e+00  
    74    91      8.001  +2.937223578268570e-04  2.2e-04  4.0e-01  
    75    92      8.001  +2.937201426598879e-04  2.4e-04  1.0e+00  
    76    93      8.001  +2.937187758592068e-04  1.8e-04  1.0e+00  
    77    95      8.001  +2.937169668102822e-04  6.6e-05  5.0e-01  
    78    97      8.001  +2.937167045913685e-04  1.6e-04  1.9e-01  
    79    98     12.001  +2.937161308786513e-04  1.9e-04  1.0e+00  
    80    99     12.001  +2.937145418783188e-04  2.1e-04  1.0e+00  
    81   100     12.001  +2.937126830402479e-04  7.7e-05  1.0e+00  
    82   102     12.001  +2.937119950899304e-04  1.9e-04  3.4e-01  
    83   103     12.001  +2.937103197572409e-04  3.0e-04  1.0e+00  
    84   104     12.001  +2.937081325220577e-04  1.3e-04  1.0e+00  
    85   106     12.001  +2.937067731152529e-04  1.5e-05  4.2e-01  
    86   109     12.001  +2.937061298844395e-04  9.7e-05  5.7e-02  
    87   110     12.001  +2.937057792029250e-04  3.3e-04  1.0e+00  
    88   111     12.001  +2.937048989862912e-04  1.6e-04  1.0e+00  
    89   112     12.001  +2.937037498661225e-04  6.0e-05  1.0e+00  
    90   113     12.001  +2.937020302605030e-04  2.2e-04  1.0e+00  
    91   114     12.001  +2.937011876780409e-04  2.4e-04  1.0e+00  
    92   116     12.001  +2.936994036462835e-04  2.7e-04  4.0e-01  
    93   117     12.001  +2.936932742505855e-04  4.2e-05  1.0e+00  
    94   119     12.001  +2.936925011344764e-04  2.5e-04  1.2e-01  
    95   120     12.001  +2.936903903706649e-04  2.4e-04  1.0e+00  
    96   121     12.001  +2.936864971751230e-04  1.6e-04  1.0e+00  
    97   122     12.001  +2.936833519272741e-04  2.7e-05  1.0e+00  
    98   125     12.001  +2.936823989527786e-04  1.3e-04  5.9e-02  
    99   127     12.001  +2.936814369909003e-04  2.8e-04  5.1e-01  
   100   128     12.001  +2.936801889576564e-04  2.5e-04  1.0e+00  
   101   129     12.001  +2.936781670510260e-04  6.2e-06  1.0e+00  
   102   131     12.001  +2.936773383070480e-04  1.3e-04  2.7e-01  
   103   133     12.001  +2.936767971224333e-04  2.1e-04  4.8e-01  
   104   134     12.001  +2.936757371420169e-04  2.0e-04  1.0e+00  
   105   136     12.001  +2.936755119527722e-04  1.9e-04  1.7e-01  
   106   137     12.001  +2.936739331071090e-04  6.8e-05  1.0e+00  
   107   139     16.001  +2.936733609422002e-04  6.7e-05  2.4e-01  
   108   141     16.001  +2.936731441199923e-04  1.5e-04  4.5e-01  
   109   142     16.001  +2.936728734176120e-04  1.5e-04  1.0e+00  
   110   143     16.001  +2.936727646558677e-04  1.2e-04  1.0e+00  
   111   144     16.001  +2.936720719650833e-04  5.3e-05  1.0e+00  
   112   146     16.001  +2.936718160655674e-04  5.7e-05  5.0e-01  
   113   147     16.001  +2.936716335691947e-04  8.9e-05  1.0e+00  
   114   148     16.001  +2.936713673939239e-04  1.0e-04  1.0e+00  
   115   149     16.001  +2.936711604644687e-04  1.8e-06  1.0e+00  
   116   150     16.001  +2.936710464585561e-04  7.8e-05  1.0e+00  
   117   151     16.001  +2.936709734203265e-04  2.0e-05  1.0e+00  
   118   152     16.001  +2.936709005854026e-04  2.0e-05  1.0e+00  
   119   154     16.001  +2.936708447037076e-04  5.4e-05  3.7e-01  
   120   155     16.001  +2.936707215906627e-04  5.5e-05  1.0e+00  
   121   156     16.001  +2.936703043174316e-04  1.9e-05  1.0e+00  
   122   158     16.001  +2.936700146863054e-04  9.4e-05  4.5e-01  
   123   160     16.001  +2.936693047392297e-04  1.0e-04  5.0e-01  
   124   161     16.001  +2.936685401469610e-04  1.2e-04  1.0e+00  
   125   163     16.001  +2.936679641926337e-04  1.8e-05  1.9e-01  
   126   165     16.001  +2.936674792095312e-04  1.1e-04  3.2e-01  
   127   166     16.001  +2.936668316559686e-04  2.9e-04  1.0e+00  
   128   167     16.001  +2.936662100391527e-04  5.3e-05  1.0e+00  
   129   168     16.001  +2.936656178325533e-04  8.7e-05  1.0e+00  
   130   170     16.001  +2.936651583330866e-04  1.5e-04  5.0e-01  
   131   171     16.001  +2.936647742964451e-04  1.4e-04  1.0e+00  
   132   173     16.001  +2.936646566758439e-04  1.2e-04  2.0e-01  
   133   174     16.001  +2.936641713973722e-04  7.2e-05  1.0e+00  
   134   176     16.001  +2.936637890170677e-04  1.2e-04  4.3e-01  
   135   177     20.001  +2.936630264588969e-04  4.5e-05  1.0e+00  
   136   179     20.001  +2.936628969739628e-04  1.1e-04  4.5e-01  
   137   180     20.001  +2.936625655838410e-04  8.3e-05  1.0e+00  
   138   181     20.001  +2.936624300065082e-04  2.9e-05  1.0e+00  
   139   182     20.001  +2.936622977829990e-04  7.7e-05  1.0e+00  
   140   183     20.001  +2.936622477588315e-04  1.0e-05  1.0e+00  
   141   184     20.001  +2.936622031232782e-04  1.4e-05  1.0e+00  
   142   185     20.001  +2.936621779293315e-04  4.8e-05  1.0e+00  
   143   186     20.001  +2.936621567734476e-04  3.0e-06  1.0e+00  
   144   187     20.001  +2.936621506624571e-04  2.4e-06  1.0e+00  
   145   188     20.001  +2.936621474513797e-04  7.8e-06  1.0e+00  
   146   189     20.001  +2.936621458663817e-04  2.2e-06  1.0e+00  
   147   190     20.001  +2.936621447656716e-04  1.4e-06  1.0e+00  
   148   191     20.001  +2.936621438322216e-04  3.6e-06  1.0e+00  
   149   192     20.001  +2.936621407224748e-04  7.2e-06  1.0e+00  
   150   193     20.001  +2.936621353581356e-04  8.7e-06  1.0e+00  
   151   194     20.001  +2.936621275310319e-04  7.5e-06  1.0e+00  
   152   195     20.001  +2.936621223335431e-04  6.9e-06  1.0e+00  
   153   197     20.001  +2.936621209792176e-04  3.3e-06  2.2e-01  
   154   198     20.001  +2.936621173468774e-04  7.0e-06  1.0e+00  
   155   199     20.001  +2.936621156967350e-04  1.2e-05  1.0e+00  
   156   200     20.001  +2.936621127659403e-04  1.1e-05  1.0e+00  
   157   201     20.001  +2.936620879068670e-04  1.8e-05  1.0e+00  
   158   202     20.001  +2.936620341924160e-04  1.5e-06  1.0e+00  
   159   204     20.001  +2.936619396711716e-04  1.8e-05  4.0e-01  
   160   206     20.001  +2.936618809583579e-04  4.6e-05  4.9e-01  
   161   207     20.001  +2.936618437961445e-04  3.1e-05  1.0e+00  
   162   208     20.001  +2.936618135595330e-04  1.7e-05  1.0e+00  
   163   209     20.001  +2.936617994124585e-04  1.5e-05  1.0e+00  
   164   211     20.001  +2.936617977401772e-04  8.7e-06  2.1e-01  
   165   212     20.001  +2.936617949948577e-04  7.8e-06  1.0e+00  
   166   213     24.002  +2.936617942029165e-04  4.8e-06  1.0e+00  
   167   214     24.002  +2.936617936336488e-04  7.0e-07  1.0e+00  
   168   215     24.002  +2.936617935577645e-04  6.6e-07  1.0e+00  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 10 (N=2): Brown badly scaled function.
# Method 0 (NDIR=2): Limited Memory BFGS (VMLM with NDIR=2)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +9.999980000030000e+11  2.0e+06  0.0e+00  
     1    10      0.000  +8.405068809937695e+11  1.5e+10  8.7e+04  
     2    12      0.000  +6.534530905604027e+11  2.6e+10  1.2e-01  
     3    14      0.000  +5.259989045876316e+11  1.6e+11  2.1e-01  
     4    16      0.000  +2.692902690480896e+11  8.1e+10  3.7e-01  
     5    17      0.000  +1.587055937831890e+11  4.5e+11  1.8e-01  
     6    18      0.000  +5.786251940191312e+10  3.2e+10  9.8e-01  
     7    19      0.000  +2.014729184788555e+10  1.3e+11  1.0e+00  
     8    20      0.000  +3.789073790387382e+09  6.5e+10  7.6e-01  
     9    21      0.000  +7.582658601419518e+08  2.1e+10  4.9e-01  
    10    22      0.000  +1.532406522092270e+08  1.3e+10  5.1e-01  
    11    23      0.000  +8.382857608319093e+07  6.5e+09  3.7e-01  
    12    24      0.000  +1.653294988314359e+07  2.9e+09  5.7e-01  
    13    25      0.000  +3.263611062004277e+06  1.3e+09  5.5e-01  
    14    26      0.000  +6.471465292335765e+05  6.7e+08  5.5e-01  
    15    27      0.000  +2.722789943285238e+05  4.0e+08  5.0e-01  
    16    28      0.000  +5.377870916293834e+04  1.7e+08  5.3e-01  
    17    29      0.000  +1.062250565109277e+04  7.8e+07  5.6e-01  
    18    30      0.000  +2.098255912542021e+03  3.5e+07  5.6e-01  
    19    31      0.000  +4.150644198176832e+02  1.4e+07  5.6e-01  
    20    32      0.000  +9.195149511769590e+01  1.2e+07  5.4e-01  
    21    33      0.000  +7.394055311418897e+01  6.1e+06  1.4e-02  
    22    34      0.000  +1.460552054965025e+01  2.7e+06  5.6e-01  
    23    35      0.000  +2.885039269609231e+00  1.2e+06  5.6e-01  
    24    36      0.000  +5.698841404349454e-01  5.4e+05  5.6e-01  
    25    37      0.000  +1.125697148814101e-01  2.4e+05  5.6e-01  
    26    38      0.000  +2.223674412281545e-02  1.1e+05  5.6e-01  
    27    39      0.000  +4.419596330611485e-03  3.8e+04  5.6e-01  
    28    40      0.000  +1.226680528641698e-03  5.3e+04  5.2e-01  
    29    41      0.000  +3.552382989525306e-04  9.7e+03  4.1e-02  
    30    42      0.000  +7.017052848565110e-05  4.3e+03  5.6e-01  
    31    43      0.000  +1.386084529266547e-05  1.9e+03  5.6e-01  
    32    44      0.000  +2.737944677494988e-06  8.5e+02  5.6e-01  
    33    45      0.000  +5.408290745856043e-07  3.8e+02  5.6e-01  
    34    46      0.000  +1.069191494379131e-07  1.5e+02  5.6e-01  
    35    47      0.000  +3.099248909852002e-08  2.6e+02  5.4e-01  
    36    48      0.000  +8.015714097213813e-09  5.7e+01  7.0e-02  
    37    49      0.000  +1.583352621921838e-09  2.5e+01  5.6e-01  
    38    50      0.000  +3.127629493167706e-10  1.1e+01  5.6e-01  
    39    51      0.000  +6.178050732586073e-11  5.0e+00  5.6e-01  
    40    52      0.000  +1.220343418206337e-11  2.2e+00  5.6e-01  
    41    53      0.000  +2.410577466990187e-12  9.9e-01  5.6e-01  
    42    54      0.000  +4.761860264644440e-13  4.5e-01  5.6e-01  
    43    55      0.000  +9.529309271044640e-14  1.3e-01  5.5e-01  
    44    56      0.000  +3.454718805039423e-14  3.0e-01  4.7e-01  
    45    57      0.000  +7.000760536493319e-15  1.2e-01  2.0e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 11 (N=4): Brown and Dennis function.
# Method 0 (NDIR=4): Limited Memory BFGS (VMLM with NDIR=4)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +7.926693336997432e+06  2.1e+06  0.0e+00  
     1     2      0.000  +6.049349781006352e+06  1.6e+06  1.0e+00  
     2     3      0.000  +2.838871733130934e+06  4.3e+05  1.0e+00  
     3     4      0.000  +2.432298103636766e+06  2.6e+05  1.0e+00  
     4     5      0.000  +2.100775303409475e+06  3.1e+05  1.0e+00  
     5     6      0.000  +1.323784908907083e+06  3.3e+05  1.0e+00  
     6     7      0.000  +5.656591397675695e+05  8.5e+04  1.0e+00  
     7     8      4.000  +3.430980546283170e+05  4.1e+04  1.0e+00  
     8     9      4.000  +1.878284295308689e+05  3.3e+04  1.0e+00  
     9    11      4.000  +1.436998832262278e+05  7.0e+04  4.8e-01  
    10    12      4.000  +9.738492091554010e+04  2.9e+04  1.0e+00  
    11    13      4.000  +9.084457699916144e+04  9.6e+03  1.0e+00  
    12    14      4.000  +8.891237239806094e+04  5.0e+03  1.0e+00  
    13    15      4.000  +8.705530186352410e+04  6.8e+03  1.0e+00  
    14    16      4.000  +8.608483951495643e+04  1.3e+03  1.0e+00  
    15    17      4.000  +8.599075237276051e+04  7.5e+02  1.0e+00  
    16    18      4.000  +8.590306517851379e+04  9.1e+02  1.0e+00  
    17    20      4.000  +8.585776884341528e+04  1.4e+03  3.1e-01  
    18    21      4.000  +8.582231434220298e+04  9.3e+01  1.0e+00  
    19    22      4.000  +8.582220228898624e+04  4.8e+00  1.0e+00  
    20    23      4.000  +8.582220180473091e+04  2.0e+00  1.0e+00  
    21    24      4.000  +8.582220164639555e+04  3.4e-01  1.0e+00  
    22    25      4.000  +8.582220163995650e+04  2.7e-01  1.0e+00  
# op_vmlmb_next: FRTOL test satisfied
#
#
# Problem 12 (N=3): Gulf research and development function.
# Method 0 (NDIR=3): Limited Memory BFGS (VMLM with NDIR=3)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      4.000  +1.211070582556949e+01  4.0e+01  0.0e+00  
     1     3      4.000  +7.037432998984529e+00  1.5e+01  1.7e-01  
     2     5      4.000  +6.621351881374275e+00  3.1e-01  5.0e-01  
     3     6      8.000  +6.621101702040585e+00  2.3e-01  1.0e+00  
     4     7      8.000  +6.620679188673091e+00  3.3e-01  1.0e+00  
     5     8      8.000  +6.619037491331203e+00  8.0e-01  1.0e+00  
     6     9      8.000  +6.615310780340258e+00  1.5e+00  1.0e+00  
     7    10      8.000  +6.604547336243583e+00  2.7e+00  1.0e+00  
     8    11      8.000  +6.573884980436160e+00  4.7e+00  1.0e+00  
     9    12     12.001  +6.499049562962999e+00  7.4e+00  1.0e+00  
    10    13     12.001  +6.336057520157562e+00  8.7e+00  1.0e+00  
    11    14     12.001  +5.892999608485755e+00  2.4e+00  1.0e+00  
    12    15     12.001  +5.662280493431998e+00  1.4e+01  1.0e+00  
    13    16     12.001  +5.449061619118568e+00  3.9e+00  1.0e+00  
    14    17     16.001  +5.234241685722618e+00  2.1e+00  1.0e+00  
    15    18     16.001  +4.865169222646597e+00  1.8e+01  1.0e+00  
    16    19     16.001  +4.453895249926380e+00  5.9e+00  1.0e+00  
    17    20     16.001  +3.976830574245754e+00  2.9e+00  1.0e+00  
    18    22     20.001  +1.779414184967219e-01  5.4e+00  1.7e+00  
    19    24     20.001  +1.417710645204940e-01  3.9e+00  8.2e-02  
    20    25     20.001  +2.557537679786676e-02  1.8e+00  7.2e-01  
    21    26     20.001  +6.611690206271554e-03  6.2e-01  5.2e-01  
    22    27     24.001  +4.564494341401721e-03  3.3e-02  1.0e+00  
    23    28     24.001  +4.543334030131170e-03  1.0e-02  1.0e+00  
    24    29     24.001  +4.539678138594905e-03  1.0e-02  1.0e+00  
    25    31     24.001  +4.538933737699077e-03  2.0e-03  4.3e-02  
    26    32     28.002  +4.538084042484109e-03  1.2e-03  1.0e+00  
    27    37     32.002  +3.469460838544598e-03  3.0e-01  3.4e+02  
    28    38     32.002  +2.928359037254009e-03  1.6e-01  1.0e+00  
    29    40     32.002  +2.474054806017020e-03  2.4e-01  2.6e-01  
    30    41     32.002  +1.565633067221580e-03  2.3e-01  1.0e+00  
    31    43     36.002  +1.413550255660053e-03  1.2e-01  9.7e-02  
    32    44     36.002  +9.024611061567671e-04  1.6e-02  1.0e+00  
    33    46     36.002  +7.003267516821486e-04  1.1e-01  1.8e-01  
    34    47     36.002  +5.735129820311213e-04  2.3e-01  1.0e+00  
    35    48     40.002  +3.123330023579667e-04  4.1e-02  1.0e+00  
    36    49     40.002  +1.947752299522285e-04  3.4e-02  1.0e+00  
    37    51     40.002  +1.638242201908890e-04  8.3e-02  2.9e-01  
    38    52     40.002  +1.048439465991671e-04  7.0e-02  1.0e+00  
    39    53     44.003  +3.709259481404306e-05  2.7e-03  5.5e-01  
    40    54     44.003  +1.091378850908817e-05  2.3e-02  8.2e-01  
    41    55     44.003  +2.536658359037260e-06  1.5e-02  7.5e-01  
    42    56     44.003  +5.748894725508491e-07  4.4e-03  6.2e-01  
    43    57     44.003  +1.301070142934200e-07  3.2e-03  5.7e-01  
    44    58     48.003  +8.850638573840128e-08  1.2e-03  1.6e-01  
    45    59     48.003  +1.929576324643203e-08  4.9e-04  6.2e-01  
    46    60     48.003  +5.601806973787550e-09  2.1e-04  7.4e-01  
    47    61     48.003  +2.535490761789031e-09  3.4e-05  1.0e+00  
    48    62     48.003  +1.322572045394975e-09  7.9e-05  1.0e+00  
    49    63     52.003  +8.287306876272502e-10  1.5e-04  1.0e+00  
    50    64     52.003  +3.454513513192700e-10  7.7e-05  1.0e+00  
    51    65     52.003  +1.279735809853422e-10  6.8e-05  1.0e+00  
    52    66     52.003  +2.590444871831076e-11  3.7e-05  5.6e-01  
    53    67     52.003  +5.131187839211650e-12  1.8e-05  5.6e-01  
    54    68     56.003  +1.096260941388581e-12  4.6e-06  5.5e-01  
    55    69     56.003  +2.320936116341532e-13  3.7e-06  4.9e-01  
    56    71     56.003  +1.720714526990411e-13  3.0e-07  3.5e-02  
    57    72     56.003  +3.399938346550955e-14  1.3e-07  5.6e-01  
    58    73     60.004  +6.724520326208138e-15  6.0e-08  5.6e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 13 (N=10): Trigonometric function.
# Method 0 (NDIR=10): Limited Memory BFGS (VMLM with NDIR=10)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +7.075759466222607e-03  9.9e-02  0.0e+00  
     1     2      0.000  +1.847318266210997e-03  2.8e-02  7.9e-02  
     2     3      0.000  +1.337289272696683e-03  2.6e-02  1.0e+00  
     3     4      0.000  +9.099932601024449e-04  2.0e-02  1.0e+00  
     4     5      0.000  +6.559192696755177e-04  1.4e-02  1.0e+00  
     5     6      0.000  +4.686579245332390e-04  1.5e-02  1.0e+00  
     6     7      0.000  +2.915051473509156e-04  1.4e-02  1.0e+00  
     7     8      0.000  +1.433277880070397e-04  1.7e-02  1.7e-01  
     8     9      0.000  +7.147757750781793e-05  5.4e-03  5.9e-01  
     9    10      0.000  +5.887928681982255e-05  2.8e-03  1.0e+00  
    10    11      0.000  +5.263481793491030e-05  2.1e-03  1.0e+00  
    11    12      0.000  +4.522784407286506e-05  1.8e-03  1.0e+00  
    12    13      0.000  +4.260697310099406e-05  1.7e-03  1.0e+00  
    13    14      0.000  +4.033897074809929e-05  1.2e-03  1.0e+00  
    14    15      0.000  +3.597768894272814e-05  1.6e-03  1.0e+00  
    15    17      0.000  +3.282850339569031e-05  1.9e-03  4.0e-01  
    16    19      0.000  +3.030246929870708e-05  1.7e-03  4.7e-01  
    17    20      0.000  +2.874543857699578e-05  1.2e-03  1.0e+00  
    18    21      0.000  +2.839516499584868e-05  7.6e-04  1.0e+00  
    19    22      0.000  +2.805891729461959e-05  3.7e-04  1.0e+00  
    20    23      0.000  +2.801778561737049e-05  1.4e-04  1.0e+00  
    21    24      0.000  +2.800096728737016e-05  1.1e-04  1.0e+00  
    22    25      0.000  +2.796003401543012e-05  9.0e-05  1.0e+00  
    23    26      0.000  +2.795364460348979e-05  8.1e-05  1.0e+00  
    24    27      0.000  +2.795145020217185e-05  4.2e-05  1.0e+00  
    25    28      0.000  +2.795057495098975e-05  4.8e-06  1.0e+00  
    26    29      0.000  +2.795056448092877e-05  1.7e-06  1.0e+00  
    27    30      0.000  +2.795056214675631e-05  9.8e-07  1.0e+00  
    28    31      0.000  +2.795056136433344e-05  7.1e-07  1.0e+00  
    29    32      0.000  +2.795056130890243e-05  5.4e-07  1.0e+00  
    30    33      0.000  +2.795056121893572e-05  1.6e-08  1.0e+00  
    31    34      0.000  +2.795056121878748e-05  3.9e-09  1.0e+00  
# op_vmlmb_next: FRTOL test satisfied
#
#
# Problem 14 (N=10): Extended Rosenbrock function.
# Method 0 (NDIR=10): Limited Memory BFGS (VMLM with NDIR=10)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.210000000000000e+02  5.2e+02  0.0e+00  
     1     2      0.000  +3.333875559382903e+01  1.7e+02  2.6e-01  
     2     3      0.000  +2.099690543341773e+01  2.7e+01  1.0e+00  
     3     4      0.000  +2.064737829082273e+01  4.4e+00  1.0e+00  
     4     5      4.000  +2.062947719722462e+01  4.0e+00  1.0e+00  
     5     6      4.000  +2.055056296009381e+01  8.2e+00  1.0e+00  
     6     7      4.000  +2.036601960781752e+01  1.6e+01  1.0e+00  
     7    11      4.000  +1.270403994373162e+01  2.9e+01  7.3e+00  
     8    13      4.000  +1.266492082784074e+01  2.4e+01  1.3e-01  
     9    15      4.000  +1.160881636531017e+01  2.0e+01  5.0e+00  
    10    17      4.000  +1.014905429393288e+01  2.3e+01  5.2e-01  
    11    18      4.000  +8.256388073653257e+00  2.2e+01  1.0e+00  
    12    19      4.000  +6.515652375585378e+00  7.3e+00  1.0e+00  
    13    21      4.000  +5.313683620850455e+00  6.8e+00  3.2e-01  
    14    23      4.000  +5.001446956969033e+00  1.2e+01  2.3e-01  
    15    24      4.000  +4.582646809321272e+00  1.3e+01  1.0e+00  
    16    25      4.000  +3.603604585846324e+00  1.2e+01  1.0e+00  
    17    26      4.000  +2.675900088307497e+00  2.9e+00  1.0e+00  
    18    28      4.000  +2.296387307115140e+00  8.0e+00  3.1e-01  
    19    29      4.000  +1.954912440237827e+00  1.7e+01  1.0e+00  
    20    30      4.000  +1.378522055959003e+00  3.5e+00  1.0e+00  
    21    31      4.000  +9.484804947450111e-01  8.2e+00  1.0e+00  
    22    32      4.000  +6.713411428693927e-01  1.1e+01  1.0e+00  
    23    33      4.000  +3.822925991805740e-01  5.5e+00  1.0e+00  
    24    35      4.000  +2.191730723230072e-01  4.4e+00  4.7e-01  
    25    36      4.000  +1.887020522506004e-01  1.1e+01  1.0e+00  
    26    37      4.000  +1.125336324978479e-01  4.1e+00  1.0e+00  
    27    38      4.000  +4.747278490703725e-02  1.8e+00  1.0e+00  
    28    39      4.000  +2.164097573626416e-02  4.3e+00  1.0e+00  
    29    40      4.000  +5.971361214373413e-03  8.7e-01  8.5e-01  
    30    41      4.000  +1.514300265908568e-03  9.7e-01  7.8e-01  
    31    42      4.000  +3.293711779148185e-04  3.4e-01  6.8e-01  
    32    43      4.000  +6.882146001996125e-05  1.9e-01  6.4e-01  
    33    44      4.000  +1.402734044478412e-05  7.0e-02  5.9e-01  
    34    45      4.000  +2.827846239737803e-06  3.8e-02  5.7e-01  
    35    46      4.000  +5.657367678388773e-07  1.4e-02  5.6e-01  
    36    47      4.000  +1.126657341335922e-07  7.5e-03  5.5e-01  
    37    48      4.000  +2.236521035181264e-08  2.9e-03  5.5e-01  
    38    49      4.000  +4.430894630373603e-09  1.4e-03  5.5e-01  
    39    50      4.000  +8.766285485792653e-10  6.0e-04  5.5e-01  
    40    51      4.000  +1.751634425012838e-10  3.2e-04  5.5e-01  
    41    52      4.000  +4.269613882266779e-11  3.6e-05  5.1e-01  
    42    53      4.000  +8.563903609021838e-12  3.2e-05  5.0e-01  
    43    55      4.000  +8.011613923905404e-12  2.8e-06  8.9e-03  
    44    56      4.000  +1.582541862741472e-12  1.3e-06  5.6e-01  
    45    57      4.000  +3.126009356473569e-13  5.6e-07  5.6e-01  
    46    58      4.000  +6.174833942884158e-14  2.5e-07  5.6e-01  
    47    59      4.000  +1.219720341626072e-14  1.1e-07  5.6e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 15 (N=12): Extended Powell function.
# Method 0 (NDIR=12): Limited Memory BFGS (VMLM with NDIR=12)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +6.450000000000000e+02  7.9e+02  0.0e+00  
     1     2      0.000  +2.126398786342238e+02  2.7e+02  9.0e-01  
     2     3      0.000  +1.002223459053673e+02  1.4e+02  1.0e+00  
     3     4      0.000  +4.372578508635030e+01  4.1e+01  1.0e+00  
     4     5      0.000  +3.492275772532622e+01  3.1e+01  1.0e+00  
     5     6      0.000  +2.371218382737346e+01  1.8e+01  1.0e+00  
     6     7      0.000  +1.840511402191540e+01  1.5e+01  1.0e+00  
     7     8      0.000  +5.385458666855794e+00  1.4e+01  1.0e+00  
     8     9      0.000  +1.387075054330895e+00  5.4e+00  7.5e-01  
     9    10      0.000  +4.338250784945510e-01  5.3e+00  1.0e+00  
    10    11      4.000  +2.021610832573901e-01  3.7e+00  9.0e-01  
    11    12      4.000  +8.424287893602030e-02  1.4e+00  1.0e+00  
    12    13      4.000  +2.416572403566977e-02  6.8e-01  9.8e-01  
    13    14      4.000  +9.539455035955798e-03  3.4e-01  1.0e+00  
    14    15      4.000  +4.018557231556538e-03  1.2e-01  1.0e+00  
    15    16      4.000  +2.359119570961944e-03  6.5e-02  1.0e+00  
    16    17      4.000  +1.410815508220599e-03  9.5e-02  1.0e+00  
    17    18      4.000  +6.664117905074039e-04  4.2e-02  1.0e+00  
    18    19      4.000  +3.278858525866031e-04  2.2e-02  1.0e+00  
    19    20      4.000  +1.301355227806065e-04  2.9e-02  1.0e+00  
    20    21      4.000  +5.051539438473153e-05  4.1e-02  9.6e-01  
    21    22      4.000  +1.933558681673291e-05  1.0e-02  1.0e+00  
    22    23      4.000  +1.385853063374876e-05  1.9e-03  1.0e+00  
    23    24      4.000  +1.325733364422288e-05  6.1e-03  1.0e+00  
    24    25      4.000  +1.042889374455694e-05  1.5e-02  1.0e+00  
    25    26      4.000  +5.019830828798650e-06  1.6e-02  1.0e+00  
    26    28      4.000  +4.246579321514016e-06  2.7e-03  3.0e-02  
    27    29      4.000  +1.264335976216658e-06  6.3e-04  1.0e+00  
    28    30      4.000  +4.235261754358550e-07  9.7e-05  1.0e+00  
    29    31      4.000  +1.358585713215724e-07  4.3e-05  1.0e+00  
    30    32      4.000  +4.490260964925541e-08  3.5e-04  1.0e+00  
    31    33      4.000  +1.435728201106651e-08  2.0e-04  1.0e+00  
    32    34      4.000  +4.659469517411141e-09  1.9e-05  1.0e+00  
    33    35      4.000  +3.197807521383443e-09  5.6e-04  9.5e-01  
    34    36      4.000  +8.129560805831940e-10  1.5e-04  8.3e-01  
    35    37      4.000  +2.639089711885569e-10  2.5e-05  1.0e+00  
    36    38      4.000  +1.238902847308503e-10  3.8e-05  1.0e+00  
    37    39      4.000  +3.693522871395788e-11  2.6e-05  1.0e+00  
    38    40      4.000  +1.262527367596187e-11  1.7e-05  9.9e-01  
    39    41      4.000  +4.121104687115640e-12  6.1e-06  8.0e-01  
    40    42      4.000  +1.510459349123597e-12  1.4e-06  1.0e+00  
    41    43      4.000  +5.074496790632610e-13  2.9e-07  1.0e+00  
    42    44      4.000  +1.788275537869560e-13  1.2e-06  1.0e+00  
    43    45      4.000  +5.912068107118078e-14  1.1e-06  1.0e+00  
    44    46      4.000  +2.328813604908046e-14  3.7e-07  1.0e+00  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 16 (N=2): Beale function.
# Method 0 (NDIR=2): Limited Memory BFGS (VMLM with NDIR=2)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.420312500000000e+01  2.8e+01  0.0e+00  
     1     2      0.000  +5.837321962114054e+00  9.0e+00  5.7e-01  
     2     3      0.000  +3.543247835494009e+00  6.4e+00  1.0e+00  
     3     4      0.000  +1.309302199158894e+00  2.7e+00  8.3e-01  
     4     5      0.000  +8.188817853278094e-01  2.2e+00  1.0e+00  
     5     6      0.000  +2.196594007426552e-01  9.2e-01  6.3e-01  
     6     7      0.000  +5.892697837805581e-02  3.1e-01  9.0e-01  
     7     8      0.000  +2.970214723480817e-02  1.1e+00  1.0e+00  
     8     9      0.000  +7.437526283530453e-03  2.6e-01  6.0e-01  
     9    10      0.000  +1.762547800263668e-03  5.2e-02  8.1e-01  
    10    11      0.000  +3.806254994795292e-04  3.8e-02  7.5e-01  
    11    13      0.000  +3.601037933927141e-04  1.8e-02  1.6e-02  
    12    14      0.000  +7.333268718739307e-05  6.9e-03  6.4e-01  
    13    15      0.000  +1.475615358477659e-05  3.5e-03  5.9e-01  
    14    17      0.000  +1.418392844246689e-05  6.2e-03  1.9e-02  
    15    18      0.000  +2.813440877948162e-06  2.6e-03  5.7e-01  
    16    19      0.000  +5.569285817905507e-07  1.1e-03  5.6e-01  
    17    20      0.000  +2.389901351508039e-07  3.9e-03  5.4e-01  
    18    21      0.000  +4.719137850755555e-08  1.7e-03  2.6e-01  
    19    22      0.000  +9.318027774792144e-09  7.6e-04  5.5e-01  
    20    23      0.000  +1.840271195971691e-09  3.4e-04  5.6e-01  
    21    24      0.000  +3.634816763291771e-10  1.5e-04  5.6e-01  
    22    25      0.000  +7.179633292922795e-11  6.7e-05  5.6e-01  
    23    26      0.000  +1.418177095511089e-11  3.0e-05  5.6e-01  
    24    27      0.000  +2.801318130710862e-12  1.3e-05  5.6e-01  
    25    28      0.000  +5.533450993015748e-13  5.9e-06  5.6e-01  
    26    29      0.000  +1.093025883599040e-13  2.6e-06  5.6e-01  
    27    30      0.000  +2.159062213224393e-14  1.2e-06  5.6e-01  
    28    31      0.000  +4.264813197124873e-15  5.2e-07  5.6e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 17 (N=4): Wood function.
# Method 0 (NDIR=4): Limited Memory BFGS (VMLM with NDIR=4)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.919200000000000e+04  1.6e+04  0.0e+00  
     1     2      0.000  +7.427890102322217e+03  7.9e+03  1.0e+00  
     2     3      0.000  +2.438439115206284e+03  3.3e+03  1.0e+00  
     3     4      0.000  +8.528820526783926e+02  1.5e+03  1.0e+00  
     4     5      4.000  +2.768216485716339e+02  6.1e+02  1.0e+00  
     5     6      4.000  +8.327982562502508e+01  2.4e+02  1.0e+00  
     6     7      4.000  +3.108746833161832e+01  7.1e+01  1.0e+00  
     7     8      4.000  +2.380525415568198e+01  2.4e+01  1.0e+00  
     8     9      4.000  +2.251089219753886e+01  2.6e+01  1.0e+00  
     9    10      4.000  +1.855299679936986e+01  4.3e+01  1.0e+00  
    10    12      4.000  +1.160837562431893e+01  4.5e+01  3.8e-01  
    11    14      4.000  +8.137724551705739e+00  1.9e+01  1.1e-01  
    12    16      4.000  +7.878690238212614e+00  1.2e+00  3.4e-01  
    13    17      4.000  +7.877411159067403e+00  8.8e-01  1.0e+00  
    14    18      4.000  +7.876880489799159e+00  4.4e-02  1.0e+00  
    15    19      4.000  +7.876879132206481e+00  1.1e-02  1.0e+00  
    16    20      4.000  +7.876878876272726e+00  4.8e-03  1.0e+00  
    17    22      4.000  +7.876878490252988e+00  7.0e-03  5.0e+00  
    18    23      4.000  +7.876876755266399e+00  1.9e-02  1.0e+00  
    19    24      4.000  +7.876870816217647e+00  3.5e-02  1.0e+00  
    20    26      4.000  +7.876865204511740e+00  1.3e-01  4.0e-01  
    21    27      4.000  +7.876844389583843e+00  1.4e-01  1.0e+00  
    22    28      4.000  +7.876583706646104e+00  3.2e-01  1.0e+00  
    23    29      4.000  +7.876423129704414e+00  8.5e-01  1.0e+00  
    24    30      4.000  +7.875060453829682e+00  1.6e+00  1.0e+00  
    25    31      4.000  +7.872131119796703e+00  3.0e+00  1.0e+00  
    26    33      4.000  +7.869170139094837e+00  3.3e+00  2.0e-01  
    27    35      4.000  +7.864052623536911e+00  3.4e+00  3.6e-01  
    28    36      4.000  +7.855001610484345e+00  2.9e+00  1.0e+00  
    29    37      4.000  +7.849625111708809e+00  4.1e+00  1.0e+00  
    30    38      4.000  +7.839170804391435e+00  3.0e+00  1.0e+00  
    31    39      4.000  +7.824568101062441e+00  2.8e+00  1.0e+00  
    32    41      4.000  +7.813646935560872e+00  4.1e+00  2.4e-01  
    33    43      4.000  +7.789494013946371e+00  5.7e+00  2.3e-01  
    34    44      4.000  +7.722263757787657e+00  7.4e+00  1.0e+00  
    35    46      4.000  +7.693814493002182e+00  1.2e+01  1.6e-01  
    36    47      4.000  +7.541393104832614e+00  4.3e+00  1.0e+00  
    37    48      4.000  +7.434111139448211e+00  5.1e+00  1.0e+00  
    38    50      4.000  +7.420136912558213e+00  6.7e+00  9.8e-02  
    39    51      4.000  +7.323032564057124e+00  6.2e+00  1.0e+00  
    40    53      4.000  +7.216964400808464e+00  1.4e+01  2.7e-01  
    41    54      4.000  +6.911125334280928e+00  1.1e+01  1.0e+00  
    42    55      4.000  +6.512566568432114e+00  4.0e+01  1.0e+00  
    43    56      4.000  +5.720835039047132e+00  7.6e+00  1.0e+00  
    44    57      4.000  +5.672818396981924e+00  1.6e+01  1.0e+00  
    45    59      4.000  +5.202278173076890e+00  1.9e+01  2.2e-01  
    46    62      4.000  +5.061832019786340e+00  2.0e+01  6.4e-02  
    47    63      4.000  +4.875017742525158e+00  2.0e+01  1.0e+00  
    48    64      4.000  +4.616628933510177e+00  1.3e+01  1.0e+00  
    49    65      4.000  +4.405532645759691e+00  1.7e+01  1.0e+00  
    50    66      4.000  +3.915460121738099e+00  1.8e+01  1.0e+00  
    51    67      4.000  +3.571117225615803e+00  1.8e+01  1.0e+00  
    52    69      4.000  +3.342807282681064e+00  6.6e+00  3.0e-01  
    53    70      4.000  +3.169420327958804e+00  8.2e+00  1.0e+00  
    54    71      4.000  +3.083714115933907e+00  7.5e+00  1.0e+00  
    55    72      4.000  +2.842571930210177e+00  6.2e+00  1.0e+00  
    56    73      4.000  +2.407959483920122e+00  1.8e+01  1.0e+00  
    57    75      4.000  +2.310997032934655e+00  1.5e+01  2.4e-01  
    58    77      4.000  +1.874303903557421e+00  9.1e+00  3.9e-01  
    59    79      4.000  +1.747352207978819e+00  4.5e+00  4.3e-01  
    60    80      4.000  +1.616702123440979e+00  6.3e+00  1.0e+00  
    61    81      4.000  +1.551453286562933e+00  1.7e+01  1.0e+00  
    62    82      4.000  +1.445642573680781e+00  1.1e+01  1.0e+00  
    63    84      4.000  +1.291548725488739e+00  7.3e+00  5.2e-01  
    64    85      4.000  +1.146267070283055e+00  1.3e+01  1.0e+00  
    65    86      4.000  +8.736037619411690e-01  6.2e+00  1.0e+00  
    66    88      4.000  +7.587510486192135e-01  6.2e+00  4.3e-01  
    67    89      4.000  +6.272474461111625e-01  2.7e+00  1.0e+00  
    68    91      4.000  +6.154503738538099e-01  2.9e+00  3.6e-01  
    69    92      4.000  +6.025386870053662e-01  2.3e+00  1.0e+00  
    70    93      4.000  +5.569297053304927e-01  2.8e+00  1.0e+00  
    71    94      4.000  +4.939103897295918e-01  6.0e+00  1.0e+00  
    72    95      4.000  +3.289194049732398e-01  5.1e+00  1.0e+00  
    73    97      4.000  +2.689387273180264e-01  8.0e+00  2.0e-01  
    74    98      4.000  +1.220581321270582e-01  8.6e+00  8.6e-01  
    75    99      8.001  +6.663309577533551e-02  8.9e+00  4.3e-01  
    76   100      8.001  +3.637323340490146e-02  1.1e+00  1.0e+00  
    77   101      8.001  +2.712208655572348e-02  1.5e+00  1.0e+00  
    78   102      8.001  +1.116522496174569e-02  3.7e+00  7.9e-01  
    79   103      8.001  +3.900482707955074e-03  2.0e+00  4.8e-01  
    80   104      8.001  +1.004136803886999e-03  6.9e-01  9.3e-01  
    81   105      8.001  +2.226638008945489e-04  3.5e-01  7.3e-01  
    82   106      8.001  +5.106876720624694e-05  7.5e-02  6.0e-01  
    83   107      8.001  +1.071982128302296e-05  2.6e-02  6.0e-01  
    84   108      8.001  +4.441881481174797e-06  6.4e-02  5.2e-01  
    85   109      8.001  +9.368857777996710e-07  2.8e-02  4.1e-01  
    86   110      8.001  +1.923710022206024e-07  1.3e-02  5.7e-01  
    87   111      8.001  +4.207762167723878e-08  5.8e-03  6.1e-01  
    88   112      8.001  +1.181228459744630e-08  2.3e-03  7.0e-01  
    89   113      8.001  +6.562748229821411e-09  8.5e-04  1.0e+00  
    90   114      8.001  +5.554256689700290e-09  7.8e-04  1.0e+00  
    91   115      8.001  +3.484975951958208e-09  1.1e-03  1.0e+00  
    92   116      8.001  +8.872950699360685e-10  9.9e-04  9.6e-01  
    93   117      8.001  +1.837384368516011e-10  3.9e-04  4.7e-01  
    94   118      8.001  +3.863280276302230e-11  1.8e-04  5.7e-01  
    95   119      8.001  +9.862952976040704e-12  8.1e-05  6.1e-01  
    96   120      8.001  +3.643236162973744e-12  3.2e-05  6.8e-01  
    97   121      8.001  +2.484476074089160e-12  8.5e-06  1.0e+00  
    98   122      8.001  +2.082579068068493e-12  1.4e-05  1.0e+00  
    99   123      8.001  +7.291374932118642e-13  2.4e-05  1.0e+00  
   100   124      8.001  +3.315075555077437e-13  9.7e-06  5.1e-01  
   101   125      8.001  +7.622499994371465e-14  7.5e-06  7.5e-01  
   102   126      8.001  +4.174888567594510e-14  6.3e-06  1.5e-01  
# op_vmlmb_next: FATOL test satisfied
#
#
# Problem 18 (N=25): Chebyquad function.
# Method 0 (NDIR=25): Limited Memory BFGS (VMLM with NDIR=25)
#
# ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN
# ---------------------------------------------------------------
     0     1      0.000  +1.248791904880204e-02  6.5e-01  0.0e+00  
     1     3      4.000  +1.049431287352932e-02  5.8e-01  5.7e-03  
     2     4      8.000  +9.609006926829304e-03  2.8e-01  1.0e+00  
     3     5      8.000  +9.337302507733160e-03  1.3e-01  1.0e+00  
     4     6     12.000  +9.170073298832805e-03  1.2e-01  1.0e+00  
     5     7     12.000  +8.991254191516106e-03  1.1e-01  1.0e+00  
     6     8     16.001  +8.846941541915740e-03  7.7e-02  1.0e+00  
     7     9     16.001  +8.801166872704557e-03  9.3e-02  1.0e+00  
     8    10     20.001  +8.756693487815655e-03  4.5e-02  1.0e+00  
     9    11     20.001  +8.739152782891746e-03  3.3e-02  1.0e+00  
    10    12     20.001  +8.714552799449523e-03  3.1e-02  1.0e+00  
    11    13     24.001  +8.692796444352035e-03  3.2e-02  1.0e+00  
    12    14     24.001  +8.667777829095081e-03  2.6e-02  1.0e+00  
    13    15     28.001  +8.654662603946484e-03  4.0e-02  1.0e+00  
    14    16     28.001  +8.643693770592379e-03  1.7e-02  1.0e+00  
    15    17     32.002  +8.637815829617758e-03  1.5e-02  1.0e+00  
    16    18     32.002  +8.633008188826369e-03  1.8e-02  1.0e+00  
    17    19     36.002  +8.620907535587131e-03  4.2e-02  1.0e+00  
    18    21     40.002  +8.614998716828056e-03  2.6e-02  4.1e-01  
    19    22     40.002  +8.610412652519038e-03  1.1e-02  1.0e+00  
    20    23     40.002  +8.608556239357218e-03  7.1e-03  1.0e+00  
    21    24     44.002  +8.607605459630636e-03  6.9e-03  1.0e+00  
    22    25     44.002  +8.602572986472511e-03  1.3e-02  1.0e+00  
    23    26     48.003  +8.590054454806751e-03  2.8e-02  1.0e+00  
    24    27     48.003  +8.564183633311328e-03  7.5e-02  1.0e+00  
    25    28     52.003  +8.532458576242349e-03  9.3e-02  1.0e+00  
    26    29     52.003  +8.493452768781006e-03  7.0e-02  1.0e+00  
    27    30     56.003  +8.474787010915145e-03  6.7e-02  1.0e+00  
    28    31     56.003  +8.458773326847066e-03  4.5e-02  1.0e+00  
    29    32     60.003  +8.457999627479094e-03  4.1e-02  1.0e+00  
    30    33     60.003  +8.449532870934518e-03  2.2e-02  1.0e+00  
    31    34     64.004  +8.447840743807028e-03  2.8e-02  1.0e+00  
    32    35     64.004  +8.445692845529283e-03  1.1e-02  1.0e+00  
    33    36     68.004  +8.444165323560711e-03  9.6e-03  1.0e+00  
    34    37     68.004  +8.443207951672584e-03  1.0e-02  1.0e+00  
    35    38     68.004  +8.441994339191562e-03  2.0e-02  1.0e+00  
    36    39     72.004  +8.439832619160158e-03  1.4e-02  1.0e+00  
    37    40     72.004  +8.437231750924349e-03  1.1e-02  1.0e+00  
    38    41     76.004  +8.433302937380200e-03  1.2e-02  1.0e+00  
    39    43     80.005  +8.432489353555114e-03  9.1e-03  3.7e-01  
    40    44     80.005  +8.432123509481731e-03  4.7e-03  1.0e+00  
    41    45     84.005  +8.432035588096611e-03  2.3e-03  1.0e+00  
    42    46     84.005  +8.431999120538823e-03  1.5e-03  1.0e+00  
    43    47     88.005  +8.431966728031759e-03  1.2e-03  1.0e+00  
    44    48     88.005  +8.431924365562692e-03  1.6e-03  1.0e+00  
    45    50     92.005  +8.431891947171172e-03  3.1e-03  4.2e-01  
    46    51     92.005  +8.431831354671862e-03  2.3e-03  1.0e+00  
    47    52     96.006  +8.431668636095641e-03  3.3e-03  1.0e+00  
    48    53     96.006  +8.431437099609954e-03  5.4e-03  1.0e+00  
    49    54    100.006  +8.431000851063426e-03  5.3e-03  1.0e+00  
    50    55    100.006  +8.430678732503366e-03  1.6e-02  1.0e+00  
    51    56    104.006  +8.429876682496911e-03  7.2e-03  1.0e+00  
    52    57    104.006  +8.428910142166941e-03  6.9e-03  1.0e+00  
    53    58    108.006  +8.428161202850929e-03  9.8e-03  1.0e+00  
    54    59    108.006  +8.427149557235504e-03  1.2e-02  1.0e+00  
    55    60    112.007  +8.426884594329293e-03  1.0e-02  1.0e+00  
    56    62    116.007  +8.425929204745749e-03  9.6e-03  4.4e-01  
    57    63    116.007  +8.425078821369147e-03  6.2e-03  1.0e+00  
    58    65    120.007  +8.424962146289759e-03  6.7e-03  2.7e-01  
    59    66    124.007  +8.424706166580516e-03  6.3e-03  1.0e+00  
    60    67    124.007  +8.424483854096705e-03  4.1e-03  1.0e+00  
    61    68    124.007  +8.424346241895737e-03  2.7e-03  1.0e+00  
    62    69    128.008  +8.424196521199122e-03  4.1e-03  1.0e+00  
    63    70    128.008  +8.423947181728741e-03  3.3e-03  1.0e+00  
    64    72    132.008  +8.423857716916193e-03  3.9e-03  4.8e-01  
    65    73    136.008  +8.423772029357686e-03  1.3e-03  1.0e+00  
    66    74    136.008  +8.423740800437915e-03  1.7e-03  1.0e+00  
    67    75    140.008  +8.423721211048594e-03  2.0e-03  1.0e+00  
    68    76    140.008  +8.423707802726785e-03  6.8e-04  1.0e+00  
    69    77    144.009  +8.423705094214971e-03  2.9e-04  1.0e+00  
    70    78    144.009  +8.423704078604773e-03  2.7e-04  1.0e+00  
    71    79    148.009  +8.423703211145708e-03  2.3e-04  1.0e+00  
    72    80    148.009  +8.423702337458264e-03  1.9e-04  1.0e+00  
    73    81    148.009  +8.423702265665172e-03  4.1e-04  1.0e+00  
    74    82    152.009  +8.423701658411723e-03  1.6e-04  1.0e+00  
    75    83    152.009  +8.423701425312869e-03  1.7e-04  1.0e+00  
    76    84    156.009  +8.423700442240544e-03  3.0e-04  1.0e+00  
    77    85    156.009  +8.423698956540247e-03  4.1e-04  1.0e+00  
    78    86    160.010  +8.423696594839578e-03  6.2e-04  1.0e+00  
    79    87    160.010  +8.423693749784765e-03  5.9e-04  1.0e+00  
    80    88    164.010  +8.423691373336607e-03  3.1e-04  1.0e+00  
    81    89    164.010  +8.423689724709164e-03  1.6e-04  1.0e+00  
    82    91    168.010  +8.423689561087022e-03  2.0e-04  4.0e-01  
    83    92    172.010  +8.423689406081498e-03  1.2e-04  1.0e+00  
    84    93    172.010  +8.423689325881282e-03  3.0e-05  1.0e+00  
    85    94    172.010  +8.423689316751977e-03  2.9e-05  1.0e+00  
    86    95    176.011  +8.423689305145607e-03  2.4e-05  1.0e+00  
    87    96    176.011  +8.423689289622477e-03  2.8e-05  1.0e+00  
    88    97    180.011  +8.423689257662553e-03  3.4e-05  1.0e+00  
    89    98    180.011  +8.423689218774710e-03  3.7e-05  1.0e+00  
    90    99    184.011  +8.423689151546083e-03  7.2e-05  1.0e+00  
    91   100    184.011  +8.423689072351309e-03  6.8e-05  1.0e+00  
    92   101    188.011  +8.423688995763033e-03  6.2e-05  1.0e+00  
    93   102    188.011  +8.423688928736774e-03  7.4e-05  1.0e+00  
    94   103    192.012  +8.423688881914616e-03  4.9e-05  1.0e+00  
    95   104    192.012  +8.423688840104407e-03  4.0e-05  1.0e+00  
    96   106    196.012  +8.423688821486053e-03  7.3e-05  4.4e-01  
    97   107    196.012  +8.423688798581467e-03  3.0e-05  1.0e+00  
    98   108    200.012  +8.423688787360375e-03  1.9e-05  1.0e+00  
    99   109    200.012  +8.423688776709048e-03  1.3e-05  1.0e+00  
   100   111    204.012  +8.423688774926129e-03  2.1e-05  4.6e-01  
   101   112    208.013  +8.423688773115171e-03  7.6e-06  1.0e+00  
   102   113    208.013  +8.423688772436546e-03  6.9e-06  1.0e+00  
   103   114    212.013  +8.423688771155470e-03  1.1e-05  1.0e+00  
   104   115    212.013  +8.423688769387254e-03  1.4e-05  1.0e+00  
   105   116    216.013  +8.423688766337282e-03  1.4e-05  1.0e+00  
   106   118    220.013  +8.423688765114607e-03  1.5e-05  2.8e-01  
   107   119    220.013  +8.423688763449228e-03  6.4e-06  1.0e+00  
   108   120    220.013  +8.423688762532369e-03  7.1e-06  1.0e+00  
   109   121    224.014  +8.423688761837404e-03  9.9e-06  1.0e+00  
   110   122    224.014  +8.423688760262529e-03  1.3e-05  1.0e+00  
   111   123    228.014  +8.423688759272251e-03  3.6e-05  1.0e+00  
   112   124    228.014  +8.423688756130365e-03  1.7e-05  1.0e+00  
   113   125    232.014  +8.423688753374270e-03  9.2e-06  1.0e+00  
   114   126    232.014  +8.423688751373724e-03  1.1e-05  1.0e+00  
   115   127    236.014  +8.423688750014176e-03  7.3e-06  1.0e+00  
   116   128    236.014  +8.423688749391211e-03  7.7e-06  1.0e+00  
   117   129    240.015  +8.423688748986261e-03  5.8e-06  1.0e+00  
# op_vmlmb_next: FRTOL test satisfied
#
OptimPackLegacy-release-1.4.0/yorick/optimpacklegacy.i000066400000000000000000000375301303525653100230070ustar00rootroot00000000000000/*
 * optimpacklegacy.i --
 *
 * Main startup file for OptimPackLegacy extension of Yorick.
 *
 *-----------------------------------------------------------------------------
 *
 * This file is part of OptimPack .
 *
 * Copyright (c) 2003-2009, 2016 Éric Thiébaut.
 *
 * OptimPack 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.
 *
 * OptimPack 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
 * OptimPack (file "LICENSE" in the top source directory); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *
 *-----------------------------------------------------------------------------
 */

if (is_func(plug_in)) plug_in, "optimpacklegacy";

local OPL_TASK_START, OPL_TASK_FG, OPL_TASK_FREEVARS, OPL_TASK_NEWX;
local OPL_TASK_CONV, OPL_TASK_WARN, OPL_TASK_ERROR;
extern opl_vmlmb_create;
/* DOCUMENT ws = opl_vmlmb_create(dims, mem, key1=val1, key2=val2, ...);

     Create a new workspace for the VMLMB algorithm.  DIMS gives the dimension
     list of the variables (like `dimsof`) and MEM is the number of previous
     steps to memorize.

     The workspace WS can be used to retrieve the following attributes:

       ws.dims ............. Dimension list of the variables.
       ws.size ............. Size of the problem (number of variables).
       ws.mem .............. Number of previous steps to memorize.
       ws.task ............. Current pending task.
       ws.evaluations ...... Number of function calls.
       ws.iterations ....... Number of iterations.
       ws.restarts ......... Number of algorithm restarts.
       ws.step ............. Lenght of the current or last step.
       ws.status ........... Current status value.
       ws.reason ........... Explanatory message about current status/task.
       ws.gnorm ............ Euclidean norm of the (projected) gradient at the
                             last successful step.
       ws.fmin ............. Strict lower bound for the function (NaN if not
                             set).
       ws.fatol ............ Absolute function tolerance for the convergence.
       ws.frtol ............ Relative function tolerance for the convergence.
       ws.sftol ............ Tolerance for the sufficient decrease condition.
       ws.sgtol ............ Tolerance for the curvature condition.
       ws.sxtol ............ Relative tolerance for an acceptable step.
       ws.delta ............ Relative size of a small step.
       ws.epsilon .......... Threshold for the sufficient descent condition.

     Attributes FMIN, FATOL, FRTOL, SFTOL, SGTOL, SXTOL, DELTA and EPSILON are
     configurable via keywords when calling `opl_vmlmb_create`, they may be
     configure later with `opl_vmlmb_configure`.  The other attributes are
     read-only.

     It not recommended to have MEM larger than the number of variables and it
     is often the case that a modest value for MEM, say MEM=5, is as efficient
     as larger values.  As you may expect, MEM has an incidence on the size of
     the neessary memory which is about `(2*m*(n + 1) + n)*sizeof(double)`
     where `n` is the number of variables and `m` is MEM.  Allocated memory is
     automatically released when the returned workspace is no longer in use.

     The pending task can take one of the following values:

       OPL_TASK_START ...... Start line search.
       OPL_TASK_FG ......... Caller has to compute function and gradient.
       OPL_TASK_FREEVARS ... Caller has to determine the free variables.
       OPL_TASK_NEWX ....... New variables available for inspection.
       OPL_TASK_CONV ....... Search has converged.
       OPL_TASK_WARN ....... Search aborted with warning.
       OPL_TASK_ERROR ...... Search aborted with error.


   SEE ALSO opl_vmlmb_configure, opl_vmlmb_iterate, dimsof.
*/

extern opl_vmlmb_configure;
/* DOCUMENT opl_vmlmb_configure, ws, key1=val1, key2=val2, ...;

     Configure VMLMB workspace WS.  Parameters are provided as keyword-value
     pairs.  See `opl_vmlmb_create` for a list of configurable settings. When
     called as a function, WS is returned.

   SEE ALSO opl_vmlmb_create
*/

extern opl_vmlmb_iterate;
/* DOCUMENT task = opl_vmlmb_iterate(ws, x, f, g);
         or task = opl_vmlmb_iterate(ws, x, f, g, isfree);
         or task = opl_vmlmb_iterate(ws, x, f, g, isfree, h);

     Perform one step of the VMLMB algorithm.  WS is VMLMB workspace, X gives
     the variables, F and G are the function value and gradient at X.  ISFREE
     is an optional array which indicates which variables are free to vary.
     H is an optional array which provides a diagonal preconditioner.  The
     returned value is the next pending task.

     All specified arrays must have the same dimensions as those expected by
     WS.  F must be a simple variable reference (not an expression), X and G
     must be arrays of double's; if specified, ISFREE is an array of int's; if
     specified, H is an array of double's.

   SEE ALSO opl_vmlmb_create, opl_vmlmb_restore.
*/

extern opl_vmlmb_restore;
/* DOCUMENT task = opl_vmlmb_restore(ws, x, f, g);

     Restore last line search starting point for VMLMB workspace WS.  Calling
     this is only effective if task is OPL_TASK_FG.  Arguments X, F and G are
     the same as in `opl_vmlmb_iterate`.

   SEE ALSO opl_vmlmb_iterate.
*/

extern opl_vmlmb_restart;
/* DOCUMENT task = opl_vmlmb_restart(ws);

      Set VMLMB workspace WS so that it can be used for a new optimization with
      the same parameters.

   SEE ALSO opl_vmlmb_create, opl_vmlmb_iterate.
*/

func opl_vmlmb(f, x, &fx, &gx, fmin=, extra=, xmin=, xmax=, flags=, mem=,
               verb=, quiet=, viewer=, printer=, maxiter=, maxeval=, output=,
               frtol=, fatol=, gatol=, grtol=, sftol=, sgtol=, sxtol=)
/* DOCUMENT opl_vmlmb(f, x);
         or opl_vmlmb(f, x, fout, gout);

     Returns a minimum of a multivariate function F by an iterative
     minimization algorithm (limited memory variable metric) possibly with
     simple bound constraints on the parameters.  F is the function
     to minimize, its prototype is:

         func f(x, &gx) {
             fx = ....; // compute function value at X
             gx = ....; // store gradient of F in GX
             return fx; // return F(X)
         }

     Argument X is the starting solution (a double precision floating point
     array).  FOUT and GOUT are optional output variables to store the value of
     F and its gradient at the minimum.

     If the multivariate function has more than one minimum, which minimum is
     returned is undefined (although it depends on the starting parameters X).

     In case of early termination, the best solution found so far is returned.


   KEYWORDS

     EXTRA - Supplemental argument for F; if non-nil, F is called as
         F(X,GX,EXTRA) so its prototype must be: func F(x, &gx, extra).  It is
         however more flexible to use a closure for F if additional data is
         needed.

     XMIN, XMAX - Lower/upper bounds for X.  Must be conformable with X.  For
         instance with XMIN=0, the non-negative solution will be returned.

     MEM - Number of previous directions used in variable metric limited memory
         method (default min(7, numberof(X))).

     MAXITER - Maximum number of iterations (default: no limits).

     MAXEVAL - Maximum number of function evaluations (default: no limits).

     FATOL, FRTOL - Relative function change tolerance for convergence
         (default: 1.5e-8).

     GATOL, GRTOL - Absolute and relative gradient tolerances for convergence
         which is assumed whenever the Euclidean norm of the (projected)
         gradient is smaller or equal max(GATOL, GRTOL*GINIT) where GINIT is
         the Euclidean norm of the (projected) initila gradient.  By default,
         GTAOL=0 and GRTOL=1e-6.

     VERB - Verbose mode?  If non-nil and non-zero, print out information every
         VERB iterations and for the final one.

     QUIET - If true and not in verbose mode, do not print warning nor
         convergence error messages.

     OUPTPUT - Output for verbose mode.  For instance, text file stream opened
         for writing.

     VIEWER - User defined subroutine to call every VERB iterations (see
         keyword VERB above)to display the solution X.  The subroutine will be
         called as:

            viewer, x, extra;

         where X is the current solution and EXTRA is the value of keyword
         EXTRA (which to see).  If the viewer uses Yorick graphics window(s) it
         may call "pause, 1;" before returning to make sure that graphics get
         correctly updated.

     PRINTER - User defined subroutine to call every VERB iterations (see
         keyword VERB above) to printout iteration information.  The subroutine
         will be called as:

            printer, output, iter, eval, cpu, fx, gnorm, steplen, x, extra;

         where OUTPUT is the value of keyword OUTPUT (which to see), ITER is
         the number of iterations, EVAL is the number of function evaluations,
         CPU is the elapsed CPU time in seconds, FX is the function value at X,
         GNORM is the Euclidean norm of the gradient at X, STEPLEN is the
         length of the step along the search direction, X is the current
         solution and EXTRA is the value of keyword EXTRA (which to see).

     SFTOL, SGTOL, SXTOL - Line search tolerance and safeguard parameters (see
        opl_csrch).

   SEE ALSO: opl_vmlmb_config, opl_vmlmb_create, opl_vmlmb_iterate.
*/
{
  /* Largest value of a long integer. */
  LONG_MAX = (1 << (sizeof(long)*8 - 1)) - 1;

  /* Get function. */
  if (is_void(f) || is_array(f)) {
    error, "expecting a function for argument F";
  }
  use_extra = (! is_void(extra));

  /* Starting parameters. */
  if ((s = structof(x)) != double && s != float && s != long &&
      s != int && s != short && s != char) {
    error, "expecting a numerical array for initial parameters X";
  }
  dims = dimsof(x);

  /* Bounds on parameters. */
  bounds = 0;
  if (! is_void(xmin)) {
    if (is_void((t = dimsof(x, xmin))) || t(1) != dims(1)
        || anyof(t != dims)) {
      error, "bad dimensions for lower bound XMIN";
    }
    if ((convert = (s = structof(xmin)) != double) && s != float &&
        s != long && s != int && s != short && s != char) {
      error, "bad data type for lower bound XMIN";
    }
    if (convert || (t = dimsof(xmin))(1) != dims(1) || anyof(t != dims)) {
      xmin += array(double, dims);
    }
    bounds |= 1;
  }
  if (! is_void(xmax)) {
    if (is_void((t = dimsof(x, xmax))) || t(1) != dims(1)
        || anyof(t != dims)) {
      error, "bad dimensions for lower bound XMAX";
    }
    if ((convert = (s = structof(xmax)) != double) && s != float &&
        s != long && s != int && s != short && s != char) {
      error, "bad data type for lower bound XMAX";
    }
    if (convert || (t = dimsof(xmax))(1) != dims(1) || anyof(t != dims)) {
      xmax += array(double, dims);
    }
    bounds |= 2;
  }

  /* Output stream. */
  if (! is_void(output)) {
    if (structof(output) == string) {
      output = open(output, "a");
    } else if (typeof(output) != "text_stream") {
      error, "bad value for keyword OUTPUT";
    }
  }

  /* Maximum number of iterations and function evaluations. */
  if (is_void(maxiter)) maxiter = LONG_MAX;
  if (is_void(maxeval)) maxeval = LONG_MAX;
  if (maxeval < 1) {
    error, "MAXEVAL must be at least 1";
  }

  /* Viewer and printer subroutines. */
  use_printer = (! is_void(printer));
  use_viewer  = (! is_void(viewer));

  /* Global convergence parameters. */
  if (is_void(gatol)) {
    gatol = 0.0;
  } else if (is_scalar(gatol) && identof(gatol) <= Y_DOUBLE &&
             gatol >= 0) {
    gatol = double(gatol);
  } else {
    error, "bad value for GATOL";
  }
  if (is_void(grtol)) {
    grtol = 0.0;
  } else if (is_scalar(grtol) && identof(grtol) <= Y_DOUBLE &&
             grtol >= 0 && grtol <= 1) {
    grtol = double(grtol);
  } else {
    error, "bad value for GRTOL";
  }
  gtest = double(gatol);

  /* Choose minimization method. */
  if (is_void(mem)) mem = min(numberof(x), 7);
  method_name = swrite(format="VMLMB %s bounds and MEM=%d",
                       (bounds != 0 ? "with" : "without"), mem);
  ws = opl_vmlmb_create(dims, mem, fmin=fmin,
                        fatol=fatol, frtol=frtol,
                        sftol=sftol, sgtol=sgtol, sxtol=sxtol);

  /* Start iterations. */
  task = 1;
  eval = 0;
  stop = 0n;
  if (verb) {
    elapsed = array(double, 3);
    timer, elapsed;
    cpu_start = elapsed(1);
  }
  if (structof(x) != double) {
    x = double(x);
  }
  local gx, gnorm, isfree, iter, step;
  task = ws.task;
  for (;;) {
    if (task == OPL_TASK_FG) {
      /* Evaluate function and gradient. */
      if (eval >= maxeval) {
        /* Too many function evaluations.  We restore the variables at the
           start of the line search which is a cheap way (no extra memory cost)
           to recover variables which should be nearly the best ones. */
        stop = 1n;
        msg = swrite(format="too many function evaluations (%d)", eval);
        opl_vmlmb_restore, ws, x, fx, gx;
      } else {
        if (bounds != 0) {
          if ((bounds & 1) == 1) {
            x = max(unref(x), xmin);
          }
          if ((bounds & 2) == 2) {
            x = min(unref(x), xmax);
          }
        }
        fx = (use_extra ? f(x, gx, extra) : f(x, gx));
        ++eval;
      }
    }
    if (task == OPL_TASK_FREEVARS && bounds != 0) {
      /* Determine the set of free variables. */
      isfree = [];
      if (bounds == 1) {
        isfree = ((x > xmin) | (gx < 0.0));
      } else if (bounds == 2) {
        isfree = ((x < xmax) | (gx > 0.0));
      } else {
        isfree = (((x > xmin) | (gx < 0.0)) & ((x < xmax) | (gx > 0.0)));
      }
    }

    /* Check for convergence. */
    if (task >= OPL_TASK_NEWX) {
      iter = ws.iterations;
      if (task >= OPL_TASK_WARN) {
        /* Error or warning. */
        stop = 1n;
        msg = ws.reason;
      } else if (ws.gnorm <= gtest) {
        stop = 1n;
        msg = swrite(format="convergence (%s)", "gradient small enough");
      } else if (iter > maxiter) {
        stop = 1n;
        msg = swrite(format="too many iterations (%d)", iter);
      }
    }
    if (verb && (stop || task >= OPL_TASK_NEWX && (iter % verb) == 0)) {
      if (eval == 1 && ! use_printer) {
        write, output, format="# Method %d (MEM=%d): %s\n#\n",
          0, mem, method_name;
        write, output, format="# %s\n# %s\n",
          "ITER  EVAL   CPU (ms)        FUNC               GNORM   STEPLEN",
          "---------------------------------------------------------------";
      }
      timer, elapsed;
      cpu = 1e3*(elapsed(1) - cpu_start);
      step = ws.step;
      gnorm = ws.gnorm;
      if (use_printer) {
        printer, output, iter, eval, cpu, fx, gnorm, step, x, extra;
      } else {
        write, output, format=" %5d %5d %10.3f  %+-24.15e%-9.1e%-9.1e\n",
          iter, eval, cpu, fx, gnorm, step;
      }
      if (use_viewer) {
        viewer, x, extra;
      }
    }
    if (stop) {
      if (msg && (verb || (task != 3 && ! quiet))) {
        write, output, format="# %s\n", strtrim(msg, 2, blank=" \t\v\n\r");
      }
      return x;
    }

    /* Call optimizer. */
    task = opl_vmlmb_iterate(ws, x, fx, gx, isfree);
  }
}

extern _opl_init;
/* DOCUMENT _opl_init;

     Restore/set global variables used by YOPL.  In principle, it is not needed
     to call this subroutine (this is automatically done at startup) unless you
     destroyed some constants.
*/
_opl_init; /* restore global variables */